From d86dfadc8664e7d9cb65a20007db294da9bc0f4d Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Tue, 24 Oct 2023 11:41:30 +0200 Subject: [PATCH] add model cloning to model_builder python + sample --- ortools/linear_solver/python/model_builder.py | 6 ++ .../python/model_builder_helper.cc | 1 + ortools/linear_solver/samples/BUILD.bazel | 2 + .../linear_solver/samples/copy_model_mb.py | 92 +++++++++++++++++++ .../wrappers/model_builder_helper.cc | 4 + .../wrappers/model_builder_helper.h | 1 + 6 files changed, 106 insertions(+) create mode 100644 ortools/linear_solver/samples/copy_model_mb.py diff --git a/ortools/linear_solver/python/model_builder.py b/ortools/linear_solver/python/model_builder.py index e601031d2b..95001c9595 100644 --- a/ortools/linear_solver/python/model_builder.py +++ b/ortools/linear_solver/python/model_builder.py @@ -631,6 +631,12 @@ class ModelBuilder: def __init__(self): self.__helper: mbh.ModelBuilderHelper = mbh.ModelBuilderHelper() + def clone(self) -> "ModelBuilder": + """Returns a clone of the current model.""" + clone = ModelBuilder() + clone.helper.overwrite_model(self.helper) + return clone + @typing.overload def _get_linear_constraints(self, constraints: Optional[pd.Index]) -> pd.Index: ... diff --git a/ortools/linear_solver/python/model_builder_helper.cc b/ortools/linear_solver/python/model_builder_helper.cc index 4759581fac..6de3bbaad3 100644 --- a/ortools/linear_solver/python/model_builder_helper.cc +++ b/ortools/linear_solver/python/model_builder_helper.cc @@ -169,6 +169,7 @@ PYBIND11_MODULE(model_builder_helper, m) { py::class_(m, "ModelBuilderHelper") .def(py::init<>()) + .def("overwrite_model", &ModelBuilderHelper::OverwriteModel, arg("other_helper")) .def("export_to_mps_string", &ModelBuilderHelper::ExportToMpsString, arg("options") = MPModelExportOptions()) .def("export_to_lp_string", &ModelBuilderHelper::ExportToLpString, diff --git a/ortools/linear_solver/samples/BUILD.bazel b/ortools/linear_solver/samples/BUILD.bazel index 0221c51fa8..2a0c4f37c2 100644 --- a/ortools/linear_solver/samples/BUILD.bazel +++ b/ortools/linear_solver/samples/BUILD.bazel @@ -44,6 +44,8 @@ code_sample_py(name = "assignment_mb") code_sample_py(name = "bin_packing_mb") +code_sample_py(name = "copy_model_mb") + code_sample_py(name = "simple_lp_program_mb") code_sample_py(name = "simple_mip_program_mb") diff --git a/ortools/linear_solver/samples/copy_model_mb.py b/ortools/linear_solver/samples/copy_model_mb.py new file mode 100644 index 0000000000..3b20fec4a9 --- /dev/null +++ b/ortools/linear_solver/samples/copy_model_mb.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# Copyright 2010-2022 Google LLC +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START program] +"""Integer programming examples that show how to use the APIs.""" +# [START import] +import math + +from ortools.linear_solver.python import model_builder +# [END import] + + +def main(): + # [START model] + # Create the model. + model = model_builder.ModelBuilder() + # [END model] + + # [START variables] + # x and y are integer non-negative variables. + x = model.new_int_var(0.0, math.inf, "x") + y = model.new_int_var(0.0, math.inf, "y") + # [END variables] + + # [START constraints] + # x + 7 * y <= 17.5. + c1 = model.add(x + 7 * y <= 17.5) + + # x <= 3.5. + c2 = model.add(x <= 3.5) + # [END constraints] + + # [START objective] + # Maximize x + 10 * y. + model.maximize(x + 10 * y) + # [END objective] + + # Deep copy. + print("Cloning the model.") + model_copy = model.clone() + x_copy = model_copy.var_from_index(x.index) + y_copy = model_copy.var_from_index(y.index) + z_copy = model_copy.new_bool_var("z") + c2_copy = model_copy.linear_constraint_from_index(c2.index) + + # Add new constraint. + model_copy.add(x_copy >= 1) + print("Number of constraints in original model =", model.num_constraints) + print("Number of constraints in cloned model =", model_copy.num_constraints) + + # Modify a constraint. + c2_copy.add_term(z_copy, 2.0) + + print(model_copy.export_to_lp_string()) + + # [START solve] + # Create the solver with the SCIP backend, and solve the model. + solver = model_builder.ModelSolver("scip") + status = solver.solve(model_copy) + # [END solve] + + # [START print_solution] + if status == model_builder.SolveStatus.OPTIMAL: + print("Solution:") + print("Objective value =", solver.objective_value) + print("x =", solver.value(x_copy)) + print("y =", solver.value(y_copy)) + print("z =", solver.value(z_copy)) + else: + print("The problem does not have an optimal solution.") + # [END print_solution] + + # [START advanced] + print("\nAdvanced usage:") + print("Problem solved in %f seconds" % solver.wall_time) + # [END advanced] + + +if __name__ == "__main__": + main() +# [END program] diff --git a/ortools/linear_solver/wrappers/model_builder_helper.cc b/ortools/linear_solver/wrappers/model_builder_helper.cc index 9b08026f7b..d44069995d 100644 --- a/ortools/linear_solver/wrappers/model_builder_helper.cc +++ b/ortools/linear_solver/wrappers/model_builder_helper.cc @@ -40,6 +40,10 @@ namespace operations_research { +void ModelBuilderHelper::OverwriteModel(const ModelBuilderHelper& other_helper) { + model_ = other_helper.model(); +} + std::string ModelBuilderHelper::ExportToMpsString( const MPModelExportOptions& options) { return operations_research::ExportModelAsMpsFormat(model_, options) diff --git a/ortools/linear_solver/wrappers/model_builder_helper.h b/ortools/linear_solver/wrappers/model_builder_helper.h index 4abc54e30d..53af17dc09 100644 --- a/ortools/linear_solver/wrappers/model_builder_helper.h +++ b/ortools/linear_solver/wrappers/model_builder_helper.h @@ -45,6 +45,7 @@ namespace operations_research { // absl::Status or absl::StatusOr. class ModelBuilderHelper { public: + void OverwriteModel(const ModelBuilderHelper& other_helper); std::string ExportToMpsString(const operations_research::MPModelExportOptions& options = MPModelExportOptions()); std::string ExportToLpString(const operations_research::MPModelExportOptions&