1414 lines
58 KiB
Python
1414 lines
58 KiB
Python
#!/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.
|
|
"""Tests for ortools.sat.python.cp_model."""
|
|
|
|
from absl.testing import absltest
|
|
from ortools.sat.python import cp_model
|
|
|
|
|
|
class SolutionCounter(cp_model.CpSolverSolutionCallback):
|
|
"""Count solutions."""
|
|
|
|
def __init__(self):
|
|
cp_model.CpSolverSolutionCallback.__init__(self)
|
|
self.__solution_count = 0
|
|
|
|
def OnSolutionCallback(self):
|
|
self.__solution_count += 1
|
|
|
|
def SolutionCount(self):
|
|
return self.__solution_count
|
|
|
|
|
|
class SolutionSum(cp_model.CpSolverSolutionCallback):
|
|
"""Record the sum of variables in the solution."""
|
|
|
|
def __init__(self, variables):
|
|
cp_model.CpSolverSolutionCallback.__init__(self)
|
|
self.__sum = 0
|
|
self.__vars = variables
|
|
|
|
def OnSolutionCallback(self):
|
|
self.__sum = sum(self.Value(x) for x in self.__vars)
|
|
|
|
def Sum(self):
|
|
return self.__sum
|
|
|
|
|
|
class SolutionObjective(cp_model.CpSolverSolutionCallback):
|
|
"""Record the objective value of the solution."""
|
|
|
|
def __init__(self):
|
|
cp_model.CpSolverSolutionCallback.__init__(self)
|
|
self.__obj = 0
|
|
|
|
def OnSolutionCallback(self):
|
|
self.__obj = self.ObjectiveValue()
|
|
|
|
def Obj(self):
|
|
return self.__obj
|
|
|
|
|
|
class LogToString(object):
|
|
"""Record log in a string."""
|
|
|
|
def __init__(self):
|
|
self.__log = ''
|
|
|
|
def NewMessage(self, message: str):
|
|
self.__log += message
|
|
self.__log += '\n'
|
|
|
|
def Log(self):
|
|
return self.__log
|
|
|
|
|
|
class CpModelTest(absltest.TestCase):
|
|
|
|
def testCreateIntegerVariable(self):
|
|
print('testCreateIntegerVariable')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
self.assertEqual('x', str(x))
|
|
self.assertEqual('x(-10..10)', repr(x))
|
|
y = model.NewIntVarFromDomain(
|
|
cp_model.Domain.FromIntervals([[2, 4], [7]]), 'y')
|
|
self.assertEqual('y', str(y))
|
|
self.assertEqual('y(2..4, 7)', repr(y))
|
|
z = model.NewIntVarFromDomain(cp_model.Domain.FromValues([2, 3, 4, 7]),
|
|
'z')
|
|
self.assertEqual('z', str(z))
|
|
self.assertEqual('z(2..4, 7)', repr(z))
|
|
t = model.NewIntVarFromDomain(
|
|
cp_model.Domain.FromFlatIntervals([2, 4, 7, 7]), 't')
|
|
self.assertEqual('t', str(t))
|
|
self.assertEqual('t(2..4, 7)', repr(t))
|
|
cst = model.NewConstant(5)
|
|
self.assertEqual('5', str(cst))
|
|
|
|
def testNegation(self):
|
|
print('testNegation')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
b = model.NewBoolVar('b')
|
|
nb = b.Not()
|
|
self.assertEqual(b.Not(), nb)
|
|
self.assertEqual(b.Not().Not(), b)
|
|
self.assertEqual(nb.Index(), -b.Index() - 1)
|
|
self.assertRaises(TypeError, x.Not)
|
|
|
|
def testEqualityOverload(self):
|
|
print('testEqualityOverload')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
self.assertEqual(x, x)
|
|
self.assertNotEqual(x, y)
|
|
|
|
def testLinear(self):
|
|
print('testLinear')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
model.AddLinearConstraint(x + 2 * y, 0, 10)
|
|
model.Minimize(y)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual(cp_model.OPTIMAL, solver.Solve(model))
|
|
self.assertEqual(10, solver.Value(x))
|
|
self.assertEqual(-5, solver.Value(y))
|
|
|
|
def testLinearNonEqual(self):
|
|
print('testLinearNonEqual')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.Add(-x + y != 3).Proto()
|
|
self.assertLen(ct.linear.domain, 4)
|
|
self.assertEqual(cp_model.INT_MIN, ct.linear.domain[0])
|
|
self.assertEqual(2, ct.linear.domain[1])
|
|
self.assertEqual(4, ct.linear.domain[2])
|
|
self.assertEqual(cp_model.INT_MAX, ct.linear.domain[3])
|
|
|
|
def testEq(self):
|
|
print('testEq')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
ct = model.Add(x == 2).Proto()
|
|
self.assertLen(ct.linear.vars, 1)
|
|
self.assertLen(ct.linear.coeffs, 1)
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(2, ct.linear.domain[0])
|
|
self.assertEqual(2, ct.linear.domain[1])
|
|
|
|
def testGe(self):
|
|
print('testGe')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
ct = model.Add(x >= 2).Proto()
|
|
self.assertLen(ct.linear.vars, 1)
|
|
self.assertLen(ct.linear.coeffs, 1)
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(2, ct.linear.domain[0])
|
|
self.assertEqual(cp_model.INT_MAX, ct.linear.domain[1])
|
|
|
|
def testGt(self):
|
|
print('testGt')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
ct = model.Add(x > 2).Proto()
|
|
self.assertLen(ct.linear.vars, 1)
|
|
self.assertLen(ct.linear.coeffs, 1)
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(3, ct.linear.domain[0])
|
|
self.assertEqual(cp_model.INT_MAX, ct.linear.domain[1])
|
|
|
|
def testLe(self):
|
|
print('testLe')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
ct = model.Add(x <= 2).Proto()
|
|
self.assertLen(ct.linear.vars, 1)
|
|
self.assertLen(ct.linear.coeffs, 1)
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(cp_model.INT_MIN, ct.linear.domain[0])
|
|
self.assertEqual(2, ct.linear.domain[1])
|
|
|
|
def testLt(self):
|
|
print('testLt')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
ct = model.Add(x < 2).Proto()
|
|
self.assertLen(ct.linear.vars, 1)
|
|
self.assertLen(ct.linear.coeffs, 1)
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(cp_model.INT_MIN, ct.linear.domain[0])
|
|
self.assertEqual(1, ct.linear.domain[1])
|
|
|
|
def testEqVar(self):
|
|
print('testEqVar')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.Add(x == y + 2).Proto()
|
|
self.assertLen(ct.linear.vars, 2)
|
|
self.assertEqual(1, ct.linear.vars[0] + ct.linear.vars[1])
|
|
self.assertLen(ct.linear.coeffs, 2)
|
|
self.assertEqual(0, ct.linear.coeffs[0] + ct.linear.coeffs[1])
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(2, ct.linear.domain[0])
|
|
self.assertEqual(2, ct.linear.domain[1])
|
|
|
|
def testGeVar(self):
|
|
print('testGeVar')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.Add(x >= 1 - y).Proto()
|
|
self.assertLen(ct.linear.vars, 2)
|
|
self.assertEqual(1, ct.linear.vars[0] + ct.linear.vars[1])
|
|
self.assertLen(ct.linear.coeffs, 2)
|
|
self.assertEqual(1, ct.linear.coeffs[0])
|
|
self.assertEqual(1, ct.linear.coeffs[1])
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(1, ct.linear.domain[0])
|
|
self.assertEqual(cp_model.INT_MAX, ct.linear.domain[1])
|
|
|
|
def testGtVar(self):
|
|
print('testGeVar')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.Add(x > 1 - y).Proto()
|
|
self.assertLen(ct.linear.vars, 2)
|
|
self.assertEqual(1, ct.linear.vars[0] + ct.linear.vars[1])
|
|
self.assertLen(ct.linear.coeffs, 2)
|
|
self.assertEqual(1, ct.linear.coeffs[0])
|
|
self.assertEqual(1, ct.linear.coeffs[1])
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(2, ct.linear.domain[0])
|
|
self.assertEqual(cp_model.INT_MAX, ct.linear.domain[1])
|
|
|
|
def testLeVar(self):
|
|
print('testLeVar')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.Add(x <= 1 - y).Proto()
|
|
self.assertLen(ct.linear.vars, 2)
|
|
self.assertEqual(1, ct.linear.vars[0] + ct.linear.vars[1])
|
|
self.assertLen(ct.linear.coeffs, 2)
|
|
self.assertEqual(1, ct.linear.coeffs[0])
|
|
self.assertEqual(1, ct.linear.coeffs[1])
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(cp_model.INT_MIN, ct.linear.domain[0])
|
|
self.assertEqual(1, ct.linear.domain[1])
|
|
|
|
def testLtVar(self):
|
|
print('testLtVar')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.Add(x < 1 - y).Proto()
|
|
self.assertLen(ct.linear.vars, 2)
|
|
self.assertEqual(1, ct.linear.vars[0] + ct.linear.vars[1])
|
|
self.assertLen(ct.linear.coeffs, 2)
|
|
self.assertEqual(1, ct.linear.coeffs[0])
|
|
self.assertEqual(1, ct.linear.coeffs[1])
|
|
self.assertLen(ct.linear.domain, 2)
|
|
self.assertEqual(cp_model.INT_MIN, ct.linear.domain[0])
|
|
self.assertEqual(0, ct.linear.domain[1])
|
|
|
|
def testSimplification1(self):
|
|
print('testSimplification1')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
prod = (x * 2) * 2
|
|
self.assertEqual(x, prod.Expression())
|
|
self.assertEqual(4, prod.Coefficient())
|
|
|
|
def testSimplification2(self):
|
|
print('testSimplification2')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
prod = 2 * (x * 2)
|
|
self.assertEqual(x, prod.Expression())
|
|
self.assertEqual(4, prod.Coefficient())
|
|
|
|
def testSimplification3(self):
|
|
print('testSimplification3')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
prod = (2 * x) * 2
|
|
self.assertEqual(x, prod.Expression())
|
|
self.assertEqual(4, prod.Coefficient())
|
|
|
|
def testSimplification4(self):
|
|
print('testSimplification4')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
prod = 2 * (2 * x)
|
|
self.assertEqual(x, prod.Expression())
|
|
self.assertEqual(4, prod.Coefficient())
|
|
|
|
def testLinearNonEqualWithConstant(self):
|
|
print('testLinearNonEqualWithConstant')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.Add(x + y + 5 != 3).Proto()
|
|
self.assertLen(ct.linear.domain, 4)
|
|
# Checks that saturated arithmetics worked.
|
|
self.assertEqual(cp_model.INT_MIN, ct.linear.domain[0])
|
|
self.assertEqual(-3, ct.linear.domain[1])
|
|
self.assertEqual(-1, ct.linear.domain[2])
|
|
self.assertEqual(cp_model.INT_MAX, ct.linear.domain[3])
|
|
|
|
def testLinearWithEnforcement(self):
|
|
print('testLinearWithEnforcement')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
b = model.NewBoolVar('b')
|
|
model.AddLinearConstraint(x + 2 * y, 0, 10).OnlyEnforceIf(b.Not())
|
|
model.Minimize(y)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertEqual(-3,
|
|
model.Proto().constraints[0].enforcement_literal[0])
|
|
c = model.NewBoolVar('c')
|
|
model.AddLinearConstraint(x + 4 * y, 0, 10).OnlyEnforceIf([b, c])
|
|
self.assertLen(model.Proto().constraints, 2)
|
|
self.assertEqual(2, model.Proto().constraints[1].enforcement_literal[0])
|
|
self.assertEqual(3, model.Proto().constraints[1].enforcement_literal[1])
|
|
model.AddLinearConstraint(x + 5 * y, 0, 10).OnlyEnforceIf(c.Not(), b)
|
|
self.assertLen(model.Proto().constraints, 3)
|
|
self.assertEqual(-4,
|
|
model.Proto().constraints[2].enforcement_literal[0])
|
|
self.assertEqual(2, model.Proto().constraints[2].enforcement_literal[1])
|
|
|
|
def testConstraintWithName(self):
|
|
print('testConstraintWithName')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
ct = model.AddLinearConstraint(x + 2 * y, 0,
|
|
10).WithName('test_constraint')
|
|
self.assertEqual('test_constraint', ct.Name())
|
|
|
|
def testNaturalApiMinimize(self):
|
|
print('testNaturalApiMinimize')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
model.Add(x * 2 - 1 * y == 1)
|
|
model.Minimize(x * 1 - 2 * y + 3)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('OPTIMAL', solver.StatusName(solver.Solve(model)))
|
|
self.assertEqual(5, solver.Value(x))
|
|
self.assertEqual(15, solver.Value(x * 3))
|
|
self.assertEqual(6, solver.Value(1 + x))
|
|
self.assertEqual(-10.0, solver.ObjectiveValue())
|
|
|
|
def testNaturalApiMaximizeFloat(self):
|
|
print('testNaturalApiMaximizeFloat')
|
|
model = cp_model.CpModel()
|
|
x = model.NewBoolVar('x')
|
|
y = model.NewIntVar(0, 10, 'y')
|
|
model.Maximize(x.Not() * 3.5 + x.Not() - y + 2 * y + 1.6)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('OPTIMAL', solver.StatusName(solver.Solve(model)))
|
|
self.assertFalse(solver.BooleanValue(x))
|
|
self.assertTrue(solver.BooleanValue(x.Not()))
|
|
self.assertEqual(-10, solver.Value(-y))
|
|
self.assertEqual(16.1, solver.ObjectiveValue())
|
|
|
|
def testNaturalApiMaximizeComplex(self):
|
|
print('testNaturalApiMaximizeFloat')
|
|
model = cp_model.CpModel()
|
|
x1 = model.NewBoolVar('x1')
|
|
x2 = model.NewBoolVar('x1')
|
|
x3 = model.NewBoolVar('x1')
|
|
x4 = model.NewBoolVar('x1')
|
|
model.Maximize(
|
|
cp_model.LinearExpr.Sum([x1, x2]) +
|
|
cp_model.LinearExpr.WeightedSum([x3, x4.Not()], [2, 4]))
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('OPTIMAL', solver.StatusName(solver.Solve(model)))
|
|
self.assertEqual(5, solver.Value(3 + 2 * x1))
|
|
self.assertEqual(3, solver.Value(x1 + x2 + x3))
|
|
self.assertEqual(
|
|
1, solver.Value(cp_model.LinearExpr.Sum([x1, x2, x3, 0, -2])))
|
|
self.assertEqual(
|
|
7,
|
|
solver.Value(
|
|
cp_model.LinearExpr.WeightedSum([x1, x2, x4, 3], [2, 2, 2, 1])))
|
|
self.assertEqual(5, solver.Value(5 * x4.Not()))
|
|
self.assertEqual(8, solver.ObjectiveValue())
|
|
|
|
def testNaturalApiMaximize(self):
|
|
print('testNaturalApiMaximize')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
model.Add(2 * x - y == 1)
|
|
model.Maximize(x - 2 * y + 3)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('OPTIMAL', solver.StatusName(solver.Solve(model)))
|
|
self.assertEqual(-4, solver.Value(x))
|
|
self.assertEqual(-9, solver.Value(y))
|
|
self.assertEqual(17, solver.ObjectiveValue())
|
|
|
|
def testMinimizeConstant(self):
|
|
print('testMinimizeConstant')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
model.Add(x >= -1)
|
|
model.Minimize(10)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('OPTIMAL', solver.StatusName(solver.Solve(model)))
|
|
self.assertEqual(10, solver.ObjectiveValue())
|
|
|
|
def testMaximizeConstant(self):
|
|
print('testMinimizeConstant')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
model.Add(x >= -1)
|
|
model.Maximize(5)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('OPTIMAL', solver.StatusName(solver.Solve(model)))
|
|
self.assertEqual(5, solver.ObjectiveValue())
|
|
|
|
def testAddTrue(self):
|
|
print('testAddTrue')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
model.Add(3 >= -1)
|
|
model.Minimize(x)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('OPTIMAL', solver.StatusName(solver.Solve(model)))
|
|
self.assertEqual(-10, solver.Value(x))
|
|
|
|
def testAddFalse(self):
|
|
print('testAddFalse')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
model.Add(3 <= -1)
|
|
model.Minimize(x)
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual('INFEASIBLE', solver.StatusName(solver.Solve(model)))
|
|
|
|
def testSum(self):
|
|
print('testSum')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 2, 'x%i' % i) for i in range(100)]
|
|
model.Add(sum(x) <= 1)
|
|
model.Maximize(x[99])
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual(cp_model.OPTIMAL, solver.Solve(model))
|
|
self.assertEqual(1.0, solver.ObjectiveValue())
|
|
for i in range(100):
|
|
self.assertEqual(solver.Value(x[i]), 1 if i == 99 else 0)
|
|
|
|
def testSumWithApi(self):
|
|
print('testSumWithApi')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 2, 'x%i' % i) for i in range(100)]
|
|
model.Add(cp_model.LinearExpr.Sum(x) <= 1)
|
|
model.Maximize(x[99])
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual(cp_model.OPTIMAL, solver.Solve(model))
|
|
self.assertEqual(1.0, solver.ObjectiveValue())
|
|
for i in range(100):
|
|
self.assertEqual(solver.Value(x[i]), 1 if i == 99 else 0)
|
|
|
|
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)]
|
|
model.Add(cp_model.LinearExpr.WeightedSum(x, c) <= 3)
|
|
model.Maximize(x[99])
|
|
solver = cp_model.CpSolver()
|
|
self.assertEqual(cp_model.OPTIMAL, solver.Solve(model))
|
|
self.assertEqual(1.0, solver.ObjectiveValue())
|
|
for i in range(100):
|
|
self.assertEqual(solver.Value(x[i]), 1 if i == 99 else 0)
|
|
|
|
def testAllDifferent(self):
|
|
print('testAllDifferent')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 4, 'x%i' % i) for i in range(5)]
|
|
model.AddAllDifferent(x)
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].all_diff.exprs, 5)
|
|
|
|
def testAllDifferentGen(self):
|
|
print('testAllDifferentGen')
|
|
model = cp_model.CpModel()
|
|
model.AddAllDifferent(
|
|
model.NewIntVar(0, 4, 'x%i' % i) for i in range(5))
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].all_diff.exprs, 5)
|
|
|
|
def testAllDifferentList(self):
|
|
print('testAllDifferentList')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 4, 'x%i' % i) for i in range(5)]
|
|
model.AddAllDifferent(x[0], x[1], x[2], x[3], x[4])
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].all_diff.exprs, 5)
|
|
|
|
def testElement(self):
|
|
print('testElement')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 4, 'x%i' % i) for i in range(5)]
|
|
model.AddElement(x[0], [x[1], 2, 4, x[2]], x[4])
|
|
self.assertLen(model.Proto().variables, 7)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].element.vars, 4)
|
|
self.assertEqual(0, model.Proto().constraints[0].element.index)
|
|
self.assertEqual(4, model.Proto().constraints[0].element.target)
|
|
self.assertRaises(ValueError, model.AddElement, x[0], [], x[4])
|
|
|
|
def testCircuit(self):
|
|
print('testCircuit')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar(f'x{i}') for i in range(5)]
|
|
model.AddCircuit((i, i + 1, x[i]) for i in range(5))
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].circuit.heads, 5)
|
|
self.assertLen(model.Proto().constraints[0].circuit.tails, 5)
|
|
self.assertLen(model.Proto().constraints[0].circuit.literals, 5)
|
|
self.assertRaises(ValueError, model.AddCircuit, [])
|
|
|
|
def testMultipleCircuit(self):
|
|
print('testMultipleCircuit')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar(f'x{i}') for i in range(5)]
|
|
model.AddMultipleCircuit((i, i + 1, x[i]) for i in range(5))
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].routes.heads, 5)
|
|
self.assertLen(model.Proto().constraints[0].routes.tails, 5)
|
|
self.assertLen(model.Proto().constraints[0].routes.literals, 5)
|
|
self.assertRaises(ValueError, model.AddMultipleCircuit, [])
|
|
|
|
def testAllowedAssignments(self):
|
|
print('testAllowedAssignments')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 4, 'x%i' % i) for i in range(5)]
|
|
model.AddAllowedAssignments(x, [(0, 1, 2, 3, 4), (4, 3, 2, 1, 1),
|
|
(0, 0, 0, 0, 0)])
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].table.vars, 5)
|
|
self.assertLen(model.Proto().constraints[0].table.values, 15)
|
|
self.assertRaises(TypeError, model.AddAllowedAssignments, x,
|
|
[(0, 1, 2, 3, 4), (4, 3, 2, 1, 1), (0, 0, 0, 0)])
|
|
self.assertRaises(ValueError, model.AddAllowedAssignments, [],
|
|
[(0, 1, 2, 3, 4), (4, 3, 2, 1, 1), (0, 0, 0, 0)])
|
|
|
|
def testForbiddenAssignments(self):
|
|
print('testForbiddenAssignments')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 4, 'x%i' % i) for i in range(5)]
|
|
model.AddForbiddenAssignments(x, [(0, 1, 2, 3, 4), (4, 3, 2, 1, 1),
|
|
(0, 0, 0, 0, 0)])
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].table.vars, 5)
|
|
self.assertLen(model.Proto().constraints[0].table.values, 15)
|
|
self.assertTrue(model.Proto().constraints[0].table.negated)
|
|
self.assertRaises(TypeError, model.AddForbiddenAssignments, x,
|
|
[(0, 1, 2, 3, 4), (4, 3, 2, 1, 1), (0, 0, 0, 0)])
|
|
self.assertRaises(ValueError, model.AddForbiddenAssignments, [],
|
|
[(0, 1, 2, 3, 4), (4, 3, 2, 1, 1), (0, 0, 0, 0)])
|
|
|
|
def testAutomaton(self):
|
|
print('testAutomaton')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 4, 'x%i' % i) for i in range(5)]
|
|
model.AddAutomaton(x, 0, [2, 3], [(0, 0, 0), (0, 1, 1), (1, 2, 2),
|
|
(2, 3, 3)])
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].automaton.vars, 5)
|
|
self.assertLen(model.Proto().constraints[0].automaton.transition_tail,
|
|
4)
|
|
self.assertLen(model.Proto().constraints[0].automaton.transition_head,
|
|
4)
|
|
self.assertLen(model.Proto().constraints[0].automaton.transition_label,
|
|
4)
|
|
self.assertLen(model.Proto().constraints[0].automaton.final_states, 2)
|
|
self.assertEqual(0,
|
|
model.Proto().constraints[0].automaton.starting_state)
|
|
self.assertRaises(TypeError, model.AddAutomaton, x, 0, [2, 3],
|
|
[(0, 0, 0), (0, 1, 1), (2, 2), (2, 3, 3)])
|
|
self.assertRaises(ValueError, model.AddAutomaton, [], 0, [2, 3],
|
|
[(0, 0, 0), (0, 1, 1), (2, 3, 3)])
|
|
self.assertRaises(ValueError, model.AddAutomaton, x, 0, [], [(0, 0, 0),
|
|
(0, 1, 1),
|
|
(2, 3, 3)])
|
|
self.assertRaises(ValueError, model.AddAutomaton, x, 0, [2, 3], [])
|
|
|
|
def testInverse(self):
|
|
print('testInverse')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, 4, 'x%i' % i) for i in range(5)]
|
|
y = [model.NewIntVar(0, 4, 'y%i' % i) for i in range(5)]
|
|
model.AddInverse(x, y)
|
|
self.assertLen(model.Proto().variables, 10)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].inverse.f_direct, 5)
|
|
self.assertLen(model.Proto().constraints[0].inverse.f_inverse, 5)
|
|
|
|
def testMaxEquality(self):
|
|
print('testMaxEquality')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = [model.NewIntVar(0, 4, 'y%i' % i) for i in range(5)]
|
|
model.AddMaxEquality(x, y)
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].lin_max.exprs, 5)
|
|
self.assertEqual(0, model.Proto().constraints[0].lin_max.target.vars[0])
|
|
self.assertEqual(1,
|
|
model.Proto().constraints[0].lin_max.target.coeffs[0])
|
|
|
|
def testMinEquality(self):
|
|
print('testMinEquality')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = [model.NewIntVar(0, 4, 'y%i' % i) for i in range(5)]
|
|
model.AddMinEquality(x, y)
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertLen(model.Proto().constraints[0].lin_max.exprs, 5)
|
|
self.assertEqual(0, model.Proto().constraints[0].lin_max.target.vars[0])
|
|
self.assertEqual(-1,
|
|
model.Proto().constraints[0].lin_max.target.coeffs[0])
|
|
|
|
def testMinEqualityList(self):
|
|
print('testMinEqualityList')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = [model.NewIntVar(0, 4, 'y%i' % i) for i in range(5)]
|
|
model.AddMinEquality(x, [y[0], y[2], y[1], y[3]])
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertLen(model.Proto().constraints[0].lin_max.exprs, 4)
|
|
self.assertEqual(0, model.Proto().constraints[0].lin_max.target.vars[0])
|
|
self.assertEqual(-1,
|
|
model.Proto().constraints[0].lin_max.target.coeffs[0])
|
|
|
|
def testMinEqualityTuple(self):
|
|
print('testMinEqualityTuple')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = [model.NewIntVar(0, 4, 'y%i' % i) for i in range(5)]
|
|
model.AddMinEquality(x, (y[0], y[2], y[1], y[3]))
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertLen(model.Proto().constraints[0].lin_max.exprs, 4)
|
|
self.assertEqual(0, model.Proto().constraints[0].lin_max.target.vars[0])
|
|
self.assertEqual(-1,
|
|
model.Proto().constraints[0].lin_max.target.coeffs[0])
|
|
|
|
def testMinEqualityGenerator(self):
|
|
print('testMinEqualityGenerator')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = [model.NewIntVar(0, 4, 'y%i' % i) for i in range(5)]
|
|
model.AddMinEquality(x, (z for z in y))
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertLen(model.Proto().constraints[0].lin_max.exprs, 5)
|
|
self.assertEqual(0, model.Proto().constraints[0].lin_max.target.vars[0])
|
|
self.assertEqual(-1,
|
|
model.Proto().constraints[0].lin_max.target.coeffs[0])
|
|
|
|
def testMinEqualityWithConstant(self):
|
|
print('testMinEqualityWithConstant')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(0, 4, 'y')
|
|
model.AddMinEquality(x, [y, 3])
|
|
self.assertLen(model.Proto().variables, 2)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
lin_max = model.Proto().constraints[0].lin_max
|
|
self.assertLen(lin_max.exprs, 2)
|
|
self.assertLen(lin_max.exprs[0].vars, 1)
|
|
self.assertEqual(1, lin_max.exprs[0].vars[0])
|
|
self.assertEqual(-1, lin_max.exprs[0].coeffs[0])
|
|
self.assertEqual(0, lin_max.exprs[0].offset)
|
|
self.assertEmpty(lin_max.exprs[1].vars)
|
|
self.assertEqual(-3, lin_max.exprs[1].offset)
|
|
|
|
def testAbs(self):
|
|
print('testAbs')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(-5, 5, 'y')
|
|
model.AddAbsEquality(x, y)
|
|
self.assertLen(model.Proto().variables, 2)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].lin_max.exprs, 2)
|
|
self.assertEqual(1,
|
|
model.Proto().constraints[0].lin_max.exprs[0].vars[0])
|
|
self.assertEqual(
|
|
1,
|
|
model.Proto().constraints[0].lin_max.exprs[0].coeffs[0])
|
|
self.assertEqual(1,
|
|
model.Proto().constraints[0].lin_max.exprs[1].vars[0])
|
|
self.assertEqual(
|
|
-1,
|
|
model.Proto().constraints[0].lin_max.exprs[1].coeffs[0])
|
|
passed = False
|
|
error_msg = None
|
|
try:
|
|
abs(x)
|
|
except NotImplementedError as e:
|
|
error_msg = str(e)
|
|
passed = True
|
|
self.assertEqual(
|
|
'calling abs() on a linear expression is not supported, '
|
|
'please use CpModel.AddAbsEquality', error_msg)
|
|
self.assertTrue(passed)
|
|
|
|
def testDivision(self):
|
|
print('testDivision')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 10, 'x')
|
|
y = model.NewIntVar(0, 50, 'y')
|
|
model.AddDivisionEquality(x, y, 6)
|
|
self.assertLen(model.Proto().variables, 2)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].int_div.exprs, 2)
|
|
self.assertEqual(model.Proto().constraints[0].int_div.exprs[0].vars[0],
|
|
1)
|
|
self.assertEqual(
|
|
model.Proto().constraints[0].int_div.exprs[0].coeffs[0], 1)
|
|
self.assertEmpty(model.Proto().constraints[0].int_div.exprs[1].vars)
|
|
self.assertEqual(model.Proto().constraints[0].int_div.exprs[1].offset,
|
|
6)
|
|
passed = False
|
|
error_msg = None
|
|
try:
|
|
x / 3
|
|
except NotImplementedError as e:
|
|
error_msg = str(e)
|
|
passed = True
|
|
self.assertEqual(
|
|
'calling // on a linear expression is not supported, '
|
|
'please use CpModel.AddDivisionEquality', error_msg)
|
|
self.assertTrue(passed)
|
|
|
|
def testModulo(self):
|
|
print('testModulo')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 10, 'x')
|
|
y = model.NewIntVar(0, 50, 'y')
|
|
model.AddModuloEquality(x, y, 6)
|
|
self.assertLen(model.Proto().variables, 2)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].int_mod.exprs, 2)
|
|
self.assertEqual(model.Proto().constraints[0].int_mod.exprs[0].vars[0],
|
|
1)
|
|
self.assertEqual(
|
|
model.Proto().constraints[0].int_mod.exprs[0].coeffs[0], 1)
|
|
self.assertEmpty(model.Proto().constraints[0].int_mod.exprs[1].vars)
|
|
self.assertEqual(model.Proto().constraints[0].int_mod.exprs[1].offset,
|
|
6)
|
|
passed = False
|
|
error_msg = None
|
|
try:
|
|
x % 3
|
|
except NotImplementedError as e:
|
|
error_msg = str(e)
|
|
passed = True
|
|
self.assertEqual(
|
|
'calling %% on a linear expression is not supported, '
|
|
'please use CpModel.AddModuloEquality', error_msg)
|
|
self.assertTrue(passed)
|
|
|
|
def testMultiplicationEquality(self):
|
|
print('testMultiplicationEquality')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = [model.NewIntVar(0, 4, 'y%i' % i) for i in range(5)]
|
|
model.AddMultiplicationEquality(x, y)
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].int_prod.exprs, 5)
|
|
self.assertEqual(0,
|
|
model.Proto().constraints[0].int_prod.target.vars[0])
|
|
|
|
def testImplication(self):
|
|
print('testImplication')
|
|
model = cp_model.CpModel()
|
|
x = model.NewBoolVar('x')
|
|
y = model.NewBoolVar('y')
|
|
model.AddImplication(x, y)
|
|
self.assertLen(model.Proto().variables, 2)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].bool_or.literals, 1)
|
|
self.assertLen(model.Proto().constraints[0].enforcement_literal, 1)
|
|
self.assertEqual(x.Index(),
|
|
model.Proto().constraints[0].enforcement_literal[0])
|
|
self.assertEqual(y.Index(),
|
|
model.Proto().constraints[0].bool_or.literals[0])
|
|
|
|
def testBoolOr(self):
|
|
print('testBoolOr')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
model.AddBoolOr(x)
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].bool_or.literals, 5)
|
|
model.AddBoolOr([x[0], x[1], False])
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertRaises(TypeError, model.AddBoolOr, [x[2], 2])
|
|
y = model.NewIntVar(0, 4, 'y')
|
|
self.assertRaises(TypeError, model.AddBoolOr, [y, False])
|
|
|
|
def testBoolOrListOrGet(self):
|
|
print('testBoolOrListOrGet')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
model.AddBoolOr(x)
|
|
model.AddBoolOr(True, x[0], x[2])
|
|
model.AddBoolOr(False, x[0])
|
|
model.AddBoolOr(x[i] for i in [0, 2, 3, 4])
|
|
self.assertLen(model.Proto().variables, 7)
|
|
self.assertLen(model.Proto().constraints, 4)
|
|
self.assertLen(model.Proto().constraints[0].bool_or.literals, 5)
|
|
self.assertLen(model.Proto().constraints[1].bool_or.literals, 3)
|
|
self.assertLen(model.Proto().constraints[2].bool_or.literals, 2)
|
|
self.assertLen(model.Proto().constraints[3].bool_or.literals, 4)
|
|
|
|
def testAtLeastOne(self):
|
|
print('testAtLeastOne')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
model.AddAtLeastOne(x)
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].bool_or.literals, 5)
|
|
model.AddAtLeastOne([x[0], x[1], False])
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertRaises(TypeError, model.AddAtLeastOne, [x[2], 2])
|
|
y = model.NewIntVar(0, 4, 'y')
|
|
self.assertRaises(TypeError, model.AddAtLeastOne, [y, False])
|
|
|
|
def testAtMostOne(self):
|
|
print('testAtMostOne')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
model.AddAtMostOne(x)
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].at_most_one.literals, 5)
|
|
model.AddAtMostOne([x[0], x[1], False])
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertRaises(TypeError, model.AddAtMostOne, [x[2], 2])
|
|
y = model.NewIntVar(0, 4, 'y')
|
|
self.assertRaises(TypeError, model.AddAtMostOne, [y, False])
|
|
|
|
def testExactlyOne(self):
|
|
print('testExactlyOne')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
model.AddExactlyOne(x)
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].exactly_one.literals, 5)
|
|
model.AddExactlyOne([x[0], x[1], False])
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertRaises(TypeError, model.AddExactlyOne, [x[2], 2])
|
|
y = model.NewIntVar(0, 4, 'y')
|
|
self.assertRaises(TypeError, model.AddExactlyOne, [y, False])
|
|
|
|
def testBoolAnd(self):
|
|
print('testBoolAnd')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
model.AddBoolAnd(x)
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].bool_and.literals, 5)
|
|
model.AddBoolAnd([x[1], x[2].Not(), True])
|
|
self.assertEqual(1, model.Proto().constraints[1].bool_and.literals[0])
|
|
self.assertEqual(-3, model.Proto().constraints[1].bool_and.literals[1])
|
|
self.assertEqual(5, model.Proto().constraints[1].bool_and.literals[2])
|
|
|
|
def testBoolXOr(self):
|
|
print('testBoolXOr')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
model.AddBoolXOr(x)
|
|
self.assertLen(model.Proto().variables, 5)
|
|
self.assertLen(model.Proto().constraints, 1)
|
|
self.assertLen(model.Proto().constraints[0].bool_xor.literals, 5)
|
|
|
|
def testMapDomain(self):
|
|
print('testMapDomain')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewBoolVar('x%i' % i) for i in range(5)]
|
|
y = model.NewIntVar(0, 10, 'y')
|
|
model.AddMapDomain(y, x, 2)
|
|
self.assertLen(model.Proto().variables, 6)
|
|
self.assertLen(model.Proto().constraints, 10)
|
|
|
|
def testInterval(self):
|
|
print('testInterval')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(0, 3, 'y')
|
|
i = model.NewIntervalVar(x, 3, y, 'i')
|
|
self.assertEqual(1, i.Index())
|
|
|
|
j = model.NewFixedSizeIntervalVar(x, 2, 'j')
|
|
self.assertEqual(2, j.Index())
|
|
start_expr = j.StartExpr()
|
|
size_expr = j.SizeExpr()
|
|
end_expr = j.EndExpr()
|
|
self.assertEqual(x.Index(), start_expr.Index())
|
|
self.assertEqual(size_expr, 2)
|
|
self.assertEqual(str(end_expr), '(x + 2)')
|
|
|
|
def testOptionalInterval(self):
|
|
print('testOptionalInterval')
|
|
model = cp_model.CpModel()
|
|
b = model.NewBoolVar('b')
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(0, 3, 'y')
|
|
i = model.NewOptionalIntervalVar(x, 3, y, b, 'i')
|
|
j = model.NewOptionalIntervalVar(x, y, 10, b, 'j')
|
|
k = model.NewOptionalIntervalVar(x, -y, 10, b, 'k')
|
|
l = model.NewOptionalIntervalVar(x, 10, -y, b, 'l')
|
|
self.assertEqual(1, i.Index())
|
|
self.assertEqual(3, j.Index())
|
|
self.assertEqual(5, k.Index())
|
|
self.assertEqual(7, l.Index())
|
|
self.assertRaises(TypeError, model.NewOptionalIntervalVar, 1, 2, 3, x,
|
|
'x')
|
|
self.assertRaises(TypeError, model.NewOptionalIntervalVar, b + x, 2, 3,
|
|
b, 'x')
|
|
self.assertRaises(AttributeError, model.NewOptionalIntervalVar, 1, 2, 3,
|
|
b + 1, 'x')
|
|
|
|
def testNoOverlap(self):
|
|
print('testNoOverlap')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(0, 3, 'y')
|
|
z = model.NewIntVar(0, 3, 'y')
|
|
i = model.NewIntervalVar(x, 3, y, 'i')
|
|
j = model.NewIntervalVar(x, 5, z, 'j')
|
|
ct = model.AddNoOverlap([i, j])
|
|
self.assertEqual(4, ct.Index())
|
|
self.assertLen(ct.Proto().no_overlap.intervals, 2)
|
|
self.assertEqual(1, ct.Proto().no_overlap.intervals[0])
|
|
self.assertEqual(3, ct.Proto().no_overlap.intervals[1])
|
|
|
|
def testNoOverlap2D(self):
|
|
print('testNoOverlap2D')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(0, 3, 'y')
|
|
z = model.NewIntVar(0, 3, 'y')
|
|
i = model.NewIntervalVar(x, 3, y, 'i')
|
|
j = model.NewIntervalVar(x, 5, z, 'j')
|
|
ct = model.AddNoOverlap2D([i, j], [j, i])
|
|
self.assertEqual(4, ct.Index())
|
|
self.assertLen(ct.Proto().no_overlap_2d.x_intervals, 2)
|
|
self.assertEqual(1, ct.Proto().no_overlap_2d.x_intervals[0])
|
|
self.assertEqual(3, ct.Proto().no_overlap_2d.x_intervals[1])
|
|
self.assertLen(ct.Proto().no_overlap_2d.y_intervals, 2)
|
|
self.assertEqual(3, ct.Proto().no_overlap_2d.y_intervals[0])
|
|
self.assertEqual(1, ct.Proto().no_overlap_2d.y_intervals[1])
|
|
|
|
def testCumulative(self):
|
|
print('testCumulative')
|
|
model = cp_model.CpModel()
|
|
intervals = [
|
|
model.NewIntervalVar(model.NewIntVar(0, 10, f's_{i}'), 5,
|
|
model.NewIntVar(5, 15, f'e_{i}'),
|
|
f'interval[{i}]') for i in range(10)
|
|
]
|
|
demands = [1, 3, 5, 2, 4, 5, 3, 4, 2, 3]
|
|
capacity = 4
|
|
ct = model.AddCumulative(intervals, demands, capacity)
|
|
self.assertEqual(20, ct.Index())
|
|
self.assertLen(ct.Proto().cumulative.intervals, 10)
|
|
self.assertRaises(TypeError, model.AddCumulative, [intervals[0], 3],
|
|
[2, 3], 3)
|
|
|
|
def testGetOrMakeIndexFromConstant(self):
|
|
print('testGetOrMakeIndexFromConstant')
|
|
model = cp_model.CpModel()
|
|
self.assertEqual(0, model.GetOrMakeIndexFromConstant(3))
|
|
self.assertEqual(0, model.GetOrMakeIndexFromConstant(3))
|
|
self.assertEqual(1, model.GetOrMakeIndexFromConstant(5))
|
|
model_var = model.Proto().variables[0]
|
|
self.assertLen(model_var.domain, 2)
|
|
self.assertEqual(3, model_var.domain[0])
|
|
self.assertEqual(3, model_var.domain[1])
|
|
|
|
def testStr(self):
|
|
print('testStr')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
self.assertEqual(str(x == 2), 'x == 2')
|
|
self.assertEqual(str(x >= 2), 'x >= 2')
|
|
self.assertEqual(str(x <= 2), 'x <= 2')
|
|
self.assertEqual(str(x > 2), 'x >= 3')
|
|
self.assertEqual(str(x < 2), 'x <= 1')
|
|
self.assertEqual(str(x != 2), 'x != 2')
|
|
self.assertEqual(str(x * 3), '(3 * x)')
|
|
self.assertEqual(str(-x), '-x')
|
|
self.assertEqual(str(x + 3), '(x + 3)')
|
|
self.assertEqual(str(x <= cp_model.INT_MAX), 'True (unbounded expr x)')
|
|
self.assertEqual(str(x != 9223372036854775807),
|
|
'x <= 9223372036854775806')
|
|
self.assertEqual(str(x != -9223372036854775808),
|
|
'x >= -9223372036854775807')
|
|
y = model.NewIntVar(0, 4, 'y')
|
|
self.assertEqual(
|
|
str(cp_model.LinearExpr.WeightedSum([x, y + 1, 2], [1, -2, 3])),
|
|
'x - 2 * (y + 1) + 6')
|
|
self.assertEqual(str(cp_model.LinearExpr.Term(x, 3)), '(3 * x)')
|
|
self.assertEqual(str(x != y), '(x + -y) != 0')
|
|
self.assertEqual('0 <= x <= 10',
|
|
str(cp_model.BoundedLinearExpression(x, [0, 10])))
|
|
print(str(model))
|
|
b = model.NewBoolVar('b')
|
|
self.assertEqual(str(cp_model.LinearExpr.Term(b.Not(), 3)),
|
|
'(3 * not(b))')
|
|
|
|
i = model.NewIntervalVar(x, 2, y, 'i')
|
|
self.assertEqual(str(i), 'i')
|
|
|
|
def testRepr(self):
|
|
print('testRepr')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(0, 3, 'y')
|
|
z = model.NewIntVar(0, 3, 'z')
|
|
self.assertEqual(repr(x), 'x(0..4)')
|
|
self.assertEqual(repr(x * 2), 'ProductCst(x(0..4), 2)')
|
|
self.assertEqual(repr(x + y), 'Sum(x(0..4), y(0..3))')
|
|
self.assertEqual(repr(cp_model.LinearExpr.Sum([x, y, z])),
|
|
'SumArray(x(0..4), y(0..3), z(0..3), 0)')
|
|
self.assertEqual(
|
|
repr(cp_model.LinearExpr.WeightedSum([x, y, 2], [1, 2, 3])),
|
|
'WeightedSum([x(0..4), y(0..3)], [1, 2], 6)')
|
|
i = model.NewIntervalVar(x, 2, y, 'i')
|
|
self.assertEqual(repr(i), 'i(start = x, size = 2, end = y)')
|
|
b = model.NewBoolVar('b')
|
|
x1 = model.NewIntVar(0, 4, 'x1')
|
|
y1 = model.NewIntVar(0, 3, 'y1')
|
|
j = model.NewOptionalIntervalVar(x1, 2, y1, b, 'j')
|
|
self.assertEqual(repr(j),
|
|
'j(start = x1, size = 2, end = y1, is_present = b)')
|
|
x2 = model.NewIntVar(0, 4, 'x2')
|
|
y2 = model.NewIntVar(0, 3, 'y2')
|
|
k = model.NewOptionalIntervalVar(x2, 2, y2, b.Not(), 'k')
|
|
self.assertEqual(
|
|
repr(k), 'k(start = x2, size = 2, end = y2, is_present = Not(b))')
|
|
|
|
def testDisplayBounds(self):
|
|
print('testDisplayBounds')
|
|
self.assertEqual('10..20', cp_model.DisplayBounds([10, 20]))
|
|
self.assertEqual('10', cp_model.DisplayBounds([10, 10]))
|
|
self.assertEqual('10..15, 20..30',
|
|
cp_model.DisplayBounds([10, 15, 20, 30]))
|
|
|
|
def testShortName(self):
|
|
print('testShortName')
|
|
model = cp_model.CpModel()
|
|
v = model.Proto().variables.add()
|
|
v.domain.extend([5, 10])
|
|
self.assertEqual('[5..10]', cp_model.ShortName(model.Proto(), 0))
|
|
|
|
def testIntegerExpressionErrors(self):
|
|
print('testIntegerExpressionErrors')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 1, 'x')
|
|
y = model.NewIntVar(0, 3, 'y')
|
|
self.assertRaises(TypeError, x.__mul__, y)
|
|
self.assertRaises(NotImplementedError, x.__div__, y)
|
|
self.assertRaises(NotImplementedError, x.__truediv__, y)
|
|
self.assertRaises(NotImplementedError, x.__mod__, y)
|
|
self.assertRaises(NotImplementedError, x.__pow__, y)
|
|
self.assertRaises(NotImplementedError, x.__lshift__, y)
|
|
self.assertRaises(NotImplementedError, x.__rshift__, y)
|
|
self.assertRaises(NotImplementedError, x.__and__, y)
|
|
self.assertRaises(NotImplementedError, x.__or__, y)
|
|
self.assertRaises(NotImplementedError, x.__xor__, y)
|
|
self.assertRaises(ArithmeticError, x.__lt__, cp_model.INT_MIN)
|
|
self.assertRaises(ArithmeticError, x.__gt__, cp_model.INT_MAX)
|
|
self.assertRaises(TypeError, x.__add__, 'dummy')
|
|
self.assertRaises(TypeError, x.__mul__, 'dummy')
|
|
|
|
def testModelErrors(self):
|
|
print('testModelErrors')
|
|
model = cp_model.CpModel()
|
|
self.assertRaises(TypeError, model.Add, 'dummy')
|
|
self.assertRaises(TypeError, model.GetOrMakeIndex, 'dummy')
|
|
self.assertRaises(TypeError, model.Minimize, 'dummy')
|
|
|
|
def testSolverErrors(self):
|
|
print('testSolverErrors')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 1, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
model.AddLinearConstraint(x + 2 * y, 0, 10)
|
|
model.Minimize(y)
|
|
solver = cp_model.CpSolver()
|
|
self.assertRaises(RuntimeError, solver.Value, x)
|
|
solver.Solve(model)
|
|
self.assertRaises(TypeError, solver.Value, 'not_a_variable')
|
|
self.assertRaises(TypeError, model.AddBoolOr, [x, y])
|
|
|
|
def testHasObjectiveMinimize(self):
|
|
print('testHasObjectiveMinimizs')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 1, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
model.AddLinearConstraint(x + 2 * y, 0, 10)
|
|
self.assertFalse(model.HasObjective())
|
|
model.Minimize(y)
|
|
self.assertTrue(model.HasObjective())
|
|
|
|
def testHasObjectiveMaximize(self):
|
|
print('testHasObjectiveMaximizs')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 1, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
model.AddLinearConstraint(x + 2 * y, 0, 10)
|
|
self.assertFalse(model.HasObjective())
|
|
model.Maximize(y)
|
|
self.assertTrue(model.HasObjective())
|
|
|
|
def testSearchForAllSolutions(self):
|
|
print('testSearchForAllSolutions')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddLinearConstraint(x + y, 6, 6)
|
|
|
|
solver = cp_model.CpSolver()
|
|
solution_counter = SolutionCounter()
|
|
status = solver.SearchForAllSolutions(model, solution_counter)
|
|
self.assertEqual(cp_model.OPTIMAL, status)
|
|
self.assertEqual(5, solution_counter.SolutionCount())
|
|
model.Minimize(x)
|
|
self.assertRaises(TypeError, solver.SearchForAllSolutions, model,
|
|
solution_counter)
|
|
|
|
def testSolveWithSolutionCallback(self):
|
|
print('testSolveWithSolutionCallback')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddLinearConstraint(x + y, 6, 6)
|
|
|
|
solver = cp_model.CpSolver()
|
|
solution_sum = SolutionSum([x, y])
|
|
self.assertRaises(RuntimeError, solution_sum.Value, x)
|
|
status = solver.SolveWithSolutionCallback(model, solution_sum)
|
|
self.assertEqual(cp_model.OPTIMAL, status)
|
|
self.assertEqual(6, solution_sum.Sum())
|
|
|
|
def testValue(self):
|
|
print('testValue')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 10, 'x')
|
|
y = model.NewIntVar(0, 10, 'y')
|
|
model.Add(x + 2 * y == 29)
|
|
solver = cp_model.CpSolver()
|
|
status = solver.Solve(model)
|
|
self.assertEqual(cp_model.OPTIMAL, status)
|
|
self.assertEqual(solver.Value(x), 9)
|
|
self.assertEqual(solver.Value(y), 10)
|
|
self.assertEqual(solver.Value(2), 2)
|
|
|
|
def testBooleanValue(self):
|
|
print('testBooleanValue')
|
|
model = cp_model.CpModel()
|
|
x = model.NewBoolVar('x')
|
|
y = model.NewBoolVar('y')
|
|
z = model.NewBoolVar('z')
|
|
model.AddBoolOr([x, z.Not()])
|
|
model.AddBoolOr([x, z])
|
|
model.AddBoolOr([x.Not(), y.Not()])
|
|
solver = cp_model.CpSolver()
|
|
status = solver.Solve(model)
|
|
self.assertEqual(cp_model.OPTIMAL, status)
|
|
self.assertEqual(solver.BooleanValue(x), True)
|
|
self.assertEqual(solver.Value(x), 1 - solver.Value(x.Not()))
|
|
self.assertEqual(solver.Value(y), 1 - solver.Value(y.Not()))
|
|
self.assertEqual(solver.Value(z), 1 - solver.Value(z.Not()))
|
|
self.assertEqual(solver.BooleanValue(y), False)
|
|
self.assertEqual(solver.BooleanValue(True), True)
|
|
self.assertEqual(solver.BooleanValue(False), False)
|
|
self.assertEqual(solver.BooleanValue(2), True)
|
|
self.assertEqual(solver.BooleanValue(0), False)
|
|
|
|
def testUnsupportedOperators(self):
|
|
print('testUnsupportedOperators')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 10, 'x')
|
|
y = model.NewIntVar(0, 10, 'y')
|
|
z = model.NewIntVar(0, 10, 'z')
|
|
|
|
with self.assertRaises(NotImplementedError):
|
|
model.Add(x == min(y, z))
|
|
with self.assertRaises(NotImplementedError):
|
|
if x > y:
|
|
print('passed1')
|
|
with self.assertRaises(NotImplementedError):
|
|
if x == 2:
|
|
print('passed2')
|
|
|
|
def testIsLiteralTrueFalse(self):
|
|
print('testIsLiteralTrueFalse')
|
|
model = cp_model.CpModel()
|
|
x = model.NewConstant(0)
|
|
self.assertFalse(cp_model.ObjectIsATrueLiteral(x))
|
|
self.assertTrue(cp_model.ObjectIsAFalseLiteral(x))
|
|
self.assertTrue(cp_model.ObjectIsATrueLiteral(x.Not()))
|
|
self.assertFalse(cp_model.ObjectIsAFalseLiteral(x.Not()))
|
|
self.assertTrue(cp_model.ObjectIsATrueLiteral(True))
|
|
self.assertTrue(cp_model.ObjectIsAFalseLiteral(False))
|
|
self.assertFalse(cp_model.ObjectIsATrueLiteral(False))
|
|
self.assertFalse(cp_model.ObjectIsAFalseLiteral(True))
|
|
|
|
def testSolveMinimizeWithSolutionCallback(self):
|
|
print('testSolveMinimizeWithSolutionCallback')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddLinearConstraint(x + y, 6, 6)
|
|
model.Maximize(x + 2 * y)
|
|
|
|
solver = cp_model.CpSolver()
|
|
solution_obj = SolutionObjective()
|
|
status = solver.SolveWithSolutionCallback(model, solution_obj)
|
|
self.assertEqual(cp_model.OPTIMAL, status)
|
|
print('obj = ', solution_obj.Obj())
|
|
self.assertEqual(11, solution_obj.Obj())
|
|
|
|
def testSolutionHinting(self):
|
|
print('testSolutionHinting')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddLinearConstraint(x + y, 6, 6)
|
|
model.AddHint(x, 2)
|
|
model.AddHint(y, 4)
|
|
solver = cp_model.CpSolver()
|
|
solver.parameters.cp_model_presolve = False
|
|
status = solver.Solve(model)
|
|
self.assertEqual(cp_model.OPTIMAL, status)
|
|
self.assertEqual(2, solver.Value(x))
|
|
self.assertEqual(4, solver.Value(y))
|
|
|
|
def testStats(self):
|
|
print('testStats')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddLinearConstraint(x + y, 4, 6)
|
|
model.AddLinearConstraint(2 * x + y, 0, 10)
|
|
model.Maximize(x + 2 * y)
|
|
|
|
solver = cp_model.CpSolver()
|
|
status = solver.Solve(model)
|
|
self.assertEqual(cp_model.OPTIMAL, status)
|
|
self.assertEqual(solver.NumBooleans(), 0)
|
|
self.assertEqual(solver.NumConflicts(), 0)
|
|
self.assertEqual(solver.NumBranches(), 0)
|
|
self.assertGreater(solver.WallTime(), 0.0)
|
|
|
|
def testSearchStrategy(self):
|
|
print('testSearchStrategy')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddDecisionStrategy([y, x], cp_model.CHOOSE_MIN_DOMAIN_SIZE,
|
|
cp_model.SELECT_MAX_VALUE)
|
|
self.assertLen(model.Proto().search_strategy, 1)
|
|
strategy = model.Proto().search_strategy[0]
|
|
self.assertLen(strategy.variables, 2)
|
|
self.assertEqual(y.Index(), strategy.variables[0])
|
|
self.assertEqual(x.Index(), strategy.variables[1])
|
|
self.assertEqual(cp_model.CHOOSE_MIN_DOMAIN_SIZE,
|
|
strategy.variable_selection_strategy)
|
|
self.assertEqual(cp_model.SELECT_MAX_VALUE,
|
|
strategy.domain_reduction_strategy)
|
|
|
|
def testModelAndResponseStats(self):
|
|
print('testStats')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddLinearConstraint(x + y, 6, 6)
|
|
model.Maximize(x + 2 * y)
|
|
self.assertTrue(model.ModelStats())
|
|
|
|
solver = cp_model.CpSolver()
|
|
solver.Solve(model)
|
|
self.assertTrue(solver.ResponseStats())
|
|
|
|
def testValidateModel(self):
|
|
print('testValidateModel')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, 5, 'x')
|
|
y = model.NewIntVar(0, 5, 'y')
|
|
model.AddLinearConstraint(x + y, 6, 6)
|
|
model.Maximize(x + 2 * y)
|
|
self.assertFalse(model.Validate())
|
|
|
|
def testValidateModelWithOverflow(self):
|
|
print('testValidateModel')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(0, cp_model.INT_MAX, 'x')
|
|
y = model.NewIntVar(0, 10, 'y')
|
|
model.AddLinearConstraint(x + y, 6, cp_model.INT_MAX)
|
|
model.Maximize(x + 2 * y)
|
|
self.assertTrue(model.Validate())
|
|
|
|
def testCopyModel(self):
|
|
print('testCopyModel')
|
|
model = cp_model.CpModel()
|
|
b = model.NewBoolVar('b')
|
|
x = model.NewIntVar(0, 4, 'x')
|
|
y = model.NewIntVar(0, 3, 'y')
|
|
i = model.NewOptionalIntervalVar(x, 12, y, b, 'i')
|
|
lin = model.Add(x + y <= 10)
|
|
|
|
new_model = cp_model.CpModel()
|
|
new_model.CopyFrom(model)
|
|
copy_b = new_model.GetBoolVarFromProtoIndex(b.Index())
|
|
copy_x = new_model.GetIntVarFromProtoIndex(x.Index())
|
|
copy_y = new_model.GetIntVarFromProtoIndex(y.Index())
|
|
copy_i = new_model.GetIntervalVarFromProtoIndex(i.Index())
|
|
|
|
self.assertEqual(b.Index(), copy_b.Index())
|
|
self.assertEqual(x.Index(), copy_x.Index())
|
|
self.assertEqual(y.Index(), copy_y.Index())
|
|
self.assertEqual(i.Index(), copy_i.Index())
|
|
|
|
with self.assertRaises(ValueError):
|
|
new_model.GetBoolVarFromProtoIndex(-1)
|
|
|
|
with self.assertRaises(ValueError):
|
|
new_model.GetIntVarFromProtoIndex(-1)
|
|
|
|
with self.assertRaises(ValueError):
|
|
new_model.GetIntervalVarFromProtoIndex(-1)
|
|
|
|
with self.assertRaises(ValueError):
|
|
new_model.GetBoolVarFromProtoIndex(x.Index())
|
|
|
|
with self.assertRaises(ValueError):
|
|
new_model.GetIntervalVarFromProtoIndex(lin.Index())
|
|
|
|
interval_ct = new_model.Proto().constraints[copy_i.Index()].interval
|
|
self.assertEqual(12, interval_ct.size.offset)
|
|
|
|
def testCustomLog(self):
|
|
print('testCustomLog')
|
|
model = cp_model.CpModel()
|
|
x = model.NewIntVar(-10, 10, 'x')
|
|
y = model.NewIntVar(-10, 10, 'y')
|
|
model.AddLinearConstraint(x + 2 * y, 0, 10)
|
|
model.Minimize(y)
|
|
solver = cp_model.CpSolver()
|
|
solver.parameters.log_search_progress = True
|
|
solver.parameters.log_to_stdout = False
|
|
log_callback = LogToString()
|
|
solver.log_callback = log_callback.NewMessage
|
|
|
|
self.assertEqual(cp_model.OPTIMAL, solver.Solve(model))
|
|
self.assertEqual(10, solver.Value(x))
|
|
self.assertEqual(-5, solver.Value(y))
|
|
|
|
self.assertRegex(log_callback.Log(), 'Parameters.*log_to_stdout.*')
|
|
|
|
def testIssue2762(self):
|
|
print('testIssue2762')
|
|
model = cp_model.CpModel()
|
|
|
|
x = [model.NewBoolVar('a'), model.NewBoolVar('b')]
|
|
with self.assertRaises(NotImplementedError):
|
|
model.Add((x[0] != 0) or (x[1] != 0))
|
|
|
|
def testModelError(self):
|
|
print('TestModelError')
|
|
model = cp_model.CpModel()
|
|
x = [model.NewIntVar(0, -2, 'x%i' % i) for i in range(100)]
|
|
model.Add(sum(x) <= 1)
|
|
solver = cp_model.CpSolver()
|
|
solver.parameters.log_search_progress = True
|
|
self.assertEqual(cp_model.MODEL_INVALID, solver.Solve(model))
|
|
self.assertEqual(solver.SolutionInfo(),
|
|
'var #0 has no domain(): name: "x0"')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
absltest.main()
|