diff --git a/ortools/sat/docs/model.md b/ortools/sat/docs/model.md index 1bc3f3ce50..42cb8f758d 100644 --- a/ortools/sat/docs/model.md +++ b/ortools/sat/docs/model.md @@ -360,17 +360,22 @@ func main() { ## Model copy -The CpModel classes supports deep copy from a previous model. This is useful to -solve variations of a base model. The trick is to recover the copies of the +The `CpModel` classes supports deep copy from a previous model. This is useful +to solve variations of a base model. The trick is to recover the copies of the variables in the original model to be able to manipulate the new model. This is illustrated in the following examples. ### Python code +The deep copy python mechanism relies on the +[`copy` Python Standard Library](https://docs.python.org/3/library/copy.html). + ```python #!/usr/bin/env python3 """Showcases deep copying of a model.""" +import copy + from ortools.sat.python import cp_model @@ -397,15 +402,24 @@ def clone_model_sample_sat(): if status == cp_model.OPTIMAL: print("Optimal value of the original model: {}".format(solver.objective_value)) - # Clones the model. - copy = model.clone() + # Creates a dictionary holding the model and the variables you want to use. + to_clone = { + "model": model, + "x": x, + "y": y, + "z": z, + } - copy_x = copy.get_int_var_from_proto_index(x.index) - copy_y = copy.get_int_var_from_proto_index(y.index) + # Deep copy the dictionary. + clone = copy.deepcopy(to_clone) - copy.add(copy_x + copy_y <= 1) + # Retrieve the cloned model and variables. + cloned_model: cp_model.CpModel = clone["model"] + cloned_x = clone["x"] + cloned_y = clone["y"] + cloned_model.add(cloned_x + cloned_y <= 1) - status = solver.solve(copy) + status = solver.solve(cloned_model) if status == cp_model.OPTIMAL: print("Optimal value of the modified model: {}".format(solver.objective_value)) diff --git a/ortools/sat/python/cp_model.py b/ortools/sat/python/cp_model.py index b404e01587..db156958d8 100644 --- a/ortools/sat/python/cp_model.py +++ b/ortools/sat/python/cp_model.py @@ -266,7 +266,7 @@ class IntVar(cmh.BaseIntVar): """Returns a shallowcopy of the variable.""" return IntVar(self.__model, self.index, self.is_boolean, None) - def __deepcopy__(self, memo) -> "IntVar": + def __deepcopy__(self, memo: Any) -> "IntVar": """Returns a deepcopy of the variable.""" return IntVar( copy.deepcopy(self.__model, memo), self.index, self.is_boolean, None diff --git a/ortools/sat/python/cp_model_test.py b/ortools/sat/python/cp_model_test.py index c2cb5812c1..aa88cfd5c5 100644 --- a/ortools/sat/python/cp_model_test.py +++ b/ortools/sat/python/cp_model_test.py @@ -1799,6 +1799,18 @@ class CpModelTest(absltest.TestCase): self.assertEqual(y.index, clone_y.index) self.assertEqual(i.index, clone_i.index) + solo_copy_b = copy.copy(b) + self.assertEqual(b.index, solo_copy_b.index) + self.assertEqual(b.is_boolean, solo_copy_b.is_boolean) + self.assertIs(solo_copy_b.model_proto, b.model_proto) + solo_copy_x = copy.copy(x) + self.assertEqual(x.index, solo_copy_x.index) + self.assertEqual(x.is_boolean, solo_copy_x.is_boolean) + self.assertIs(solo_copy_x.model_proto, x.model_proto) + solo_copy_i = copy.copy(i) + self.assertEqual(i.index, solo_copy_i.index) + self.assertIs(solo_copy_i.model_proto, i.model_proto) + model_copy = copy.copy(model) copy_b = model_copy.get_bool_var_from_proto_index(b.index) copy_x = model_copy.get_int_var_from_proto_index(x.index) diff --git a/ortools/sat/samples/clone_model_sample_sat.py b/ortools/sat/samples/clone_model_sample_sat.py index ab9b7b9547..6f32e4cb48 100644 --- a/ortools/sat/samples/clone_model_sample_sat.py +++ b/ortools/sat/samples/clone_model_sample_sat.py @@ -15,6 +15,8 @@ """Showcases deep copying of a model.""" # [START program] +import copy + from ortools.sat.python import cp_model @@ -51,17 +53,26 @@ def clone_model_sample_sat(): if status == cp_model.OPTIMAL: print("Optimal value of the original model: {}".format(solver.objective_value)) - # Clones the model. # [START clone] - copy = model.clone() + # Creates a dictionary holding the model and the variables you want to use. + to_clone = { + "model": model, + "x": x, + "y": y, + "z": z, + } - copy_x = copy.get_int_var_from_proto_index(x.index) - copy_y = copy.get_int_var_from_proto_index(y.index) + # Deep copy the dictionary. + clone = copy.deepcopy(to_clone) - copy.add(copy_x + copy_y <= 1) + # Retrieve the cloned model and variables. + cloned_model: cp_model.CpModel = clone["model"] + cloned_x = clone["x"] + cloned_y = clone["y"] + cloned_model.add(cloned_x + cloned_y <= 1) # [END clone] - status = solver.solve(copy) + status = solver.solve(cloned_model) if status == cp_model.OPTIMAL: print("Optimal value of the modified model: {}".format(solver.objective_value)) diff --git a/ortools/xpress/environment.h b/ortools/xpress/environment.h index ee26c279fd..326528754c 100644 --- a/ortools/xpress/environment.h +++ b/ortools/xpress/environment.h @@ -1,4 +1,4 @@ -// Copyright 2010-2025 Google LLC +// Copyright 2019-2023 RTE // 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