change solution observer on sat to take a CpSolverResponse as parameter
This commit is contained in:
@@ -173,7 +173,7 @@ void Solve(const std::vector<int>& durations, const std::vector<int>& due_dates,
|
||||
// Optional preprocessing: add precedences that don't change the optimal
|
||||
// solution value.
|
||||
//
|
||||
// Proof: in any schedule, if such precendece between task A and B is not
|
||||
// Proof: in any schedule, if such precedence between task A and B is not
|
||||
// satisfied, then it is always better (or the same) to swap A and B. This is
|
||||
// because the tasks between A and B will be completed earlier (because the
|
||||
// duration of A is smaller), and the cost of the swap itself is also smaller.
|
||||
@@ -211,15 +211,15 @@ void Solve(const std::vector<int>& durations, const std::vector<int>& due_dates,
|
||||
// lower bound for the objective and the tardiness variables.
|
||||
Model model;
|
||||
model.Add(NewSatParameters(FLAGS_params));
|
||||
model.Add(NewFeasibleSolutionObserver([&](const std::vector<int64>& values) {
|
||||
model.Add(NewFeasibleSolutionObserver([&](const CpSolverResponse& r) {
|
||||
// Note that we conpute the "real" cost here and do not use the tardiness
|
||||
// variables. This is because in the core based appraoch, the tardiness
|
||||
// variables. This is because in the core based approach, the tardiness
|
||||
// variable might be fixed before the end date, and we just have a >=
|
||||
// relation.
|
||||
int64 objective = 0;
|
||||
for (int i = 0; i < num_tasks; ++i) {
|
||||
objective +=
|
||||
weights[i] * std::max(0ll, values[tasks_end[i]] - due_dates[i]);
|
||||
weights[i] * std::max<int64>(0ll, r.solution(tasks_end[i]) - due_dates[i]);
|
||||
}
|
||||
LOG(INFO) << "Cost " << objective;
|
||||
|
||||
@@ -227,21 +227,21 @@ void Solve(const std::vector<int>& durations, const std::vector<int>& due_dates,
|
||||
std::vector<int> sorted_tasks(num_tasks);
|
||||
std::iota(sorted_tasks.begin(), sorted_tasks.end(), 0);
|
||||
std::sort(sorted_tasks.begin(), sorted_tasks.end(), [&](int v1, int v2) {
|
||||
return values[tasks_start[v1]] < values[tasks_start[v2]];
|
||||
return r.solution(tasks_start[v1]) < r.solution(tasks_start[v2]);
|
||||
});
|
||||
std::string solution = "0";
|
||||
int end = 0;
|
||||
for (const int i : sorted_tasks) {
|
||||
const int64 cost = weights[i] * values[tardiness_vars[i]];
|
||||
const int64 cost = weights[i] * r.solution(tardiness_vars[i]);
|
||||
StrAppend(&solution, "| #", i, " ");
|
||||
if (cost > 0) {
|
||||
// Display the cost in red.
|
||||
StrAppend(&solution, "\033[1;31m(+", cost, ") \033[0m");
|
||||
}
|
||||
StrAppend(&solution, "|", values[tasks_end[i]]);
|
||||
CHECK_EQ(end, values[tasks_start[i]]);
|
||||
StrAppend(&solution, "|", r.solution(tasks_end[i]));
|
||||
CHECK_EQ(end, r.solution(tasks_start[i]));
|
||||
end += durations[i];
|
||||
CHECK_EQ(end, values[tasks_end[i]]);
|
||||
CHECK_EQ(end, r.solution(tasks_end[i]));
|
||||
}
|
||||
LOG(INFO) << "solution: " << solution;
|
||||
}));
|
||||
|
||||
@@ -863,10 +863,10 @@ void SolveFzWithCpModelProto(const fz::Model& fz_model,
|
||||
if (FLAGS_use_flatzinc_format && p.all_solutions) {
|
||||
int solution_count = 1; // Start at 1 as in the sat solver output.
|
||||
auto printer = [&fz_model, &solution_count,
|
||||
&m](const std::vector<int64>& values) {
|
||||
&m](const sat::CpSolverResponse& response) {
|
||||
const std::string solution_string =
|
||||
SolutionString(fz_model, [&values, &m](fz::IntegerVariable* v) {
|
||||
return values[m.fz_var_to_index[v]];
|
||||
SolutionString(fz_model, [&response, &m](fz::IntegerVariable* v) {
|
||||
return response.solution(m.fz_var_to_index[v]);
|
||||
});
|
||||
std::cout << "%% solution #" << solution_count++ << std::endl;
|
||||
std::cout << solution_string << std::endl;
|
||||
|
||||
@@ -65,7 +65,7 @@ message IntegerVariableProto {
|
||||
// value in its domain. As of 2017/09/18, only linear constraints with two
|
||||
// terms support this (i.e. precedence constraints).
|
||||
//
|
||||
// This can be a powerfull concept because it allows the solver to propagate
|
||||
// This can be a powerful concept because it allows the solver to propagate
|
||||
// the variable regardless of the enforcement literal, and if its domain
|
||||
// become empty, it can propagate this literal to false.
|
||||
repeated int32 enforcement_literal = 3;
|
||||
@@ -220,7 +220,7 @@ message ConstraintProto {
|
||||
// constraint must be true when this literal is true, if it is false, then it
|
||||
// doesn't matter. This is also called half-reification. To have an
|
||||
// equivalence between a literal and a constraint (full reification), one must
|
||||
// add both a constraint (controled by a literal l) and its negation
|
||||
// add both a constraint (controlled by a literal l) and its negation
|
||||
// (controlled by the negation of l).
|
||||
repeated int32 enforcement_literal = 2;
|
||||
|
||||
|
||||
@@ -1977,11 +1977,11 @@ void ExtractLinearObjective(const CpModelProto& model_proto,
|
||||
// Used by NewFeasibleSolutionObserver to register observers.
|
||||
struct SolutionObservers {
|
||||
explicit SolutionObservers(Model* model) {}
|
||||
std::vector<std::function<void(const std::vector<int64>& values)>> observers;
|
||||
std::vector<std::function<void(const CpSolverResponse& response)>> observers;
|
||||
};
|
||||
|
||||
std::function<void(Model*)> NewFeasibleSolutionObserver(
|
||||
const std::function<void(const std::vector<int64>& values)>& observer) {
|
||||
const std::function<void(const CpSolverResponse& response)>& observer) {
|
||||
return [=](Model* model) {
|
||||
model->GetOrCreate<SolutionObservers>()->observers.push_back(observer);
|
||||
};
|
||||
@@ -2378,14 +2378,7 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model) {
|
||||
model_proto, true,
|
||||
[&](const CpSolverResponse& response) {
|
||||
for (const auto& observer : observers) {
|
||||
if (response.solution().empty()) {
|
||||
observer(
|
||||
std::vector<int64>(response.solution_lower_bounds().begin(),
|
||||
response.solution_lower_bounds().end()));
|
||||
} else {
|
||||
observer(std::vector<int64>(response.solution().begin(),
|
||||
response.solution().end()));
|
||||
}
|
||||
observer(response);
|
||||
}
|
||||
},
|
||||
model);
|
||||
@@ -2405,13 +2398,7 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model) {
|
||||
CpSolverResponse copy = response;
|
||||
PostsolveResponse(model_proto, mapping_proto, postsolve_mapping, ©);
|
||||
for (const auto& observer : observers) {
|
||||
if (copy.solution().empty()) {
|
||||
observer(std::vector<int64>(copy.solution_lower_bounds().begin(),
|
||||
copy.solution_lower_bounds().end()));
|
||||
} else {
|
||||
observer(std::vector<int64>(copy.solution().begin(),
|
||||
copy.solution().end()));
|
||||
}
|
||||
observer(copy);
|
||||
}
|
||||
},
|
||||
model);
|
||||
|
||||
@@ -49,11 +49,8 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model);
|
||||
//
|
||||
// Hack: For the non-fully instantiated variables, the value will be the
|
||||
// propagated lower bound. Note that this will be fixed with the TODO below.
|
||||
//
|
||||
// TODO(user): Change the API to take the full CpSolverResponse() so we have
|
||||
// solve statistics and the current objective value.
|
||||
std::function<void(Model*)> NewFeasibleSolutionObserver(
|
||||
const std::function<void(const std::vector<int64>& values)>& observer);
|
||||
const std::function<void(const CpSolverResponse& response)>& observer);
|
||||
|
||||
// Allows to change the default parameters with
|
||||
// model->Add(NewSatParameters(parameters_as_string_or_proto))
|
||||
|
||||
@@ -43,6 +43,7 @@ PY_PROTO_TYPEMAP(ortools.sat.sat_parameters_pb2,
|
||||
%unignore operations_research::sat::SatHelper;
|
||||
%unignore operations_research::sat::SatHelper::Solve;
|
||||
%unignore operations_research::sat::SatHelper::SolveWithParameters;
|
||||
%unignore operations_research::sat::SatHelper::SolveWithParametersAndSolutionObserver;
|
||||
|
||||
%include "ortools/sat/swig_helper.h"
|
||||
|
||||
|
||||
@@ -43,6 +43,18 @@ class SatHelper {
|
||||
model.Add(NewSatParameters(parameters));
|
||||
return SolveCpModel(model_proto, &model);
|
||||
}
|
||||
|
||||
static operations_research::sat::CpSolverResponse
|
||||
SolveWithParametersAndSolutionObserver(
|
||||
const operations_research::sat::CpModelProto& model_proto,
|
||||
const operations_research::sat::SatParameters& parameters,
|
||||
const std::function<void(const operations_research::sat::CpSolverResponse&
|
||||
response)>& observer) {
|
||||
Model model;
|
||||
model.Add(NewSatParameters(parameters));
|
||||
model.Add(NewFeasibleSolutionObserver(observer));
|
||||
return SolveCpModel(model_proto, &model);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sat
|
||||
|
||||
Reference in New Issue
Block a user