From 9d9ca5ccaf5273eda89c3324b3d8dd44d52a75d2 Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Sat, 4 Nov 2023 20:58:00 +0100 Subject: [PATCH] add hinting support for model_builder --- .../ortools/modelbuilder/ModelBuilder.java | 10 ++++++++++ ortools/linear_solver/csharp/ModelBuilder.cs | 15 +++++++++++++++ ortools/linear_solver/csharp/model_builder.i | 4 ++++ ortools/linear_solver/java/modelbuilder.i | 4 ++++ ortools/linear_solver/python/model_builder.py | 18 ++++++++++++++++++ .../python/model_builder_helper.cc | 2 ++ .../wrappers/model_builder_helper.cc | 9 +++++++++ .../wrappers/model_builder_helper.h | 3 +++ 8 files changed, 65 insertions(+) diff --git a/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java b/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java index 86da1f31fd..7b955fd300 100644 --- a/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java +++ b/ortools/java/com/google/ortools/modelbuilder/ModelBuilder.java @@ -208,6 +208,16 @@ public final class ModelBuilder { helper.setObjectiveOffset(offset); } + /** Clears all hints from the solver. */ + void clearHints() { + helper.clearHints(); + } + + /** Adds var == value as a hint to the model. Note that variables must not appear more than once in the list of hints. */ + void addHint(Variable var, double value) { + helper.addHint(var.getIndex(), value); + } + // Model getters, import, export. /** Returns the name of the model. */ diff --git a/ortools/linear_solver/csharp/ModelBuilder.cs b/ortools/linear_solver/csharp/ModelBuilder.cs index 95b24a5d8e..21dd0e0669 100644 --- a/ortools/linear_solver/csharp/ModelBuilder.cs +++ b/ortools/linear_solver/csharp/ModelBuilder.cs @@ -262,6 +262,21 @@ public class ModelBuilder } } + /// + /// Remove all hints from the model. + /// + public void ClearHints() { + helper_.ClearHints(); + } + + /// + /// Adds var == value as a hint to the model. Note that variables must not appear more than once in the list of hints. + /// + public void AddHint(Variable var, double value) + { + helper_.AddHint(var.Index, value); + } + /// /// The name of the model. /// diff --git a/ortools/linear_solver/csharp/model_builder.i b/ortools/linear_solver/csharp/model_builder.i index c66c7a2760..afdc1a7fc5 100644 --- a/ortools/linear_solver/csharp/model_builder.i +++ b/ortools/linear_solver/csharp/model_builder.i @@ -86,6 +86,10 @@ VECTOR_AS_CSHARP_ARRAY(double, double, double, DoubleVector); %unignore operations_research::ModelBuilderHelper::ObjectiveOffset; %unignore operations_research::ModelBuilderHelper::SetObjectiveOffset; +// Hints +%unignore operations_research::ModelBuilderHelper::ClearHints; +%unignore operations_research::ModelBuilderHelper::AddHint; + // Model API. %rename (Name) operations_research::ModelBuilderHelper::name; %unignore operations_research::ModelBuilderHelper::SetName; diff --git a/ortools/linear_solver/java/modelbuilder.i b/ortools/linear_solver/java/modelbuilder.i index e8581b15f3..e071715f09 100644 --- a/ortools/linear_solver/java/modelbuilder.i +++ b/ortools/linear_solver/java/modelbuilder.i @@ -144,6 +144,10 @@ class GlobalRefGuard { %rename (getObjectiveOffset) operations_research::ModelBuilderHelper::ObjectiveOffset; %rename (setObjectiveOffset) operations_research::ModelBuilderHelper::SetObjectiveOffset; +// Hints. +%rename (clearHints) operations_research::ModelBuilderHelper::ClearHints; +%rename (addHint) operations_research::ModelBuilderHelper::AddHint; + // Model API. %rename (getName) operations_research::ModelBuilderHelper::name; %rename (setName) operations_research::ModelBuilderHelper::SetName; diff --git a/ortools/linear_solver/python/model_builder.py b/ortools/linear_solver/python/model_builder.py index 95001c9595..7c464f45b0 100644 --- a/ortools/linear_solver/python/model_builder.py +++ b/ortools/linear_solver/python/model_builder.py @@ -1115,13 +1115,16 @@ class ModelBuilder: @property def num_constraints(self) -> int: + """The number of constraints in the model.""" return self.__helper.num_constraints() # Objective. def minimize(self, linear_expr: LinearExprT) -> None: + """Minimize the given objective.""" self.__optimize(linear_expr, False) def maximize(self, linear_expr: LinearExprT) -> None: + """Maximize the given objective.""" self.__optimize(linear_expr, True) def __optimize(self, linear_expr: LinearExprT, maximize: bool) -> None: @@ -1146,6 +1149,7 @@ class ModelBuilder: @property def objective_offset(self) -> np.double: + """Returns the fixed offset of the objective.""" return self.__helper.objective_offset() @objective_offset.setter @@ -1153,6 +1157,7 @@ class ModelBuilder: self.__helper.set_objective_offset(value) def objective_expression(self) -> "_LinearExpression": + """Returns the expression to optimize.""" return _as_flat_linear_expression( sum( variable * self.__helper.var_objective_coefficient(variable.index) @@ -1162,6 +1167,18 @@ class ModelBuilder: + self.__helper.objective_offset() ) + # Hints. + def clear_hints(self): + """Clear all solution hints.""" + self.__helper.clear_hints(); + + def add_hint(self, var:Variable, value:NumberT): + """Add var == value as a hint to the model. + + Note that variables must not appear more than once in the list of hints. + """ + self.__helper.add_hint(var.index, value) + # Input/Output def export_to_lp_string(self, obfuscate: bool = False) -> str: options: mbh.MPModelExportOptions = mbh.MPModelExportOptions() @@ -1192,6 +1209,7 @@ class ModelBuilder: # Utilities @property def name(self) -> str: + """The name of the model.""" return self.__helper.name() @name.setter diff --git a/ortools/linear_solver/python/model_builder_helper.cc b/ortools/linear_solver/python/model_builder_helper.cc index c597ac80c3..35f224763f 100644 --- a/ortools/linear_solver/python/model_builder_helper.cc +++ b/ortools/linear_solver/python/model_builder_helper.cc @@ -345,6 +345,8 @@ PYBIND11_MODULE(model_builder_helper, m) { .def("set_objective_offset", &ModelBuilderHelper::SetObjectiveOffset, arg("offset")) .def("objective_offset", &ModelBuilderHelper::ObjectiveOffset) + .def("clear_hints", &ModelBuilderHelper::ClearHints) + .def("add_hint", &ModelBuilderHelper::AddHint, arg("var_index"), arg("var_value")) .def("sort_and_regroup_terms", [](ModelBuilderHelper* helper, py::array_t indices, py::array_t coefficients) { diff --git a/ortools/linear_solver/wrappers/model_builder_helper.cc b/ortools/linear_solver/wrappers/model_builder_helper.cc index 277debb5c7..26fee427f7 100644 --- a/ortools/linear_solver/wrappers/model_builder_helper.cc +++ b/ortools/linear_solver/wrappers/model_builder_helper.cc @@ -266,6 +266,15 @@ void ModelBuilderHelper::SetObjectiveOffset(double offset) { model_.set_objective_offset(offset); } +void ModelBuilderHelper::ClearHints() { + model_.clear_solution_hint(); +} + +void ModelBuilderHelper::AddHint(int var_index, double var_value) { + model_.mutable_solution_hint()->add_var_index(var_index); + model_.mutable_solution_hint()->add_var_value(var_value); +} + std::optional ModelSolverHelper::SolveRequest( const MPModelRequest& request) { if (!MPSolver::SupportsProblemType( diff --git a/ortools/linear_solver/wrappers/model_builder_helper.h b/ortools/linear_solver/wrappers/model_builder_helper.h index 28bc659d43..483c44980a 100644 --- a/ortools/linear_solver/wrappers/model_builder_helper.h +++ b/ortools/linear_solver/wrappers/model_builder_helper.h @@ -102,6 +102,9 @@ class ModelBuilderHelper { double ObjectiveOffset() const; void SetObjectiveOffset(double offset); + void ClearHints(); + void AddHint(int var_index, double var_value); + private: MPModelProto model_; };