Summary sheet
More extensive user documentation in Modeling and solving with CPMpy.
import cpmpy as cp
Model class
model = cp.Model()
– Create aModel
.model += constraint
– Add a constraint (anExpression
) to the model.model.maximize(obj)
ormodel.minimize(obj)
– Set the objective (anExpression
).model.solve()
– Solve the model with the default solver, returns True/False.model.solveAll()
– Solve and enumerate all solutions, returns number of solutions.model.status()
– Get the status of the last solver run.model.objective_value()
– Get the objective value obtained during the last solver run.
Solvers
Solvers
have the same API as Model
. Solvers are instantiated throught the static cp.SolverLookup
class:
cp.SolverLookup.solvernames()
– List all installed solvers (including subsolvers).cp.SolverLookup.get(solvername, model=None)
– Initialize a specific solver.
Decision Variables
Decision variables
are NumPy-like objects: shape=None|1
creates one variable, shape=4
creates a vector of 4 variables, shape=(2,3)
creates a matrix of 2x3 variables, etc.
Name is optional too, indices are automatically added to the name so each variable has a unique name.
x = cp.boolvar(shape=4, name="x")
– Create four Boolean decision variables.x = cp.intvar(lb, ub)
– Create one integer decision variable with domain[lb, ub]
(inclusive).x.value()
– Get the value ofx
obtained during the last solver run.
Core Expressions
You can apply the following standard Python operators on CPMpy expressions, which creates the corresponding Core Expression
object:
Comparison:
==
,!=
,<
,<=
,>
,>=
Arithmetic:
+
,-
,*
,//
(integer division),%
(modulo),**
(power)Logical:
&
(and),|
(or),~
(not),^
(xor)Logical implication:
x.implies(y)
Logical operators only work on Boolean variables/constraints, numeric operators work on both integer and Boolean variables/expressions.
CPMpy overwrites the following Python built-ins
, they allow vectorized operations:
You can index CPMpy expressions with an integer decision variable: x[y]
, which will create an Element
expression object.
To index non-CPMpy arrays, wrap them with cpm_array()
: cpm_array([1,2,3])[y]
.
Global Functions
Global functions
are numeric functions that some solvers support natively (through a solver-specific global constraint). CPMpy automatically rewrites the global function as needed to work with any solver.
Computes the minimum value of the arguments |
|
Computes the maximum value of the arguments |
|
Computes the absolute value of the argument |
|
The 'Element' global constraint enforces that the result equals Arr[Idx] with 'Arr' an array of constants or variables (the first argument) and 'Idx' an integer decision variable, representing the index into the array. |
|
The Count (numerical) global constraint represents the number of occurrences of val in arr |
|
The Among (numerical) global constraint represents the number of variable that take values among the values in arr |
|
The NValue constraint counts the number of distinct values in a given set of variables. |
|
The NValueExceptN constraint counts the number of distinct values, |
Global Constraints
Global constraints
are constraints (Boolean functions) that some solvers support natively. All global constraints can be reified (implication, equivalence) and used in other expressions, which CPMpy will handle.
All arguments have a different (distinct) value |
|
All nonzero arguments have a distinct value |
|
All arguments except those equal to a value in n have a distinct value. |
|
All arguments have the same value |
|
All arguments except those equal to a value in n have the same value. |
|
The sequence of variables form a circuit, where x[i] = j means that j is the successor of i. |
|
Inverse (aka channeling / assignment) constraint. |
|
The values of the variables in 'array' correspond to a row in 'table' |
|
Extension of the Table constraint where the table matrix may contain wildcards (STAR), meaning there are no restrictions for the corresponding variable in that tuple. |
|
The values of the variables in 'array' do not correspond to any row in 'table' |
|
The IfThenElse constraint, defining a conditional expression of the form: if condition then if_true else if_false where condition, if_true and if_false are all boolean expressions. |
|
The "InDomain" constraint, defining non-interval domains for an expression |
|
The |
|
Global cumulative constraint. |
|
Constraint enforcing some values have precedence over others. |
|
NoOverlap constraint, enforcing that the intervals defined by start, duration and end do not overlap. |
|
The number of occurrences of each value vals[i] in the list of variables vars must be equal to occ[i]. |
|
The "Increasing" constraint, the expressions will have increasing (not strictly) values |
|
The "Decreasing" constraint, the expressions will have decreasing (not strictly) values |
|
The "IncreasingStrict" constraint, the expressions will have increasing (strictly) values |
|
The "DecreasingStrict" constraint, the expressions will have decreasing (strictly) values |
|
Given lists X,Y, enforcing that X is lexicographically less than Y. |
|
Given lists X,Y, enforcing that X is lexicographically less than Y (or equal). |
|
Given a matrix X, |
|
Given a matrix X, LexChainLessEq enforces that all rows are lexicographically ordered. |
|
A |
Guidelines and tips
Do not
from cpmpy import *
, the implicit overloading of any/all and sum may break or slow down other libraries.Explicitly use CPMpy versions of built-in functions (
cp.sum
,cp.all
, etc.).Use global constraints/global functions where possible, some solvers will be much faster.
Stick to integer constants; floats and fractional numbers are not supported.
For maintainability, use logical code organization and comments to explain your constraints.
Toy example
import cpmpy as cp
# Decision Variables
b = cp.boolvar()
x1, x2, x3 = x = cp.intvar(1, 10, shape=3)
# Constraints
model = cp.Model()
model += (x[0] == 1)
model += cp.AllDifferent(x)
model += cp.Count(x, 9) == 1
model += b.implies(x[1] + x[2] > 5)
# Objective
model.maximize(cp.sum(x) + 100 * b)
# Solving
solved = model.solve()
if solved:
print("Solution found:")
print('b:', b.value(), ' x:', x.value().tolist())
else:
print("No solution found.")