118 lines
3.6 KiB
C++
118 lines
3.6 KiB
C++
#include "ortools/sat/cp_model.pb.h"
|
|
#include "ortools/sat/cp_model_solver.h"
|
|
#include "ortools/sat/cp_model_utils.h"
|
|
#include "ortools/sat/model.h"
|
|
#include "ortools/sat/sat_parameters.pb.h"
|
|
|
|
namespace operations_research {
|
|
namespace sat {
|
|
|
|
void Solve() {
|
|
CpModelProto cp_model;
|
|
cp_model.set_name("variable intervals");
|
|
|
|
// Helpers. (will be obsolete in the next release (v6.10))
|
|
auto new_variable = [&cp_model](int64 lb, int64 ub) {
|
|
CHECK_LE(lb, ub);
|
|
const int index = cp_model.variables_size();
|
|
IntegerVariableProto* const var = cp_model.add_variables();
|
|
var->add_domain(lb);
|
|
var->add_domain(ub);
|
|
return index;
|
|
};
|
|
|
|
auto new_constant = [&cp_model, &new_variable](int64 v) {
|
|
return new_variable(v, v);
|
|
};
|
|
|
|
auto new_interval = [&cp_model](int start, int duration, int end) {
|
|
const int index = cp_model.constraints_size();
|
|
ConstraintProto* const ct = cp_model.add_constraints();
|
|
ct->mutable_interval()->set_start(start);
|
|
ct->mutable_interval()->set_size(duration);
|
|
ct->mutable_interval()->set_end(end);
|
|
return index;
|
|
};
|
|
|
|
auto add_precedence = [&cp_model](int before, int after) {
|
|
LinearConstraintProto* const lin =
|
|
cp_model.add_constraints()->mutable_linear();
|
|
lin->add_vars(after);
|
|
lin->add_coeffs(1L);
|
|
lin->add_vars(before);
|
|
lin->add_coeffs(-1L);
|
|
lin->add_domain(0);
|
|
lin->add_domain(kint64max);
|
|
};
|
|
|
|
auto add_sum_equal = [&cp_model](const std::vector<int> vars, int64 value) {
|
|
LinearConstraintProto* const lin =
|
|
cp_model.add_constraints()->mutable_linear();
|
|
for (const int var : vars) {
|
|
lin->add_vars(var);
|
|
lin->add_coeffs(1L);
|
|
}
|
|
lin->add_domain(value);
|
|
lin->add_domain(value);
|
|
};
|
|
|
|
auto add_no_overlap = [&cp_model](const std::vector<int>& intervals) {
|
|
NoOverlapConstraintProto* const no_overlap =
|
|
cp_model.add_constraints()->mutable_no_overlap();
|
|
for (const int i : intervals) {
|
|
no_overlap->add_intervals(i);
|
|
}
|
|
};
|
|
|
|
// Actual model.
|
|
|
|
const int start_ins = new_variable(660, 755);
|
|
const int duration_ins = new_constant(25);
|
|
const int end_ins = new_variable(685, 780);
|
|
const int ins = new_interval(start_ins, duration_ins, end_ins);
|
|
|
|
const int start_p1 = new_variable(500, 800);
|
|
const int duration_p1 = new_variable(1, 360);
|
|
const int end_p1 = new_variable(500, 1000);
|
|
const int p1 = new_interval(start_p1, duration_p1, end_p1);
|
|
|
|
const int start_p2 = new_variable(500, 800);
|
|
const int duration_p2 = new_variable(1, 360);
|
|
const int end_p2 = new_variable(500, 1000);
|
|
const int p2 = new_interval(start_p2, duration_p2, end_p2);
|
|
|
|
add_sum_equal({duration_p1, duration_p2}, 360);
|
|
add_precedence(end_p1, start_p2);
|
|
|
|
add_no_overlap({ins, p1, p2});
|
|
|
|
Model model;
|
|
|
|
// Tell the solver to enumerate all solutions.
|
|
SatParameters parameters;
|
|
parameters.set_enumerate_all_solutions(true);
|
|
model.Add(NewSatParameters(parameters));
|
|
|
|
int num_solutions = 0;
|
|
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse& r) {
|
|
LOG(INFO) << "Solution " << num_solutions;
|
|
LOG(INFO) << " start_p1 = " << r.solution(start_p1);
|
|
LOG(INFO) << " duration_p1 = " << r.solution(duration_p1);
|
|
LOG(INFO) << " start_p2 = " << r.solution(start_p2);
|
|
LOG(INFO) << " duration_p2 = " << r.solution(duration_p2);
|
|
LOG(INFO) << " start_ins = " << r.solution(start_ins);
|
|
num_solutions++;
|
|
}));
|
|
const CpSolverResponse response = SolveCpModel(cp_model, &model);
|
|
LOG(INFO) << "Number of solutions found: " << num_solutions;
|
|
}
|
|
|
|
} // namespace sat
|
|
} // namespace operations_research
|
|
|
|
int main() {
|
|
operations_research::sat::Solve();
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|