Closed timothylowjc closed 4 years ago
A follow up from a friend:
The following code block also produces infeasible:
from ortools.sat.python import cp_model
model = cp_model.CpModel()
start_bool = model.NewBoolVar("x0")
fill_2_bool = model.NewBoolVar("x2")
fill_8_bool = model.NewBoolVar("x8")
empty_12_bool = model.NewBoolVar("x12")
start = model.NewIntVar(0, 0, "start")
fill_time_2 = model.NewIntVar(2, 2, "fill_time_2")
fill_time_8 = model.NewIntVar(8, 8, "fill_time_8",)
empty_time_12 = model.NewIntVar(12, 12, "empty_time_12")
times = [start, fill_time_2, fill_time_8, empty_time_12]
demands = [10, 1, 1, -3]
actives = [start_bool, fill_2_bool, fill_8_bool, empty_12_bool]
model.AddReservoirConstraintWithActive(times, demands, actives, 0, 20)
model.Add(start_bool == 1)
model.Add(fill_2_bool == 0)
model.Add(fill_8_bool == 1)
# model.Add(empty_12_bool == 0)
solver = cp_model.CpSolver()
solver.Solve(model)
print(solver.ResponseStats())
print(solver.Value(start_bool), solver.Value(fill_2_bool), solver.Value(fill_8_bool), solver.Value(empty_12_bool))
On ortools 7.5.7466
Thanks Mizux! You're the best!
C++ version:
#include "ortools/sat/cp_model.h"
#include <stdexcept>
#include <vector>
#include <list>
#include <functional>
namespace operations_research {
namespace sat {
ReservoirConstraint AddReservoirConstraintWithActive(
CpModelBuilder& model,
const std::vector<std::reference_wrapper<const IntVar>>& times,
const std::vector<int>& demands,
const std::vector<std::reference_wrapper<const BoolVar>>& actives,
int64 min_level,
int64 max_level) {
if (max_level < min_level) {
throw std::invalid_argument("Reservoir constraint must have a max_level >= min_level");
}
ReservoirConstraint rc = model.AddReservoirConstraint(min_level, max_level);
ConstraintProto* ct_proto = rc.MutableProto();
ReservoirConstraintProto* reservoir = ct_proto->mutable_reservoir();
for(const auto& it : times) {
reservoir->add_times(it.get().index());
}
for(auto it : demands) {
reservoir->add_demands(it);
}
for(const auto& it : actives) {
reservoir->add_actives(it.get().index());
}
reservoir->set_min_level(min_level);
reservoir->set_max_level(max_level);
return rc;
}
void SimpleSatProgram() {
CpModelBuilder model;
const BoolVar start_bool = model.NewBoolVar().WithName("x0");
const BoolVar fill_2_bool = model.NewBoolVar().WithName("x2");
const BoolVar fill_8_bool = model.NewBoolVar().WithName("x8");
const BoolVar empty_12_bool = model.NewBoolVar().WithName("x12");
//const Domain domain(0, 2);
const IntVar start = model.NewIntVar({0, 0}).WithName("start");
const IntVar fill_time_2 = model.NewIntVar({2, 2}).WithName("fill_time_2");
const IntVar fill_time_8 = model.NewIntVar({8, 8}).WithName("fill_time_8");
const IntVar empty_time_12 = model.NewIntVar({12, 12}).WithName("empty_time_8");
std::vector<std::reference_wrapper<const IntVar>> times { start, fill_time_2, fill_time_8, empty_time_12 };
std::vector<int> demands {10, 1, 1, -3};
std::vector<std::reference_wrapper<const BoolVar>> actives { start_bool, fill_2_bool, fill_8_bool, empty_12_bool };
AddReservoirConstraintWithActive(model, times, demands, actives, 0, 20);
model.AddEquality(start_bool, true);
model.AddEquality(fill_2_bool, false);
model.AddEquality(fill_8_bool, true);
//model.AddEquality(empty_12_bool, false);
// Solving part.
const CpSolverResponse response = Solve(model.Build());
LOG(INFO) << CpSolverResponseStats(response);
if (response.status() == CpSolverStatus::FEASIBLE) {
// Get the value of x in the solution.
LOG(INFO) << "start_bool = " << SolutionIntegerValue(response, start_bool);
LOG(INFO) << "fill_2_bool = " << SolutionIntegerValue(response, fill_2_bool);
LOG(INFO) << "fill_8_bool = " << SolutionIntegerValue(response, fill_8_bool);
LOG(INFO) << "empty_12_bool = " << SolutionIntegerValue(response, empty_12_bool);
}
}
} // namespace sat
} // namespace operations_research
int main() {
operations_research::sat::SimpleSatProgram();
return EXIT_SUCCESS;
}
I just pushed the fix. Thanks again for the report.
What version of OR-tools and what language are you using? Version: master, 7.5.7515 Language: Python
Which solver are you using (e.g. CP-SAT, Routing Solver, GLOP, BOP, Gurobi) CP-SAT
What operating system (Linux, Windows, ...) and version? Windows Subsystem Linux, Ubuntu 18.04
What did you do? Model was working perfectly, until I attempted to port my model into master last week. This required me to run all the specific apt-get commands as stipulated in https://developers.google.com/optimization/install/python/source_linux
After which I attempted to run the solver again, and suddenly it begins to produce conflicts, or solverstatus = 3.
From investigation, it seems to be caused by the AddReservoirConstraintWithActive constraints. This "infeasible" only occurs when I attempt to set a relevant "Active" in these constraints, such as x[1,1], to a constant value using a constraint, such as model.Add(x[1,1] == 1), with a corresponding IntVar, such as starts[1,1], that is used in a relevant IntervalVar as well.
I've also tested this by setting a AddReservoirConstraintWithActive constraint with my "actives" just being a list of zeroes. Produces the "infeasible" as well. NumConflicts is also = 0.
I believe the bug is most likely something to do with setting up a reservoir constraint, by pairing a constant active to a variable IntVar. Apologies if I'm wrong.
What did you expect to see Prior to this week the model would at least solve. The reservoir constraint was definitely functional, and I could force booleans to be true or false using model.Add(x[1,1] == 1) or 0, without causing any "infeasible".
Proto as below. Apologies if I did something wrong, or if I'm posting in the wrong area.
modelproto.txt
piplist if useful: