簡體   English   中英

或工具:瑣碎的問題在cpp中不可行,但在python中有效

[英]or-tools: Trivial problem is infeasible in cpp, but works in python

我遇到了一個優化問題,在該問題中,瑣碎的可行約束導致我的cpp程序在嘗試解決時返回“不可行”。

為了演示,我創建了一個由3名護士和5個插槽組成的護士時間表優化程序。

我有兩個瑣碎的約束條件:1)第一位護士占用第一個空位,以及2)每個插槽中最多允許一位護士。

一次使用一個約束時,這些約束導致or-tools返回一個可行的解決方案,但是當我同時使用兩個約束時,則得到了一個不可行的解決方案。 即使同時使用了兩個約束,完全相同的問題在python API中也能正常工作。

我懷疑我在設置第一個約束( cp_model.AddEquality(LinearExpr(slots[0][0]), 1); )時以某種方式濫用了AddEquality ,但是我無法弄清楚問題出在哪里。

請幫忙。

#include <iostream>
#include <vector>

#include "ortools/sat/cp_model.h"
#include "ortools/sat/sat_parameters.pb.h"

namespace operations_research {

namespace sat {
void slots(bool add_sum, bool add_const) {

  CpModelBuilder cp_model;

  const int num_nurses = 3;
  const int num_slots = 5;

  std::vector<std::vector<IntVar>> slots(num_nurses);

  for (int n = 0; n < num_nurses; n++) {
    for (int d = 0; d < num_slots; d++) {
      const IntVar var = cp_model.NewIntVar({0, 1});
      slots[n].push_back(var);
    }
  }

  if (add_const) {
    // trival constraint
    cp_model.AddEquality(LinearExpr(slots[0][0]), 1);
  }

  if (add_sum) {
    // make the first row sum to one; should be trivial too
    std::vector<IntVar> this_nurse_vals(num_nurses);
    for (int n = 0; n < num_nurses; n++) {
      const IntVar var = slots[n][0];
      this_nurse_vals.push_back(var);
    }
    cp_model.AddEquality(LinearExpr::Sum(this_nurse_vals), 1);
  }

  // solve
  const CpSolverResponse response = Solve(cp_model.Build());
  LOG(INFO) << CpSolverResponseStats(response);

  for (int d = 0; d < num_slots; d++) {
    for (int n = 0; n < num_nurses; n++) {
      std::cout << SolutionIntegerValue(response, slots[n][d]);
    }
    std::cout << std::endl;
  }
  std::cout << std::endl;

  // [END solve]
}

} // namespace sat
} // namespace operations_research

// ----- MAIN -----
int main(int argc, char **argv) {
  operations_research::sat::slots(false, true); // works
  operations_research::sat::slots(true, false); // works
  operations_research::sat::slots(true, true);  // infeasible

  return EXIT_SUCCESS;
}
// [END program]

在python中可以正常工作的相同程序:

from ortools.sat.python import cp_model
num_nurses = 3
num_slots = 5

model = cp_model.CpModel()

# make vars
slots = {}
for n in range(num_nurses):
    for d in range(num_slots):
        slots[(n, d)] = model.NewIntVar(0, 1, "slot")


model.Add(slots[(0, 0)] == 1)

model.Add(sum(slots[(n, 0)] for n in range(num_nurses)) == 1)

solver = cp_model.CpSolver()

solver.Solve(model)

solution = []


for d in range(num_slots):
    solution.append([])
    for n in range(num_nurses):
        solution[d].append(solver.Value(slots[(n, d)]))

print(solution)

你的護士太多了。

這個:

std::vector<IntVar> this_nurse_vals(num_nurses);

num_nurses元素創建一個向量。
然后,您將另一個num_nurses元素push_back num_nurses ,從而獲得所需的兩倍。

要么以一個空向量開始,然后將push_back插入其中:

std::vector<IntVar> this_nurse_vals;
for (int n = 0; n < num_nurses; n++) {
    this_nurse_vals.push_back(IntVar(slots[n][0]));
}

或以“完整”向量開始並分配給它:

std::vector<IntVar> this_nurse_vals(num_nurses);
for (int n = 0; n < num_nurses; n++) {
    this_nurse_vals[n] = IntVar(slots[n][0]);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM