diff --git a/ortools/sat/python/cp_model.py b/ortools/sat/python/cp_model.py index 7aa939da5f6..0a30abe38d0 100644 --- a/ortools/sat/python/cp_model.py +++ b/ortools/sat/python/cp_model.py @@ -612,7 +612,7 @@ def __str__(self): ) if not exprs_str: return "0" - return exprs_str + return f"({exprs_str})" def __repr__(self): exprs_str = ", ".join(map(repr, self.__expressions)) @@ -757,7 +757,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return "%s(%s)" % (self.__var.name, DisplayBounds(self.__var.domain)) - def Name(self) -> Optional[str]: + def Name(self) -> str: + if not self.__var or not self.__var.name: + return "" return self.__var.name def Not(self) -> "_NotBooleanVariable": @@ -946,6 +948,8 @@ def WithName(self, name: str) -> "Constraint": def Name(self) -> str: """Returns the name of the constraint.""" + if not self.__constraint or not self.__constraint.name: + return "" return self.__constraint.name def Index(self) -> int: @@ -1036,6 +1040,8 @@ def __repr__(self): ) def Name(self) -> str: + if not self.__ct or not self.__ct.name: + return "" return self.__ct.name def StartExpr(self) -> LinearExprT: @@ -1096,6 +1102,8 @@ def __init__(self): # Naming. def Name(self) -> str: """Returns the name of the model.""" + if not self.__model or not self.__model.name: + return "" return self.__model.name def SetName(self, name: str): diff --git a/ortools/sat/python/cp_model_test.py b/ortools/sat/python/cp_model_test.py index 328cd5a7644..825cbababba 100644 --- a/ortools/sat/python/cp_model_test.py +++ b/ortools/sat/python/cp_model_test.py @@ -13,8 +13,9 @@ # limitations under the License. """Tests for ortools.sat.python.cp_model.""" - from absl.testing import absltest +import pandas as pd + from ortools.sat.python import cp_model @@ -61,7 +62,7 @@ def Obj(self): return self.__obj -class LogToString(object): +class LogToString: """Record log in a string.""" def __init__(self): @@ -473,7 +474,7 @@ def testWeightedSum(self): print("testWeightedSum") model = cp_model.CpModel() x = [model.NewIntVar(0, 2, "x%i" % i) for i in range(100)] - c = [2 for i in range(100)] + c = [2] * 100 model.Add(cp_model.LinearExpr.WeightedSum(x, c) <= 3) model.Maximize(x[99]) solver = cp_model.CpSolver() @@ -1089,8 +1090,7 @@ def testDisplayBounds(self): def testShortName(self): print("testShortName") model = cp_model.CpModel() - v = model.Proto().variables.add() - v.domain.extend([5, 10]) + model.Proto().variables.add(domain=[5, 10]) self.assertEqual("[5..10]", cp_model.ShortName(model.Proto(), 0)) def testIntegerExpressionErrors(self): @@ -1420,6 +1420,30 @@ def testModelError(self): self.assertEqual(cp_model.MODEL_INVALID, solver.Solve(model)) self.assertEqual(solver.SolutionInfo(), 'var #0 has no domain(): name: "x0"') + def testIntVarSeries(self): + print("testIntVarSeries") + df = pd.DataFrame([1, -1, 1], columns=["coeffs"]) + model = cp_model.CpModel() + x = model.NewIntVarSeries( + name="x", index=df.index, lower_bounds=0, upper_bounds=5 + ) + model.Minimize(df.coeffs.dot(x)) + solver = cp_model.CpSolver() + self.assertEqual(cp_model.OPTIMAL, solver.Solve(model)) + solution = solver.Values(x) + self.assertTrue((solution.values == [0, 5, 0]).all()) + + def testBoolVarSeries(self): + print("testBoolVarSeries") + df = pd.DataFrame([1, -1, 1], columns=["coeffs"]) + model = cp_model.CpModel() + x = model.NewBoolVarSeries(name="x", index=df.index) + model.Minimize(df.coeffs.dot(x)) + solver = cp_model.CpSolver() + self.assertEqual(cp_model.OPTIMAL, solver.Solve(model)) + solution = solver.BooleanValues(x) + self.assertTrue((solution.values == [False, True, False]).all()) + if __name__ == "__main__": absltest.main()