LinearExpr: Methods for creating constraints
+and the objective from large arrays of coefficients.
+
+
+
Other methods and functions listed are primarily used for developing OR-Tools,
+rather than for solving specific optimization problems.
+
+
+
+ View Source
+
# Copyright 2010-2021 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.
+"""Methods for building and solving CP-SAT models.
+
+The following two sections describe the main
+methods for building and solving CP-SAT models.
+
+* [`CpModel`](#cp_model.CpModel): Methods for creating
+models, including variables and constraints.
+* [`CPSolver`](#cp_model.CpSolver): Methods for solving
+a model and evaluating solutions.
+
+The following methods implement callbacks that the
+solver calls each time it finds a new solution.
+
+* [`CpSolverSolutionCallback`](#cp_model.CpSolverSolutionCallback):
+ A general method for implementing callbacks.
+* [`ObjectiveSolutionPrinter`](#cp_model.ObjectiveSolutionPrinter):
+ Print objective values and elapsed time for intermediate solutions.
+* [`VarArraySolutionPrinter`](#cp_model.VarArraySolutionPrinter):
+ Print intermediate solutions (variable values, time).
+* [`VarArrayAndObjectiveSolutionPrinter`]
+ (#cp_model.VarArrayAndObjectiveSolutionPrinter):
+ Print both intermediate solutions and objective values.
+
+Additional methods for solving CP-SAT models:
+
+* [`Constraint`](#cp_model.Constraint): A few utility methods for modifying
+ constraints created by `CpModel`.
+* [`LinearExpr`](#lineacp_model.LinearExpr): Methods for creating constraints
+ and the objective from large arrays of coefficients.
+
+Other methods and functions listed are primarily used for developing OR-Tools,
+rather than for solving specific optimization problems.
+"""
+
+importcollections
+importthreading
+importtime
+importwarnings
+
+fromortools.satimportcp_model_pb2
+fromortools.satimportsat_parameters_pb2
+fromortools.sat.pythonimportcp_model_helperascmh
+fromortools.sat.pythonimportswig_helper
+fromortools.util.pythonimportsorted_interval_list
+
+Domain=sorted_interval_list.Domain
+
+# The classes below allow linear expressions to be expressed naturally with the
+# usual arithmetic operators + - * / and with constant numbers, which makes the
+# python API very intuitive. See../ samples/*.py for examples.
+
+INT_MIN=-9223372036854775808# hardcoded to be platform independent.
+INT_MAX=9223372036854775807
+INT32_MAX=2147483647
+INT32_MIN=-2147483648
+
+# CpSolver status (exported to avoid importing cp_model_cp2).
+UNKNOWN=cp_model_pb2.UNKNOWN
+MODEL_INVALID=cp_model_pb2.MODEL_INVALID
+FEASIBLE=cp_model_pb2.FEASIBLE
+INFEASIBLE=cp_model_pb2.INFEASIBLE
+OPTIMAL=cp_model_pb2.OPTIMAL
+
+# Variable selection strategy
+CHOOSE_FIRST=cp_model_pb2.DecisionStrategyProto.CHOOSE_FIRST
+CHOOSE_LOWEST_MIN=cp_model_pb2.DecisionStrategyProto.CHOOSE_LOWEST_MIN
+CHOOSE_HIGHEST_MAX=cp_model_pb2.DecisionStrategyProto.CHOOSE_HIGHEST_MAX
+CHOOSE_MIN_DOMAIN_SIZE=(
+ cp_model_pb2.DecisionStrategyProto.CHOOSE_MIN_DOMAIN_SIZE)
+CHOOSE_MAX_DOMAIN_SIZE=(
+ cp_model_pb2.DecisionStrategyProto.CHOOSE_MAX_DOMAIN_SIZE)
+
+# Domain reduction strategy
+SELECT_MIN_VALUE=cp_model_pb2.DecisionStrategyProto.SELECT_MIN_VALUE
+SELECT_MAX_VALUE=cp_model_pb2.DecisionStrategyProto.SELECT_MAX_VALUE
+SELECT_LOWER_HALF=cp_model_pb2.DecisionStrategyProto.SELECT_LOWER_HALF
+SELECT_UPPER_HALF=cp_model_pb2.DecisionStrategyProto.SELECT_UPPER_HALF
+
+# Search branching
+AUTOMATIC_SEARCH=sat_parameters_pb2.SatParameters.AUTOMATIC_SEARCH
+FIXED_SEARCH=sat_parameters_pb2.SatParameters.FIXED_SEARCH
+PORTFOLIO_SEARCH=sat_parameters_pb2.SatParameters.PORTFOLIO_SEARCH
+LP_SEARCH=sat_parameters_pb2.SatParameters.LP_SEARCH
+
+
+defDisplayBounds(bounds):
+ """Displays a flattened list of intervals."""
+ out=''
+ foriinrange(0,len(bounds),2):
+ ifi!=0:
+ out+=', '
+ ifbounds[i]==bounds[i+1]:
+ out+=str(bounds[i])
+ else:
+ out+=str(bounds[i])+'..'+str(bounds[i+1])
+ returnout
+
+
+defShortName(model,i):
+ """Returns a short name of an integer variable, or its negation."""
+ ifi<0:
+ return'Not(%s)'%ShortName(model,-i-1)
+ v=model.variables[i]
+ ifv.name:
+ returnv.name
+ eliflen(v.domain)==2andv.domain[0]==v.domain[1]:
+ returnstr(v.domain[0])
+ else:
+ return'[%s]'%DisplayBounds(v.domain)
+
+
+defShortExprName(model,e):
+ """Pretty-print LinearExpressionProto instances."""
+ ifnote.vars:
+ returnstr(e.offset)
+ iflen(e.vars)==1:
+ var_name=ShortName(model,e.vars[0])
+ coeff=e.coeffs[0]
+ result=''
+ ifcoeff==1:
+ result=var_name
+ elifcoeff==-1:
+ result=f'-{var_name}'
+ elifcoeff!=0:
+ result=f'{coeff} * {var_name}'
+ ife.offset>0:
+ result=f'{result} + {e.offset}'
+ elife.offset<0:
+ result=f'{result} - {-e.offset}'
+ returnresult
+ # TODO(user): Support more than affine expressions.
+ returnstr(e)
+
+
+classLinearExpr(object):
+ """Holds an integer linear expression.
+
+ A linear expression is built from integer constants and variables.
+ For example, `x + 2 * (y - z + 1)`.
+
+ Linear expressions are used in CP-SAT models in constraints and in the
+ objective:
+
+ * You can define linear constraints as in:
+
+ ```
+ model.Add(x + 2 * y <= 5)
+ model.Add(sum(array_of_vars) == 5)
+ ```
+
+ * In CP-SAT, the objective is a linear expression:
+
+ ```
+ model.Minimize(x + 2 * y + z)
+ ```
+
+ * For large arrays, using the LinearExpr class is faster that using the python
+ `sum()` function. You can create constraints and the objective from lists of
+ linear expressions or coefficients as follows:
+
+ ```
+ model.Minimize(cp_model.LinearExpr.Sum(expressions))
+ model.Add(cp_model.LinearExpr.WeightedSum(expressions, coefficients) >= 0)
+ ```
+ """
+
+ @classmethod
+ defSum(cls,expressions):
+ """Creates the expression sum(expressions)."""
+ iflen(expressions)==1:
+ returnexpressions[0]
+ return_SumArray(expressions)
+
+ @classmethod
+ defWeightedSum(cls,expressions,coefficients):
+ """Creates the expression sum(expressions[i] * coefficients[i])."""
+ ifLinearExpr.IsEmptyOrAllNull(coefficients):
+ return0
+ eliflen(expressions)==1:
+ returnexpressions[0]*coefficients[0]
+ else:
+ return_WeightedSum(expressions,coefficients)
+
+ @classmethod
+ defTerm(cls,expression,coefficient):
+ """Creates `expression * coefficient`."""
+ ifcmh.is_zero(coefficient):
+ return0
+ else:
+ returnexpression*coefficient
+
+ @classmethod
+ defIsEmptyOrAllNull(cls,coefficients):
+ forcincoefficients:
+ ifnotcmh.is_zero(c):
+ returnFalse
+ returnTrue
+
+ @classmethod
+ defRebuildFromLinearExpressionProto(cls,model,proto):
+ """Recreate a LinearExpr from a LinearExpressionProto."""
+ offset=proto.offset
+ num_elements=len(proto.vars)
+ ifnum_elements==0:
+ returnoffset
+ elifnum_elements==1:
+ returnIntVar(model,proto.vars[0],None)*proto.coeffs[0]+offset
+ else:
+ variables=[]
+ coeffs=[]
+ all_ones=True
+ forindex,coeffinzip(proto.vars(),proto.coeffs()):
+ variables.append(IntVar(model,index,None))
+ coeffs.append(coeff)
+ ifnotcmh.is_one(coeff):
+ all_ones=False
+ ifall_ones:
+ return_SumArray(variables,offset)
+ else:
+ return_WeightedSum(variables,coeffs,offset)
+
+ defGetIntegerVarValueMap(self):
+ """Scans the expression, and returns (var_coef_map, constant)."""
+ coeffs=collections.defaultdict(int)
+ constant=0
+ to_process=[(self,1)]
+ whileto_process:# Flatten to avoid recursion.
+ expr,coeff=to_process.pop()
+ ifcmh.is_integral(expr):
+ constant+=coeff*int(expr)
+ elifisinstance(expr,_ProductCst):
+ to_process.append(
+ (expr.Expression(),coeff*expr.Coefficient()))
+ elifisinstance(expr,_Sum):
+ to_process.append((expr.Left(),coeff))
+ to_process.append((expr.Right(),coeff))
+ elifisinstance(expr,_SumArray):
+ foreinexpr.Expressions():
+ to_process.append((e,coeff))
+ constant+=expr.Constant()*coeff
+ elifisinstance(expr,_WeightedSum):
+ fore,cinzip(expr.Expressions(),expr.Coefficients()):
+ to_process.append((e,coeff*c))
+ constant+=expr.Constant()*coeff
+ elifisinstance(expr,IntVar):
+ coeffs[expr]+=coeff
+ elifisinstance(expr,_NotBooleanVariable):
+ constant+=coeff
+ coeffs[expr.Not()]-=coeff
+ else:
+ raiseTypeError('Unrecognized linear expression: '+str(expr))
+
+ returncoeffs,constant
+
+ defGetFloatVarValueMap(self):
+ """Scans the expression. Returns (var_coef_map, constant, is_integer)."""
+ coeffs={}
+ constant=0
+ to_process=[(self,1)]
+ whileto_process:# Flatten to avoid recursion.
+ expr,coeff=to_process.pop()
+ ifcmh.is_integral(expr):# Keep integrality.
+ constant+=coeff*int(expr)
+ elifcmh.is_a_number(expr):
+ constant+=coeff*float(expr)
+ elifisinstance(expr,_ProductCst):
+ to_process.append(
+ (expr.Expression(),coeff*expr.Coefficient()))
+ elifisinstance(expr,_Sum):
+ to_process.append((expr.Left(),coeff))
+ to_process.append((expr.Right(),coeff))
+ elifisinstance(expr,_SumArray):
+ foreinexpr.Expressions():
+ to_process.append((e,coeff))
+ constant+=expr.Constant()*coeff
+ elifisinstance(expr,_WeightedSum):
+ fore,cinzip(expr.Expressions(),expr.Coefficients()):
+ to_process.append((e,coeff*c))
+ constant+=expr.Constant()*coeff
+ elifisinstance(expr,IntVar):
+ ifexprincoeffs:
+ coeffs[expr]+=coeff
+ else:
+ coeffs[expr]=coeff
+ elifisinstance(expr,_NotBooleanVariable):
+ constant+=coeff
+ ifexpr.Not()incoeffs:
+ coeffs[expr.Not()]-=coeff
+ else:
+ coeffs[expr.Not()]=-coeff
+ else:
+ raiseTypeError('Unrecognized linear expression: '+str(expr))
+ is_integer=cmh.is_integral(constant)
+ ifis_integer:
+ forcoeffincoeffs.values():
+ ifnotcmh.is_integral(coeff):
+ is_integer=False
+ break
+ returncoeffs,constant,is_integer
+
+ def__hash__(self):
+ returnobject.__hash__(self)
+
+ def__abs__(self):
+ raiseNotImplementedError(
+ 'calling abs() on a linear expression is not supported, '
+ 'please use CpModel.AddAbsEquality')
+
+ def__add__(self,arg):
+ ifcmh.is_zero(arg):
+ returnself
+ return_Sum(self,arg)
+
+ def__radd__(self,arg):
+ ifcmh.is_zero(arg):
+ returnself
+ return_Sum(self,arg)
+
+ def__sub__(self,arg):
+ ifcmh.is_zero(arg):
+ returnself
+ return_Sum(self,-arg)
+
+ def__rsub__(self,arg):
+ return_Sum(-self,arg)
+
+ def__mul__(self,arg):
+ arg=cmh.assert_is_a_number(arg)
+ ifcmh.is_one(arg):
+ returnself
+ elifcmh.is_zero(arg):
+ return0
+ return_ProductCst(self,arg)
+
+ def__rmul__(self,arg):
+ arg=cmh.assert_is_a_number(arg)
+ ifcmh.is_one(arg):
+ returnself
+ elifcmh.is_zero(arg):
+ return0
+ return_ProductCst(self,arg)
+
+ def__div__(self,_):
+ raiseNotImplementedError(
+ 'calling / on a linear expression is not supported, '
+ 'please use CpModel.AddDivisionEquality')
+
+ def__truediv__(self,_):
+ raiseNotImplementedError(
+ 'calling // on a linear expression is not supported, '
+ 'please use CpModel.AddDivisionEquality')
+
+ def__mod__(self,_):
+ raiseNotImplementedError(
+ 'calling %% on a linear expression is not supported, '
+ 'please use CpModel.AddModuloEquality')
+
+ def__pow__(self,_):
+ raiseNotImplementedError(
+ 'calling ** on a linear expression is not supported, '
+ 'please use CpModel.AddMultiplicationEquality')
+
+ def__lshift__(self,_):
+ raiseNotImplementedError(
+ 'calling left shift on a linear expression is not supported')
+
+ def__rshift__(self,_):
+ raiseNotImplementedError(
+ 'calling right shift on a linear expression is not supported')
+
+ def__and__(self,_):
+ raiseNotImplementedError(
+ 'calling and on a linear expression is not supported, '
+ 'please use CpModel.AddBoolAnd')
+
+ def__or__(self,_):
+ raiseNotImplementedError(
+ 'calling or on a linear expression is not supported, '
+ 'please use CpModel.AddBoolOr')
+
+ def__xor__(self,_):
+ raiseNotImplementedError(
+ 'calling xor on a linear expression is not supported, '
+ 'please use CpModel.AddBoolXor')
+
+ def__neg__(self):
+ return_ProductCst(self,-1)
+
+ def__bool__(self):
+ raiseNotImplementedError(
+ 'Evaluating a LinearExpr instance as a Boolean is not implemented.')
+
+ def__eq__(self,arg):
+ ifargisNone:
+ returnFalse
+ ifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ returnBoundedLinearExpression(self,[arg,arg])
+ else:
+ returnBoundedLinearExpression(self-arg,[0,0])
+
+ def__ge__(self,arg):
+ ifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ returnBoundedLinearExpression(self,[arg,INT_MAX])
+ else:
+ returnBoundedLinearExpression(self-arg,[0,INT_MAX])
+
+ def__le__(self,arg):
+ ifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ returnBoundedLinearExpression(self,[INT_MIN,arg])
+ else:
+ returnBoundedLinearExpression(self-arg,[INT_MIN,0])
+
+ def__lt__(self,arg):
+ ifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ ifarg==INT_MIN:
+ raiseArithmeticError('< INT_MIN is not supported')
+ returnBoundedLinearExpression(self,[INT_MIN,arg-1])
+ else:
+ returnBoundedLinearExpression(self-arg,[INT_MIN,-1])
+
+ def__gt__(self,arg):
+ ifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ ifarg==INT_MAX:
+ raiseArithmeticError('> INT_MAX is not supported')
+ returnBoundedLinearExpression(self,[arg+1,INT_MAX])
+ else:
+ returnBoundedLinearExpression(self-arg,[1,INT_MAX])
+
+ def__ne__(self,arg):
+ ifargisNone:
+ returnTrue
+ ifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ ifarg==INT_MAX:
+ returnBoundedLinearExpression(self,[INT_MIN,INT_MAX-1])
+ elifarg==INT_MIN:
+ returnBoundedLinearExpression(self,[INT_MIN+1,INT_MAX])
+ else:
+ returnBoundedLinearExpression(
+ self,[INT_MIN,arg-1,arg+1,INT_MAX])
+ else:
+ returnBoundedLinearExpression(self-arg,
+ [INT_MIN,-1,1,INT_MAX])
+
+
+class_Sum(LinearExpr):
+ """Represents the sum of two LinearExprs."""
+
+ def__init__(self,left,right):
+ forxin[left,right]:
+ ifnotcmh.is_a_number(x)andnotisinstance(x,LinearExpr):
+ raiseTypeError('Not an linear expression: '+str(x))
+ self.__left=left
+ self.__right=right
+
+ defLeft(self):
+ returnself.__left
+
+ defRight(self):
+ returnself.__right
+
+ def__str__(self):
+ returnf'({self.__left} + {self.__right})'
+
+ def__repr__(self):
+ returnf'Sum({repr(self.__left)}, {repr(self.__right)})'
+
+
+class_ProductCst(LinearExpr):
+ """Represents the product of a LinearExpr by a constant."""
+
+ def__init__(self,expr,coeff):
+ coeff=cmh.assert_is_a_number(coeff)
+ ifisinstance(expr,_ProductCst):
+ self.__expr=expr.Expression()
+ self.__coef=expr.Coefficient()*coeff
+ else:
+ self.__expr=expr
+ self.__coef=coeff
+
+ def__str__(self):
+ ifself.__coef==-1:
+ return'-'+str(self.__expr)
+ else:
+ return'('+str(self.__coef)+' * '+str(self.__expr)+')'
+
+ def__repr__(self):
+ return'ProductCst('+repr(self.__expr)+', '+repr(
+ self.__coef)+')'
+
+ defCoefficient(self):
+ returnself.__coef
+
+ defExpression(self):
+ returnself.__expr
+
+
+class_SumArray(LinearExpr):
+ """Represents the sum of a list of LinearExpr and a constant."""
+
+ def__init__(self,expressions,constant=0):
+ self.__expressions=[]
+ self.__constant=constant
+ forxinexpressions:
+ ifcmh.is_a_number(x):
+ ifcmh.is_zero(x):
+ continue
+ x=cmh.assert_is_a_number(x)
+ self.__constant+=x
+ elifisinstance(x,LinearExpr):
+ self.__expressions.append(x)
+ else:
+ raiseTypeError('Not an linear expression: '+str(x))
+
+ def__str__(self):
+ ifself.__constant==0:
+ return'({})'.format(' + '.join(map(str,self.__expressions)))
+ else:
+ return'({} + {})'.format(' + '.join(map(str,self.__expressions)),
+ self.__constant)
+
+ def__repr__(self):
+ return'SumArray({}, {})'.format(
+ ', '.join(map(repr,self.__expressions)),self.__constant)
+
+ defExpressions(self):
+ returnself.__expressions
+
+ defConstant(self):
+ returnself.__constant
+
+
+class_WeightedSum(LinearExpr):
+ """Represents sum(ai * xi) + b."""
+
+ def__init__(self,expressions,coefficients,constant=0):
+ self.__expressions=[]
+ self.__coefficients=[]
+ self.__constant=constant
+ iflen(expressions)!=len(coefficients):
+ raiseTypeError(
+ 'In the LinearExpr.WeightedSum method, the expression array and the '
+ ' coefficient array must have the same length.')
+ fore,cinzip(expressions,coefficients):
+ c=cmh.assert_is_a_number(c)
+ ifcmh.is_zero(c):
+ continue
+ ifcmh.is_a_number(e):
+ e=cmh.assert_is_a_number(e)
+ self.__constant+=e*c
+ elifisinstance(e,LinearExpr):
+ self.__expressions.append(e)
+ self.__coefficients.append(c)
+ else:
+ raiseTypeError('Not an linear expression: '+str(e))
+
+ def__str__(self):
+ output=None
+ forexpr,coeffinzip(self.__expressions,self.__coefficients):
+ ifnotoutputandcmh.is_one(coeff):
+ output=str(expr)
+ elifnotoutputandcmh.is_minus_one(coeff):
+ output='-'+str(expr)
+ elifnotoutput:
+ output='{} * {}'.format(coeff,str(expr))
+ elifcmh.is_one(coeff):
+ output+=' + {}'.format(str(expr))
+ elifcmh.is_minus_one(coeff):
+ output+=' - {}'.format(str(expr))
+ elifcoeff>1:
+ output+=' + {} * {}'.format(coeff,str(expr))
+ elifcoeff<-1:
+ output+=' - {} * {}'.format(-coeff,str(expr))
+ ifself.__constant>0:
+ output+=' + {}'.format(self.__constant)
+ elifself.__constant<0:
+ output+=' - {}'.format(-self.__constant)
+ ifoutputisNone:
+ output='0'
+ returnoutput
+
+ def__repr__(self):
+ return'WeightedSum([{}], [{}], {})'.format(
+ ', '.join(map(repr,self.__expressions)),
+ ', '.join(map(repr,self.__coefficients)),self.__constant)
+
+ defExpressions(self):
+ returnself.__expressions
+
+ defCoefficients(self):
+ returnself.__coefficients
+
+ defConstant(self):
+ returnself.__constant
+
+
+classIntVar(LinearExpr):
+ """An integer variable.
+
+ An IntVar is an object that can take on any integer value within defined
+ ranges. Variables appear in constraint like:
+
+ x + y >= 5
+ AllDifferent([x, y, z])
+
+ Solving a model is equivalent to finding, for each variable, a single value
+ from the set of initial values (called the initial domain), such that the
+ model is feasible, or optimal if you provided an objective function.
+ """
+
+ def__init__(self,model,domain,name):
+ """See CpModel.NewIntVar below."""
+ self.__model=model
+ self.__negation=None
+ # Python do not support multiple __init__ methods.
+ # This method is only called from the CpModel class.
+ # We hack the parameter to support the two cases:
+ # case 1:
+ # model is a CpModelProto, domain is a Domain, and name is a string.
+ # case 2:
+ # model is a CpModelProto, domain is an index (int), and name is None.
+ ifcmh.is_integral(domain)andnameisNone:
+ self.__index=int(domain)
+ self.__var=model.variables[domain]
+ else:
+ self.__index=len(model.variables)
+ self.__var=model.variables.add()
+ self.__var.domain.extend(domain.FlattenedIntervals())
+ self.__var.name=name
+
+ defIndex(self):
+ """Returns the index of the variable in the model."""
+ returnself.__index
+
+ defProto(self):
+ """Returns the variable protobuf."""
+ returnself.__var
+
+ defIsEqualTo(self,other):
+ """Returns true if self == other in the python sense."""
+ ifnotisinstance(other,IntVar):
+ returnFalse
+ returnself.Index()==other.Index()
+
+ def__str__(self):
+ ifnotself.__var.name:
+ iflen(self.__var.domain
+ )==2andself.__var.domain[0]==self.__var.domain[1]:
+ # Special case for constants.
+ returnstr(self.__var.domain[0])
+ else:
+ return'unnamed_var_%i'%self.__index
+ returnself.__var.name
+
+ def__repr__(self):
+ return'%s(%s)'%(self.__var.name,DisplayBounds(self.__var.domain))
+
+ defName(self):
+ returnself.__var.name
+
+ defNot(self):
+ """Returns the negation of a Boolean variable.
+
+ This method implements the logical negation of a Boolean variable.
+ It is only valid if the variable has a Boolean domain (0 or 1).
+
+ Note that this method is nilpotent: `x.Not().Not() == x`.
+ """
+
+ forboundinself.__var.domain:
+ ifbound<0orbound>1:
+ raiseTypeError(
+ 'Cannot call Not on a non boolean variable: %s'%self)
+ ifself.__negationisNone:
+ self.__negation=_NotBooleanVariable(self)
+ returnself.__negation
+
+
+class_NotBooleanVariable(LinearExpr):
+ """Negation of a boolean variable."""
+
+ def__init__(self,boolvar):
+ self.__boolvar=boolvar
+
+ defIndex(self):
+ return-self.__boolvar.Index()-1
+
+ defNot(self):
+ returnself.__boolvar
+
+ def__str__(self):
+ return'not(%s)'%str(self.__boolvar)
+
+ def__bool__(self):
+ raiseNotImplementedError(
+ 'Evaluating a literal as a Boolean value is not implemented.')
+
+
+classBoundedLinearExpression(object):
+ """Represents a linear constraint: `lb <= linear expression <= ub`.
+
+ The only use of this class is to be added to the CpModel through
+ `CpModel.Add(expression)`, as in:
+
+ model.Add(x + 2 * y -1 >= z)
+ """
+
+ def__init__(self,expr,bounds):
+ self.__expr=expr
+ self.__bounds=bounds
+
+ def__str__(self):
+ iflen(self.__bounds)==2:
+ lb=self.__bounds[0]
+ ub=self.__bounds[1]
+ iflb>INT_MINandub<INT_MAX:
+ iflb==ub:
+ returnstr(self.__expr)+' == '+str(lb)
+ else:
+ returnstr(lb)+' <= '+str(
+ self.__expr)+' <= '+str(ub)
+ eliflb>INT_MIN:
+ returnstr(self.__expr)+' >= '+str(lb)
+ elifub<INT_MAX:
+ returnstr(self.__expr)+' <= '+str(ub)
+ else:
+ return'True (unbounded expr '+str(self.__expr)+')'
+ elif(len(self.__bounds)==4andself.__bounds[0]==INT_MINand
+ self.__bounds[1]+2==self.__bounds[2]and
+ self.__bounds[3]==INT_MAX):
+ returnstr(self.__expr)+' != '+str(self.__bounds[1]+1)
+ else:
+ returnstr(self.__expr)+' in ['+DisplayBounds(
+ self.__bounds)+']'
+
+ defExpression(self):
+ returnself.__expr
+
+ defBounds(self):
+ returnself.__bounds
+
+ def__bool__(self):
+ coeffs_map,constant=self.__expr.GetIntegerVarValueMap()
+ all_coeffs=set(coeffs_map.values())
+ same_var=set([0])
+ eq_bounds=[0,0]
+ different_vars=set([-1,1])
+ ne_bounds=[INT_MIN,-1,1,INT_MAX]
+ if(len(coeffs_map)==1andall_coeffs==same_varand
+ constant==0and
+ (self.__bounds==eq_boundsorself.__bounds==ne_bounds)):
+ returnself.__bounds==eq_bounds
+ if(len(coeffs_map)==2andall_coeffs==different_varsand
+ constant==0and
+ (self.__bounds==eq_boundsorself.__bounds==ne_bounds)):
+ returnself.__bounds==ne_bounds
+
+ raiseNotImplementedError(
+ f'Evaluating a BoundedLinearExpression \'{self}\' as a Boolean value'
+ +' is not supported.')
+
+
+classConstraint(object):
+ """Base class for constraints.
+
+ Constraints are built by the CpModel through the Add<XXX> methods.
+ Once created by the CpModel class, they are automatically added to the model.
+ The purpose of this class is to allow specification of enforcement literals
+ for this constraint.
+
+ b = model.NewBoolVar('b')
+ x = model.NewIntVar(0, 10, 'x')
+ y = model.NewIntVar(0, 10, 'y')
+
+ model.Add(x + 2 * y == 5).OnlyEnforceIf(b.Not())
+ """
+
+ def__init__(self,constraints):
+ self.__index=len(constraints)
+ self.__constraint=constraints.add()
+
+ defOnlyEnforceIf(self,*boolvar):
+ """Adds an enforcement literal to the constraint.
+
+ This method adds one or more literals (that is, a boolean variable or its
+ negation) as enforcement literals. The conjunction of all these literals
+ determines whether the constraint is active or not. It acts as an
+ implication, so if the conjunction is true, it implies that the constraint
+ must be enforced. If it is false, then the constraint is ignored.
+
+ BoolOr, BoolAnd, and linear constraints all support enforcement literals.
+
+ Args:
+ *boolvar: One or more Boolean literals.
+
+ Returns:
+ self.
+ """
+ forlitinExpandGeneratorOrTuple(boolvar):
+ if(isinstance(lit,bool)and
+ bool(lit))or(cmh.is_integral(lit)andint(lit)==1):
+ # Always true. Do nothing.
+ pass
+ else:
+ self.__constraint.enforcement_literal.append(lit.Index())
+ returnself
+
+ defIndex(self):
+ """Returns the index of the constraint in the model."""
+ returnself.__index
+
+ defProto(self):
+ """Returns the constraint protobuf."""
+ returnself.__constraint
+
+
+classIntervalVar(object):
+ """Represents an Interval variable.
+
+ An interval variable is both a constraint and a variable. It is defined by
+ three integer variables: start, size, and end.
+
+ It is a constraint because, internally, it enforces that start + size == end.
+
+ It is also a variable as it can appear in specific scheduling constraints:
+ NoOverlap, NoOverlap2D, Cumulative.
+
+ Optionally, an enforcement literal can be added to this constraint, in which
+ case these scheduling constraints will ignore interval variables with
+ enforcement literals assigned to false. Conversely, these constraints will
+ also set these enforcement literals to false if they cannot fit these
+ intervals into the schedule.
+ """
+
+ def__init__(self,model,start,size,end,is_present_index,name):
+ self.__model=model
+ # As with the IntVar::__init__ method, we hack the __init__ method to
+ # support two use cases:
+ # case 1: called when creating a new interval variable.
+ # {start|size|end} are linear expressions, is_present_index is either
+ # None or the index of a Boolean literal. name is a string
+ # case 2: called when querying an existing interval variable.
+ # start_index is an int, all parameters after are None.
+ if(sizeisNoneandendisNoneandis_present_indexisNoneand
+ nameisNone):
+ self.__index=start
+ self.__ct=model.constraints[start]
+ else:
+ self.__index=len(model.constraints)
+ self.__ct=self.__model.constraints.add()
+ self.__ct.interval.start.CopyFrom(start)
+ self.__ct.interval.size.CopyFrom(size)
+ self.__ct.interval.end.CopyFrom(end)
+ ifis_present_indexisnotNone:
+ self.__ct.enforcement_literal.append(is_present_index)
+ ifname:
+ self.__ct.name=name
+
+ defIndex(self):
+ """Returns the index of the interval constraint in the model."""
+ returnself.__index
+
+ defProto(self):
+ """Returns the interval protobuf."""
+ returnself.__ct.interval
+
+ def__str__(self):
+ returnself.__ct.name
+
+ def__repr__(self):
+ interval=self.__ct.interval
+ ifself.__ct.enforcement_literal:
+ return'%s(start = %s, size = %s, end = %s, is_present = %s)'%(
+ self.__ct.name,ShortExprName(self.__model,interval.start),
+ ShortExprName(self.__model,interval.size),
+ ShortExprName(self.__model,interval.end),
+ ShortName(self.__model,self.__ct.enforcement_literal[0]))
+ else:
+ return'%s(start = %s, size = %s, end = %s)'%(
+ self.__ct.name,ShortExprName(self.__model,interval.start),
+ ShortExprName(self.__model,interval.size),
+ ShortExprName(self.__model,interval.end))
+
+ defName(self):
+ returnself.__ct.name
+
+ defStartExpr(self):
+ returnLinearExpr.RebuildFromLinearExpressionProto(
+ self.__model,self.__ct.interval.start)
+
+ defSizeExpr(self):
+ returnLinearExpr.RebuildFromLinearExpressionProto(
+ self.__model,self.__ct.interval.size)
+
+ defEndExpr(self):
+ returnLinearExpr.RebuildFromLinearExpressionProto(
+ self.__model,self.__ct.interval.end)
+
+
+defObjectIsATrueLiteral(literal):
+ """Checks if literal is either True, or a Boolean literals fixed to True."""
+ ifisinstance(literal,IntVar):
+ proto=literal.Proto()
+ return(len(proto.domain)==2andproto.domain[0]==1and
+ proto.domain[1]==1)
+ ifisinstance(literal,_NotBooleanVariable):
+ proto=literal.Not().Proto()
+ return(len(proto.domain)==2andproto.domain[0]==0and
+ proto.domain[1]==0)
+ ifcmh.is_integral(literal):
+ returnint(literal)==1
+ returnFalse
+
+
+defObjectIsAFalseLiteral(literal):
+ """Checks if literal is either False, or a Boolean literals fixed to False."""
+ ifisinstance(literal,IntVar):
+ proto=literal.Proto()
+ return(len(proto.domain)==2andproto.domain[0]==0and
+ proto.domain[1]==0)
+ ifisinstance(literal,_NotBooleanVariable):
+ proto=literal.Not().Proto()
+ return(len(proto.domain)==2andproto.domain[0]==1and
+ proto.domain[1]==1)
+ ifcmh.is_integral(literal):
+ returnint(literal)==0
+ returnFalse
+
+
+classCpModel(object):
+ """Methods for building a CP model.
+
+ Methods beginning with:
+
+ * ```New``` create integer, boolean, or interval variables.
+ * ```Add``` create new constraints and add them to the model.
+ """
+
+ def__init__(self):
+ self.__model=cp_model_pb2.CpModelProto()
+ self.__constant_map={}
+
+ # Integer variable.
+
+ defNewIntVar(self,lb,ub,name):
+ """Create an integer variable with domain [lb, ub].
+
+ The CP-SAT solver is limited to integer variables. If you have fractional
+ values, scale them up so that they become integers; if you have strings,
+ encode them as integers.
+
+ Args:
+ lb: Lower bound for the variable.
+ ub: Upper bound for the variable.
+ name: The name of the variable.
+
+ Returns:
+ a variable whose domain is [lb, ub].
+ """
+
+ returnIntVar(self.__model,Domain(lb,ub),name)
+
+ defNewIntVarFromDomain(self,domain,name):
+ """Create an integer variable from a domain.
+
+ A domain is a set of integers specified by a collection of intervals.
+ For example, `model.NewIntVarFromDomain(cp_model.
+ Domain.FromIntervals([[1, 2], [4, 6]]), 'x')`
+
+ Args:
+ domain: An instance of the Domain class.
+ name: The name of the variable.
+
+ Returns:
+ a variable whose domain is the given domain.
+ """
+ returnIntVar(self.__model,domain,name)
+
+ defNewBoolVar(self,name):
+ """Creates a 0-1 variable with the given name."""
+ returnIntVar(self.__model,Domain(0,1),name)
+
+ defNewConstant(self,value):
+ """Declares a constant integer."""
+ returnIntVar(self.__model,self.GetOrMakeIndexFromConstant(value),
+ None)
+
+ # Linear constraints.
+
+ defAddLinearConstraint(self,linear_expr,lb,ub):
+ """Adds the constraint: `lb <= linear_expr <= ub`."""
+ returnself.AddLinearExpressionInDomain(linear_expr,Domain(lb,ub))
+
+ defAddLinearExpressionInDomain(self,linear_expr,domain):
+ """Adds the constraint: `linear_expr` in `domain`."""
+ ifisinstance(linear_expr,LinearExpr):
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ coeffs_map,constant=linear_expr.GetIntegerVarValueMap()
+ fortincoeffs_map.items():
+ ifnotisinstance(t[0],IntVar):
+ raiseTypeError('Wrong argument'+str(t))
+ c=cmh.assert_is_int64(t[1])
+ model_ct.linear.vars.append(t[0].Index())
+ model_ct.linear.coeffs.append(c)
+ model_ct.linear.domain.extend([
+ cmh.capped_subtraction(x,constant)
+ forxindomain.FlattenedIntervals()
+ ])
+ returnct
+ elifcmh.is_integral(linear_expr):
+ ifnotdomain.Contains(int(linear_expr)):
+ returnself.AddBoolOr([])# Evaluate to false.
+ # Nothing to do otherwise.
+ else:
+ raiseTypeError(
+ 'Not supported: CpModel.AddLinearExpressionInDomain('+
+ str(linear_expr)+' '+str(domain)+')')
+
+ defAdd(self,ct):
+ """Adds a `BoundedLinearExpression` to the model.
+
+ Args:
+ ct: A [`BoundedLinearExpression`](#boundedlinearexpression).
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ifisinstance(ct,BoundedLinearExpression):
+ returnself.AddLinearExpressionInDomain(
+ ct.Expression(),Domain.FromFlatIntervals(ct.Bounds()))
+ elifctandisinstance(ct,bool):
+ returnself.AddBoolOr([True])
+ elifnotctandisinstance(ct,bool):
+ returnself.AddBoolOr([])# Evaluate to false.
+ else:
+ raiseTypeError('Not supported: CpModel.Add('+str(ct)+')')
+
+ # General Integer Constraints.
+
+ defAddAllDifferent(self,*expressions):
+ """Adds AllDifferent(expressions).
+
+ This constraint forces all expressions to have different values.
+
+ Args:
+ *expressions: simple expressions of the form a * var + constant.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ expanded=ExpandGeneratorOrTuple(expressions)
+ model_ct.all_diff.exprs.extend(
+ [self.ParseLinearExpression(x)forxinexpanded])
+ returnct
+
+ defAddElement(self,index,variables,target):
+ """Adds the element constraint: `variables[index] == target`."""
+
+ ifnotvariables:
+ raiseValueError('AddElement expects a non-empty variables array')
+
+ ifcmh.is_integral(index):
+ returnself.Add(list(variables)[int(index)]==target)
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.element.index=self.GetOrMakeIndex(index)
+ model_ct.element.vars.extend(
+ [self.GetOrMakeIndex(x)forxinvariables])
+ model_ct.element.target=self.GetOrMakeIndex(target)
+ returnct
+
+ defAddCircuit(self,arcs):
+ """Adds Circuit(arcs).
+
+ Adds a circuit constraint from a sparse list of arcs that encode the graph.
+
+ A circuit is a unique Hamiltonian path in a subgraph of the total
+ graph. In case a node 'i' is not in the path, then there must be a
+ loop arc 'i -> i' associated with a true literal. Otherwise
+ this constraint will fail.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError('AddCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.circuit.tails.append(tail)
+ model_ct.circuit.heads.append(head)
+ model_ct.circuit.literals.append(lit)
+ returnct
+
+ defAddMultipleCircuit(self,arcs):
+ """Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+ The direct graph where arc #i (from tails[i] to head[i]) is present iff
+ literals[i] is true must satisfy this set of properties:
+ - #incoming arcs == 1 except for node 0.
+ - #outgoing arcs == 1 except for node 0.
+ - for node zero, #incoming arcs == #outgoing arcs.
+ - There are no duplicate arcs.
+ - Self-arcs are allowed except for node 0.
+ - There is no cycle in this graph, except through node 0.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError(
+ 'AddMultipleCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.routes.tails.append(tail)
+ model_ct.routes.heads.append(head)
+ model_ct.routes.literals.append(lit)
+ returnct
+
+ defAddAllowedAssignments(self,variables,tuples_list):
+ """Adds AllowedAssignments(variables, tuples_list).
+
+ An AllowedAssignments constraint is a constraint on an array of variables,
+ which requires that when all variables are assigned values, the resulting
+ array equals one of the tuples in `tuple_list`.
+
+ Args:
+ variables: A list of variables.
+ tuples_list: A list of admissible tuples. Each tuple must have the same
+ length as the variables, and the ith value of a tuple corresponds to the
+ ith variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: If a tuple does not have the same size as the list of
+ variables.
+ ValueError: If the array of variables is empty.
+ """
+
+ ifnotvariables:
+ raiseValueError(
+ 'AddAllowedAssignments expects a non-empty variables '
+ 'array')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.table.vars.extend([self.GetOrMakeIndex(x)forxinvariables])
+ arity=len(variables)
+ fortintuples_list:
+ iflen(t)!=arity:
+ raiseTypeError('Tuple '+str(t)+' has the wrong arity')
+ ar=[]
+ forvint:
+ ar.append(cmh.assert_is_int64(v))
+ model_ct.table.values.extend(ar)
+ returnct
+
+ defAddForbiddenAssignments(self,variables,tuples_list):
+ """Adds AddForbiddenAssignments(variables, [tuples_list]).
+
+ A ForbiddenAssignments constraint is a constraint on an array of variables
+ where the list of impossible combinations is provided in the tuples list.
+
+ Args:
+ variables: A list of variables.
+ tuples_list: A list of forbidden tuples. Each tuple must have the same
+ length as the variables, and the *i*th value of a tuple corresponds to
+ the *i*th variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: If a tuple does not have the same size as the list of
+ variables.
+ ValueError: If the array of variables is empty.
+ """
+
+ ifnotvariables:
+ raiseValueError(
+ 'AddForbiddenAssignments expects a non-empty variables '
+ 'array')
+
+ index=len(self.__model.constraints)
+ ct=self.AddAllowedAssignments(variables,tuples_list)
+ self.__model.constraints[index].table.negated=True
+ returnct
+
+ defAddAutomaton(self,transition_variables,starting_state,final_states,
+ transition_triples):
+ """Adds an automaton constraint.
+
+ An automaton constraint takes a list of variables (of size *n*), an initial
+ state, a set of final states, and a set of transitions. A transition is a
+ triplet (*tail*, *transition*, *head*), where *tail* and *head* are states,
+ and *transition* is the label of an arc from *head* to *tail*,
+ corresponding to the value of one variable in the list of variables.
+
+ This automaton will be unrolled into a flow with *n* + 1 phases. Each phase
+ contains the possible states of the automaton. The first state contains the
+ initial state. The last phase contains the final states.
+
+ Between two consecutive phases *i* and *i* + 1, the automaton creates a set
+ of arcs. For each transition (*tail*, *transition*, *head*), it will add
+ an arc from the state *tail* of phase *i* and the state *head* of phase
+ *i* + 1. This arc is labeled by the value *transition* of the variables
+ `variables[i]`. That is, this arc can only be selected if `variables[i]`
+ is assigned the value *transition*.
+
+ A feasible solution of this constraint is an assignment of variables such
+ that, starting from the initial state in phase 0, there is a path labeled by
+ the values of the variables that ends in one of the final states in the
+ final phase.
+
+ Args:
+ transition_variables: A non-empty list of variables whose values
+ correspond to the labels of the arcs traversed by the automaton.
+ starting_state: The initial state of the automaton.
+ final_states: A non-empty list of admissible final states.
+ transition_triples: A list of transitions for the automaton, in the
+ following format (current_state, variable_value, next_state).
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if `transition_variables`, `final_states`, or
+ `transition_triples` are empty.
+ """
+
+ ifnottransition_variables:
+ raiseValueError(
+ 'AddAutomaton expects a non-empty transition_variables '
+ 'array')
+ ifnotfinal_states:
+ raiseValueError('AddAutomaton expects some final states')
+
+ ifnottransition_triples:
+ raiseValueError('AddAutomaton expects some transition triples')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.automaton.vars.extend(
+ [self.GetOrMakeIndex(x)forxintransition_variables])
+ starting_state=cmh.assert_is_int64(starting_state)
+ model_ct.automaton.starting_state=starting_state
+ forvinfinal_states:
+ v=cmh.assert_is_int64(v)
+ model_ct.automaton.final_states.append(v)
+ fortintransition_triples:
+ iflen(t)!=3:
+ raiseTypeError('Tuple '+str(t)+
+ ' has the wrong arity (!= 3)')
+ tail=cmh.assert_is_int64(t[0])
+ label=cmh.assert_is_int64(t[1])
+ head=cmh.assert_is_int64(t[2])
+ model_ct.automaton.transition_tail.append(tail)
+ model_ct.automaton.transition_label.append(label)
+ model_ct.automaton.transition_head.append(head)
+ returnct
+
+ defAddInverse(self,variables,inverse_variables):
+ """Adds Inverse(variables, inverse_variables).
+
+ An inverse constraint enforces that if `variables[i]` is assigned a value
+ `j`, then `inverse_variables[j]` is assigned a value `i`. And vice versa.
+
+ Args:
+ variables: An array of integer variables.
+ inverse_variables: An array of integer variables.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: if variables and inverse_variables have different lengths, or
+ if they are empty.
+ """
+
+ ifnotvariablesornotinverse_variables:
+ raiseTypeError(
+ 'The Inverse constraint does not accept empty arrays')
+ iflen(variables)!=len(inverse_variables):
+ raiseTypeError(
+ 'In the inverse constraint, the two array variables and'
+ ' inverse_variables must have the same length.')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.inverse.f_direct.extend(
+ [self.GetOrMakeIndex(x)forxinvariables])
+ model_ct.inverse.f_inverse.extend(
+ [self.GetOrMakeIndex(x)forxininverse_variables])
+ returnct
+
+ defAddReservoirConstraint(self,times,level_changes,min_level,
+ max_level):
+ """Adds Reservoir(times, level_changes, min_level, max_level).
+
+ Maintains a reservoir level within bounds. The water level starts at 0, and
+ at any time, it must be between min_level and max_level.
+
+ If the affine expression `times[i]` is assigned a value t, then the current
+ level changes by `level_changes[i]`, which is constant, at time t.
+
+ Note that min level must be <= 0, and the max level must be >= 0. Please
+ use fixed level_changes to simulate initial state.
+
+ Therefore, at any time:
+ sum(level_changes[i] if times[i] <= t) in [min_level, max_level]
+
+ Args:
+ times: A list of affine expressions which specify the time of the filling
+ or emptying the reservoir.
+ level_changes: A list of integer values that specifies the amount of the
+ emptying or filling.
+ min_level: At any time, the level of the reservoir must be greater or
+ equal than the min level.
+ max_level: At any time, the level of the reservoir must be less or equal
+ than the max level.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if max_level < min_level.
+
+ ValueError: if max_level < 0.
+
+ ValueError: if min_level > 0
+ """
+
+ ifmax_level<min_level:
+ returnValueError(
+ 'Reservoir constraint must have a max_level >= min_level')
+
+ ifmax_level<0:
+ returnValueError('Reservoir constraint must have a max_level >= 0')
+
+ ifmin_level>0:
+ returnValueError('Reservoir constraint must have a min_level <= 0')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.reservoir.time_exprs.extend(
+ [self.ParseLinearExpression(x)forxintimes])
+ model_ct.reservoir.level_changes.extend(level_changes)
+ model_ct.reservoir.min_level=min_level
+ model_ct.reservoir.max_level=max_level
+ returnct
+
+ defAddReservoirConstraintWithActive(self,times,level_changes,actives,
+ min_level,max_level):
+ """Adds Reservoir(times, level_changes, actives, min_level, max_level).
+
+ Maintains a reservoir level within bounds. The water level starts at 0, and
+ at any time, it must be between min_level and max_level.
+
+ If the variable `times[i]` is assigned a value t, and `actives[i]` is
+ `True`, then the current level changes by `level_changes[i]`, which is
+ constant,
+ at time t.
+
+ Note that min level must be <= 0, and the max level must be >= 0. Please
+ use fixed level_changes to simulate initial state.
+
+ Therefore, at any time:
+ sum(level_changes[i] * actives[i] if times[i] <= t) in [min_level,
+ max_level]
+
+
+ The array of boolean variables 'actives', if defined, indicates which
+ actions are actually performed.
+
+ Args:
+ times: A list of affine expressions which specify the time of the filling
+ or emptying the reservoir.
+ level_changes: A list of integer values that specifies the amount of the
+ emptying or filling.
+ actives: a list of boolean variables. They indicates if the
+ emptying/refilling events actually take place.
+ min_level: At any time, the level of the reservoir must be greater or
+ equal than the min level.
+ max_level: At any time, the level of the reservoir must be less or equal
+ than the max level.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if max_level < min_level.
+
+ ValueError: if max_level < 0.
+
+ ValueError: if min_level > 0
+ """
+
+ ifmax_level<min_level:
+ returnValueError(
+ 'Reservoir constraint must have a max_level >= min_level')
+
+ ifmax_level<0:
+ returnValueError('Reservoir constraint must have a max_level >= 0')
+
+ ifmin_level>0:
+ returnValueError('Reservoir constraint must have a min_level <= 0')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.reservoir.time_exprs.extend(
+ [self.ParseLinearExpression(x)forxintimes])
+ model_ct.reservoir.level_changes.extend(level_changes)
+ model_ct.reservoir.active_literals.extend(
+ [self.GetOrMakeIndex(x)forxinactives])
+ model_ct.reservoir.min_level=min_level
+ model_ct.reservoir.max_level=max_level
+ returnct
+
+ defAddMapDomain(self,var,bool_var_array,offset=0):
+ """Adds `var == i + offset <=> bool_var_array[i] == true for all i`."""
+
+ fori,bool_varinenumerate(bool_var_array):
+ b_index=bool_var.Index()
+ var_index=var.Index()
+ model_ct=self.__model.constraints.add()
+ model_ct.linear.vars.append(var_index)
+ model_ct.linear.coeffs.append(1)
+ model_ct.linear.domain.extend([offset+i,offset+i])
+ model_ct.enforcement_literal.append(b_index)
+
+ model_ct=self.__model.constraints.add()
+ model_ct.linear.vars.append(var_index)
+ model_ct.linear.coeffs.append(1)
+ model_ct.enforcement_literal.append(-b_index-1)
+ ifoffset+i-1>=INT_MIN:
+ model_ct.linear.domain.extend([INT_MIN,offset+i-1])
+ ifoffset+i+1<=INT_MAX:
+ model_ct.linear.domain.extend([offset+i+1,INT_MAX])
+
+ defAddImplication(self,a,b):
+ """Adds `a => b` (`a` implies `b`)."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_or.literals.append(self.GetOrMakeBooleanIndex(b))
+ model_ct.enforcement_literal.append(self.GetOrMakeBooleanIndex(a))
+ returnct
+
+ defAddBoolOr(self,*literals):
+ """Adds `Or(literals) == true`: Sum(literals) >= 1."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_or.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddAtLeastOne(self,*literals):
+ """Same as `AddBoolOr`: `Sum(literals) >= 1`."""
+ returnself.AddBoolOr(*literals)
+
+ defAddAtMostOne(self,*literals):
+ """Adds `AtMostOne(literals)`: `Sum(literals) <= 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.at_most_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddExactlyOne(self,*literals):
+ """Adds `ExactlyOne(literals)`: `Sum(literals) == 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.exactly_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddBoolAnd(self,*literals):
+ """Adds `And(literals) == true`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_and.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddBoolXOr(self,*literals):
+ """Adds `XOr(literals) == true`.
+
+ In contrast to AddBoolOr and AddBoolAnd, it does not support
+ .OnlyEnforceIf().
+
+ Args:
+ *literals: the list of literals in the constraint.
+
+ Returns:
+ An `Constraint` object.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_xor.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddMinEquality(self,target,exprs):
+ """Adds `target == Min(exprs)`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.lin_max.exprs.extend(
+ [self.ParseLinearExpression(x,True)forxinexprs])
+ model_ct.lin_max.target.CopyFrom(
+ self.ParseLinearExpression(target,True))
+ returnct
+
+ defAddMaxEquality(self,target,exprs):
+ """Adds `target == Max(exprs)`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.lin_max.exprs.extend(
+ [self.ParseLinearExpression(x)forxinexprs])
+ model_ct.lin_max.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddDivisionEquality(self,target,num,denom):
+ """Adds `target == num // denom` (integer division rounded towards 0)."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.int_div.exprs.append(self.ParseLinearExpression(num))
+ model_ct.int_div.exprs.append(self.ParseLinearExpression(denom))
+ model_ct.int_div.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddAbsEquality(self,target,expr):
+ """Adds `target == Abs(var)`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.lin_max.exprs.append(self.ParseLinearExpression(expr))
+ model_ct.lin_max.exprs.append(self.ParseLinearExpression(expr,True))
+ model_ct.lin_max.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddModuloEquality(self,target,var,mod):
+ """Adds `target = var % mod`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.int_mod.exprs.append(self.ParseLinearExpression(var))
+ model_ct.int_mod.exprs.append(self.ParseLinearExpression(mod))
+ model_ct.int_mod.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddMultiplicationEquality(self,target,*expressions):
+ """Adds `target == expressions[0] * .. * expressions[n]`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.int_prod.exprs.extend([
+ self.ParseLinearExpression(expr)
+ forexprinExpandGeneratorOrTuple(expressions)
+ ])
+ model_ct.int_prod.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ # Scheduling support
+
+ defNewIntervalVar(self,start,size,end,name):
+ """Creates an interval variable from start, size, and end.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Internally, it ensures that `start + size == end`.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It can be an affine or constant
+ expression.
+ end: The end of the interval. It can be an affine or constant expression.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+
+ self.Add(start+size==end)
+
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(end)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ iflen(size_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: size must be affine or constant.')
+ iflen(end_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: end must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,None,
+ name)
+
+ defNewFixedSizeIntervalVar(self,start,size,name):
+ """Creates an interval variable from start, and a fixed size.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It must be an integer value.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+ size=cmh.assert_is_int64(size)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(start+size)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,None,
+ name)
+
+ defNewOptionalIntervalVar(self,start,size,end,is_present,name):
+ """Creates an optional interval var from start, size, end, and is_present.
+
+ An optional interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap. This constraint is protected by an is_present
+ literal that indicates if it is active or not.
+
+ Internally, it ensures that `is_present` implies `start + size == end`.
+
+ Args:
+ start: The start of the interval. It can be an integer value, or an
+ integer variable.
+ size: The size of the interval. It can be an integer value, or an integer
+ variable.
+ end: The end of the interval. It can be an integer value, or an integer
+ variable.
+ is_present: A literal that indicates if the interval is active or not. A
+ inactive interval is simply ignored by all constraints.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+
+ # Add the linear constraint.
+ self.Add(start+size==end).OnlyEnforceIf(is_present)
+
+ # Creates the IntervalConstraintProto object.
+ is_present_index=self.GetOrMakeBooleanIndex(is_present)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(end)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ iflen(size_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: size must be affine or constant.')
+ iflen(end_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: end must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,
+ is_present_index,name)
+
+ defNewOptionalFixedSizeIntervalVar(self,start,size,is_present,name):
+ """Creates an interval variable from start, and a fixed size.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It must be an integer value.
+ is_present: A literal that indicates if the interval is active or not. A
+ inactive interval is simply ignored by all constraints.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+ size=cmh.assert_is_int64(size)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(start+size)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ is_present_index=self.GetOrMakeBooleanIndex(is_present)
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,
+ is_present_index,name)
+
+ defAddNoOverlap(self,interval_vars):
+ """Adds NoOverlap(interval_vars).
+
+ A NoOverlap constraint ensures that all present intervals do not overlap
+ in time.
+
+ Args:
+ interval_vars: The list of interval variables to constrain.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.no_overlap.intervals.extend(
+ [self.GetIntervalIndex(x)forxininterval_vars])
+ returnct
+
+ defAddNoOverlap2D(self,x_intervals,y_intervals):
+ """Adds NoOverlap2D(x_intervals, y_intervals).
+
+ A NoOverlap2D constraint ensures that all present rectangles do not overlap
+ on a plane. Each rectangle is aligned with the X and Y axis, and is defined
+ by two intervals which represent its projection onto the X and Y axis.
+
+ Furthermore, one box is optional if at least one of the x or y interval is
+ optional.
+
+ Args:
+ x_intervals: The X coordinates of the rectangles.
+ y_intervals: The Y coordinates of the rectangles.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.no_overlap_2d.x_intervals.extend(
+ [self.GetIntervalIndex(x)forxinx_intervals])
+ model_ct.no_overlap_2d.y_intervals.extend(
+ [self.GetIntervalIndex(x)forxiny_intervals])
+ returnct
+
+ defAddCumulative(self,intervals,demands,capacity):
+ """Adds Cumulative(intervals, demands, capacity).
+
+ This constraint enforces that:
+
+ for all t:
+ sum(demands[i]
+ if (start(intervals[i]) <= t < end(intervals[i])) and
+ (intervals[i] is present)) <= capacity
+
+ Args:
+ intervals: The list of intervals.
+ demands: The list of demands for each interval. Each demand must be >= 0.
+ Each demand can be an integer value, or an integer variable.
+ capacity: The maximum capacity of the cumulative constraint. It must be a
+ positive integer value or variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.cumulative.intervals.extend(
+ [self.GetIntervalIndex(x)forxinintervals])
+ fordindemands:
+ model_ct.cumulative.demands.append(self.ParseLinearExpression(d))
+ model_ct.cumulative.capacity.CopyFrom(
+ self.ParseLinearExpression(capacity))
+ returnct
+
+ # Support for deep copy.
+ defCopyFrom(self,other_model):
+ """Reset the model, and creates a new one from a CpModelProto instance."""
+ self.__model.CopyFrom(other_model.Proto())
+
+ # Rebuild constant map.
+ self.__constant_map.clear()
+ fori,varinenumerate(self.__model.variables):
+ iflen(var.domain)==2andvar.domain[0]==var.domain[1]:
+ self.__constant_map[var.domain[0]]=i
+
+ defGetBoolVarFromProtoIndex(self,index):
+ """Returns an already created Boolean variable from its index."""
+ ifindex<0orindex>=len(self.__model.variables):
+ raiseValueError(
+ f'GetBoolVarFromProtoIndex: out of bound index {index}')
+ var=self.__model.variables[index]
+ iflen(var.domain)!=2orvar.domain[0]<0orvar.domain[1]>1:
+ raiseValueError(
+ f'GetBoolVarFromProtoIndex: index {index} does not reference'+
+ ' a Boolean variable')
+
+ returnIntVar(self.__model,index,None)
+
+ defGetIntVarFromProtoIndex(self,index):
+ """Returns an already created integer variable from its index."""
+ ifindex<0orindex>=len(self.__model.variables):
+ raiseValueError(
+ f'GetIntVarFromProtoIndex: out of bound index {index}')
+ returnIntVar(self.__model,index,None)
+
+ defGetIntervalVarFromProtoIndex(self,index):
+ """Returns an already created interval variable from its index."""
+ ifindex<0orindex>=len(self.__model.constraints):
+ raiseValueError(
+ f'GetIntervalVarFromProtoIndex: out of bound index {index}')
+ ct=self.__model.constraints[index]
+ ifnotct.HasField('interval'):
+ raiseValueError(
+ f'GetIntervalVarFromProtoIndex: index {index} does not reference an'
+ +' interval variable')
+
+ returnIntervalVar(self.__model,index,None,None,None,None)
+
+ # Helpers.
+
+ def__str__(self):
+ returnstr(self.__model)
+
+ defProto(self):
+ """Returns the underlying CpModelProto."""
+ returnself.__model
+
+ defNegated(self,index):
+ return-index-1
+
+ defGetOrMakeIndex(self,arg):
+ """Returns the index of a variable, its negation, or a number."""
+ ifisinstance(arg,IntVar):
+ returnarg.Index()
+ elif(isinstance(arg,_ProductCst)and
+ isinstance(arg.Expression(),IntVar)andarg.Coefficient()==-1):
+ return-arg.Expression().Index()-1
+ elifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ returnself.GetOrMakeIndexFromConstant(arg)
+ else:
+ raiseTypeError('NotSupported: model.GetOrMakeIndex('+str(arg)+
+ ')')
+
+ defGetOrMakeBooleanIndex(self,arg):
+ """Returns an index from a boolean expression."""
+ ifisinstance(arg,IntVar):
+ self.AssertIsBooleanVariable(arg)
+ returnarg.Index()
+ elifisinstance(arg,_NotBooleanVariable):
+ self.AssertIsBooleanVariable(arg.Not())
+ returnarg.Index()
+ elifcmh.is_integral(arg):
+ cmh.assert_is_boolean(arg)
+ returnself.GetOrMakeIndexFromConstant(int(arg))
+ else:
+ raiseTypeError('NotSupported: model.GetOrMakeBooleanIndex('+
+ str(arg)+')')
+
+ defGetIntervalIndex(self,arg):
+ ifnotisinstance(arg,IntervalVar):
+ raiseTypeError('NotSupported: model.GetIntervalIndex(%s)'%arg)
+ returnarg.Index()
+
+ defGetOrMakeIndexFromConstant(self,value):
+ ifvalueinself.__constant_map:
+ returnself.__constant_map[value]
+ index=len(self.__model.variables)
+ var=self.__model.variables.add()
+ var.domain.extend([value,value])
+ self.__constant_map[value]=index
+ returnindex
+
+ defVarIndexToVarProto(self,var_index):
+ ifvar_index>=0:
+ returnself.__model.variables[var_index]
+ else:
+ returnself.__model.variables[-var_index-1]
+
+ defParseLinearExpression(self,linear_expr,negate=False):
+ """Returns a LinearExpressionProto built from a LinearExpr instance."""
+ result=cp_model_pb2.LinearExpressionProto()
+ mult=-1ifnegateelse1
+ ifcmh.is_integral(linear_expr):
+ result.offset=int(linear_expr)*mult
+ returnresult
+
+ ifisinstance(linear_expr,IntVar):
+ result.vars.append(self.GetOrMakeIndex(linear_expr))
+ result.coeffs.append(mult)
+ returnresult
+
+ coeffs_map,constant=linear_expr.GetIntegerVarValueMap()
+ result.offset=constant*mult
+ fortincoeffs_map.items():
+ ifnotisinstance(t[0],IntVar):
+ raiseTypeError('Wrong argument'+str(t))
+ c=cmh.assert_is_int64(t[1])
+ result.vars.append(t[0].Index())
+ result.coeffs.append(c*mult)
+ returnresult
+
+ def_SetObjective(self,obj,minimize):
+ """Sets the objective of the model."""
+ self.__model.ClearField('objective')
+ self.__model.ClearField('floating_point_objective')
+ ifisinstance(obj,IntVar):
+ self.__model.objective.coeffs.append(1)
+ self.__model.objective.offset=0
+ ifminimize:
+ self.__model.objective.vars.append(obj.Index())
+ self.__model.objective.scaling_factor=1
+ else:
+ self.__model.objective.vars.append(self.Negated(obj.Index()))
+ self.__model.objective.scaling_factor=-1
+ elifisinstance(obj,LinearExpr):
+ coeffs_map,constant,is_integer=obj.GetFloatVarValueMap()
+ ifis_integer:
+ ifminimize:
+ self.__model.objective.scaling_factor=1
+ self.__model.objective.offset=constant
+ else:
+ self.__model.objective.scaling_factor=-1
+ self.__model.objective.offset=-constant
+ forv,c,incoeffs_map.items():
+ self.__model.objective.coeffs.append(c)
+ ifminimize:
+ self.__model.objective.vars.append(v.Index())
+ else:
+ self.__model.objective.vars.append(
+ self.Negated(v.Index()))
+ else:
+ self.__model.floating_point_objective.maximize=notminimize
+ self.__model.floating_point_objective.offset=constant
+ forv,c,incoeffs_map.items():
+ self.__model.floating_point_objective.coeffs.append(c)
+ self.__model.floating_point_objective.vars.append(v.Index())
+ elifcmh.is_integral(obj):
+ self.__model.objective.offset=int(obj)
+ self.__model.objective.scaling_factor=1
+ else:
+ raiseTypeError('TypeError: '+str(obj)+
+ ' is not a valid objective')
+
+ defMinimize(self,obj):
+ """Sets the objective of the model to minimize(obj)."""
+ self._SetObjective(obj,minimize=True)
+
+ defMaximize(self,obj):
+ """Sets the objective of the model to maximize(obj)."""
+ self._SetObjective(obj,minimize=False)
+
+ defHasObjective(self):
+ returnself.__model.HasField('objective')
+
+ defAddDecisionStrategy(self,variables,var_strategy,domain_strategy):
+ """Adds a search strategy to the model.
+
+ Args:
+ variables: a list of variables this strategy will assign.
+ var_strategy: heuristic to choose the next variable to assign.
+ domain_strategy: heuristic to reduce the domain of the selected variable.
+ Currently, this is advanced code: the union of all strategies added to
+ the model must be complete, i.e. instantiates all variables.
+ Otherwise, Solve() will fail.
+ """
+
+ strategy=self.__model.search_strategy.add()
+ forvinvariables:
+ strategy.variables.append(v.Index())
+ strategy.variable_selection_strategy=var_strategy
+ strategy.domain_reduction_strategy=domain_strategy
+
+ defModelStats(self):
+ """Returns a string containing some model statistics."""
+ returnswig_helper.CpSatHelper.SerializedModelStats(
+ self.__model.SerializeToString())
+
+ defValidate(self):
+ """Returns a string indicating that the model is invalid."""
+ returnswig_helper.CpSatHelper.SerializedValidateModel(
+ self.__model.SerializeToString())
+
+ defExportToFile(self,file):
+ """Write the model as a protocol buffer to 'file'.
+
+ Args:
+ file: file to write the model to. If the filename ends with 'txt', the
+ model will be written as a text file, otherwise, the binary format will
+ be used.
+
+ Returns:
+ True if the model was correctly written.
+ """
+ returnswig_helper.CpSatHelper.SerializedWriteModelToFile(
+ self.__model.SerializeToString(),file)
+
+ defAssertIsBooleanVariable(self,x):
+ ifisinstance(x,IntVar):
+ var=self.__model.variables[x.Index()]
+ iflen(var.domain)!=2orvar.domain[0]<0orvar.domain[1]>1:
+ raiseTypeError('TypeError: '+str(x)+
+ ' is not a boolean variable')
+ elifnotisinstance(x,_NotBooleanVariable):
+ raiseTypeError('TypeError: '+str(x)+
+ ' is not a boolean variable')
+
+ defAddHint(self,var,value):
+ """Adds 'var == value' as a hint to the solver."""
+ self.__model.solution_hint.vars.append(self.GetOrMakeIndex(var))
+ self.__model.solution_hint.values.append(value)
+
+ defClearHints(self):
+ """Remove any solution hint from the model."""
+ self.__model.ClearField('solution_hint')
+
+ defAddAssumption(self,lit):
+ """Add the literal 'lit' to the model as assumptions."""
+ self.__model.assumptions.append(self.GetOrMakeBooleanIndex(lit))
+
+ defAddAssumptions(self,literals):
+ """Add the literals to the model as assumptions."""
+ forlitinliterals:
+ self.AddAssumption(lit)
+
+ defClearAssumptions(self):
+ """Remove all assumptions from the model."""
+ self.__model.ClearField('assumptions')
+
+
+defExpandGeneratorOrTuple(args):
+ ifhasattr(args,'__len__'):# Tuple
+ iflen(args)!=1:
+ returnargs
+ ifcmh.is_a_number(args[0])orisinstance(args[0],LinearExpr):
+ returnargs
+ # Generator
+ returnargs[0]
+
+
+defEvaluateLinearExpr(expression,solution):
+ """Evaluate a linear expression against a solution."""
+ ifcmh.is_integral(expression):
+ returnint(expression)
+ ifnotisinstance(expression,LinearExpr):
+ raiseTypeError('Cannot interpret %s as a linear expression.'%
+ expression)
+
+ value=0
+ to_process=[(expression,1)]
+ whileto_process:
+ expr,coeff=to_process.pop()
+ ifcmh.is_integral(expr):
+ value+=int(expr)*coeff
+ elifisinstance(expr,_ProductCst):
+ to_process.append((expr.Expression(),coeff*expr.Coefficient()))
+ elifisinstance(expr,_Sum):
+ to_process.append((expr.Left(),coeff))
+ to_process.append((expr.Right(),coeff))
+ elifisinstance(expr,_SumArray):
+ foreinexpr.Expressions():
+ to_process.append((e,coeff))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,_WeightedSum):
+ fore,cinzip(expr.Expressions(),expr.Coefficients()):
+ to_process.append((e,coeff*c))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,IntVar):
+ value+=coeff*solution.solution[expr.Index()]
+ elifisinstance(expr,_NotBooleanVariable):
+ value+=coeff*(1-solution.solution[expr.Not().Index()])
+ else:
+ raiseTypeError(f'Cannot interpret {expr} as a linear expression.')
+
+ returnvalue
+
+
+defEvaluateBooleanExpression(literal,solution):
+ """Evaluate a boolean expression against a solution."""
+ ifcmh.is_integral(literal):
+ returnbool(literal)
+ elifisinstance(literal,IntVar)orisinstance(literal,
+ _NotBooleanVariable):
+ index=literal.Index()
+ ifindex>=0:
+ returnbool(solution.solution[index])
+ else:
+ returnnotsolution.solution[-index-1]
+ else:
+ raiseTypeError(f'Cannot interpret {literal} as a boolean expression.')
+
+
+classCpSolver(object):
+ """Main solver class.
+
+ The purpose of this class is to search for a solution to the model provided
+ to the Solve() method.
+
+ Once Solve() is called, this class allows inspecting the solution found
+ with the Value() and BooleanValue() methods, as well as general statistics
+ about the solve procedure.
+ """
+
+ def__init__(self):
+ self.__model=None
+ self.__solution:cp_model_pb2.CpSolverResponse=None
+ self.parameters=sat_parameters_pb2.SatParameters()
+ self.log_callback=None
+ self.__solve_wrapper:swig_helper.SolveWrapper=None
+ self.__lock=threading.Lock()
+
+ defSolve(self,model,solution_callback=None):
+ """Solves a problem and passes each solution to the callback if not null."""
+ withself.__lock:
+ solve_wrapper=swig_helper.SolveWrapper()
+
+ swig_helper.SolveWrapper.SetSerializedParameters(
+ self.parameters.SerializeToString(),solve_wrapper)
+ ifsolution_callbackisnotNone:
+ solve_wrapper.AddSolutionCallback(solution_callback)
+
+ ifself.log_callbackisnotNone:
+ solve_wrapper.AddLogCallback(self.log_callback)
+
+ self.__solution=cp_model_pb2.CpSolverResponse.FromString(
+ swig_helper.SolveWrapper.SerializedSolve(
+ model.Proto().SerializeToString(),solve_wrapper))
+
+ ifsolution_callbackisnotNone:
+ solve_wrapper.ClearSolutionCallback(solution_callback)
+
+ withself.__lock:
+ self.__solve_wrapper=None
+
+ returnself.__solution.status
+
+ defSolveWithSolutionCallback(self,model,callback):
+ """DEPRECATED Use Solve() with the callback argument."""
+ warnings.warn(
+ 'SolveWithSolutionCallback is deprecated; use Solve() with'+
+ 'the callback argument.',DeprecationWarning)
+ returnself.Solve(model,callback)
+
+ defSearchForAllSolutions(self,model,callback):
+ """DEPRECATED Use Solve() with the right parameter.
+
+ Search for all solutions of a satisfiability problem.
+
+ This method searches for all feasible solutions of a given model.
+ Then it feeds the solution to the callback.
+
+ Note that the model cannot contain an objective.
+
+ Args:
+ model: The model to solve.
+ callback: The callback that will be called at each solution.
+
+ Returns:
+ The status of the solve:
+
+ * *FEASIBLE* if some solutions have been found
+ * *INFEASIBLE* if the solver has proved there are no solution
+ * *OPTIMAL* if all solutions have been found
+ """
+ warnings.warn(
+ 'SearchForAllSolutions is deprecated; use Solve() with'+
+ 'enumerate_all_solutions = True.',DeprecationWarning)
+ ifmodel.HasObjective():
+ raiseTypeError('Search for all solutions is only defined on '
+ 'satisfiability problems')
+ # Store old parameter.
+ enumerate_all=self.parameters.enumerate_all_solutions
+ self.parameters.enumerate_all_solutions=True
+
+ self.Solve(model,callback)
+
+ # Restore parameter.
+ self.parameters.enumerate_all_solutions=enumerate_all
+ returnself.__solution.status
+
+ defStopSearch(self):
+ """Stops the current search asynchronously."""
+ withself.__lock:
+ ifself.__solve_wrapper:
+ self.__solve_wrapper.StopSearch()
+
+ defValue(self,expression):
+ """Returns the value of a linear expression after solve."""
+ ifnotself.__solution:
+ raiseRuntimeError('Solve() has not be called.')
+ returnEvaluateLinearExpr(expression,self.__solution)
+
+ defBooleanValue(self,literal):
+ """Returns the boolean value of a literal after solve."""
+ ifnotself.__solution:
+ raiseRuntimeError('Solve() has not be called.')
+ returnEvaluateBooleanExpression(literal,self.__solution)
+
+ defObjectiveValue(self):
+ """Returns the value of the objective after solve."""
+ returnself.__solution.objective_value
+
+ defBestObjectiveBound(self):
+ """Returns the best lower (upper) bound found when min(max)imizing."""
+ returnself.__solution.best_objective_bound
+
+ defStatusName(self,status=None):
+ """Returns the name of the status returned by Solve()."""
+ ifstatusisNone:
+ status=self.__solution.status
+ returncp_model_pb2.CpSolverStatus.Name(status)
+
+ defNumBooleans(self):
+ """Returns the number of boolean variables managed by the SAT solver."""
+ returnself.__solution.num_booleans
+
+ defNumConflicts(self):
+ """Returns the number of conflicts since the creation of the solver."""
+ returnself.__solution.num_conflicts
+
+ defNumBranches(self):
+ """Returns the number of search branches explored by the solver."""
+ returnself.__solution.num_branches
+
+ defWallTime(self):
+ """Returns the wall time in seconds since the creation of the solver."""
+ returnself.__solution.wall_time
+
+ defUserTime(self):
+ """Returns the user time in seconds since the creation of the solver."""
+ returnself.__solution.user_time
+
+ defResponseStats(self):
+ """Returns some statistics on the solution found as a string."""
+ returnswig_helper.CpSatHelper.SerializedSolverResponseStats(
+ self.__solution.SerializeToString())
+
+ defResponseProto(self):
+ """Returns the response object."""
+ returnself.__solution
+
+ defSufficientAssumptionsForInfeasibility(self):
+ """Returns the indices of the infeasible assumptions."""
+ returnself.__solution.sufficient_assumptions_for_infeasibility
+
+ defSolutionInfo(self):
+ """Returns some information on the solve process.
+
+ Returns some information on how the solution was found, or the reason
+ why the model or the parameters are invalid.
+ """
+ returnself.__solution.solution_info
+
+
+classCpSolverSolutionCallback(swig_helper.SolutionCallback):
+ """Solution callback.
+
+ This class implements a callback that will be called at each new solution
+ found during search.
+
+ The method OnSolutionCallback() will be called by the solver, and must be
+ implemented. The current solution can be queried using the BooleanValue()
+ and Value() methods.
+
+ It inherits the following methods from its base class:
+
+ * `ObjectiveValue(self)`
+ * `BestObjectiveBound(self)`
+ * `NumBooleans(self)`
+ * `NumConflicts(self)`
+ * `NumBranches(self)`
+ * `WallTime(self)`
+ * `UserTime(self)`
+
+ These methods returns the same information as their counterpart in the
+ `CpSolver` class.
+ """
+
+ def__init__(self):
+ swig_helper.SolutionCallback.__init__(self)
+
+ defOnSolutionCallback(self):
+ """Proxy for the same method in snake case."""
+ self.on_solution_callback()
+
+ defBooleanValue(self,lit):
+ """Returns the boolean value of a boolean literal.
+
+ Args:
+ lit: A boolean variable or its negation.
+
+ Returns:
+ The Boolean value of the literal in the solution.
+
+ Raises:
+ RuntimeError: if `lit` is not a boolean variable or its negation.
+ """
+ ifnotself.HasResponse():
+ raiseRuntimeError('Solve() has not be called.')
+ ifcmh.is_integral(lit):
+ returnbool(lit)
+ elifisinstance(lit,IntVar)orisinstance(lit,_NotBooleanVariable):
+ index=lit.Index()
+ returnself.SolutionBooleanValue(index)
+ else:
+ raiseTypeError(f'Cannot interpret {lit} as a boolean expression.')
+
+ defValue(self,expression):
+ """Evaluates an linear expression in the current solution.
+
+ Args:
+ expression: a linear expression of the model.
+
+ Returns:
+ An integer value equal to the evaluation of the linear expression
+ against the current solution.
+
+ Raises:
+ RuntimeError: if 'expression' is not a LinearExpr.
+ """
+ ifnotself.HasResponse():
+ raiseRuntimeError('Solve() has not be called.')
+
+ value=0
+ to_process=[(expression,1)]
+ whileto_process:
+ expr,coeff=to_process.pop()
+ ifcmh.is_integral(expr):
+ value+=int(expr)*coeff
+ elifisinstance(expr,_ProductCst):
+ to_process.append(
+ (expr.Expression(),coeff*expr.Coefficient()))
+ elifisinstance(expr,_Sum):
+ to_process.append((expr.Left(),coeff))
+ to_process.append((expr.Right(),coeff))
+ elifisinstance(expr,_SumArray):
+ foreinexpr.Expressions():
+ to_process.append((e,coeff))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,_WeightedSum):
+ fore,cinzip(expr.Expressions(),expr.Coefficients()):
+ to_process.append((e,coeff*c))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,IntVar):
+ value+=coeff*self.SolutionIntegerValue(expr.Index())
+ elifisinstance(expr,_NotBooleanVariable):
+ value+=coeff*(1-
+ self.SolutionIntegerValue(expr.Not().Index()))
+ else:
+ raiseTypeError(
+ f'Cannot interpret {expression} as a linear expression.')
+
+ returnvalue
+
+ defResponse(self):
+ """Returns the current solution response."""
+ returncp_model_pb2.CpSolverResponse.FromString(
+ swig_helper.SolutionCallback.SerializedResponse(self))
+
+
+classObjectiveSolutionPrinter(CpSolverSolutionCallback):
+ """Display the objective value and time of intermediate solutions."""
+
+ def__init__(self):
+ CpSolverSolutionCallback.__init__(self)
+ self.__solution_count=0
+ self.__start_time=time.time()
+
+ defon_solution_callback(self):
+ """Called on each new solution."""
+ current_time=time.time()
+ obj=self.ObjectiveValue()
+ print('Solution %i, time = %0.2f s, objective = %i'%
+ (self.__solution_count,current_time-self.__start_time,obj))
+ self.__solution_count+=1
+
+ defsolution_count(self):
+ """Returns the number of solutions found."""
+ returnself.__solution_count
+
+
+classVarArrayAndObjectiveSolutionPrinter(CpSolverSolutionCallback):
+ """Print intermediate solutions (objective, variable values, time)."""
+
+ def__init__(self,variables):
+ CpSolverSolutionCallback.__init__(self)
+ self.__variables=variables
+ self.__solution_count=0
+ self.__start_time=time.time()
+
+ defon_solution_callback(self):
+ """Called on each new solution."""
+ current_time=time.time()
+ obj=self.ObjectiveValue()
+ print('Solution %i, time = %0.2f s, objective = %i'%
+ (self.__solution_count,current_time-self.__start_time,obj))
+ forvinself.__variables:
+ print(' %s = %i'%(v,self.Value(v)),end=' ')
+ print()
+ self.__solution_count+=1
+
+ defsolution_count(self):
+ """Returns the number of solutions found."""
+ returnself.__solution_count
+
+
+classVarArraySolutionPrinter(CpSolverSolutionCallback):
+ """Print intermediate solutions (variable values, time)."""
+
+ def__init__(self,variables):
+ CpSolverSolutionCallback.__init__(self)
+ self.__variables=variables
+ self.__solution_count=0
+ self.__start_time=time.time()
+
+ defon_solution_callback(self):
+ """Called on each new solution."""
+ current_time=time.time()
+ print('Solution %i, time = %0.2f s'%
+ (self.__solution_count,current_time-self.__start_time))
+ forvinself.__variables:
+ print(' %s = %i'%(v,self.Value(v)),end=' ')
+ print()
+ self.__solution_count+=1
+
+ defsolution_count(self):
+ """Returns the number of solutions found."""
+ returnself.__solution_count
+
defShortName(model,i):
+ """Returns a short name of an integer variable, or its negation."""
+ ifi<0:
+ return'Not(%s)'%ShortName(model,-i-1)
+ v=model.variables[i]
+ ifv.name:
+ returnv.name
+ eliflen(v.domain)==2andv.domain[0]==v.domain[1]:
+ returnstr(v.domain[0])
+ else:
+ return'[%s]'%DisplayBounds(v.domain)
+
+
+
+
+
Returns a short name of an integer variable, or its negation.
For large arrays, using the LinearExpr class is faster that using the python
+sum() function. You can create constraints and the objective from lists of
+linear expressions or coefficients as follows:
classIntVar(LinearExpr):
+ """An integer variable.
+
+ An IntVar is an object that can take on any integer value within defined
+ ranges. Variables appear in constraint like:
+
+ x + y >= 5
+ AllDifferent([x, y, z])
+
+ Solving a model is equivalent to finding, for each variable, a single value
+ from the set of initial values (called the initial domain), such that the
+ model is feasible, or optimal if you provided an objective function.
+ """
+
+ def__init__(self,model,domain,name):
+ """See CpModel.NewIntVar below."""
+ self.__model=model
+ self.__negation=None
+ # Python do not support multiple __init__ methods.
+ # This method is only called from the CpModel class.
+ # We hack the parameter to support the two cases:
+ # case 1:
+ # model is a CpModelProto, domain is a Domain, and name is a string.
+ # case 2:
+ # model is a CpModelProto, domain is an index (int), and name is None.
+ ifcmh.is_integral(domain)andnameisNone:
+ self.__index=int(domain)
+ self.__var=model.variables[domain]
+ else:
+ self.__index=len(model.variables)
+ self.__var=model.variables.add()
+ self.__var.domain.extend(domain.FlattenedIntervals())
+ self.__var.name=name
+
+ defIndex(self):
+ """Returns the index of the variable in the model."""
+ returnself.__index
+
+ defProto(self):
+ """Returns the variable protobuf."""
+ returnself.__var
+
+ defIsEqualTo(self,other):
+ """Returns true if self == other in the python sense."""
+ ifnotisinstance(other,IntVar):
+ returnFalse
+ returnself.Index()==other.Index()
+
+ def__str__(self):
+ ifnotself.__var.name:
+ iflen(self.__var.domain
+ )==2andself.__var.domain[0]==self.__var.domain[1]:
+ # Special case for constants.
+ returnstr(self.__var.domain[0])
+ else:
+ return'unnamed_var_%i'%self.__index
+ returnself.__var.name
+
+ def__repr__(self):
+ return'%s(%s)'%(self.__var.name,DisplayBounds(self.__var.domain))
+
+ defName(self):
+ returnself.__var.name
+
+ defNot(self):
+ """Returns the negation of a Boolean variable.
+
+ This method implements the logical negation of a Boolean variable.
+ It is only valid if the variable has a Boolean domain (0 or 1).
+
+ Note that this method is nilpotent: `x.Not().Not() == x`.
+ """
+
+ forboundinself.__var.domain:
+ ifbound<0orbound>1:
+ raiseTypeError(
+ 'Cannot call Not on a non boolean variable: %s'%self)
+ ifself.__negationisNone:
+ self.__negation=_NotBooleanVariable(self)
+ returnself.__negation
+
+
+
+
+
An integer variable.
+
+
An IntVar is an object that can take on any integer value within defined
+ranges. Variables appear in constraint like:
+
+
x + y >= 5
+AllDifferent([x, y, z])
+
+
+
Solving a model is equivalent to finding, for each variable, a single value
+from the set of initial values (called the initial domain), such that the
+model is feasible, or optimal if you provided an objective function.
def__init__(self,model,domain,name):
+ """See CpModel.NewIntVar below."""
+ self.__model=model
+ self.__negation=None
+ # Python do not support multiple __init__ methods.
+ # This method is only called from the CpModel class.
+ # We hack the parameter to support the two cases:
+ # case 1:
+ # model is a CpModelProto, domain is a Domain, and name is a string.
+ # case 2:
+ # model is a CpModelProto, domain is an index (int), and name is None.
+ ifcmh.is_integral(domain)andnameisNone:
+ self.__index=int(domain)
+ self.__var=model.variables[domain]
+ else:
+ self.__index=len(model.variables)
+ self.__var=model.variables.add()
+ self.__var.domain.extend(domain.FlattenedIntervals())
+ self.__var.name=name
+
defIsEqualTo(self,other):
+ """Returns true if self == other in the python sense."""
+ ifnotisinstance(other,IntVar):
+ returnFalse
+ returnself.Index()==other.Index()
+
+
+
+
+
Returns true if self == other in the python sense.
defNot(self):
+ """Returns the negation of a Boolean variable.
+
+ This method implements the logical negation of a Boolean variable.
+ It is only valid if the variable has a Boolean domain (0 or 1).
+
+ Note that this method is nilpotent: `x.Not().Not() == x`.
+ """
+
+ forboundinself.__var.domain:
+ ifbound<0orbound>1:
+ raiseTypeError(
+ 'Cannot call Not on a non boolean variable: %s'%self)
+ ifself.__negationisNone:
+ self.__negation=_NotBooleanVariable(self)
+ returnself.__negation
+
+
+
+
+
Returns the negation of a Boolean variable.
+
+
This method implements the logical negation of a Boolean variable.
+It is only valid if the variable has a Boolean domain (0 or 1).
+
+
Note that this method is nilpotent: x.Not().Not() == x.
classConstraint(object):
+ """Base class for constraints.
+
+ Constraints are built by the CpModel through the Add<XXX> methods.
+ Once created by the CpModel class, they are automatically added to the model.
+ The purpose of this class is to allow specification of enforcement literals
+ for this constraint.
+
+ b = model.NewBoolVar('b')
+ x = model.NewIntVar(0, 10, 'x')
+ y = model.NewIntVar(0, 10, 'y')
+
+ model.Add(x + 2 * y == 5).OnlyEnforceIf(b.Not())
+ """
+
+ def__init__(self,constraints):
+ self.__index=len(constraints)
+ self.__constraint=constraints.add()
+
+ defOnlyEnforceIf(self,*boolvar):
+ """Adds an enforcement literal to the constraint.
+
+ This method adds one or more literals (that is, a boolean variable or its
+ negation) as enforcement literals. The conjunction of all these literals
+ determines whether the constraint is active or not. It acts as an
+ implication, so if the conjunction is true, it implies that the constraint
+ must be enforced. If it is false, then the constraint is ignored.
+
+ BoolOr, BoolAnd, and linear constraints all support enforcement literals.
+
+ Args:
+ *boolvar: One or more Boolean literals.
+
+ Returns:
+ self.
+ """
+ forlitinExpandGeneratorOrTuple(boolvar):
+ if(isinstance(lit,bool)and
+ bool(lit))or(cmh.is_integral(lit)andint(lit)==1):
+ # Always true. Do nothing.
+ pass
+ else:
+ self.__constraint.enforcement_literal.append(lit.Index())
+ returnself
+
+ defIndex(self):
+ """Returns the index of the constraint in the model."""
+ returnself.__index
+
+ defProto(self):
+ """Returns the constraint protobuf."""
+ returnself.__constraint
+
+
+
+
+
Base class for constraints.
+
+
Constraints are built by the CpModel through the Add methods.
+Once created by the CpModel class, they are automatically added to the model.
+The purpose of this class is to allow specification of enforcement literals
+for this constraint.
defOnlyEnforceIf(self,*boolvar):
+ """Adds an enforcement literal to the constraint.
+
+ This method adds one or more literals (that is, a boolean variable or its
+ negation) as enforcement literals. The conjunction of all these literals
+ determines whether the constraint is active or not. It acts as an
+ implication, so if the conjunction is true, it implies that the constraint
+ must be enforced. If it is false, then the constraint is ignored.
+
+ BoolOr, BoolAnd, and linear constraints all support enforcement literals.
+
+ Args:
+ *boolvar: One or more Boolean literals.
+
+ Returns:
+ self.
+ """
+ forlitinExpandGeneratorOrTuple(boolvar):
+ if(isinstance(lit,bool)and
+ bool(lit))or(cmh.is_integral(lit)andint(lit)==1):
+ # Always true. Do nothing.
+ pass
+ else:
+ self.__constraint.enforcement_literal.append(lit.Index())
+ returnself
+
+
+
+
+
Adds an enforcement literal to the constraint.
+
+
This method adds one or more literals (that is, a boolean variable or its
+negation) as enforcement literals. The conjunction of all these literals
+determines whether the constraint is active or not. It acts as an
+implication, so if the conjunction is true, it implies that the constraint
+must be enforced. If it is false, then the constraint is ignored.
+
+
BoolOr, BoolAnd, and linear constraints all support enforcement literals.
classIntervalVar(object):
+ """Represents an Interval variable.
+
+ An interval variable is both a constraint and a variable. It is defined by
+ three integer variables: start, size, and end.
+
+ It is a constraint because, internally, it enforces that start + size == end.
+
+ It is also a variable as it can appear in specific scheduling constraints:
+ NoOverlap, NoOverlap2D, Cumulative.
+
+ Optionally, an enforcement literal can be added to this constraint, in which
+ case these scheduling constraints will ignore interval variables with
+ enforcement literals assigned to false. Conversely, these constraints will
+ also set these enforcement literals to false if they cannot fit these
+ intervals into the schedule.
+ """
+
+ def__init__(self,model,start,size,end,is_present_index,name):
+ self.__model=model
+ # As with the IntVar::__init__ method, we hack the __init__ method to
+ # support two use cases:
+ # case 1: called when creating a new interval variable.
+ # {start|size|end} are linear expressions, is_present_index is either
+ # None or the index of a Boolean literal. name is a string
+ # case 2: called when querying an existing interval variable.
+ # start_index is an int, all parameters after are None.
+ if(sizeisNoneandendisNoneandis_present_indexisNoneand
+ nameisNone):
+ self.__index=start
+ self.__ct=model.constraints[start]
+ else:
+ self.__index=len(model.constraints)
+ self.__ct=self.__model.constraints.add()
+ self.__ct.interval.start.CopyFrom(start)
+ self.__ct.interval.size.CopyFrom(size)
+ self.__ct.interval.end.CopyFrom(end)
+ ifis_present_indexisnotNone:
+ self.__ct.enforcement_literal.append(is_present_index)
+ ifname:
+ self.__ct.name=name
+
+ defIndex(self):
+ """Returns the index of the interval constraint in the model."""
+ returnself.__index
+
+ defProto(self):
+ """Returns the interval protobuf."""
+ returnself.__ct.interval
+
+ def__str__(self):
+ returnself.__ct.name
+
+ def__repr__(self):
+ interval=self.__ct.interval
+ ifself.__ct.enforcement_literal:
+ return'%s(start = %s, size = %s, end = %s, is_present = %s)'%(
+ self.__ct.name,ShortExprName(self.__model,interval.start),
+ ShortExprName(self.__model,interval.size),
+ ShortExprName(self.__model,interval.end),
+ ShortName(self.__model,self.__ct.enforcement_literal[0]))
+ else:
+ return'%s(start = %s, size = %s, end = %s)'%(
+ self.__ct.name,ShortExprName(self.__model,interval.start),
+ ShortExprName(self.__model,interval.size),
+ ShortExprName(self.__model,interval.end))
+
+ defName(self):
+ returnself.__ct.name
+
+ defStartExpr(self):
+ returnLinearExpr.RebuildFromLinearExpressionProto(
+ self.__model,self.__ct.interval.start)
+
+ defSizeExpr(self):
+ returnLinearExpr.RebuildFromLinearExpressionProto(
+ self.__model,self.__ct.interval.size)
+
+ defEndExpr(self):
+ returnLinearExpr.RebuildFromLinearExpressionProto(
+ self.__model,self.__ct.interval.end)
+
+
+
+
+
Represents an Interval variable.
+
+
An interval variable is both a constraint and a variable. It is defined by
+three integer variables: start, size, and end.
+
+
It is a constraint because, internally, it enforces that start + size == end.
+
+
It is also a variable as it can appear in specific scheduling constraints:
+NoOverlap, NoOverlap2D, Cumulative.
+
+
Optionally, an enforcement literal can be added to this constraint, in which
+case these scheduling constraints will ignore interval variables with
+enforcement literals assigned to false. Conversely, these constraints will
+also set these enforcement literals to false if they cannot fit these
+intervals into the schedule.
def__init__(self,model,start,size,end,is_present_index,name):
+ self.__model=model
+ # As with the IntVar::__init__ method, we hack the __init__ method to
+ # support two use cases:
+ # case 1: called when creating a new interval variable.
+ # {start|size|end} are linear expressions, is_present_index is either
+ # None or the index of a Boolean literal. name is a string
+ # case 2: called when querying an existing interval variable.
+ # start_index is an int, all parameters after are None.
+ if(sizeisNoneandendisNoneandis_present_indexisNoneand
+ nameisNone):
+ self.__index=start
+ self.__ct=model.constraints[start]
+ else:
+ self.__index=len(model.constraints)
+ self.__ct=self.__model.constraints.add()
+ self.__ct.interval.start.CopyFrom(start)
+ self.__ct.interval.size.CopyFrom(size)
+ self.__ct.interval.end.CopyFrom(end)
+ ifis_present_indexisnotNone:
+ self.__ct.enforcement_literal.append(is_present_index)
+ ifname:
+ self.__ct.name=name
+
classCpModel(object):
+ """Methods for building a CP model.
+
+ Methods beginning with:
+
+ * ```New``` create integer, boolean, or interval variables.
+ * ```Add``` create new constraints and add them to the model.
+ """
+
+ def__init__(self):
+ self.__model=cp_model_pb2.CpModelProto()
+ self.__constant_map={}
+
+ # Integer variable.
+
+ defNewIntVar(self,lb,ub,name):
+ """Create an integer variable with domain [lb, ub].
+
+ The CP-SAT solver is limited to integer variables. If you have fractional
+ values, scale them up so that they become integers; if you have strings,
+ encode them as integers.
+
+ Args:
+ lb: Lower bound for the variable.
+ ub: Upper bound for the variable.
+ name: The name of the variable.
+
+ Returns:
+ a variable whose domain is [lb, ub].
+ """
+
+ returnIntVar(self.__model,Domain(lb,ub),name)
+
+ defNewIntVarFromDomain(self,domain,name):
+ """Create an integer variable from a domain.
+
+ A domain is a set of integers specified by a collection of intervals.
+ For example, `model.NewIntVarFromDomain(cp_model.
+ Domain.FromIntervals([[1, 2], [4, 6]]), 'x')`
+
+ Args:
+ domain: An instance of the Domain class.
+ name: The name of the variable.
+
+ Returns:
+ a variable whose domain is the given domain.
+ """
+ returnIntVar(self.__model,domain,name)
+
+ defNewBoolVar(self,name):
+ """Creates a 0-1 variable with the given name."""
+ returnIntVar(self.__model,Domain(0,1),name)
+
+ defNewConstant(self,value):
+ """Declares a constant integer."""
+ returnIntVar(self.__model,self.GetOrMakeIndexFromConstant(value),
+ None)
+
+ # Linear constraints.
+
+ defAddLinearConstraint(self,linear_expr,lb,ub):
+ """Adds the constraint: `lb <= linear_expr <= ub`."""
+ returnself.AddLinearExpressionInDomain(linear_expr,Domain(lb,ub))
+
+ defAddLinearExpressionInDomain(self,linear_expr,domain):
+ """Adds the constraint: `linear_expr` in `domain`."""
+ ifisinstance(linear_expr,LinearExpr):
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ coeffs_map,constant=linear_expr.GetIntegerVarValueMap()
+ fortincoeffs_map.items():
+ ifnotisinstance(t[0],IntVar):
+ raiseTypeError('Wrong argument'+str(t))
+ c=cmh.assert_is_int64(t[1])
+ model_ct.linear.vars.append(t[0].Index())
+ model_ct.linear.coeffs.append(c)
+ model_ct.linear.domain.extend([
+ cmh.capped_subtraction(x,constant)
+ forxindomain.FlattenedIntervals()
+ ])
+ returnct
+ elifcmh.is_integral(linear_expr):
+ ifnotdomain.Contains(int(linear_expr)):
+ returnself.AddBoolOr([])# Evaluate to false.
+ # Nothing to do otherwise.
+ else:
+ raiseTypeError(
+ 'Not supported: CpModel.AddLinearExpressionInDomain('+
+ str(linear_expr)+' '+str(domain)+')')
+
+ defAdd(self,ct):
+ """Adds a `BoundedLinearExpression` to the model.
+
+ Args:
+ ct: A [`BoundedLinearExpression`](#boundedlinearexpression).
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ifisinstance(ct,BoundedLinearExpression):
+ returnself.AddLinearExpressionInDomain(
+ ct.Expression(),Domain.FromFlatIntervals(ct.Bounds()))
+ elifctandisinstance(ct,bool):
+ returnself.AddBoolOr([True])
+ elifnotctandisinstance(ct,bool):
+ returnself.AddBoolOr([])# Evaluate to false.
+ else:
+ raiseTypeError('Not supported: CpModel.Add('+str(ct)+')')
+
+ # General Integer Constraints.
+
+ defAddAllDifferent(self,*expressions):
+ """Adds AllDifferent(expressions).
+
+ This constraint forces all expressions to have different values.
+
+ Args:
+ *expressions: simple expressions of the form a * var + constant.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ expanded=ExpandGeneratorOrTuple(expressions)
+ model_ct.all_diff.exprs.extend(
+ [self.ParseLinearExpression(x)forxinexpanded])
+ returnct
+
+ defAddElement(self,index,variables,target):
+ """Adds the element constraint: `variables[index] == target`."""
+
+ ifnotvariables:
+ raiseValueError('AddElement expects a non-empty variables array')
+
+ ifcmh.is_integral(index):
+ returnself.Add(list(variables)[int(index)]==target)
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.element.index=self.GetOrMakeIndex(index)
+ model_ct.element.vars.extend(
+ [self.GetOrMakeIndex(x)forxinvariables])
+ model_ct.element.target=self.GetOrMakeIndex(target)
+ returnct
+
+ defAddCircuit(self,arcs):
+ """Adds Circuit(arcs).
+
+ Adds a circuit constraint from a sparse list of arcs that encode the graph.
+
+ A circuit is a unique Hamiltonian path in a subgraph of the total
+ graph. In case a node 'i' is not in the path, then there must be a
+ loop arc 'i -> i' associated with a true literal. Otherwise
+ this constraint will fail.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError('AddCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.circuit.tails.append(tail)
+ model_ct.circuit.heads.append(head)
+ model_ct.circuit.literals.append(lit)
+ returnct
+
+ defAddMultipleCircuit(self,arcs):
+ """Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+ The direct graph where arc #i (from tails[i] to head[i]) is present iff
+ literals[i] is true must satisfy this set of properties:
+ - #incoming arcs == 1 except for node 0.
+ - #outgoing arcs == 1 except for node 0.
+ - for node zero, #incoming arcs == #outgoing arcs.
+ - There are no duplicate arcs.
+ - Self-arcs are allowed except for node 0.
+ - There is no cycle in this graph, except through node 0.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError(
+ 'AddMultipleCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.routes.tails.append(tail)
+ model_ct.routes.heads.append(head)
+ model_ct.routes.literals.append(lit)
+ returnct
+
+ defAddAllowedAssignments(self,variables,tuples_list):
+ """Adds AllowedAssignments(variables, tuples_list).
+
+ An AllowedAssignments constraint is a constraint on an array of variables,
+ which requires that when all variables are assigned values, the resulting
+ array equals one of the tuples in `tuple_list`.
+
+ Args:
+ variables: A list of variables.
+ tuples_list: A list of admissible tuples. Each tuple must have the same
+ length as the variables, and the ith value of a tuple corresponds to the
+ ith variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: If a tuple does not have the same size as the list of
+ variables.
+ ValueError: If the array of variables is empty.
+ """
+
+ ifnotvariables:
+ raiseValueError(
+ 'AddAllowedAssignments expects a non-empty variables '
+ 'array')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.table.vars.extend([self.GetOrMakeIndex(x)forxinvariables])
+ arity=len(variables)
+ fortintuples_list:
+ iflen(t)!=arity:
+ raiseTypeError('Tuple '+str(t)+' has the wrong arity')
+ ar=[]
+ forvint:
+ ar.append(cmh.assert_is_int64(v))
+ model_ct.table.values.extend(ar)
+ returnct
+
+ defAddForbiddenAssignments(self,variables,tuples_list):
+ """Adds AddForbiddenAssignments(variables, [tuples_list]).
+
+ A ForbiddenAssignments constraint is a constraint on an array of variables
+ where the list of impossible combinations is provided in the tuples list.
+
+ Args:
+ variables: A list of variables.
+ tuples_list: A list of forbidden tuples. Each tuple must have the same
+ length as the variables, and the *i*th value of a tuple corresponds to
+ the *i*th variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: If a tuple does not have the same size as the list of
+ variables.
+ ValueError: If the array of variables is empty.
+ """
+
+ ifnotvariables:
+ raiseValueError(
+ 'AddForbiddenAssignments expects a non-empty variables '
+ 'array')
+
+ index=len(self.__model.constraints)
+ ct=self.AddAllowedAssignments(variables,tuples_list)
+ self.__model.constraints[index].table.negated=True
+ returnct
+
+ defAddAutomaton(self,transition_variables,starting_state,final_states,
+ transition_triples):
+ """Adds an automaton constraint.
+
+ An automaton constraint takes a list of variables (of size *n*), an initial
+ state, a set of final states, and a set of transitions. A transition is a
+ triplet (*tail*, *transition*, *head*), where *tail* and *head* are states,
+ and *transition* is the label of an arc from *head* to *tail*,
+ corresponding to the value of one variable in the list of variables.
+
+ This automaton will be unrolled into a flow with *n* + 1 phases. Each phase
+ contains the possible states of the automaton. The first state contains the
+ initial state. The last phase contains the final states.
+
+ Between two consecutive phases *i* and *i* + 1, the automaton creates a set
+ of arcs. For each transition (*tail*, *transition*, *head*), it will add
+ an arc from the state *tail* of phase *i* and the state *head* of phase
+ *i* + 1. This arc is labeled by the value *transition* of the variables
+ `variables[i]`. That is, this arc can only be selected if `variables[i]`
+ is assigned the value *transition*.
+
+ A feasible solution of this constraint is an assignment of variables such
+ that, starting from the initial state in phase 0, there is a path labeled by
+ the values of the variables that ends in one of the final states in the
+ final phase.
+
+ Args:
+ transition_variables: A non-empty list of variables whose values
+ correspond to the labels of the arcs traversed by the automaton.
+ starting_state: The initial state of the automaton.
+ final_states: A non-empty list of admissible final states.
+ transition_triples: A list of transitions for the automaton, in the
+ following format (current_state, variable_value, next_state).
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if `transition_variables`, `final_states`, or
+ `transition_triples` are empty.
+ """
+
+ ifnottransition_variables:
+ raiseValueError(
+ 'AddAutomaton expects a non-empty transition_variables '
+ 'array')
+ ifnotfinal_states:
+ raiseValueError('AddAutomaton expects some final states')
+
+ ifnottransition_triples:
+ raiseValueError('AddAutomaton expects some transition triples')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.automaton.vars.extend(
+ [self.GetOrMakeIndex(x)forxintransition_variables])
+ starting_state=cmh.assert_is_int64(starting_state)
+ model_ct.automaton.starting_state=starting_state
+ forvinfinal_states:
+ v=cmh.assert_is_int64(v)
+ model_ct.automaton.final_states.append(v)
+ fortintransition_triples:
+ iflen(t)!=3:
+ raiseTypeError('Tuple '+str(t)+
+ ' has the wrong arity (!= 3)')
+ tail=cmh.assert_is_int64(t[0])
+ label=cmh.assert_is_int64(t[1])
+ head=cmh.assert_is_int64(t[2])
+ model_ct.automaton.transition_tail.append(tail)
+ model_ct.automaton.transition_label.append(label)
+ model_ct.automaton.transition_head.append(head)
+ returnct
+
+ defAddInverse(self,variables,inverse_variables):
+ """Adds Inverse(variables, inverse_variables).
+
+ An inverse constraint enforces that if `variables[i]` is assigned a value
+ `j`, then `inverse_variables[j]` is assigned a value `i`. And vice versa.
+
+ Args:
+ variables: An array of integer variables.
+ inverse_variables: An array of integer variables.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: if variables and inverse_variables have different lengths, or
+ if they are empty.
+ """
+
+ ifnotvariablesornotinverse_variables:
+ raiseTypeError(
+ 'The Inverse constraint does not accept empty arrays')
+ iflen(variables)!=len(inverse_variables):
+ raiseTypeError(
+ 'In the inverse constraint, the two array variables and'
+ ' inverse_variables must have the same length.')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.inverse.f_direct.extend(
+ [self.GetOrMakeIndex(x)forxinvariables])
+ model_ct.inverse.f_inverse.extend(
+ [self.GetOrMakeIndex(x)forxininverse_variables])
+ returnct
+
+ defAddReservoirConstraint(self,times,level_changes,min_level,
+ max_level):
+ """Adds Reservoir(times, level_changes, min_level, max_level).
+
+ Maintains a reservoir level within bounds. The water level starts at 0, and
+ at any time, it must be between min_level and max_level.
+
+ If the affine expression `times[i]` is assigned a value t, then the current
+ level changes by `level_changes[i]`, which is constant, at time t.
+
+ Note that min level must be <= 0, and the max level must be >= 0. Please
+ use fixed level_changes to simulate initial state.
+
+ Therefore, at any time:
+ sum(level_changes[i] if times[i] <= t) in [min_level, max_level]
+
+ Args:
+ times: A list of affine expressions which specify the time of the filling
+ or emptying the reservoir.
+ level_changes: A list of integer values that specifies the amount of the
+ emptying or filling.
+ min_level: At any time, the level of the reservoir must be greater or
+ equal than the min level.
+ max_level: At any time, the level of the reservoir must be less or equal
+ than the max level.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if max_level < min_level.
+
+ ValueError: if max_level < 0.
+
+ ValueError: if min_level > 0
+ """
+
+ ifmax_level<min_level:
+ returnValueError(
+ 'Reservoir constraint must have a max_level >= min_level')
+
+ ifmax_level<0:
+ returnValueError('Reservoir constraint must have a max_level >= 0')
+
+ ifmin_level>0:
+ returnValueError('Reservoir constraint must have a min_level <= 0')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.reservoir.time_exprs.extend(
+ [self.ParseLinearExpression(x)forxintimes])
+ model_ct.reservoir.level_changes.extend(level_changes)
+ model_ct.reservoir.min_level=min_level
+ model_ct.reservoir.max_level=max_level
+ returnct
+
+ defAddReservoirConstraintWithActive(self,times,level_changes,actives,
+ min_level,max_level):
+ """Adds Reservoir(times, level_changes, actives, min_level, max_level).
+
+ Maintains a reservoir level within bounds. The water level starts at 0, and
+ at any time, it must be between min_level and max_level.
+
+ If the variable `times[i]` is assigned a value t, and `actives[i]` is
+ `True`, then the current level changes by `level_changes[i]`, which is
+ constant,
+ at time t.
+
+ Note that min level must be <= 0, and the max level must be >= 0. Please
+ use fixed level_changes to simulate initial state.
+
+ Therefore, at any time:
+ sum(level_changes[i] * actives[i] if times[i] <= t) in [min_level,
+ max_level]
+
+
+ The array of boolean variables 'actives', if defined, indicates which
+ actions are actually performed.
+
+ Args:
+ times: A list of affine expressions which specify the time of the filling
+ or emptying the reservoir.
+ level_changes: A list of integer values that specifies the amount of the
+ emptying or filling.
+ actives: a list of boolean variables. They indicates if the
+ emptying/refilling events actually take place.
+ min_level: At any time, the level of the reservoir must be greater or
+ equal than the min level.
+ max_level: At any time, the level of the reservoir must be less or equal
+ than the max level.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if max_level < min_level.
+
+ ValueError: if max_level < 0.
+
+ ValueError: if min_level > 0
+ """
+
+ ifmax_level<min_level:
+ returnValueError(
+ 'Reservoir constraint must have a max_level >= min_level')
+
+ ifmax_level<0:
+ returnValueError('Reservoir constraint must have a max_level >= 0')
+
+ ifmin_level>0:
+ returnValueError('Reservoir constraint must have a min_level <= 0')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.reservoir.time_exprs.extend(
+ [self.ParseLinearExpression(x)forxintimes])
+ model_ct.reservoir.level_changes.extend(level_changes)
+ model_ct.reservoir.active_literals.extend(
+ [self.GetOrMakeIndex(x)forxinactives])
+ model_ct.reservoir.min_level=min_level
+ model_ct.reservoir.max_level=max_level
+ returnct
+
+ defAddMapDomain(self,var,bool_var_array,offset=0):
+ """Adds `var == i + offset <=> bool_var_array[i] == true for all i`."""
+
+ fori,bool_varinenumerate(bool_var_array):
+ b_index=bool_var.Index()
+ var_index=var.Index()
+ model_ct=self.__model.constraints.add()
+ model_ct.linear.vars.append(var_index)
+ model_ct.linear.coeffs.append(1)
+ model_ct.linear.domain.extend([offset+i,offset+i])
+ model_ct.enforcement_literal.append(b_index)
+
+ model_ct=self.__model.constraints.add()
+ model_ct.linear.vars.append(var_index)
+ model_ct.linear.coeffs.append(1)
+ model_ct.enforcement_literal.append(-b_index-1)
+ ifoffset+i-1>=INT_MIN:
+ model_ct.linear.domain.extend([INT_MIN,offset+i-1])
+ ifoffset+i+1<=INT_MAX:
+ model_ct.linear.domain.extend([offset+i+1,INT_MAX])
+
+ defAddImplication(self,a,b):
+ """Adds `a => b` (`a` implies `b`)."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_or.literals.append(self.GetOrMakeBooleanIndex(b))
+ model_ct.enforcement_literal.append(self.GetOrMakeBooleanIndex(a))
+ returnct
+
+ defAddBoolOr(self,*literals):
+ """Adds `Or(literals) == true`: Sum(literals) >= 1."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_or.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddAtLeastOne(self,*literals):
+ """Same as `AddBoolOr`: `Sum(literals) >= 1`."""
+ returnself.AddBoolOr(*literals)
+
+ defAddAtMostOne(self,*literals):
+ """Adds `AtMostOne(literals)`: `Sum(literals) <= 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.at_most_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddExactlyOne(self,*literals):
+ """Adds `ExactlyOne(literals)`: `Sum(literals) == 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.exactly_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddBoolAnd(self,*literals):
+ """Adds `And(literals) == true`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_and.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddBoolXOr(self,*literals):
+ """Adds `XOr(literals) == true`.
+
+ In contrast to AddBoolOr and AddBoolAnd, it does not support
+ .OnlyEnforceIf().
+
+ Args:
+ *literals: the list of literals in the constraint.
+
+ Returns:
+ An `Constraint` object.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_xor.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddMinEquality(self,target,exprs):
+ """Adds `target == Min(exprs)`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.lin_max.exprs.extend(
+ [self.ParseLinearExpression(x,True)forxinexprs])
+ model_ct.lin_max.target.CopyFrom(
+ self.ParseLinearExpression(target,True))
+ returnct
+
+ defAddMaxEquality(self,target,exprs):
+ """Adds `target == Max(exprs)`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.lin_max.exprs.extend(
+ [self.ParseLinearExpression(x)forxinexprs])
+ model_ct.lin_max.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddDivisionEquality(self,target,num,denom):
+ """Adds `target == num // denom` (integer division rounded towards 0)."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.int_div.exprs.append(self.ParseLinearExpression(num))
+ model_ct.int_div.exprs.append(self.ParseLinearExpression(denom))
+ model_ct.int_div.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddAbsEquality(self,target,expr):
+ """Adds `target == Abs(var)`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.lin_max.exprs.append(self.ParseLinearExpression(expr))
+ model_ct.lin_max.exprs.append(self.ParseLinearExpression(expr,True))
+ model_ct.lin_max.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddModuloEquality(self,target,var,mod):
+ """Adds `target = var % mod`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.int_mod.exprs.append(self.ParseLinearExpression(var))
+ model_ct.int_mod.exprs.append(self.ParseLinearExpression(mod))
+ model_ct.int_mod.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ defAddMultiplicationEquality(self,target,*expressions):
+ """Adds `target == expressions[0] * .. * expressions[n]`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.int_prod.exprs.extend([
+ self.ParseLinearExpression(expr)
+ forexprinExpandGeneratorOrTuple(expressions)
+ ])
+ model_ct.int_prod.target.CopyFrom(self.ParseLinearExpression(target))
+ returnct
+
+ # Scheduling support
+
+ defNewIntervalVar(self,start,size,end,name):
+ """Creates an interval variable from start, size, and end.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Internally, it ensures that `start + size == end`.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It can be an affine or constant
+ expression.
+ end: The end of the interval. It can be an affine or constant expression.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+
+ self.Add(start+size==end)
+
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(end)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ iflen(size_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: size must be affine or constant.')
+ iflen(end_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: end must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,None,
+ name)
+
+ defNewFixedSizeIntervalVar(self,start,size,name):
+ """Creates an interval variable from start, and a fixed size.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It must be an integer value.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+ size=cmh.assert_is_int64(size)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(start+size)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,None,
+ name)
+
+ defNewOptionalIntervalVar(self,start,size,end,is_present,name):
+ """Creates an optional interval var from start, size, end, and is_present.
+
+ An optional interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap. This constraint is protected by an is_present
+ literal that indicates if it is active or not.
+
+ Internally, it ensures that `is_present` implies `start + size == end`.
+
+ Args:
+ start: The start of the interval. It can be an integer value, or an
+ integer variable.
+ size: The size of the interval. It can be an integer value, or an integer
+ variable.
+ end: The end of the interval. It can be an integer value, or an integer
+ variable.
+ is_present: A literal that indicates if the interval is active or not. A
+ inactive interval is simply ignored by all constraints.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+
+ # Add the linear constraint.
+ self.Add(start+size==end).OnlyEnforceIf(is_present)
+
+ # Creates the IntervalConstraintProto object.
+ is_present_index=self.GetOrMakeBooleanIndex(is_present)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(end)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ iflen(size_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: size must be affine or constant.')
+ iflen(end_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: end must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,
+ is_present_index,name)
+
+ defNewOptionalFixedSizeIntervalVar(self,start,size,is_present,name):
+ """Creates an interval variable from start, and a fixed size.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It must be an integer value.
+ is_present: A literal that indicates if the interval is active or not. A
+ inactive interval is simply ignored by all constraints.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+ size=cmh.assert_is_int64(size)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(start+size)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ is_present_index=self.GetOrMakeBooleanIndex(is_present)
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,
+ is_present_index,name)
+
+ defAddNoOverlap(self,interval_vars):
+ """Adds NoOverlap(interval_vars).
+
+ A NoOverlap constraint ensures that all present intervals do not overlap
+ in time.
+
+ Args:
+ interval_vars: The list of interval variables to constrain.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.no_overlap.intervals.extend(
+ [self.GetIntervalIndex(x)forxininterval_vars])
+ returnct
+
+ defAddNoOverlap2D(self,x_intervals,y_intervals):
+ """Adds NoOverlap2D(x_intervals, y_intervals).
+
+ A NoOverlap2D constraint ensures that all present rectangles do not overlap
+ on a plane. Each rectangle is aligned with the X and Y axis, and is defined
+ by two intervals which represent its projection onto the X and Y axis.
+
+ Furthermore, one box is optional if at least one of the x or y interval is
+ optional.
+
+ Args:
+ x_intervals: The X coordinates of the rectangles.
+ y_intervals: The Y coordinates of the rectangles.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.no_overlap_2d.x_intervals.extend(
+ [self.GetIntervalIndex(x)forxinx_intervals])
+ model_ct.no_overlap_2d.y_intervals.extend(
+ [self.GetIntervalIndex(x)forxiny_intervals])
+ returnct
+
+ defAddCumulative(self,intervals,demands,capacity):
+ """Adds Cumulative(intervals, demands, capacity).
+
+ This constraint enforces that:
+
+ for all t:
+ sum(demands[i]
+ if (start(intervals[i]) <= t < end(intervals[i])) and
+ (intervals[i] is present)) <= capacity
+
+ Args:
+ intervals: The list of intervals.
+ demands: The list of demands for each interval. Each demand must be >= 0.
+ Each demand can be an integer value, or an integer variable.
+ capacity: The maximum capacity of the cumulative constraint. It must be a
+ positive integer value or variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.cumulative.intervals.extend(
+ [self.GetIntervalIndex(x)forxinintervals])
+ fordindemands:
+ model_ct.cumulative.demands.append(self.ParseLinearExpression(d))
+ model_ct.cumulative.capacity.CopyFrom(
+ self.ParseLinearExpression(capacity))
+ returnct
+
+ # Support for deep copy.
+ defCopyFrom(self,other_model):
+ """Reset the model, and creates a new one from a CpModelProto instance."""
+ self.__model.CopyFrom(other_model.Proto())
+
+ # Rebuild constant map.
+ self.__constant_map.clear()
+ fori,varinenumerate(self.__model.variables):
+ iflen(var.domain)==2andvar.domain[0]==var.domain[1]:
+ self.__constant_map[var.domain[0]]=i
+
+ defGetBoolVarFromProtoIndex(self,index):
+ """Returns an already created Boolean variable from its index."""
+ ifindex<0orindex>=len(self.__model.variables):
+ raiseValueError(
+ f'GetBoolVarFromProtoIndex: out of bound index {index}')
+ var=self.__model.variables[index]
+ iflen(var.domain)!=2orvar.domain[0]<0orvar.domain[1]>1:
+ raiseValueError(
+ f'GetBoolVarFromProtoIndex: index {index} does not reference'+
+ ' a Boolean variable')
+
+ returnIntVar(self.__model,index,None)
+
+ defGetIntVarFromProtoIndex(self,index):
+ """Returns an already created integer variable from its index."""
+ ifindex<0orindex>=len(self.__model.variables):
+ raiseValueError(
+ f'GetIntVarFromProtoIndex: out of bound index {index}')
+ returnIntVar(self.__model,index,None)
+
+ defGetIntervalVarFromProtoIndex(self,index):
+ """Returns an already created interval variable from its index."""
+ ifindex<0orindex>=len(self.__model.constraints):
+ raiseValueError(
+ f'GetIntervalVarFromProtoIndex: out of bound index {index}')
+ ct=self.__model.constraints[index]
+ ifnotct.HasField('interval'):
+ raiseValueError(
+ f'GetIntervalVarFromProtoIndex: index {index} does not reference an'
+ +' interval variable')
+
+ returnIntervalVar(self.__model,index,None,None,None,None)
+
+ # Helpers.
+
+ def__str__(self):
+ returnstr(self.__model)
+
+ defProto(self):
+ """Returns the underlying CpModelProto."""
+ returnself.__model
+
+ defNegated(self,index):
+ return-index-1
+
+ defGetOrMakeIndex(self,arg):
+ """Returns the index of a variable, its negation, or a number."""
+ ifisinstance(arg,IntVar):
+ returnarg.Index()
+ elif(isinstance(arg,_ProductCst)and
+ isinstance(arg.Expression(),IntVar)andarg.Coefficient()==-1):
+ return-arg.Expression().Index()-1
+ elifcmh.is_integral(arg):
+ arg=cmh.assert_is_int64(arg)
+ returnself.GetOrMakeIndexFromConstant(arg)
+ else:
+ raiseTypeError('NotSupported: model.GetOrMakeIndex('+str(arg)+
+ ')')
+
+ defGetOrMakeBooleanIndex(self,arg):
+ """Returns an index from a boolean expression."""
+ ifisinstance(arg,IntVar):
+ self.AssertIsBooleanVariable(arg)
+ returnarg.Index()
+ elifisinstance(arg,_NotBooleanVariable):
+ self.AssertIsBooleanVariable(arg.Not())
+ returnarg.Index()
+ elifcmh.is_integral(arg):
+ cmh.assert_is_boolean(arg)
+ returnself.GetOrMakeIndexFromConstant(int(arg))
+ else:
+ raiseTypeError('NotSupported: model.GetOrMakeBooleanIndex('+
+ str(arg)+')')
+
+ defGetIntervalIndex(self,arg):
+ ifnotisinstance(arg,IntervalVar):
+ raiseTypeError('NotSupported: model.GetIntervalIndex(%s)'%arg)
+ returnarg.Index()
+
+ defGetOrMakeIndexFromConstant(self,value):
+ ifvalueinself.__constant_map:
+ returnself.__constant_map[value]
+ index=len(self.__model.variables)
+ var=self.__model.variables.add()
+ var.domain.extend([value,value])
+ self.__constant_map[value]=index
+ returnindex
+
+ defVarIndexToVarProto(self,var_index):
+ ifvar_index>=0:
+ returnself.__model.variables[var_index]
+ else:
+ returnself.__model.variables[-var_index-1]
+
+ defParseLinearExpression(self,linear_expr,negate=False):
+ """Returns a LinearExpressionProto built from a LinearExpr instance."""
+ result=cp_model_pb2.LinearExpressionProto()
+ mult=-1ifnegateelse1
+ ifcmh.is_integral(linear_expr):
+ result.offset=int(linear_expr)*mult
+ returnresult
+
+ ifisinstance(linear_expr,IntVar):
+ result.vars.append(self.GetOrMakeIndex(linear_expr))
+ result.coeffs.append(mult)
+ returnresult
+
+ coeffs_map,constant=linear_expr.GetIntegerVarValueMap()
+ result.offset=constant*mult
+ fortincoeffs_map.items():
+ ifnotisinstance(t[0],IntVar):
+ raiseTypeError('Wrong argument'+str(t))
+ c=cmh.assert_is_int64(t[1])
+ result.vars.append(t[0].Index())
+ result.coeffs.append(c*mult)
+ returnresult
+
+ def_SetObjective(self,obj,minimize):
+ """Sets the objective of the model."""
+ self.__model.ClearField('objective')
+ self.__model.ClearField('floating_point_objective')
+ ifisinstance(obj,IntVar):
+ self.__model.objective.coeffs.append(1)
+ self.__model.objective.offset=0
+ ifminimize:
+ self.__model.objective.vars.append(obj.Index())
+ self.__model.objective.scaling_factor=1
+ else:
+ self.__model.objective.vars.append(self.Negated(obj.Index()))
+ self.__model.objective.scaling_factor=-1
+ elifisinstance(obj,LinearExpr):
+ coeffs_map,constant,is_integer=obj.GetFloatVarValueMap()
+ ifis_integer:
+ ifminimize:
+ self.__model.objective.scaling_factor=1
+ self.__model.objective.offset=constant
+ else:
+ self.__model.objective.scaling_factor=-1
+ self.__model.objective.offset=-constant
+ forv,c,incoeffs_map.items():
+ self.__model.objective.coeffs.append(c)
+ ifminimize:
+ self.__model.objective.vars.append(v.Index())
+ else:
+ self.__model.objective.vars.append(
+ self.Negated(v.Index()))
+ else:
+ self.__model.floating_point_objective.maximize=notminimize
+ self.__model.floating_point_objective.offset=constant
+ forv,c,incoeffs_map.items():
+ self.__model.floating_point_objective.coeffs.append(c)
+ self.__model.floating_point_objective.vars.append(v.Index())
+ elifcmh.is_integral(obj):
+ self.__model.objective.offset=int(obj)
+ self.__model.objective.scaling_factor=1
+ else:
+ raiseTypeError('TypeError: '+str(obj)+
+ ' is not a valid objective')
+
+ defMinimize(self,obj):
+ """Sets the objective of the model to minimize(obj)."""
+ self._SetObjective(obj,minimize=True)
+
+ defMaximize(self,obj):
+ """Sets the objective of the model to maximize(obj)."""
+ self._SetObjective(obj,minimize=False)
+
+ defHasObjective(self):
+ returnself.__model.HasField('objective')
+
+ defAddDecisionStrategy(self,variables,var_strategy,domain_strategy):
+ """Adds a search strategy to the model.
+
+ Args:
+ variables: a list of variables this strategy will assign.
+ var_strategy: heuristic to choose the next variable to assign.
+ domain_strategy: heuristic to reduce the domain of the selected variable.
+ Currently, this is advanced code: the union of all strategies added to
+ the model must be complete, i.e. instantiates all variables.
+ Otherwise, Solve() will fail.
+ """
+
+ strategy=self.__model.search_strategy.add()
+ forvinvariables:
+ strategy.variables.append(v.Index())
+ strategy.variable_selection_strategy=var_strategy
+ strategy.domain_reduction_strategy=domain_strategy
+
+ defModelStats(self):
+ """Returns a string containing some model statistics."""
+ returnswig_helper.CpSatHelper.SerializedModelStats(
+ self.__model.SerializeToString())
+
+ defValidate(self):
+ """Returns a string indicating that the model is invalid."""
+ returnswig_helper.CpSatHelper.SerializedValidateModel(
+ self.__model.SerializeToString())
+
+ defExportToFile(self,file):
+ """Write the model as a protocol buffer to 'file'.
+
+ Args:
+ file: file to write the model to. If the filename ends with 'txt', the
+ model will be written as a text file, otherwise, the binary format will
+ be used.
+
+ Returns:
+ True if the model was correctly written.
+ """
+ returnswig_helper.CpSatHelper.SerializedWriteModelToFile(
+ self.__model.SerializeToString(),file)
+
+ defAssertIsBooleanVariable(self,x):
+ ifisinstance(x,IntVar):
+ var=self.__model.variables[x.Index()]
+ iflen(var.domain)!=2orvar.domain[0]<0orvar.domain[1]>1:
+ raiseTypeError('TypeError: '+str(x)+
+ ' is not a boolean variable')
+ elifnotisinstance(x,_NotBooleanVariable):
+ raiseTypeError('TypeError: '+str(x)+
+ ' is not a boolean variable')
+
+ defAddHint(self,var,value):
+ """Adds 'var == value' as a hint to the solver."""
+ self.__model.solution_hint.vars.append(self.GetOrMakeIndex(var))
+ self.__model.solution_hint.values.append(value)
+
+ defClearHints(self):
+ """Remove any solution hint from the model."""
+ self.__model.ClearField('solution_hint')
+
+ defAddAssumption(self,lit):
+ """Add the literal 'lit' to the model as assumptions."""
+ self.__model.assumptions.append(self.GetOrMakeBooleanIndex(lit))
+
+ defAddAssumptions(self,literals):
+ """Add the literals to the model as assumptions."""
+ forlitinliterals:
+ self.AddAssumption(lit)
+
+ defClearAssumptions(self):
+ """Remove all assumptions from the model."""
+ self.__model.ClearField('assumptions')
+
+
+
+
+
Methods for building a CP model.
+
+
Methods beginning with:
+
+
+
New create integer, boolean, or interval variables.
+
Add create new constraints and add them to the model.
defNewIntVar(self,lb,ub,name):
+ """Create an integer variable with domain [lb, ub].
+
+ The CP-SAT solver is limited to integer variables. If you have fractional
+ values, scale them up so that they become integers; if you have strings,
+ encode them as integers.
+
+ Args:
+ lb: Lower bound for the variable.
+ ub: Upper bound for the variable.
+ name: The name of the variable.
+
+ Returns:
+ a variable whose domain is [lb, ub].
+ """
+
+ returnIntVar(self.__model,Domain(lb,ub),name)
+
+
+
+
+
Create an integer variable with domain [lb, ub].
+
+
The CP-SAT solver is limited to integer variables. If you have fractional
+values, scale them up so that they become integers; if you have strings,
+encode them as integers.
defNewIntVarFromDomain(self,domain,name):
+ """Create an integer variable from a domain.
+
+ A domain is a set of integers specified by a collection of intervals.
+ For example, `model.NewIntVarFromDomain(cp_model.
+ Domain.FromIntervals([[1, 2], [4, 6]]), 'x')`
+
+ Args:
+ domain: An instance of the Domain class.
+ name: The name of the variable.
+
+ Returns:
+ a variable whose domain is the given domain.
+ """
+ returnIntVar(self.__model,domain,name)
+
+
+
+
+
Create an integer variable from a domain.
+
+
A domain is a set of integers specified by a collection of intervals.
+For example, model.NewIntVarFromDomain(cp_model.
+ Domain.FromIntervals([[1, 2], [4, 6]]), 'x')
defAddAllDifferent(self,*expressions):
+ """Adds AllDifferent(expressions).
+
+ This constraint forces all expressions to have different values.
+
+ Args:
+ *expressions: simple expressions of the form a * var + constant.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ expanded=ExpandGeneratorOrTuple(expressions)
+ model_ct.all_diff.exprs.extend(
+ [self.ParseLinearExpression(x)forxinexpanded])
+ returnct
+
+
+
+
+
Adds AllDifferent(expressions).
+
+
This constraint forces all expressions to have different values.
+
+
Args
+
+
+
*expressions: simple expressions of the form a * var + constant.
defAddCircuit(self,arcs):
+ """Adds Circuit(arcs).
+
+ Adds a circuit constraint from a sparse list of arcs that encode the graph.
+
+ A circuit is a unique Hamiltonian path in a subgraph of the total
+ graph. In case a node 'i' is not in the path, then there must be a
+ loop arc 'i -> i' associated with a true literal. Otherwise
+ this constraint will fail.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError('AddCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.circuit.tails.append(tail)
+ model_ct.circuit.heads.append(head)
+ model_ct.circuit.literals.append(lit)
+ returnct
+
+
+
+
+
Adds Circuit(arcs).
+
+
Adds a circuit constraint from a sparse list of arcs that encode the graph.
+
+
A circuit is a unique Hamiltonian path in a subgraph of the total
+graph. In case a node 'i' is not in the path, then there must be a
+loop arc 'i -> i' associated with a true literal. Otherwise
+this constraint will fail.
+
+
Args
+
+
+
arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+literal). The arc is selected in the circuit if the literal is true.
+Both source_node and destination_node must be integers between 0 and the
+number of nodes - 1.
defAddMultipleCircuit(self,arcs):
+ """Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+ The direct graph where arc #i (from tails[i] to head[i]) is present iff
+ literals[i] is true must satisfy this set of properties:
+ - #incoming arcs == 1 except for node 0.
+ - #outgoing arcs == 1 except for node 0.
+ - for node zero, #incoming arcs == #outgoing arcs.
+ - There are no duplicate arcs.
+ - Self-arcs are allowed except for node 0.
+ - There is no cycle in this graph, except through node 0.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError(
+ 'AddMultipleCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.routes.tails.append(tail)
+ model_ct.routes.heads.append(head)
+ model_ct.routes.literals.append(lit)
+ returnct
+
+
+
+
+
Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+
The direct graph where arc #i (from tails[i] to head[i]) is present iff
+literals[i] is true must satisfy this set of properties:
+
+
+
#incoming arcs == 1 except for node 0.
+
#outgoing arcs == 1 except for node 0.
+
for node zero, #incoming arcs == #outgoing arcs.
+
There are no duplicate arcs.
+
Self-arcs are allowed except for node 0.
+
There is no cycle in this graph, except through node 0.
+
+
+
Args
+
+
+
arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+literal). The arc is selected in the circuit if the literal is true.
+Both source_node and destination_node must be integers between 0 and the
+number of nodes - 1.
defAddAllowedAssignments(self,variables,tuples_list):
+ """Adds AllowedAssignments(variables, tuples_list).
+
+ An AllowedAssignments constraint is a constraint on an array of variables,
+ which requires that when all variables are assigned values, the resulting
+ array equals one of the tuples in `tuple_list`.
+
+ Args:
+ variables: A list of variables.
+ tuples_list: A list of admissible tuples. Each tuple must have the same
+ length as the variables, and the ith value of a tuple corresponds to the
+ ith variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: If a tuple does not have the same size as the list of
+ variables.
+ ValueError: If the array of variables is empty.
+ """
+
+ ifnotvariables:
+ raiseValueError(
+ 'AddAllowedAssignments expects a non-empty variables '
+ 'array')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.table.vars.extend([self.GetOrMakeIndex(x)forxinvariables])
+ arity=len(variables)
+ fortintuples_list:
+ iflen(t)!=arity:
+ raiseTypeError('Tuple '+str(t)+' has the wrong arity')
+ ar=[]
+ forvint:
+ ar.append(cmh.assert_is_int64(v))
+ model_ct.table.values.extend(ar)
+ returnct
+
+
+
+
+
Adds AllowedAssignments(variables, tuples_list).
+
+
An AllowedAssignments constraint is a constraint on an array of variables,
+which requires that when all variables are assigned values, the resulting
+array equals one of the tuples in tuple_list.
+
+
Args
+
+
+
variables: A list of variables.
+
tuples_list: A list of admissible tuples. Each tuple must have the same
+length as the variables, and the ith value of a tuple corresponds to the
+ith variable.
defAddForbiddenAssignments(self,variables,tuples_list):
+ """Adds AddForbiddenAssignments(variables, [tuples_list]).
+
+ A ForbiddenAssignments constraint is a constraint on an array of variables
+ where the list of impossible combinations is provided in the tuples list.
+
+ Args:
+ variables: A list of variables.
+ tuples_list: A list of forbidden tuples. Each tuple must have the same
+ length as the variables, and the *i*th value of a tuple corresponds to
+ the *i*th variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: If a tuple does not have the same size as the list of
+ variables.
+ ValueError: If the array of variables is empty.
+ """
+
+ ifnotvariables:
+ raiseValueError(
+ 'AddForbiddenAssignments expects a non-empty variables '
+ 'array')
+
+ index=len(self.__model.constraints)
+ ct=self.AddAllowedAssignments(variables,tuples_list)
+ self.__model.constraints[index].table.negated=True
+ returnct
+
A ForbiddenAssignments constraint is a constraint on an array of variables
+where the list of impossible combinations is provided in the tuples list.
+
+
Args
+
+
+
variables: A list of variables.
+
tuples_list: A list of forbidden tuples. Each tuple must have the same
+length as the variables, and the ith value of a tuple corresponds to
+the ith variable.
defAddAutomaton(self,transition_variables,starting_state,final_states,
+ transition_triples):
+ """Adds an automaton constraint.
+
+ An automaton constraint takes a list of variables (of size *n*), an initial
+ state, a set of final states, and a set of transitions. A transition is a
+ triplet (*tail*, *transition*, *head*), where *tail* and *head* are states,
+ and *transition* is the label of an arc from *head* to *tail*,
+ corresponding to the value of one variable in the list of variables.
+
+ This automaton will be unrolled into a flow with *n* + 1 phases. Each phase
+ contains the possible states of the automaton. The first state contains the
+ initial state. The last phase contains the final states.
+
+ Between two consecutive phases *i* and *i* + 1, the automaton creates a set
+ of arcs. For each transition (*tail*, *transition*, *head*), it will add
+ an arc from the state *tail* of phase *i* and the state *head* of phase
+ *i* + 1. This arc is labeled by the value *transition* of the variables
+ `variables[i]`. That is, this arc can only be selected if `variables[i]`
+ is assigned the value *transition*.
+
+ A feasible solution of this constraint is an assignment of variables such
+ that, starting from the initial state in phase 0, there is a path labeled by
+ the values of the variables that ends in one of the final states in the
+ final phase.
+
+ Args:
+ transition_variables: A non-empty list of variables whose values
+ correspond to the labels of the arcs traversed by the automaton.
+ starting_state: The initial state of the automaton.
+ final_states: A non-empty list of admissible final states.
+ transition_triples: A list of transitions for the automaton, in the
+ following format (current_state, variable_value, next_state).
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if `transition_variables`, `final_states`, or
+ `transition_triples` are empty.
+ """
+
+ ifnottransition_variables:
+ raiseValueError(
+ 'AddAutomaton expects a non-empty transition_variables '
+ 'array')
+ ifnotfinal_states:
+ raiseValueError('AddAutomaton expects some final states')
+
+ ifnottransition_triples:
+ raiseValueError('AddAutomaton expects some transition triples')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.automaton.vars.extend(
+ [self.GetOrMakeIndex(x)forxintransition_variables])
+ starting_state=cmh.assert_is_int64(starting_state)
+ model_ct.automaton.starting_state=starting_state
+ forvinfinal_states:
+ v=cmh.assert_is_int64(v)
+ model_ct.automaton.final_states.append(v)
+ fortintransition_triples:
+ iflen(t)!=3:
+ raiseTypeError('Tuple '+str(t)+
+ ' has the wrong arity (!= 3)')
+ tail=cmh.assert_is_int64(t[0])
+ label=cmh.assert_is_int64(t[1])
+ head=cmh.assert_is_int64(t[2])
+ model_ct.automaton.transition_tail.append(tail)
+ model_ct.automaton.transition_label.append(label)
+ model_ct.automaton.transition_head.append(head)
+ returnct
+
+
+
+
+
Adds an automaton constraint.
+
+
An automaton constraint takes a list of variables (of size n), an initial
+state, a set of final states, and a set of transitions. A transition is a
+triplet (tail, transition, head), where tail and head are states,
+and transition is the label of an arc from head to tail,
+corresponding to the value of one variable in the list of variables.
+
+
This automaton will be unrolled into a flow with n + 1 phases. Each phase
+contains the possible states of the automaton. The first state contains the
+initial state. The last phase contains the final states.
+
+
Between two consecutive phases i and i + 1, the automaton creates a set
+of arcs. For each transition (tail, transition, head), it will add
+an arc from the state tail of phase i and the state head of phase
+i + 1. This arc is labeled by the value transition of the variables
+variables[i]. That is, this arc can only be selected if variables[i]
+is assigned the value transition.
+
+
A feasible solution of this constraint is an assignment of variables such
+that, starting from the initial state in phase 0, there is a path labeled by
+the values of the variables that ends in one of the final states in the
+final phase.
+
+
Args
+
+
+
transition_variables: A non-empty list of variables whose values
+correspond to the labels of the arcs traversed by the automaton.
+
starting_state: The initial state of the automaton.
+
final_states: A non-empty list of admissible final states.
+
transition_triples: A list of transitions for the automaton, in the
+following format (current_state, variable_value, next_state).
defAddInverse(self,variables,inverse_variables):
+ """Adds Inverse(variables, inverse_variables).
+
+ An inverse constraint enforces that if `variables[i]` is assigned a value
+ `j`, then `inverse_variables[j]` is assigned a value `i`. And vice versa.
+
+ Args:
+ variables: An array of integer variables.
+ inverse_variables: An array of integer variables.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ TypeError: if variables and inverse_variables have different lengths, or
+ if they are empty.
+ """
+
+ ifnotvariablesornotinverse_variables:
+ raiseTypeError(
+ 'The Inverse constraint does not accept empty arrays')
+ iflen(variables)!=len(inverse_variables):
+ raiseTypeError(
+ 'In the inverse constraint, the two array variables and'
+ ' inverse_variables must have the same length.')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.inverse.f_direct.extend(
+ [self.GetOrMakeIndex(x)forxinvariables])
+ model_ct.inverse.f_inverse.extend(
+ [self.GetOrMakeIndex(x)forxininverse_variables])
+ returnct
+
+
+
+
+
Adds Inverse(variables, inverse_variables).
+
+
An inverse constraint enforces that if variables[i] is assigned a value
+j, then inverse_variables[j] is assigned a value i. And vice versa.
defAddReservoirConstraint(self,times,level_changes,min_level,
+ max_level):
+ """Adds Reservoir(times, level_changes, min_level, max_level).
+
+ Maintains a reservoir level within bounds. The water level starts at 0, and
+ at any time, it must be between min_level and max_level.
+
+ If the affine expression `times[i]` is assigned a value t, then the current
+ level changes by `level_changes[i]`, which is constant, at time t.
+
+ Note that min level must be <= 0, and the max level must be >= 0. Please
+ use fixed level_changes to simulate initial state.
+
+ Therefore, at any time:
+ sum(level_changes[i] if times[i] <= t) in [min_level, max_level]
+
+ Args:
+ times: A list of affine expressions which specify the time of the filling
+ or emptying the reservoir.
+ level_changes: A list of integer values that specifies the amount of the
+ emptying or filling.
+ min_level: At any time, the level of the reservoir must be greater or
+ equal than the min level.
+ max_level: At any time, the level of the reservoir must be less or equal
+ than the max level.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if max_level < min_level.
+
+ ValueError: if max_level < 0.
+
+ ValueError: if min_level > 0
+ """
+
+ ifmax_level<min_level:
+ returnValueError(
+ 'Reservoir constraint must have a max_level >= min_level')
+
+ ifmax_level<0:
+ returnValueError('Reservoir constraint must have a max_level >= 0')
+
+ ifmin_level>0:
+ returnValueError('Reservoir constraint must have a min_level <= 0')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.reservoir.time_exprs.extend(
+ [self.ParseLinearExpression(x)forxintimes])
+ model_ct.reservoir.level_changes.extend(level_changes)
+ model_ct.reservoir.min_level=min_level
+ model_ct.reservoir.max_level=max_level
+ returnct
+
defAddReservoirConstraintWithActive(self,times,level_changes,actives,
+ min_level,max_level):
+ """Adds Reservoir(times, level_changes, actives, min_level, max_level).
+
+ Maintains a reservoir level within bounds. The water level starts at 0, and
+ at any time, it must be between min_level and max_level.
+
+ If the variable `times[i]` is assigned a value t, and `actives[i]` is
+ `True`, then the current level changes by `level_changes[i]`, which is
+ constant,
+ at time t.
+
+ Note that min level must be <= 0, and the max level must be >= 0. Please
+ use fixed level_changes to simulate initial state.
+
+ Therefore, at any time:
+ sum(level_changes[i] * actives[i] if times[i] <= t) in [min_level,
+ max_level]
+
+
+ The array of boolean variables 'actives', if defined, indicates which
+ actions are actually performed.
+
+ Args:
+ times: A list of affine expressions which specify the time of the filling
+ or emptying the reservoir.
+ level_changes: A list of integer values that specifies the amount of the
+ emptying or filling.
+ actives: a list of boolean variables. They indicates if the
+ emptying/refilling events actually take place.
+ min_level: At any time, the level of the reservoir must be greater or
+ equal than the min level.
+ max_level: At any time, the level of the reservoir must be less or equal
+ than the max level.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: if max_level < min_level.
+
+ ValueError: if max_level < 0.
+
+ ValueError: if min_level > 0
+ """
+
+ ifmax_level<min_level:
+ returnValueError(
+ 'Reservoir constraint must have a max_level >= min_level')
+
+ ifmax_level<0:
+ returnValueError('Reservoir constraint must have a max_level >= 0')
+
+ ifmin_level>0:
+ returnValueError('Reservoir constraint must have a min_level <= 0')
+
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.reservoir.time_exprs.extend(
+ [self.ParseLinearExpression(x)forxintimes])
+ model_ct.reservoir.level_changes.extend(level_changes)
+ model_ct.reservoir.active_literals.extend(
+ [self.GetOrMakeIndex(x)forxinactives])
+ model_ct.reservoir.min_level=min_level
+ model_ct.reservoir.max_level=max_level
+ returnct
+
Maintains a reservoir level within bounds. The water level starts at 0, and
+at any time, it must be between min_level and max_level.
+
+
If the variable times[i] is assigned a value t, and actives[i] is
+True, then the current level changes by level_changes[i], which is
+constant,
+at time t.
+
+
Note that min level must be <= 0, and the max level must be >= 0. Please
+ use fixed level_changes to simulate initial state.
+
+
Therefore, at any time:
+ sum(level_changes[i] * actives[i] if times[i] <= t) in [min_level,
+ max_level]
+
+
The array of boolean variables 'actives', if defined, indicates which
+actions are actually performed.
+
+
Args
+
+
+
times: A list of affine expressions which specify the time of the filling
+or emptying the reservoir.
+
level_changes: A list of integer values that specifies the amount of the
+emptying or filling.
+
actives: a list of boolean variables. They indicates if the
+emptying/refilling events actually take place.
+
min_level: At any time, the level of the reservoir must be greater or
+equal than the min level.
+
max_level: At any time, the level of the reservoir must be less or equal
+than the max level.
defAddBoolXOr(self,*literals):
+ """Adds `XOr(literals) == true`.
+
+ In contrast to AddBoolOr and AddBoolAnd, it does not support
+ .OnlyEnforceIf().
+
+ Args:
+ *literals: the list of literals in the constraint.
+
+ Returns:
+ An `Constraint` object.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.bool_xor.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+
+
+
+
Adds XOr(literals) == true.
+
+
In contrast to AddBoolOr and AddBoolAnd, it does not support
+ .OnlyEnforceIf().
+
+
Args
+
+
+
*literals: the list of literals in the constraint.
defNewIntervalVar(self,start,size,end,name):
+ """Creates an interval variable from start, size, and end.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Internally, it ensures that `start + size == end`.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It can be an affine or constant
+ expression.
+ end: The end of the interval. It can be an affine or constant expression.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+
+ self.Add(start+size==end)
+
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(end)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ iflen(size_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: size must be affine or constant.')
+ iflen(end_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: end must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,None,
+ name)
+
+
+
+
+
Creates an interval variable from start, size, and end.
+
+
An interval variable is a constraint, that is itself used in other
+constraints like NoOverlap.
+
+
Internally, it ensures that start + size == end.
+
+
Args
+
+
+
start: The start of the interval. It can be an affine or constant
+expression.
+
size: The size of the interval. It can be an affine or constant
+expression.
+
end: The end of the interval. It can be an affine or constant expression.
defNewFixedSizeIntervalVar(self,start,size,name):
+ """Creates an interval variable from start, and a fixed size.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It must be an integer value.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+ size=cmh.assert_is_int64(size)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(start+size)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,None,
+ name)
+
+
+
+
+
Creates an interval variable from start, and a fixed size.
+
+
An interval variable is a constraint, that is itself used in other
+constraints like NoOverlap.
+
+
Args
+
+
+
start: The start of the interval. It can be an affine or constant
+expression.
+
size: The size of the interval. It must be an integer value.
defNewOptionalIntervalVar(self,start,size,end,is_present,name):
+ """Creates an optional interval var from start, size, end, and is_present.
+
+ An optional interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap. This constraint is protected by an is_present
+ literal that indicates if it is active or not.
+
+ Internally, it ensures that `is_present` implies `start + size == end`.
+
+ Args:
+ start: The start of the interval. It can be an integer value, or an
+ integer variable.
+ size: The size of the interval. It can be an integer value, or an integer
+ variable.
+ end: The end of the interval. It can be an integer value, or an integer
+ variable.
+ is_present: A literal that indicates if the interval is active or not. A
+ inactive interval is simply ignored by all constraints.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+
+ # Add the linear constraint.
+ self.Add(start+size==end).OnlyEnforceIf(is_present)
+
+ # Creates the IntervalConstraintProto object.
+ is_present_index=self.GetOrMakeBooleanIndex(is_present)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(end)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ iflen(size_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: size must be affine or constant.')
+ iflen(end_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: end must be affine or constant.')
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,
+ is_present_index,name)
+
+
+
+
+
Creates an optional interval var from start, size, end, and is_present.
+
+
An optional interval variable is a constraint, that is itself used in other
+constraints like NoOverlap. This constraint is protected by an is_present
+literal that indicates if it is active or not.
+
+
Internally, it ensures that is_present implies start + size == end.
+
+
Args
+
+
+
start: The start of the interval. It can be an integer value, or an
+integer variable.
+
size: The size of the interval. It can be an integer value, or an integer
+variable.
+
end: The end of the interval. It can be an integer value, or an integer
+variable.
+
is_present: A literal that indicates if the interval is active or not. A
+inactive interval is simply ignored by all constraints.
defNewOptionalFixedSizeIntervalVar(self,start,size,is_present,name):
+ """Creates an interval variable from start, and a fixed size.
+
+ An interval variable is a constraint, that is itself used in other
+ constraints like NoOverlap.
+
+ Args:
+ start: The start of the interval. It can be an affine or constant
+ expression.
+ size: The size of the interval. It must be an integer value.
+ is_present: A literal that indicates if the interval is active or not. A
+ inactive interval is simply ignored by all constraints.
+ name: The name of the interval variable.
+
+ Returns:
+ An `IntervalVar` object.
+ """
+ size=cmh.assert_is_int64(size)
+ start_expr=self.ParseLinearExpression(start)
+ size_expr=self.ParseLinearExpression(size)
+ end_expr=self.ParseLinearExpression(start+size)
+ iflen(start_expr.vars)>1:
+ raiseTypeError(
+ 'cp_model.NewIntervalVar: start must be affine or constant.')
+ is_present_index=self.GetOrMakeBooleanIndex(is_present)
+ returnIntervalVar(self.__model,start_expr,size_expr,end_expr,
+ is_present_index,name)
+
+
+
+
+
Creates an interval variable from start, and a fixed size.
+
+
An interval variable is a constraint, that is itself used in other
+constraints like NoOverlap.
+
+
Args
+
+
+
start: The start of the interval. It can be an affine or constant
+expression.
+
size: The size of the interval. It must be an integer value.
+
is_present: A literal that indicates if the interval is active or not. A
+inactive interval is simply ignored by all constraints.
defAddNoOverlap(self,interval_vars):
+ """Adds NoOverlap(interval_vars).
+
+ A NoOverlap constraint ensures that all present intervals do not overlap
+ in time.
+
+ Args:
+ interval_vars: The list of interval variables to constrain.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.no_overlap.intervals.extend(
+ [self.GetIntervalIndex(x)forxininterval_vars])
+ returnct
+
+
+
+
+
Adds NoOverlap(interval_vars).
+
+
A NoOverlap constraint ensures that all present intervals do not overlap
+in time.
+
+
Args
+
+
+
interval_vars: The list of interval variables to constrain.
defAddNoOverlap2D(self,x_intervals,y_intervals):
+ """Adds NoOverlap2D(x_intervals, y_intervals).
+
+ A NoOverlap2D constraint ensures that all present rectangles do not overlap
+ on a plane. Each rectangle is aligned with the X and Y axis, and is defined
+ by two intervals which represent its projection onto the X and Y axis.
+
+ Furthermore, one box is optional if at least one of the x or y interval is
+ optional.
+
+ Args:
+ x_intervals: The X coordinates of the rectangles.
+ y_intervals: The Y coordinates of the rectangles.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.no_overlap_2d.x_intervals.extend(
+ [self.GetIntervalIndex(x)forxinx_intervals])
+ model_ct.no_overlap_2d.y_intervals.extend(
+ [self.GetIntervalIndex(x)forxiny_intervals])
+ returnct
+
+
+
+
+
Adds NoOverlap2D(x_intervals, y_intervals).
+
+
A NoOverlap2D constraint ensures that all present rectangles do not overlap
+on a plane. Each rectangle is aligned with the X and Y axis, and is defined
+by two intervals which represent its projection onto the X and Y axis.
+
+
Furthermore, one box is optional if at least one of the x or y interval is
+optional.
defAddCumulative(self,intervals,demands,capacity):
+ """Adds Cumulative(intervals, demands, capacity).
+
+ This constraint enforces that:
+
+ for all t:
+ sum(demands[i]
+ if (start(intervals[i]) <= t < end(intervals[i])) and
+ (intervals[i] is present)) <= capacity
+
+ Args:
+ intervals: The list of intervals.
+ demands: The list of demands for each interval. Each demand must be >= 0.
+ Each demand can be an integer value, or an integer variable.
+ capacity: The maximum capacity of the cumulative constraint. It must be a
+ positive integer value or variable.
+
+ Returns:
+ An instance of the `Constraint` class.
+ """
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.cumulative.intervals.extend(
+ [self.GetIntervalIndex(x)forxinintervals])
+ fordindemands:
+ model_ct.cumulative.demands.append(self.ParseLinearExpression(d))
+ model_ct.cumulative.capacity.CopyFrom(
+ self.ParseLinearExpression(capacity))
+ returnct
+
+
+
+
+
Adds Cumulative(intervals, demands, capacity).
+
+
This constraint enforces that
+
+
+
for all t:
+ sum(demands[i]
+ if (start(intervals[i]) <= t < end(intervals[i])) and
+ (intervals[i] is present)) <= capacity
+
+
+
Args
+
+
+
intervals: The list of intervals.
+
demands: The list of demands for each interval. Each demand must be >= 0.
+Each demand can be an integer value, or an integer variable.
+
capacity: The maximum capacity of the cumulative constraint. It must be a
+positive integer value or variable.
defCopyFrom(self,other_model):
+ """Reset the model, and creates a new one from a CpModelProto instance."""
+ self.__model.CopyFrom(other_model.Proto())
+
+ # Rebuild constant map.
+ self.__constant_map.clear()
+ fori,varinenumerate(self.__model.variables):
+ iflen(var.domain)==2andvar.domain[0]==var.domain[1]:
+ self.__constant_map[var.domain[0]]=i
+
+
+
+
+
Reset the model, and creates a new one from a CpModelProto instance.
defGetBoolVarFromProtoIndex(self,index):
+ """Returns an already created Boolean variable from its index."""
+ ifindex<0orindex>=len(self.__model.variables):
+ raiseValueError(
+ f'GetBoolVarFromProtoIndex: out of bound index {index}')
+ var=self.__model.variables[index]
+ iflen(var.domain)!=2orvar.domain[0]<0orvar.domain[1]>1:
+ raiseValueError(
+ f'GetBoolVarFromProtoIndex: index {index} does not reference'+
+ ' a Boolean variable')
+
+ returnIntVar(self.__model,index,None)
+
+
+
+
+
Returns an already created Boolean variable from its index.
defGetIntVarFromProtoIndex(self,index):
+ """Returns an already created integer variable from its index."""
+ ifindex<0orindex>=len(self.__model.variables):
+ raiseValueError(
+ f'GetIntVarFromProtoIndex: out of bound index {index}')
+ returnIntVar(self.__model,index,None)
+
+
+
+
+
Returns an already created integer variable from its index.
defGetIntervalVarFromProtoIndex(self,index):
+ """Returns an already created interval variable from its index."""
+ ifindex<0orindex>=len(self.__model.constraints):
+ raiseValueError(
+ f'GetIntervalVarFromProtoIndex: out of bound index {index}')
+ ct=self.__model.constraints[index]
+ ifnotct.HasField('interval'):
+ raiseValueError(
+ f'GetIntervalVarFromProtoIndex: index {index} does not reference an'
+ +' interval variable')
+
+ returnIntervalVar(self.__model,index,None,None,None,None)
+
+
+
+
+
Returns an already created interval variable from its index.
defAddDecisionStrategy(self,variables,var_strategy,domain_strategy):
+ """Adds a search strategy to the model.
+
+ Args:
+ variables: a list of variables this strategy will assign.
+ var_strategy: heuristic to choose the next variable to assign.
+ domain_strategy: heuristic to reduce the domain of the selected variable.
+ Currently, this is advanced code: the union of all strategies added to
+ the model must be complete, i.e. instantiates all variables.
+ Otherwise, Solve() will fail.
+ """
+
+ strategy=self.__model.search_strategy.add()
+ forvinvariables:
+ strategy.variables.append(v.Index())
+ strategy.variable_selection_strategy=var_strategy
+ strategy.domain_reduction_strategy=domain_strategy
+
+
+
+
+
Adds a search strategy to the model.
+
+
Args
+
+
+
variables: a list of variables this strategy will assign.
+
var_strategy: heuristic to choose the next variable to assign.
+
domain_strategy: heuristic to reduce the domain of the selected variable.
+Currently, this is advanced code: the union of all strategies added to
+ the model must be complete, i.e. instantiates all variables.
+ Otherwise, Solve() will fail.
defModelStats(self):
+ """Returns a string containing some model statistics."""
+ returnswig_helper.CpSatHelper.SerializedModelStats(
+ self.__model.SerializeToString())
+
+
+
+
+
Returns a string containing some model statistics.
defValidate(self):
+ """Returns a string indicating that the model is invalid."""
+ returnswig_helper.CpSatHelper.SerializedValidateModel(
+ self.__model.SerializeToString())
+
+
+
+
+
Returns a string indicating that the model is invalid.
defExportToFile(self,file):
+ """Write the model as a protocol buffer to 'file'.
+
+ Args:
+ file: file to write the model to. If the filename ends with 'txt', the
+ model will be written as a text file, otherwise, the binary format will
+ be used.
+
+ Returns:
+ True if the model was correctly written.
+ """
+ returnswig_helper.CpSatHelper.SerializedWriteModelToFile(
+ self.__model.SerializeToString(),file)
+
+
+
+
+
Write the model as a protocol buffer to 'file'.
+
+
Args
+
+
+
file: file to write the model to. If the filename ends with 'txt', the
+model will be written as a text file, otherwise, the binary format will
+be used.
defAssertIsBooleanVariable(self,x):
+ ifisinstance(x,IntVar):
+ var=self.__model.variables[x.Index()]
+ iflen(var.domain)!=2orvar.domain[0]<0orvar.domain[1]>1:
+ raiseTypeError('TypeError: '+str(x)+
+ ' is not a boolean variable')
+ elifnotisinstance(x,_NotBooleanVariable):
+ raiseTypeError('TypeError: '+str(x)+
+ ' is not a boolean variable')
+
defAddHint(self,var,value):
+ """Adds 'var == value' as a hint to the solver."""
+ self.__model.solution_hint.vars.append(self.GetOrMakeIndex(var))
+ self.__model.solution_hint.values.append(value)
+
defAddAssumption(self,lit):
+ """Add the literal 'lit' to the model as assumptions."""
+ self.__model.assumptions.append(self.GetOrMakeBooleanIndex(lit))
+
+
+
+
+
Add the literal 'lit' to the model as assumptions.
classCpSolver(object):
+ """Main solver class.
+
+ The purpose of this class is to search for a solution to the model provided
+ to the Solve() method.
+
+ Once Solve() is called, this class allows inspecting the solution found
+ with the Value() and BooleanValue() methods, as well as general statistics
+ about the solve procedure.
+ """
+
+ def__init__(self):
+ self.__model=None
+ self.__solution:cp_model_pb2.CpSolverResponse=None
+ self.parameters=sat_parameters_pb2.SatParameters()
+ self.log_callback=None
+ self.__solve_wrapper:swig_helper.SolveWrapper=None
+ self.__lock=threading.Lock()
+
+ defSolve(self,model,solution_callback=None):
+ """Solves a problem and passes each solution to the callback if not null."""
+ withself.__lock:
+ solve_wrapper=swig_helper.SolveWrapper()
+
+ swig_helper.SolveWrapper.SetSerializedParameters(
+ self.parameters.SerializeToString(),solve_wrapper)
+ ifsolution_callbackisnotNone:
+ solve_wrapper.AddSolutionCallback(solution_callback)
+
+ ifself.log_callbackisnotNone:
+ solve_wrapper.AddLogCallback(self.log_callback)
+
+ self.__solution=cp_model_pb2.CpSolverResponse.FromString(
+ swig_helper.SolveWrapper.SerializedSolve(
+ model.Proto().SerializeToString(),solve_wrapper))
+
+ ifsolution_callbackisnotNone:
+ solve_wrapper.ClearSolutionCallback(solution_callback)
+
+ withself.__lock:
+ self.__solve_wrapper=None
+
+ returnself.__solution.status
+
+ defSolveWithSolutionCallback(self,model,callback):
+ """DEPRECATED Use Solve() with the callback argument."""
+ warnings.warn(
+ 'SolveWithSolutionCallback is deprecated; use Solve() with'+
+ 'the callback argument.',DeprecationWarning)
+ returnself.Solve(model,callback)
+
+ defSearchForAllSolutions(self,model,callback):
+ """DEPRECATED Use Solve() with the right parameter.
+
+ Search for all solutions of a satisfiability problem.
+
+ This method searches for all feasible solutions of a given model.
+ Then it feeds the solution to the callback.
+
+ Note that the model cannot contain an objective.
+
+ Args:
+ model: The model to solve.
+ callback: The callback that will be called at each solution.
+
+ Returns:
+ The status of the solve:
+
+ * *FEASIBLE* if some solutions have been found
+ * *INFEASIBLE* if the solver has proved there are no solution
+ * *OPTIMAL* if all solutions have been found
+ """
+ warnings.warn(
+ 'SearchForAllSolutions is deprecated; use Solve() with'+
+ 'enumerate_all_solutions = True.',DeprecationWarning)
+ ifmodel.HasObjective():
+ raiseTypeError('Search for all solutions is only defined on '
+ 'satisfiability problems')
+ # Store old parameter.
+ enumerate_all=self.parameters.enumerate_all_solutions
+ self.parameters.enumerate_all_solutions=True
+
+ self.Solve(model,callback)
+
+ # Restore parameter.
+ self.parameters.enumerate_all_solutions=enumerate_all
+ returnself.__solution.status
+
+ defStopSearch(self):
+ """Stops the current search asynchronously."""
+ withself.__lock:
+ ifself.__solve_wrapper:
+ self.__solve_wrapper.StopSearch()
+
+ defValue(self,expression):
+ """Returns the value of a linear expression after solve."""
+ ifnotself.__solution:
+ raiseRuntimeError('Solve() has not be called.')
+ returnEvaluateLinearExpr(expression,self.__solution)
+
+ defBooleanValue(self,literal):
+ """Returns the boolean value of a literal after solve."""
+ ifnotself.__solution:
+ raiseRuntimeError('Solve() has not be called.')
+ returnEvaluateBooleanExpression(literal,self.__solution)
+
+ defObjectiveValue(self):
+ """Returns the value of the objective after solve."""
+ returnself.__solution.objective_value
+
+ defBestObjectiveBound(self):
+ """Returns the best lower (upper) bound found when min(max)imizing."""
+ returnself.__solution.best_objective_bound
+
+ defStatusName(self,status=None):
+ """Returns the name of the status returned by Solve()."""
+ ifstatusisNone:
+ status=self.__solution.status
+ returncp_model_pb2.CpSolverStatus.Name(status)
+
+ defNumBooleans(self):
+ """Returns the number of boolean variables managed by the SAT solver."""
+ returnself.__solution.num_booleans
+
+ defNumConflicts(self):
+ """Returns the number of conflicts since the creation of the solver."""
+ returnself.__solution.num_conflicts
+
+ defNumBranches(self):
+ """Returns the number of search branches explored by the solver."""
+ returnself.__solution.num_branches
+
+ defWallTime(self):
+ """Returns the wall time in seconds since the creation of the solver."""
+ returnself.__solution.wall_time
+
+ defUserTime(self):
+ """Returns the user time in seconds since the creation of the solver."""
+ returnself.__solution.user_time
+
+ defResponseStats(self):
+ """Returns some statistics on the solution found as a string."""
+ returnswig_helper.CpSatHelper.SerializedSolverResponseStats(
+ self.__solution.SerializeToString())
+
+ defResponseProto(self):
+ """Returns the response object."""
+ returnself.__solution
+
+ defSufficientAssumptionsForInfeasibility(self):
+ """Returns the indices of the infeasible assumptions."""
+ returnself.__solution.sufficient_assumptions_for_infeasibility
+
+ defSolutionInfo(self):
+ """Returns some information on the solve process.
+
+ Returns some information on how the solution was found, or the reason
+ why the model or the parameters are invalid.
+ """
+ returnself.__solution.solution_info
+
+
+
+
+
Main solver class.
+
+
The purpose of this class is to search for a solution to the model provided
+to the Solve() method.
+
+
Once Solve() is called, this class allows inspecting the solution found
+with the Value() and BooleanValue() methods, as well as general statistics
+about the solve procedure.
defSolveWithSolutionCallback(self,model,callback):
+ """DEPRECATED Use Solve() with the callback argument."""
+ warnings.warn(
+ 'SolveWithSolutionCallback is deprecated; use Solve() with'+
+ 'the callback argument.',DeprecationWarning)
+ returnself.Solve(model,callback)
+
+
+
+
+
DEPRECATED Use Solve() with the callback argument.
defSearchForAllSolutions(self,model,callback):
+ """DEPRECATED Use Solve() with the right parameter.
+
+ Search for all solutions of a satisfiability problem.
+
+ This method searches for all feasible solutions of a given model.
+ Then it feeds the solution to the callback.
+
+ Note that the model cannot contain an objective.
+
+ Args:
+ model: The model to solve.
+ callback: The callback that will be called at each solution.
+
+ Returns:
+ The status of the solve:
+
+ * *FEASIBLE* if some solutions have been found
+ * *INFEASIBLE* if the solver has proved there are no solution
+ * *OPTIMAL* if all solutions have been found
+ """
+ warnings.warn(
+ 'SearchForAllSolutions is deprecated; use Solve() with'+
+ 'enumerate_all_solutions = True.',DeprecationWarning)
+ ifmodel.HasObjective():
+ raiseTypeError('Search for all solutions is only defined on '
+ 'satisfiability problems')
+ # Store old parameter.
+ enumerate_all=self.parameters.enumerate_all_solutions
+ self.parameters.enumerate_all_solutions=True
+
+ self.Solve(model,callback)
+
+ # Restore parameter.
+ self.parameters.enumerate_all_solutions=enumerate_all
+ returnself.__solution.status
+
+
+
+
+
DEPRECATED Use Solve() with the right parameter.
+
+
Search for all solutions of a satisfiability problem.
+
+
This method searches for all feasible solutions of a given model.
+Then it feeds the solution to the callback.
+
+
Note that the model cannot contain an objective.
+
+
Args
+
+
+
model: The model to solve.
+
callback: The callback that will be called at each solution.
+
+
+
Returns
+
+
+
The status of the solve:
+
+
+
FEASIBLE if some solutions have been found
+
INFEASIBLE if the solver has proved there are no solution
defValue(self,expression):
+ """Returns the value of a linear expression after solve."""
+ ifnotself.__solution:
+ raiseRuntimeError('Solve() has not be called.')
+ returnEvaluateLinearExpr(expression,self.__solution)
+
+
+
+
+
Returns the value of a linear expression after solve.
defBooleanValue(self,literal):
+ """Returns the boolean value of a literal after solve."""
+ ifnotself.__solution:
+ raiseRuntimeError('Solve() has not be called.')
+ returnEvaluateBooleanExpression(literal,self.__solution)
+
+
+
+
+
Returns the boolean value of a literal after solve.
defStatusName(self,status=None):
+ """Returns the name of the status returned by Solve()."""
+ ifstatusisNone:
+ status=self.__solution.status
+ returncp_model_pb2.CpSolverStatus.Name(status)
+
+
+
+
+
Returns the name of the status returned by Solve().
defResponseStats(self):
+ """Returns some statistics on the solution found as a string."""
+ returnswig_helper.CpSatHelper.SerializedSolverResponseStats(
+ self.__solution.SerializeToString())
+
+
+
+
+
Returns some statistics on the solution found as a string.
defSufficientAssumptionsForInfeasibility(self):
+ """Returns the indices of the infeasible assumptions."""
+ returnself.__solution.sufficient_assumptions_for_infeasibility
+
+
+
+
+
Returns the indices of the infeasible assumptions.
defSolutionInfo(self):
+ """Returns some information on the solve process.
+
+ Returns some information on how the solution was found, or the reason
+ why the model or the parameters are invalid.
+ """
+ returnself.__solution.solution_info
+
+
+
+
+
Returns some information on the solve process.
+
+
Returns some information on how the solution was found, or the reason
+why the model or the parameters are invalid.
+
+
+
+
+
+
+
+ #  
+
+
+ class
+ CpSolverSolutionCallback(ortools.sat.python.swig_helper.SolutionCallback):
+
+
+
+ View Source
+
classCpSolverSolutionCallback(swig_helper.SolutionCallback):
+ """Solution callback.
+
+ This class implements a callback that will be called at each new solution
+ found during search.
+
+ The method OnSolutionCallback() will be called by the solver, and must be
+ implemented. The current solution can be queried using the BooleanValue()
+ and Value() methods.
+
+ It inherits the following methods from its base class:
+
+ * `ObjectiveValue(self)`
+ * `BestObjectiveBound(self)`
+ * `NumBooleans(self)`
+ * `NumConflicts(self)`
+ * `NumBranches(self)`
+ * `WallTime(self)`
+ * `UserTime(self)`
+
+ These methods returns the same information as their counterpart in the
+ `CpSolver` class.
+ """
+
+ def__init__(self):
+ swig_helper.SolutionCallback.__init__(self)
+
+ defOnSolutionCallback(self):
+ """Proxy for the same method in snake case."""
+ self.on_solution_callback()
+
+ defBooleanValue(self,lit):
+ """Returns the boolean value of a boolean literal.
+
+ Args:
+ lit: A boolean variable or its negation.
+
+ Returns:
+ The Boolean value of the literal in the solution.
+
+ Raises:
+ RuntimeError: if `lit` is not a boolean variable or its negation.
+ """
+ ifnotself.HasResponse():
+ raiseRuntimeError('Solve() has not be called.')
+ ifcmh.is_integral(lit):
+ returnbool(lit)
+ elifisinstance(lit,IntVar)orisinstance(lit,_NotBooleanVariable):
+ index=lit.Index()
+ returnself.SolutionBooleanValue(index)
+ else:
+ raiseTypeError(f'Cannot interpret {lit} as a boolean expression.')
+
+ defValue(self,expression):
+ """Evaluates an linear expression in the current solution.
+
+ Args:
+ expression: a linear expression of the model.
+
+ Returns:
+ An integer value equal to the evaluation of the linear expression
+ against the current solution.
+
+ Raises:
+ RuntimeError: if 'expression' is not a LinearExpr.
+ """
+ ifnotself.HasResponse():
+ raiseRuntimeError('Solve() has not be called.')
+
+ value=0
+ to_process=[(expression,1)]
+ whileto_process:
+ expr,coeff=to_process.pop()
+ ifcmh.is_integral(expr):
+ value+=int(expr)*coeff
+ elifisinstance(expr,_ProductCst):
+ to_process.append(
+ (expr.Expression(),coeff*expr.Coefficient()))
+ elifisinstance(expr,_Sum):
+ to_process.append((expr.Left(),coeff))
+ to_process.append((expr.Right(),coeff))
+ elifisinstance(expr,_SumArray):
+ foreinexpr.Expressions():
+ to_process.append((e,coeff))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,_WeightedSum):
+ fore,cinzip(expr.Expressions(),expr.Coefficients()):
+ to_process.append((e,coeff*c))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,IntVar):
+ value+=coeff*self.SolutionIntegerValue(expr.Index())
+ elifisinstance(expr,_NotBooleanVariable):
+ value+=coeff*(1-
+ self.SolutionIntegerValue(expr.Not().Index()))
+ else:
+ raiseTypeError(
+ f'Cannot interpret {expression} as a linear expression.')
+
+ returnvalue
+
+ defResponse(self):
+ """Returns the current solution response."""
+ returncp_model_pb2.CpSolverResponse.FromString(
+ swig_helper.SolutionCallback.SerializedResponse(self))
+
+
+
+
+
Solution callback.
+
+
This class implements a callback that will be called at each new solution
+found during search.
+
+
The method OnSolutionCallback() will be called by the solver, and must be
+implemented. The current solution can be queried using the BooleanValue()
+and Value() methods.
+
+
It inherits the following methods from its base class:
+
+
+
ObjectiveValue(self)
+
BestObjectiveBound(self)
+
NumBooleans(self)
+
NumConflicts(self)
+
NumBranches(self)
+
WallTime(self)
+
UserTime(self)
+
+
+
These methods returns the same information as their counterpart in the
+CpSolver class.
defBooleanValue(self,lit):
+ """Returns the boolean value of a boolean literal.
+
+ Args:
+ lit: A boolean variable or its negation.
+
+ Returns:
+ The Boolean value of the literal in the solution.
+
+ Raises:
+ RuntimeError: if `lit` is not a boolean variable or its negation.
+ """
+ ifnotself.HasResponse():
+ raiseRuntimeError('Solve() has not be called.')
+ ifcmh.is_integral(lit):
+ returnbool(lit)
+ elifisinstance(lit,IntVar)orisinstance(lit,_NotBooleanVariable):
+ index=lit.Index()
+ returnself.SolutionBooleanValue(index)
+ else:
+ raiseTypeError(f'Cannot interpret {lit} as a boolean expression.')
+
+
+
+
+
Returns the boolean value of a boolean literal.
+
+
Args
+
+
+
lit: A boolean variable or its negation.
+
+
+
Returns
+
+
+
The Boolean value of the literal in the solution.
+
+
+
Raises
+
+
+
RuntimeError: if lit is not a boolean variable or its negation.
defValue(self,expression):
+ """Evaluates an linear expression in the current solution.
+
+ Args:
+ expression: a linear expression of the model.
+
+ Returns:
+ An integer value equal to the evaluation of the linear expression
+ against the current solution.
+
+ Raises:
+ RuntimeError: if 'expression' is not a LinearExpr.
+ """
+ ifnotself.HasResponse():
+ raiseRuntimeError('Solve() has not be called.')
+
+ value=0
+ to_process=[(expression,1)]
+ whileto_process:
+ expr,coeff=to_process.pop()
+ ifcmh.is_integral(expr):
+ value+=int(expr)*coeff
+ elifisinstance(expr,_ProductCst):
+ to_process.append(
+ (expr.Expression(),coeff*expr.Coefficient()))
+ elifisinstance(expr,_Sum):
+ to_process.append((expr.Left(),coeff))
+ to_process.append((expr.Right(),coeff))
+ elifisinstance(expr,_SumArray):
+ foreinexpr.Expressions():
+ to_process.append((e,coeff))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,_WeightedSum):
+ fore,cinzip(expr.Expressions(),expr.Coefficients()):
+ to_process.append((e,coeff*c))
+ value+=expr.Constant()*coeff
+ elifisinstance(expr,IntVar):
+ value+=coeff*self.SolutionIntegerValue(expr.Index())
+ elifisinstance(expr,_NotBooleanVariable):
+ value+=coeff*(1-
+ self.SolutionIntegerValue(expr.Not().Index()))
+ else:
+ raiseTypeError(
+ f'Cannot interpret {expression} as a linear expression.')
+
+ returnvalue
+
+
+
+
+
Evaluates an linear expression in the current solution.
+
+
Args
+
+
+
expression: a linear expression of the model.
+
+
+
Returns
+
+
+
An integer value equal to the evaluation of the linear expression
+ against the current solution.
+
+
+
Raises
+
+
+
RuntimeError: if 'expression' is not a LinearExpr.
classObjectiveSolutionPrinter(CpSolverSolutionCallback):
+ """Display the objective value and time of intermediate solutions."""
+
+ def__init__(self):
+ CpSolverSolutionCallback.__init__(self)
+ self.__solution_count=0
+ self.__start_time=time.time()
+
+ defon_solution_callback(self):
+ """Called on each new solution."""
+ current_time=time.time()
+ obj=self.ObjectiveValue()
+ print('Solution %i, time = %0.2f s, objective = %i'%
+ (self.__solution_count,current_time-self.__start_time,obj))
+ self.__solution_count+=1
+
+ defsolution_count(self):
+ """Returns the number of solutions found."""
+ returnself.__solution_count
+
+
+
+
+
Display the objective value and time of intermediate solutions.
+
+
+
+
\ No newline at end of file
diff --git a/docs/python/index.html b/docs/python/index.html
index 3350c4095c..8ac15aaa3b 100644
--- a/docs/python/index.html
+++ b/docs/python/index.html
@@ -1,58 +1,7 @@
-
+
-
-
- Module List – pdoc 8.0.0
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/docs/python/ortools/algorithms/index.html b/docs/python/ortools/algorithms/index.html
index 21859caaca..05bc993401 100644
--- a/docs/python/ortools/algorithms/index.html
+++ b/docs/python/ortools/algorithms/index.html
@@ -1,58 +1,7 @@
-
+
-
-
- Module List – pdoc 8.0.0
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/docs/python/ortools/algorithms/ortools/algorithms/pywrapknapsack_solver.html b/docs/python/ortools/algorithms/ortools/algorithms/pywrapknapsack_solver.html
new file mode 100644
index 0000000000..dcf8e1cef7
--- /dev/null
+++ b/docs/python/ortools/algorithms/ortools/algorithms/pywrapknapsack_solver.html
@@ -0,0 +1,849 @@
+
+
+
+
+
+
+ ortools.algorithms.pywrapknapsack_solver API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+ortools.algorithms.pywrapknapsack_solver
+
+
+
+ View Source
+
# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 4.0.2
+#
+# Do not make changes to this file unless you know what you are doing--modify
+# the SWIG interface file instead.
+
+fromsysimportversion_infoas_swig_python_version_info
+if_swig_python_version_info<(2,7,0):
+ raiseRuntimeError("Python 2.7 or later required")
+
+# Import the low-level C/C++ module
+if__package__or"."in__name__:
+ from.import_pywrapknapsack_solver
+else:
+ import_pywrapknapsack_solver
+
+try:
+ importbuiltinsas__builtin__
+exceptImportError:
+ import__builtin__
+
+def_swig_repr(self):
+ try:
+ strthis="proxy of "+self.this.__repr__()
+ except__builtin__.Exception:
+ strthis=""
+ return"<%s.%s; %s >"%(self.__class__.__module__,self.__class__.__name__,strthis,)
+
+
+def_swig_setattr_nondynamic_instance_variable(set):
+ defset_instance_attr(self,name,value):
+ ifname=="thisown":
+ self.this.own(value)
+ elifname=="this":
+ set(self,name,value)
+ elifhasattr(self,name)andisinstance(getattr(type(self),name),property):
+ set(self,name,value)
+ else:
+ raiseAttributeError("You cannot add instance attributes to %s"%self)
+ returnset_instance_attr
+
+
+def_swig_setattr_nondynamic_class_variable(set):
+ defset_class_attr(cls,name,value):
+ ifhasattr(cls,name)andnotisinstance(getattr(cls,name),property):
+ set(cls,name,value)
+ else:
+ raiseAttributeError("You cannot add class attributes to %s"%cls)
+ returnset_class_attr
+
+
+def_swig_add_metaclass(metaclass):
+ """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
+ defwrapper(cls):
+ returnmetaclass(cls.__name__,cls.__bases__,cls.__dict__.copy())
+ returnwrapper
+
+
+class_SwigNonDynamicMeta(type):
+ """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
+ __setattr__=_swig_setattr_nondynamic_class_variable(type.__setattr__)
+
+
+classKnapsackSolver(object):
+ r"""
+ This library solves knapsack problems.
+
+ Problems the library solves include:
+ - 0-1 knapsack problems,
+ - Multi-dimensional knapsack problems,
+
+ Given n items, each with a profit and a weight, given a knapsack of
+ capacity c, the goal is to find a subset of items which fits inside c
+ and maximizes the total profit.
+ The knapsack problem can easily be extended from 1 to d dimensions.
+ As an example, this can be useful to constrain the maximum number of
+ items inside the knapsack.
+ Without loss of generality, profits and weights are assumed to be positive.
+
+ From a mathematical point of view, the multi-dimensional knapsack problem
+ can be modeled by d linear constraints:
+
+ ForEach(j:1..d)(Sum(i:1..n)(weight_ij * item_i) <= c_j
+ where item_i is a 0-1 integer variable.
+
+ Then the goal is to maximize:
+
+ Sum(i:1..n)(profit_i * item_i).
+
+ There are several ways to solve knapsack problems. One of the most
+ efficient is based on dynamic programming (mainly when weights, profits
+ and dimensions are small, and the algorithm runs in pseudo polynomial time).
+ Unfortunately, when adding conflict constraints the problem becomes strongly
+ NP-hard, i.e. there is no pseudo-polynomial algorithm to solve it.
+ That's the reason why the most of the following code is based on branch and
+ bound search.
+
+ For instance to solve a 2-dimensional knapsack problem with 9 items,
+ one just has to feed a profit vector with the 9 profits, a vector of 2
+ vectors for weights, and a vector of capacities.
+ E.g.:
+
+ **Python**:
+
+ .. code-block:: python
+
+ profits = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
+ weights = [ [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
+ [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
+ ]
+ capacities = [ 34, 4 ]
+
+ solver = pywrapknapsack_solver.KnapsackSolver(
+ pywrapknapsack_solver.KnapsackSolver
+ .KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
+ 'Multi-dimensional solver')
+ solver.Init(profits, weights, capacities)
+ profit = solver.Solve()
+
+ **C++**:
+
+ .. code-block:: c++
+
+ const std::vector<int64_t> profits = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ const std::vector<std::vector<int64_t>> weights =
+ { { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
+ const std::vector<int64_t> capacities = { 34, 4 };
+
+ KnapsackSolver solver(
+ KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
+ "Multi-dimensional solver");
+ solver.Init(profits, weights, capacities);
+ const int64_t profit = solver.Solve();
+
+ **Java**:
+
+ .. code-block:: java
+
+ final long[] profits = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ final long[][] weights = { { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
+ final long[] capacities = { 34, 4 };
+
+ KnapsackSolver solver = new KnapsackSolver(
+ KnapsackSolver.SolverType.KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
+ "Multi-dimensional solver");
+ solver.init(profits, weights, capacities);
+ final long profit = solver.solve();
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ KNAPSACK_BRUTE_FORCE_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_BRUTE_FORCE_SOLVER
+ r"""
+ Brute force method.
+
+ Limited to 30 items and one dimension, this
+ solver uses a brute force algorithm, ie. explores all possible states.
+ Experiments show competitive performance for instances with less than
+ 15 items.
+ """
+ KNAPSACK_64ITEMS_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_64ITEMS_SOLVER
+ r"""
+ Optimized method for single dimension small problems
+
+ Limited to 64 items and one dimension, this
+ solver uses a branch & bound algorithm. This solver is about 4 times
+ faster than KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER.
+ """
+ KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER
+ r"""
+ Dynamic Programming approach for single dimension problems
+
+ Limited to one dimension, this solver is based on a dynamic programming
+ algorithm. The time and space complexity is O(capacity *
+ number_of_items).
+ """
+ KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER
+ r"""
+ CBC Based Solver
+
+ This solver can deal with both large number of items and several
+ dimensions. This solver is based on Integer Programming solver CBC.
+ """
+ KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER
+ r"""
+ Generic Solver.
+
+ This solver can deal with both large number of items and several
+ dimensions. This solver is based on branch and bound.
+ """
+ KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER
+ r"""
+ SCIP based solver
+
+ This solver can deal with both large number of items and several
+ dimensions. This solver is based on Integer Programming solver SCIP.
+ """
+
+ def__init__(self,*args):
+ _pywrapknapsack_solver.KnapsackSolver_swiginit(self,_pywrapknapsack_solver.new_KnapsackSolver(*args))
+ __swig_destroy__=_pywrapknapsack_solver.delete_KnapsackSolver
+
+ defInit(self,profits:"std::vector< int64_t > const &",weights:"std::vector< std::vector< int64_t > > const &",capacities:"std::vector< int64_t > const &")->"void":
+ r"""Initializes the solver and enters the problem to be solved."""
+ return_pywrapknapsack_solver.KnapsackSolver_Init(self,profits,weights,capacities)
+
+ defSolve(self)->"int64_t":
+ r"""Solves the problem and returns the profit of the optimal solution."""
+ return_pywrapknapsack_solver.KnapsackSolver_Solve(self)
+
+ defBestSolutionContains(self,item_id:"int")->"bool":
+ r"""Returns true if the item 'item_id' is packed in the optimal knapsack."""
+ return_pywrapknapsack_solver.KnapsackSolver_BestSolutionContains(self,item_id)
+
+ defset_use_reduction(self,use_reduction:"bool")->"void":
+ return_pywrapknapsack_solver.KnapsackSolver_set_use_reduction(self,use_reduction)
+
+ defset_time_limit(self,time_limit_seconds:"double")->"void":
+ r"""
+ Time limit in seconds.
+
+ When a finite time limit is set the solution obtained might not be optimal
+ if the limit is reached.
+ """
+ return_pywrapknapsack_solver.KnapsackSolver_set_time_limit(self,time_limit_seconds)
+
+# Register KnapsackSolver in _pywrapknapsack_solver:
+_pywrapknapsack_solver.KnapsackSolver_swigregister(KnapsackSolver)
+
classKnapsackSolver(object):
+ r"""
+ This library solves knapsack problems.
+
+ Problems the library solves include:
+ - 0-1 knapsack problems,
+ - Multi-dimensional knapsack problems,
+
+ Given n items, each with a profit and a weight, given a knapsack of
+ capacity c, the goal is to find a subset of items which fits inside c
+ and maximizes the total profit.
+ The knapsack problem can easily be extended from 1 to d dimensions.
+ As an example, this can be useful to constrain the maximum number of
+ items inside the knapsack.
+ Without loss of generality, profits and weights are assumed to be positive.
+
+ From a mathematical point of view, the multi-dimensional knapsack problem
+ can be modeled by d linear constraints:
+
+ ForEach(j:1..d)(Sum(i:1..n)(weight_ij * item_i) <= c_j
+ where item_i is a 0-1 integer variable.
+
+ Then the goal is to maximize:
+
+ Sum(i:1..n)(profit_i * item_i).
+
+ There are several ways to solve knapsack problems. One of the most
+ efficient is based on dynamic programming (mainly when weights, profits
+ and dimensions are small, and the algorithm runs in pseudo polynomial time).
+ Unfortunately, when adding conflict constraints the problem becomes strongly
+ NP-hard, i.e. there is no pseudo-polynomial algorithm to solve it.
+ That's the reason why the most of the following code is based on branch and
+ bound search.
+
+ For instance to solve a 2-dimensional knapsack problem with 9 items,
+ one just has to feed a profit vector with the 9 profits, a vector of 2
+ vectors for weights, and a vector of capacities.
+ E.g.:
+
+ **Python**:
+
+ .. code-block:: python
+
+ profits = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
+ weights = [ [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
+ [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
+ ]
+ capacities = [ 34, 4 ]
+
+ solver = pywrapknapsack_solver.KnapsackSolver(
+ pywrapknapsack_solver.KnapsackSolver
+ .KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
+ 'Multi-dimensional solver')
+ solver.Init(profits, weights, capacities)
+ profit = solver.Solve()
+
+ **C++**:
+
+ .. code-block:: c++
+
+ const std::vector<int64_t> profits = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ const std::vector<std::vector<int64_t>> weights =
+ { { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
+ const std::vector<int64_t> capacities = { 34, 4 };
+
+ KnapsackSolver solver(
+ KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
+ "Multi-dimensional solver");
+ solver.Init(profits, weights, capacities);
+ const int64_t profit = solver.Solve();
+
+ **Java**:
+
+ .. code-block:: java
+
+ final long[] profits = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ final long[][] weights = { { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
+ final long[] capacities = { 34, 4 };
+
+ KnapsackSolver solver = new KnapsackSolver(
+ KnapsackSolver.SolverType.KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER,
+ "Multi-dimensional solver");
+ solver.init(profits, weights, capacities);
+ final long profit = solver.solve();
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ KNAPSACK_BRUTE_FORCE_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_BRUTE_FORCE_SOLVER
+ r"""
+ Brute force method.
+
+ Limited to 30 items and one dimension, this
+ solver uses a brute force algorithm, ie. explores all possible states.
+ Experiments show competitive performance for instances with less than
+ 15 items.
+ """
+ KNAPSACK_64ITEMS_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_64ITEMS_SOLVER
+ r"""
+ Optimized method for single dimension small problems
+
+ Limited to 64 items and one dimension, this
+ solver uses a branch & bound algorithm. This solver is about 4 times
+ faster than KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER.
+ """
+ KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER
+ r"""
+ Dynamic Programming approach for single dimension problems
+
+ Limited to one dimension, this solver is based on a dynamic programming
+ algorithm. The time and space complexity is O(capacity *
+ number_of_items).
+ """
+ KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER
+ r"""
+ CBC Based Solver
+
+ This solver can deal with both large number of items and several
+ dimensions. This solver is based on Integer Programming solver CBC.
+ """
+ KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER
+ r"""
+ Generic Solver.
+
+ This solver can deal with both large number of items and several
+ dimensions. This solver is based on branch and bound.
+ """
+ KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER=_pywrapknapsack_solver.KnapsackSolver_KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER
+ r"""
+ SCIP based solver
+
+ This solver can deal with both large number of items and several
+ dimensions. This solver is based on Integer Programming solver SCIP.
+ """
+
+ def__init__(self,*args):
+ _pywrapknapsack_solver.KnapsackSolver_swiginit(self,_pywrapknapsack_solver.new_KnapsackSolver(*args))
+ __swig_destroy__=_pywrapknapsack_solver.delete_KnapsackSolver
+
+ defInit(self,profits:"std::vector< int64_t > const &",weights:"std::vector< std::vector< int64_t > > const &",capacities:"std::vector< int64_t > const &")->"void":
+ r"""Initializes the solver and enters the problem to be solved."""
+ return_pywrapknapsack_solver.KnapsackSolver_Init(self,profits,weights,capacities)
+
+ defSolve(self)->"int64_t":
+ r"""Solves the problem and returns the profit of the optimal solution."""
+ return_pywrapknapsack_solver.KnapsackSolver_Solve(self)
+
+ defBestSolutionContains(self,item_id:"int")->"bool":
+ r"""Returns true if the item 'item_id' is packed in the optimal knapsack."""
+ return_pywrapknapsack_solver.KnapsackSolver_BestSolutionContains(self,item_id)
+
+ defset_use_reduction(self,use_reduction:"bool")->"void":
+ return_pywrapknapsack_solver.KnapsackSolver_set_use_reduction(self,use_reduction)
+
+ defset_time_limit(self,time_limit_seconds:"double")->"void":
+ r"""
+ Time limit in seconds.
+
+ When a finite time limit is set the solution obtained might not be optimal
+ if the limit is reached.
+ """
+ return_pywrapknapsack_solver.KnapsackSolver_set_time_limit(self,time_limit_seconds)
+
+
+
+
+
This library solves knapsack problems.
+
+
Problems the library solves include:
+
+
+
0-1 knapsack problems,
+
Multi-dimensional knapsack problems,
+
+
+
Given n items, each with a profit and a weight, given a knapsack of
+capacity c, the goal is to find a subset of items which fits inside c
+and maximizes the total profit.
+The knapsack problem can easily be extended from 1 to d dimensions.
+As an example, this can be useful to constrain the maximum number of
+items inside the knapsack.
+Without loss of generality, profits and weights are assumed to be positive.
+
+
From a mathematical point of view, the multi-dimensional knapsack problem
+can be modeled by d linear constraints:
+
+
ForEach(j:1..d)(Sum(i:1..n)(weight_ij * item_i) <= c_j
+ where item_i is a 0-1 integer variable.
+
+
+
Then the goal is to maximize
+
+
+
Sum(i:1..n)(profit_i * item_i).
+
+
+
There are several ways to solve knapsack problems. One of the most
+efficient is based on dynamic programming (mainly when weights, profits
+and dimensions are small, and the algorithm runs in pseudo polynomial time).
+Unfortunately, when adding conflict constraints the problem becomes strongly
+NP-hard, i.e. there is no pseudo-polynomial algorithm to solve it.
+That's the reason why the most of the following code is based on branch and
+bound search.
+
+
For instance to solve a 2-dimensional knapsack problem with 9 items,
+one just has to feed a profit vector with the 9 profits, a vector of 2
+vectors for weights, and a vector of capacities.
+E.g.:
Limited to 30 items and one dimension, this
+solver uses a brute force algorithm, ie. explores all possible states.
+Experiments show competitive performance for instances with less than
+15 items.
Optimized method for single dimension small problems
+
+
Limited to 64 items and one dimension, this
+solver uses a branch & bound algorithm. This solver is about 4 times
+faster than KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER.
defInit(self,profits:"std::vector< int64_t > const &",weights:"std::vector< std::vector< int64_t > > const &",capacities:"std::vector< int64_t > const &")->"void":
+ r"""Initializes the solver and enters the problem to be solved."""
+ return_pywrapknapsack_solver.KnapsackSolver_Init(self,profits,weights,capacities)
+
+
+
+
+
Initializes the solver and enters the problem to be solved.
defSolve(self)->"int64_t":
+ r"""Solves the problem and returns the profit of the optimal solution."""
+ return_pywrapknapsack_solver.KnapsackSolver_Solve(self)
+
+
+
+
+
Solves the problem and returns the profit of the optimal solution.
defBestSolutionContains(self,item_id:"int")->"bool":
+ r"""Returns true if the item 'item_id' is packed in the optimal knapsack."""
+ return_pywrapknapsack_solver.KnapsackSolver_BestSolutionContains(self,item_id)
+
+
+
+
+
Returns true if the item 'item_id' is packed in the optimal knapsack.
defset_time_limit(self,time_limit_seconds:"double")->"void":
+ r"""
+ Time limit in seconds.
+
+ When a finite time limit is set the solution obtained might not be optimal
+ if the limit is reached.
+ """
+ return_pywrapknapsack_solver.KnapsackSolver_set_time_limit(self,time_limit_seconds)
+
+
+
+
+
Time limit in seconds.
+
+
When a finite time limit is set the solution obtained might not be optimal
+if the limit is reached.
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/python/ortools/constraint_solver/index.html b/docs/python/ortools/constraint_solver/index.html
index 3a1ceaa37a..9f85df8c61 100644
--- a/docs/python/ortools/constraint_solver/index.html
+++ b/docs/python/ortools/constraint_solver/index.html
@@ -1,58 +1,7 @@
-
+
-
-
- Module List – pdoc 8.0.0
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/docs/python/ortools/constraint_solver/ortools/constraint_solver/pywrapcp.html b/docs/python/ortools/constraint_solver/ortools/constraint_solver/pywrapcp.html
new file mode 100644
index 0000000000..6c8b7239ad
--- /dev/null
+++ b/docs/python/ortools/constraint_solver/ortools/constraint_solver/pywrapcp.html
@@ -0,0 +1,42106 @@
+
+
+
+
+
+
+ ortools.constraint_solver.pywrapcp API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+ortools.constraint_solver.pywrapcp
+
+
+
+ View Source
+
# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 4.0.2
+#
+# Do not make changes to this file unless you know what you are doing--modify
+# the SWIG interface file instead.
+
+fromsysimportversion_infoas_swig_python_version_info
+if_swig_python_version_info<(2,7,0):
+ raiseRuntimeError("Python 2.7 or later required")
+
+# Import the low-level C/C++ module
+if__package__or"."in__name__:
+ from.import_pywrapcp
+else:
+ import_pywrapcp
+
+try:
+ importbuiltinsas__builtin__
+exceptImportError:
+ import__builtin__
+
+def_swig_repr(self):
+ try:
+ strthis="proxy of "+self.this.__repr__()
+ except__builtin__.Exception:
+ strthis=""
+ return"<%s.%s; %s >"%(self.__class__.__module__,self.__class__.__name__,strthis,)
+
+
+def_swig_setattr_nondynamic_instance_variable(set):
+ defset_instance_attr(self,name,value):
+ ifname=="thisown":
+ self.this.own(value)
+ elifname=="this":
+ set(self,name,value)
+ elifhasattr(self,name)andisinstance(getattr(type(self),name),property):
+ set(self,name,value)
+ else:
+ raiseAttributeError("You cannot add instance attributes to %s"%self)
+ returnset_instance_attr
+
+
+def_swig_setattr_nondynamic_class_variable(set):
+ defset_class_attr(cls,name,value):
+ ifhasattr(cls,name)andnotisinstance(getattr(cls,name),property):
+ set(cls,name,value)
+ else:
+ raiseAttributeError("You cannot add class attributes to %s"%cls)
+ returnset_class_attr
+
+
+def_swig_add_metaclass(metaclass):
+ """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
+ defwrapper(cls):
+ returnmetaclass(cls.__name__,cls.__bases__,cls.__dict__.copy())
+ returnwrapper
+
+
+class_SwigNonDynamicMeta(type):
+ """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
+ __setattr__=_swig_setattr_nondynamic_class_variable(type.__setattr__)
+
+
+importweakref
+
+classDefaultPhaseParameters(object):
+ r"""
+ This struct holds all parameters for the default search.
+ DefaultPhaseParameters is only used by Solver::MakeDefaultPhase methods.
+ Note this is for advanced users only.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ CHOOSE_MAX_SUM_IMPACT=_pywrapcp.DefaultPhaseParameters_CHOOSE_MAX_SUM_IMPACT
+ CHOOSE_MAX_AVERAGE_IMPACT=_pywrapcp.DefaultPhaseParameters_CHOOSE_MAX_AVERAGE_IMPACT
+ CHOOSE_MAX_VALUE_IMPACT=_pywrapcp.DefaultPhaseParameters_CHOOSE_MAX_VALUE_IMPACT
+ SELECT_MIN_IMPACT=_pywrapcp.DefaultPhaseParameters_SELECT_MIN_IMPACT
+ SELECT_MAX_IMPACT=_pywrapcp.DefaultPhaseParameters_SELECT_MAX_IMPACT
+ NONE=_pywrapcp.DefaultPhaseParameters_NONE
+ NORMAL=_pywrapcp.DefaultPhaseParameters_NORMAL
+ VERBOSE=_pywrapcp.DefaultPhaseParameters_VERBOSE
+ var_selection_schema=property(_pywrapcp.DefaultPhaseParameters_var_selection_schema_get,_pywrapcp.DefaultPhaseParameters_var_selection_schema_set,doc=r"""
+ This parameter describes how the next variable to instantiate
+ will be chosen.
+ """)
+ value_selection_schema=property(_pywrapcp.DefaultPhaseParameters_value_selection_schema_get,_pywrapcp.DefaultPhaseParameters_value_selection_schema_set,doc=r""" This parameter describes which value to select for a given var.""")
+ initialization_splits=property(_pywrapcp.DefaultPhaseParameters_initialization_splits_get,_pywrapcp.DefaultPhaseParameters_initialization_splits_set,doc=r"""
+ Maximum number of intervals that the initialization of impacts will scan
+ per variable.
+ """)
+ run_all_heuristics=property(_pywrapcp.DefaultPhaseParameters_run_all_heuristics_get,_pywrapcp.DefaultPhaseParameters_run_all_heuristics_set,doc=r"""
+ The default phase will run heuristics periodically. This parameter
+ indicates if we should run all heuristics, or a randomly selected
+ one.
+ """)
+ heuristic_period=property(_pywrapcp.DefaultPhaseParameters_heuristic_period_get,_pywrapcp.DefaultPhaseParameters_heuristic_period_set,doc=r"""
+ The distance in nodes between each run of the heuristics. A
+ negative or null value will mean that we will not run heuristics
+ at all.
+ """)
+ heuristic_num_failures_limit=property(_pywrapcp.DefaultPhaseParameters_heuristic_num_failures_limit_get,_pywrapcp.DefaultPhaseParameters_heuristic_num_failures_limit_set,doc=r""" The failure limit for each heuristic that we run.""")
+ persistent_impact=property(_pywrapcp.DefaultPhaseParameters_persistent_impact_get,_pywrapcp.DefaultPhaseParameters_persistent_impact_set,doc=r"""
+ Whether to keep the impact from the first search for other searches,
+ or to recompute the impact for each new search.
+ """)
+ random_seed=property(_pywrapcp.DefaultPhaseParameters_random_seed_get,_pywrapcp.DefaultPhaseParameters_random_seed_set,doc=r""" Seed used to initialize the random part in some heuristics.""")
+ display_level=property(_pywrapcp.DefaultPhaseParameters_display_level_get,_pywrapcp.DefaultPhaseParameters_display_level_set,doc=r"""
+ This represents the amount of information displayed by the default search.
+ NONE means no display, VERBOSE means extra information.
+ """)
+ decision_builder=property(_pywrapcp.DefaultPhaseParameters_decision_builder_get,_pywrapcp.DefaultPhaseParameters_decision_builder_set,doc=r""" When defined, this overrides the default impact based decision builder.""")
+
+ def__init__(self):
+ _pywrapcp.DefaultPhaseParameters_swiginit(self,_pywrapcp.new_DefaultPhaseParameters())
+ __swig_destroy__=_pywrapcp.delete_DefaultPhaseParameters
+
+# Register DefaultPhaseParameters in _pywrapcp:
+_pywrapcp.DefaultPhaseParameters_swigregister(DefaultPhaseParameters)
+
+classSolver(object):
+ r"""
+ Solver Class
+
+ A solver represents the main computation engine. It implements the entire
+ range of Constraint Programming protocols:
+ - Reversibility
+ - Propagation
+ - Search
+
+ Usually, Constraint Programming code consists of
+ - the creation of the Solver,
+ - the creation of the decision variables of the model,
+ - the creation of the constraints of the model and their addition to the
+ solver() through the AddConstraint() method,
+ - the creation of the main DecisionBuilder class,
+ - the launch of the solve() method with the decision builder.
+
+ For the time being, Solver is neither MT_SAFE nor MT_HOT.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ INT_VAR_DEFAULT=_pywrapcp.Solver_INT_VAR_DEFAULT
+ r""" The default behavior is CHOOSE_FIRST_UNBOUND."""
+ INT_VAR_SIMPLE=_pywrapcp.Solver_INT_VAR_SIMPLE
+ r""" The simple selection is CHOOSE_FIRST_UNBOUND."""
+ CHOOSE_FIRST_UNBOUND=_pywrapcp.Solver_CHOOSE_FIRST_UNBOUND
+ r"""
+ Select the first unbound variable.
+ Variables are considered in the order of the vector of IntVars used
+ to create the selector.
+ """
+ CHOOSE_RANDOM=_pywrapcp.Solver_CHOOSE_RANDOM
+ r""" Randomly select one of the remaining unbound variables."""
+ CHOOSE_MIN_SIZE_LOWEST_MIN=_pywrapcp.Solver_CHOOSE_MIN_SIZE_LOWEST_MIN
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variables is the one with the lowest min
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE_HIGHEST_MIN=_pywrapcp.Solver_CHOOSE_MIN_SIZE_HIGHEST_MIN
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variable is the one with the highest min
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE_LOWEST_MAX=_pywrapcp.Solver_CHOOSE_MIN_SIZE_LOWEST_MAX
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variables is the one with the lowest max
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE_HIGHEST_MAX=_pywrapcp.Solver_CHOOSE_MIN_SIZE_HIGHEST_MAX
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variable is the one with the highest max
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_LOWEST_MIN=_pywrapcp.Solver_CHOOSE_LOWEST_MIN
+ r"""
+ Among unbound variables, select the variable with the smallest minimal
+ value.
+ In case of a tie, the first one is selected, "first" defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_HIGHEST_MAX=_pywrapcp.Solver_CHOOSE_HIGHEST_MAX
+ r"""
+ Among unbound variables, select the variable with the highest maximal
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE=_pywrapcp.Solver_CHOOSE_MIN_SIZE
+ r"""
+ Among unbound variables, select the variable with the smallest size.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MAX_SIZE=_pywrapcp.Solver_CHOOSE_MAX_SIZE
+ r"""
+ Among unbound variables, select the variable with the highest size.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MAX_REGRET_ON_MIN=_pywrapcp.Solver_CHOOSE_MAX_REGRET_ON_MIN
+ r"""
+ Among unbound variables, select the variable with the largest
+ gap between the first and the second values of the domain.
+ """
+ CHOOSE_PATH=_pywrapcp.Solver_CHOOSE_PATH
+ r"""
+ Selects the next unbound variable on a path, the path being defined by
+ the variables: var[i] corresponds to the index of the next of i.
+ """
+ INT_VALUE_DEFAULT=_pywrapcp.Solver_INT_VALUE_DEFAULT
+ r""" The default behavior is ASSIGN_MIN_VALUE."""
+ INT_VALUE_SIMPLE=_pywrapcp.Solver_INT_VALUE_SIMPLE
+ r""" The simple selection is ASSIGN_MIN_VALUE."""
+ ASSIGN_MIN_VALUE=_pywrapcp.Solver_ASSIGN_MIN_VALUE
+ r""" Selects the min value of the selected variable."""
+ ASSIGN_MAX_VALUE=_pywrapcp.Solver_ASSIGN_MAX_VALUE
+ r""" Selects the max value of the selected variable."""
+ ASSIGN_RANDOM_VALUE=_pywrapcp.Solver_ASSIGN_RANDOM_VALUE
+ r""" Selects randomly one of the possible values of the selected variable."""
+ ASSIGN_CENTER_VALUE=_pywrapcp.Solver_ASSIGN_CENTER_VALUE
+ r"""
+ Selects the first possible value which is the closest to the center
+ of the domain of the selected variable.
+ The center is defined as (min + max) / 2.
+ """
+ SPLIT_LOWER_HALF=_pywrapcp.Solver_SPLIT_LOWER_HALF
+ r"""
+ Split the domain in two around the center, and choose the lower
+ part first.
+ """
+ SPLIT_UPPER_HALF=_pywrapcp.Solver_SPLIT_UPPER_HALF
+ r"""
+ Split the domain in two around the center, and choose the lower
+ part first.
+ """
+ SEQUENCE_DEFAULT=_pywrapcp.Solver_SEQUENCE_DEFAULT
+ SEQUENCE_SIMPLE=_pywrapcp.Solver_SEQUENCE_SIMPLE
+ CHOOSE_MIN_SLACK_RANK_FORWARD=_pywrapcp.Solver_CHOOSE_MIN_SLACK_RANK_FORWARD
+ CHOOSE_RANDOM_RANK_FORWARD=_pywrapcp.Solver_CHOOSE_RANDOM_RANK_FORWARD
+ INTERVAL_DEFAULT=_pywrapcp.Solver_INTERVAL_DEFAULT
+ r""" The default is INTERVAL_SET_TIMES_FORWARD."""
+ INTERVAL_SIMPLE=_pywrapcp.Solver_INTERVAL_SIMPLE
+ r""" The simple is INTERVAL_SET_TIMES_FORWARD."""
+ INTERVAL_SET_TIMES_FORWARD=_pywrapcp.Solver_INTERVAL_SET_TIMES_FORWARD
+ r"""
+ Selects the variable with the lowest starting time of all variables,
+ and fixes its starting time to this lowest value.
+ """
+ INTERVAL_SET_TIMES_BACKWARD=_pywrapcp.Solver_INTERVAL_SET_TIMES_BACKWARD
+ r"""
+ Selects the variable with the highest ending time of all variables,
+ and fixes the ending time to this highest values.
+ """
+ TWOOPT=_pywrapcp.Solver_TWOOPT
+ r"""
+ Operator which reverses a sub-chain of a path. It is called TwoOpt
+ because it breaks two arcs on the path; resulting paths are called
+ two-optimal.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5
+ (where (1, 5) are first and last nodes of the path and can therefore not
+ be moved):
+ 1 -> [3 -> 2] -> 4 -> 5
+ 1 -> [4 -> 3 -> 2] -> 5
+ 1 -> 2 -> [4 -> 3] -> 5
+ """
+ OROPT=_pywrapcp.Solver_OROPT
+ r"""
+ Relocate: OROPT and RELOCATE.
+ Operator which moves a sub-chain of a path to another position; the
+ specified chain length is the fixed length of the chains being moved.
+ When this length is 1, the operator simply moves a node to another
+ position.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5, for a chain
+ length of 2 (where (1, 5) are first and last nodes of the path and can
+ therefore not be moved):
+ 1 -> 4 -> [2 -> 3] -> 5
+ 1 -> [3 -> 4] -> 2 -> 5
+
+ Using Relocate with chain lengths of 1, 2 and 3 together is equivalent
+ to the OrOpt operator on a path. The OrOpt operator is a limited
+ version of 3Opt (breaks 3 arcs on a path).
+ """
+ RELOCATE=_pywrapcp.Solver_RELOCATE
+ r""" Relocate neighborhood with length of 1 (see OROPT comment)."""
+ EXCHANGE=_pywrapcp.Solver_EXCHANGE
+ r"""
+ Operator which exchanges the positions of two nodes.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5
+ (where (1, 5) are first and last nodes of the path and can therefore not
+ be moved):
+ 1 -> [3] -> [2] -> 4 -> 5
+ 1 -> [4] -> 3 -> [2] -> 5
+ 1 -> 2 -> [4] -> [3] -> 5
+ """
+ CROSS=_pywrapcp.Solver_CROSS
+ r"""
+ Operator which cross exchanges the starting chains of 2 paths, including
+ exchanging the whole paths.
+ First and last nodes are not moved.
+ Possible neighbors for the paths 1 -> 2 -> 3 -> 4 -> 5 and 6 -> 7 -> 8
+ (where (1, 5) and (6, 8) are first and last nodes of the paths and can
+ therefore not be moved):
+ 1 -> [7] -> 3 -> 4 -> 5 6 -> [2] -> 8
+ 1 -> [7] -> 4 -> 5 6 -> [2 -> 3] -> 8
+ 1 -> [7] -> 5 6 -> [2 -> 3 -> 4] -> 8
+ """
+ MAKEACTIVE=_pywrapcp.Solver_MAKEACTIVE
+ r"""
+ Operator which inserts an inactive node into a path.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+ (where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 2 -> 3 -> 4
+ 1 -> 2 -> [5] -> 3 -> 4
+ 1 -> 2 -> 3 -> [5] -> 4
+ """
+ MAKEINACTIVE=_pywrapcp.Solver_MAKEINACTIVE
+ r"""
+ Operator which makes path nodes inactive.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 (where 1 and 4 are
+ first and last nodes of the path) are:
+ 1 -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> 4 with 3 inactive
+ """
+ MAKECHAININACTIVE=_pywrapcp.Solver_MAKECHAININACTIVE
+ r"""
+ Operator which makes a "chain" of path nodes inactive.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 (where 1 and 4 are
+ first and last nodes of the path) are:
+ 1 -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> 4 with 3 inactive
+ 1 -> 4 with 2 and 3 inactive
+ """
+ SWAPACTIVE=_pywrapcp.Solver_SWAPACTIVE
+ r"""
+ Operator which replaces an active node by an inactive one.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+ (where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> [5] -> 4 with 3 inactive
+ """
+ EXTENDEDSWAPACTIVE=_pywrapcp.Solver_EXTENDEDSWAPACTIVE
+ r"""
+ Operator which makes an inactive node active and an active one inactive.
+ It is similar to SwapActiveOperator except that it tries to insert the
+ inactive node in all possible positions instead of just the position of
+ the node made inactive.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+ (where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 3 -> 4 with 2 inactive
+ 1 -> 3 -> [5] -> 4 with 2 inactive
+ 1 -> [5] -> 2 -> 4 with 3 inactive
+ 1 -> 2 -> [5] -> 4 with 3 inactive
+ """
+ PATHLNS=_pywrapcp.Solver_PATHLNS
+ r"""
+ Operator which relaxes two sub-chains of three consecutive arcs each.
+ Each sub-chain is defined by a start node and the next three arcs. Those
+ six arcs are relaxed to build a new neighbor.
+ PATHLNS explores all possible pairs of starting nodes and so defines
+ n^2 neighbors, n being the number of nodes.
+ Note that the two sub-chains can be part of the same path; they even may
+ overlap.
+ """
+ FULLPATHLNS=_pywrapcp.Solver_FULLPATHLNS
+ r"""
+ Operator which relaxes one entire path and all inactive nodes, thus
+ defining num_paths neighbors.
+ """
+ UNACTIVELNS=_pywrapcp.Solver_UNACTIVELNS
+ r"""
+ Operator which relaxes all inactive nodes and one sub-chain of six
+ consecutive arcs. That way the path can be improved by inserting
+ inactive nodes or swapping arcs.
+ """
+ INCREMENT=_pywrapcp.Solver_INCREMENT
+ r"""
+ Operator which defines one neighbor per variable. Each neighbor tries to
+ increment by one the value of the corresponding variable. When a new
+ solution is found the neighborhood is rebuilt from scratch, i.e., tries
+ to increment values in the variable order.
+ Consider for instance variables x and y. x is incremented one by one to
+ its max, and when it is not possible to increment x anymore, y is
+ incremented once. If this is a solution, then next neighbor tries to
+ increment x.
+ """
+ DECREMENT=_pywrapcp.Solver_DECREMENT
+ r"""
+ Operator which defines a neighborhood to decrement values.
+ The behavior is the same as INCREMENT, except values are decremented
+ instead of incremented.
+ """
+ SIMPLELNS=_pywrapcp.Solver_SIMPLELNS
+ r"""
+ Operator which defines one neighbor per variable. Each neighbor relaxes
+ one variable.
+ When a new solution is found the neighborhood is rebuilt from scratch.
+ Consider for instance variables x and y. First x is relaxed and the
+ solver is looking for the best possible solution (with only x relaxed).
+ Then y is relaxed, and the solver is looking for a new solution.
+ If a new solution is found, then the next variable to be relaxed is x.
+ """
+ GE=_pywrapcp.Solver_GE
+ r""" Move is accepted when the current objective value >= objective.Min."""
+ LE=_pywrapcp.Solver_LE
+ r""" Move is accepted when the current objective value <= objective.Max."""
+ EQ=_pywrapcp.Solver_EQ
+ r"""
+ Move is accepted when the current objective value is in the interval
+ objective.Min .. objective.Max.
+ """
+ DELAYED_PRIORITY=_pywrapcp.Solver_DELAYED_PRIORITY
+ r"""
+ DELAYED_PRIORITY is the lowest priority: Demons will be processed after
+ VAR_PRIORITY and NORMAL_PRIORITY demons.
+ """
+ VAR_PRIORITY=_pywrapcp.Solver_VAR_PRIORITY
+ r""" VAR_PRIORITY is between DELAYED_PRIORITY and NORMAL_PRIORITY."""
+ NORMAL_PRIORITY=_pywrapcp.Solver_NORMAL_PRIORITY
+ r""" NORMAL_PRIORITY is the highest priority: Demons will be processed first."""
+
+ def__init__(self,*args):
+ _pywrapcp.Solver_swiginit(self,_pywrapcp.new_Solver(*args))
+
+ self.__python_constraints=[]
+
+
+
+ __swig_destroy__=_pywrapcp.delete_Solver
+
+ defParameters(self)->"operations_research::ConstraintSolverParameters":
+ r""" Stored Parameters."""
+ return_pywrapcp.Solver_Parameters(self)
+
+ @staticmethod
+ defDefaultSolverParameters()->"operations_research::ConstraintSolverParameters":
+ r""" Create a ConstraintSolverParameters proto with all the default values."""
+ return_pywrapcp.Solver_DefaultSolverParameters()
+
+ defAddConstraint(self,c:"Constraint")->"void":
+ r"""
+ Adds the constraint 'c' to the model.
+
+ After calling this method, and until there is a backtrack that undoes the
+ addition, any assignment of variables to values must satisfy the given
+ constraint in order to be considered feasible. There are two fairly
+ different use cases:
+
+ - the most common use case is modeling: the given constraint is really
+ part of the problem that the user is trying to solve. In this use case,
+ AddConstraint is called outside of search (i.e., with state() ==
+ OUTSIDE_SEARCH). Most users should only use AddConstraint in this
+ way. In this case, the constraint will belong to the model forever: it
+ cannot not be removed by backtracking.
+
+ - a rarer use case is that 'c' is not a real constraint of the model. It
+ may be a constraint generated by a branching decision (a constraint whose
+ goal is to restrict the search space), a symmetry breaking constraint (a
+ constraint that does restrict the search space, but in a way that cannot
+ have an impact on the quality of the solutions in the subtree), or an
+ inferred constraint that, while having no semantic value to the model (it
+ does not restrict the set of solutions), is worth having because we
+ believe it may strengthen the propagation. In these cases, it happens
+ that the constraint is added during the search (i.e., with state() ==
+ IN_SEARCH or state() == IN_ROOT_NODE). When a constraint is
+ added during a search, it applies only to the subtree of the search tree
+ rooted at the current node, and will be automatically removed by
+ backtracking.
+
+ This method does not take ownership of the constraint. If the constraint
+ has been created by any factory method (Solver::MakeXXX), it will
+ automatically be deleted. However, power users who implement their own
+ constraints should do: solver.AddConstraint(solver.RevAlloc(new
+ MyConstraint(...));
+ """
+ return_pywrapcp.Solver_AddConstraint(self,c)
+
+ defSolve(self,*args)->"bool":
+ return_pywrapcp.Solver_Solve(self,*args)
+
+ defNewSearch(self,*args)->"void":
+ return_pywrapcp.Solver_NewSearch(self,*args)
+
+ defNextSolution(self)->"bool":
+ return_pywrapcp.Solver_NextSolution(self)
+
+ defRestartSearch(self)->"void":
+ return_pywrapcp.Solver_RestartSearch(self)
+
+ defEndSearch(self)->"void":
+ return_pywrapcp.Solver_EndSearch(self)
+
+ defSolveAndCommit(self,*args)->"bool":
+ return_pywrapcp.Solver_SolveAndCommit(self,*args)
+
+ defCheckAssignment(self,solution:"Assignment")->"bool":
+ r""" Checks whether the given assignment satisfies all relevant constraints."""
+ return_pywrapcp.Solver_CheckAssignment(self,solution)
+
+ defCheckConstraint(self,ct:"Constraint")->"bool":
+ r"""
+ Checks whether adding this constraint will lead to an immediate
+ failure. It will return false if the model is already inconsistent, or if
+ adding the constraint makes it inconsistent.
+ """
+ return_pywrapcp.Solver_CheckConstraint(self,ct)
+
+ defFail(self)->"void":
+ r""" Abandon the current branch in the search tree. A backtrack will follow."""
+ return_pywrapcp.Solver_Fail(self)
+
+ @staticmethod
+ defMemoryUsage()->"int64_t":
+ r""" Current memory usage in bytes"""
+ return_pywrapcp.Solver_MemoryUsage()
+
+ defWallTime(self)->"int64_t":
+ r"""
+ DEPRECATED: Use Now() instead.
+ Time elapsed, in ms since the creation of the solver.
+ """
+ return_pywrapcp.Solver_WallTime(self)
+
+ defBranches(self)->"int64_t":
+ r""" The number of branches explored since the creation of the solver."""
+ return_pywrapcp.Solver_Branches(self)
+
+ defSolutions(self)->"int64_t":
+ r""" The number of solutions found since the start of the search."""
+ return_pywrapcp.Solver_Solutions(self)
+
+ defFailures(self)->"int64_t":
+ r""" The number of failures encountered since the creation of the solver."""
+ return_pywrapcp.Solver_Failures(self)
+
+ defAcceptedNeighbors(self)->"int64_t":
+ r""" The number of accepted neighbors."""
+ return_pywrapcp.Solver_AcceptedNeighbors(self)
+
+ defStamp(self)->"uint64_t":
+ r"""
+ The stamp indicates how many moves in the search tree we have performed.
+ It is useful to detect if we need to update same lazy structures.
+ """
+ return_pywrapcp.Solver_Stamp(self)
+
+ defFailStamp(self)->"uint64_t":
+ r""" The fail_stamp() is incremented after each backtrack."""
+ return_pywrapcp.Solver_FailStamp(self)
+
+ defIntVar(self,*args)->"operations_research::IntVar *":
+ r"""
+ *Overload 1:*
+ MakeIntVar will create the best range based int var for the bounds given.
+
+ |
+
+ *Overload 2:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 3:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 4:*
+ MakeIntVar will create the best range based int var for the bounds given.
+
+ |
+
+ *Overload 5:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 6:*
+ MakeIntVar will create a variable with the given sparse domain.
+ """
+ return_pywrapcp.Solver_IntVar(self,*args)
+
+ defBoolVar(self,*args)->"operations_research::IntVar *":
+ r"""
+ *Overload 1:*
+ MakeBoolVar will create a variable with a {0, 1} domain.
+
+ |
+
+ *Overload 2:*
+ MakeBoolVar will create a variable with a {0, 1} domain.
+ """
+ return_pywrapcp.Solver_BoolVar(self,*args)
+
+ defIntConst(self,*args)->"operations_research::IntVar *":
+ r"""
+ *Overload 1:*
+ IntConst will create a constant expression.
+
+ |
+
+ *Overload 2:*
+ IntConst will create a constant expression.
+ """
+ return_pywrapcp.Solver_IntConst(self,*args)
+
+ defSum(self,vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::IntExpr *":
+ r""" sum of all vars."""
+ return_pywrapcp.Solver_Sum(self,vars)
+
+ defScalProd(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ scalar product
+
+ |
+
+ *Overload 2:*
+ scalar product
+ """
+ return_pywrapcp.Solver_ScalProd(self,*args)
+
+ defMonotonicElement(self,values:"operations_research::Solver::IndexEvaluator1",increasing:"bool",index:"IntVar")->"operations_research::IntExpr *":
+ r"""
+ Function based element. The constraint takes ownership of the
+ callback. The callback must be monotonic. It must be able to
+ cope with any possible value in the domain of 'index'
+ (potentially negative ones too). Furtermore, monotonicity is not
+ checked. Thus giving a non-monotonic function, or specifying an
+ incorrect increasing parameter will result in undefined behavior.
+ """
+ return_pywrapcp.Solver_MonotonicElement(self,values,increasing,index)
+
+ defElement(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ values[index]
+
+ |
+
+ *Overload 2:*
+ values[index]
+
+ |
+
+ *Overload 3:*
+ Function-based element. The constraint takes ownership of the
+ callback. The callback must be able to cope with any possible
+ value in the domain of 'index' (potentially negative ones too).
+
+ |
+
+ *Overload 4:*
+ 2D version of function-based element expression, values(expr1, expr2).
+
+ |
+
+ *Overload 5:*
+ vars[expr]
+ """
+ return_pywrapcp.Solver_Element(self,*args)
+
+ defIndexExpression(self,vars:"std::vector< operations_research::IntVar * > const &",value:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ Returns the expression expr such that vars[expr] == value.
+ It assumes that vars are all different.
+ """
+ return_pywrapcp.Solver_IndexExpression(self,vars,value)
+
+ defMin(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ std::min(vars)
+
+ |
+
+ *Overload 2:*
+ std::min (left, right)
+
+ |
+
+ *Overload 3:*
+ std::min(expr, value)
+
+ |
+
+ *Overload 4:*
+ std::min(expr, value)
+ """
+ return_pywrapcp.Solver_Min(self,*args)
+
+ defMax(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ std::max(vars)
+
+ |
+
+ *Overload 2:*
+ std::max(left, right)
+
+ |
+
+ *Overload 3:*
+ std::max(expr, value)
+
+ |
+
+ *Overload 4:*
+ std::max(expr, value)
+ """
+ return_pywrapcp.Solver_Max(self,*args)
+
+ defConvexPiecewiseExpr(self,expr:"IntExpr",early_cost:"int64_t",early_date:"int64_t",late_date:"int64_t",late_cost:"int64_t")->"operations_research::IntExpr *":
+ r""" Convex piecewise function."""
+ return_pywrapcp.Solver_ConvexPiecewiseExpr(self,expr,early_cost,early_date,late_date,late_cost)
+
+ defSemiContinuousExpr(self,expr:"IntExpr",fixed_charge:"int64_t",step:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ Semi continuous Expression (x <= 0 -> f(x) = 0; x > 0 -> f(x) = ax + b)
+ a >= 0 and b >= 0
+ """
+ return_pywrapcp.Solver_SemiContinuousExpr(self,expr,fixed_charge,step)
+
+ defConditionalExpression(self,condition:"IntVar",expr:"IntExpr",unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ r""" Conditional Expr condition ? expr : unperformed_value"""
+ return_pywrapcp.Solver_ConditionalExpression(self,condition,expr,unperformed_value)
+
+ defTrueConstraint(self)->"operations_research::Constraint *":
+ r""" This constraint always succeeds."""
+ return_pywrapcp.Solver_TrueConstraint(self)
+
+ defFalseConstraint(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_FalseConstraint(self,*args)
+
+ defIsEqualCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var == value)"""
+ return_pywrapcp.Solver_IsEqualCstCt(self,var,value,boolvar)
+
+ defIsEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var == value)"""
+ return_pywrapcp.Solver_IsEqualCstVar(self,var,value)
+
+ defIsEqualCt(self,v1:"IntExpr",v2:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v1 == v2)"""
+ return_pywrapcp.Solver_IsEqualCt(self,v1,v2,b)
+
+ defIsEqualVar(self,v1:"IntExpr",v2:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (v1 == v2)"""
+ return_pywrapcp.Solver_IsEqualVar(self,v1,v2)
+
+ defIsDifferentCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var != value)"""
+ return_pywrapcp.Solver_IsDifferentCstCt(self,var,value,boolvar)
+
+ defIsDifferentCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var != value)"""
+ return_pywrapcp.Solver_IsDifferentCstVar(self,var,value)
+
+ defIsDifferentVar(self,v1:"IntExpr",v2:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (v1 != v2)"""
+ return_pywrapcp.Solver_IsDifferentVar(self,v1,v2)
+
+ defIsDifferentCt(self,v1:"IntExpr",v2:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v1 != v2)"""
+ return_pywrapcp.Solver_IsDifferentCt(self,v1,v2,b)
+
+ defIsLessOrEqualCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var <= value)"""
+ return_pywrapcp.Solver_IsLessOrEqualCstCt(self,var,value,boolvar)
+
+ defIsLessOrEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var <= value)"""
+ return_pywrapcp.Solver_IsLessOrEqualCstVar(self,var,value)
+
+ defIsLessOrEqualVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left <= right)"""
+ return_pywrapcp.Solver_IsLessOrEqualVar(self,left,right)
+
+ defIsLessOrEqualCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left <= right)"""
+ return_pywrapcp.Solver_IsLessOrEqualCt(self,left,right,b)
+
+ defIsGreaterOrEqualCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var >= value)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualCstCt(self,var,value,boolvar)
+
+ defIsGreaterOrEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var >= value)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualCstVar(self,var,value)
+
+ defIsGreaterOrEqualVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left >= right)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualVar(self,left,right)
+
+ defIsGreaterOrEqualCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left >= right)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualCt(self,left,right,b)
+
+ defIsGreaterCstCt(self,v:"IntExpr",c:"int64_t",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v > c)"""
+ return_pywrapcp.Solver_IsGreaterCstCt(self,v,c,b)
+
+ defIsGreaterCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var > value)"""
+ return_pywrapcp.Solver_IsGreaterCstVar(self,var,value)
+
+ defIsGreaterVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left > right)"""
+ return_pywrapcp.Solver_IsGreaterVar(self,left,right)
+
+ defIsGreaterCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left > right)"""
+ return_pywrapcp.Solver_IsGreaterCt(self,left,right,b)
+
+ defIsLessCstCt(self,v:"IntExpr",c:"int64_t",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v < c)"""
+ return_pywrapcp.Solver_IsLessCstCt(self,v,c,b)
+
+ defIsLessCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var < value)"""
+ return_pywrapcp.Solver_IsLessCstVar(self,var,value)
+
+ defIsLessVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left < right)"""
+ return_pywrapcp.Solver_IsLessVar(self,left,right)
+
+ defIsLessCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left < right)"""
+ return_pywrapcp.Solver_IsLessCt(self,left,right,b)
+
+ defSumLessOrEqual(self,vars:"std::vector< operations_research::IntVar * > const &",cst:"int64_t")->"operations_research::Constraint *":
+ r""" Variation on arrays."""
+ return_pywrapcp.Solver_SumLessOrEqual(self,vars,cst)
+
+ defSumGreaterOrEqual(self,vars:"std::vector< operations_research::IntVar * > const &",cst:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.Solver_SumGreaterOrEqual(self,vars,cst)
+
+ defSumEquality(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_SumEquality(self,*args)
+
+ defScalProdEquality(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ScalProdEquality(self,*args)
+
+ defScalProdGreaterOrEqual(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ScalProdGreaterOrEqual(self,*args)
+
+ defScalProdLessOrEqual(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ScalProdLessOrEqual(self,*args)
+
+ defMinEquality(self,vars:"std::vector< operations_research::IntVar * > const &",min_var:"IntVar")->"operations_research::Constraint *":
+ return_pywrapcp.Solver_MinEquality(self,vars,min_var)
+
+ defMaxEquality(self,vars:"std::vector< operations_research::IntVar * > const &",max_var:"IntVar")->"operations_research::Constraint *":
+ return_pywrapcp.Solver_MaxEquality(self,vars,max_var)
+
+ defElementEquality(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ElementEquality(self,*args)
+
+ defAbsEquality(self,var:"IntVar",abs_var:"IntVar")->"operations_research::Constraint *":
+ r""" Creates the constraint abs(var) == abs_var."""
+ return_pywrapcp.Solver_AbsEquality(self,var,abs_var)
+
+ defIndexOfConstraint(self,vars:"std::vector< operations_research::IntVar * > const &",index:"IntVar",target:"int64_t")->"operations_research::Constraint *":
+ r"""
+ This constraint is a special case of the element constraint with
+ an array of integer variables, where the variables are all
+ different and the index variable is constrained such that
+ vars[index] == target.
+ """
+ return_pywrapcp.Solver_IndexOfConstraint(self,vars,index,target)
+
+ defConstraintInitialPropagateCallback(self,ct:"Constraint")->"operations_research::Demon *":
+ r"""
+ This method is a specialized case of the MakeConstraintDemon
+ method to call the InitiatePropagate of the constraint 'ct'.
+ """
+ return_pywrapcp.Solver_ConstraintInitialPropagateCallback(self,ct)
+
+ defDelayedConstraintInitialPropagateCallback(self,ct:"Constraint")->"operations_research::Demon *":
+ r"""
+ This method is a specialized case of the MakeConstraintDemon
+ method to call the InitiatePropagate of the constraint 'ct' with
+ low priority.
+ """
+ return_pywrapcp.Solver_DelayedConstraintInitialPropagateCallback(self,ct)
+
+ defClosureDemon(self,closure:"operations_research::Solver::Closure")->"operations_research::Demon *":
+ r""" Creates a demon from a closure."""
+ return_pywrapcp.Solver_ClosureDemon(self,closure)
+
+ defBetweenCt(self,expr:"IntExpr",l:"int64_t",u:"int64_t")->"operations_research::Constraint *":
+ r""" (l <= expr <= u)"""
+ return_pywrapcp.Solver_BetweenCt(self,expr,l,u)
+
+ defIsBetweenCt(self,expr:"IntExpr",l:"int64_t",u:"int64_t",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (l <= expr <= u)"""
+ return_pywrapcp.Solver_IsBetweenCt(self,expr,l,u,b)
+
+ defIsBetweenVar(self,v:"IntExpr",l:"int64_t",u:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.Solver_IsBetweenVar(self,v,l,u)
+
+ defMemberCt(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_MemberCt(self,*args)
+
+ defNotMemberCt(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ expr not in set.
+
+ |
+
+ *Overload 2:*
+ expr should not be in the list of forbidden intervals [start[i]..end[i]].
+
+ |
+
+ *Overload 3:*
+ expr should not be in the list of forbidden intervals [start[i]..end[i]].
+ """
+ return_pywrapcp.Solver_NotMemberCt(self,*args)
+
+ defIsMemberCt(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_IsMemberCt(self,*args)
+
+ defIsMemberVar(self,*args)->"operations_research::IntVar *":
+ return_pywrapcp.Solver_IsMemberVar(self,*args)
+
+ defCount(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ |{i | vars[i] == value}| == max_count
+
+ |
+
+ *Overload 2:*
+ |{i | vars[i] == value}| == max_count
+ """
+ return_pywrapcp.Solver_Count(self,*args)
+
+ defDistribute(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ Aggregated version of count: |{i | v[i] == values[j]}| == cards[j]
+
+ |
+
+ *Overload 2:*
+ Aggregated version of count: |{i | v[i] == values[j]}| == cards[j]
+
+ |
+
+ *Overload 3:*
+ Aggregated version of count: |{i | v[i] == j}| == cards[j]
+
+ |
+
+ *Overload 4:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1: card_min <= |{i | v[i] == j}| <= card_max
+
+ |
+
+ *Overload 5:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == j}| <= card_max[j]
+
+ |
+
+ *Overload 6:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == j}| <= card_max[j]
+
+ |
+
+ *Overload 7:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == values[j]}| <= card_max[j]
+
+ |
+
+ *Overload 8:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == values[j]}| <= card_max[j]
+ """
+ return_pywrapcp.Solver_Distribute(self,*args)
+
+ defDeviation(self,vars:"std::vector< operations_research::IntVar * > const &",deviation_var:"IntVar",total_sum:"int64_t")->"operations_research::Constraint *":
+ r"""
+ Deviation constraint:
+ sum_i |n * vars[i] - total_sum| <= deviation_var and
+ sum_i vars[i] == total_sum
+ n = #vars
+ """
+ return_pywrapcp.Solver_Deviation(self,vars,deviation_var,total_sum)
+
+ defAllDifferent(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ All variables are pairwise different. This corresponds to the
+ stronger version of the propagation algorithm.
+
+ |
+
+ *Overload 2:*
+ All variables are pairwise different. If 'stronger_propagation'
+ is true, stronger, and potentially slower propagation will
+ occur. This API will be deprecated in the future.
+ """
+ return_pywrapcp.Solver_AllDifferent(self,*args)
+
+ defAllDifferentExcept(self,vars:"std::vector< operations_research::IntVar * > const &",escape_value:"int64_t")->"operations_research::Constraint *":
+ r"""
+ All variables are pairwise different, unless they are assigned to
+ the escape value.
+ """
+ return_pywrapcp.Solver_AllDifferentExcept(self,vars,escape_value)
+
+ defSortingConstraint(self,vars:"std::vector< operations_research::IntVar * > const &",sorted:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint binding the arrays of variables "vars" and
+ "sorted_vars": sorted_vars[0] must be equal to the minimum of all
+ variables in vars, and so on: the value of sorted_vars[i] must be
+ equal to the i-th value of variables invars.
+
+ This constraint propagates in both directions: from "vars" to
+ "sorted_vars" and vice-versa.
+
+ Behind the scenes, this constraint maintains that:
+ - sorted is always increasing.
+ - whatever the values of vars, there exists a permutation that
+ injects its values into the sorted variables.
+
+ For more info, please have a look at:
+ https://mpi-inf.mpg.de/~mehlhorn/ftp/Mehlhorn-Thiel.pdf
+ """
+ return_pywrapcp.Solver_SortingConstraint(self,vars,sorted)
+
+ defLexicalLess(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that left is lexicographically less
+ than right.
+ """
+ return_pywrapcp.Solver_LexicalLess(self,left,right)
+
+ defLexicalLessOrEqual(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that left is lexicographically less
+ than or equal to right.
+ """
+ return_pywrapcp.Solver_LexicalLessOrEqual(self,left,right)
+
+ defInversePermutationConstraint(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that 'left' and 'right' both
+ represent permutations of [0..left.size()-1], and that 'right' is
+ the inverse permutation of 'left', i.e. for all i in
+ [0..left.size()-1], right[left[i]] = i.
+ """
+ return_pywrapcp.Solver_InversePermutationConstraint(self,left,right)
+
+ defNullIntersect(self,first_vars:"std::vector< operations_research::IntVar * > const &",second_vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that states that all variables in the first
+ vector are different from all variables in the second
+ group. Thus the set of values in the first vector does not
+ intersect with the set of values in the second vector.
+ """
+ return_pywrapcp.Solver_NullIntersect(self,first_vars,second_vars)
+
+ defNullIntersectExcept(self,first_vars:"std::vector< operations_research::IntVar * > const &",second_vars:"std::vector< operations_research::IntVar * > const &",escape_value:"int64_t")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that states that all variables in the first
+ vector are different from all variables from the second group,
+ unless they are assigned to the escape value. Thus the set of
+ values in the first vector minus the escape value does not
+ intersect with the set of values in the second vector.
+ """
+ return_pywrapcp.Solver_NullIntersectExcept(self,first_vars,second_vars,escape_value)
+
+ defCircuit(self,nexts:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r""" Force the "nexts" variable to create a complete Hamiltonian path."""
+ return_pywrapcp.Solver_Circuit(self,nexts)
+
+ defSubCircuit(self,nexts:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Force the "nexts" variable to create a complete Hamiltonian path
+ for those that do not loop upon themselves.
+ """
+ return_pywrapcp.Solver_SubCircuit(self,nexts)
+
+ defDelayedPathCumul(self,nexts:"std::vector< operations_research::IntVar * > const &",active:"std::vector< operations_research::IntVar * > const &",cumuls:"std::vector< operations_research::IntVar * > const &",transits:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Delayed version of the same constraint: propagation on the nexts variables
+ is delayed until all constraints have propagated.
+ """
+ return_pywrapcp.Solver_DelayedPathCumul(self,nexts,active,cumuls,transits)
+
+ defPathCumul(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transits[i].
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+
+ |
+
+ *Overload 2:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]).
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+ Ownership of transit_evaluator is taken and it must be a repeatable
+ callback.
+
+ |
+
+ *Overload 3:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]) + slacks[i].
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+ Ownership of transit_evaluator is taken and it must be a repeatable
+ callback.
+ """
+ return_pywrapcp.Solver_PathCumul(self,*args)
+
+ defAllowedAssignments(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This method creates a constraint where the graph of the relation
+ between the variables is given in extension. There are 'arity'
+ variables involved in the relation and the graph is given by a
+ integer tuple set.
+
+ |
+
+ *Overload 2:*
+ Compatibility layer for Python API.
+ """
+ return_pywrapcp.Solver_AllowedAssignments(self,*args)
+
+ defTransitionConstraint(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_TransitionConstraint(self,*args)
+
+ defNonOverlappingBoxesConstraint(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_NonOverlappingBoxesConstraint(self,*args)
+
+ defPack(self,vars:"std::vector< operations_research::IntVar * > const &",number_of_bins:"int")->"operations_research::Pack *":
+ r"""
+ This constraint packs all variables onto 'number_of_bins'
+ variables. For any given variable, a value of 'number_of_bins'
+ indicates that the variable is not assigned to any bin.
+ Dimensions, i.e., cumulative constraints on this packing, can be
+ added directly from the pack class.
+ """
+ return_pywrapcp.Solver_Pack(self,vars,number_of_bins)
+
+ defFixedDurationIntervalVar(self,*args)->"operations_research::IntervalVar *":
+ r"""
+ *Overload 1:*
+ Creates an interval var with a fixed duration. The duration must
+ be greater than 0. If optional is true, then the interval can be
+ performed or unperformed. If optional is false, then the interval
+ is always performed.
+
+ |
+
+ *Overload 2:*
+ Creates a performed interval var with a fixed duration. The duration must
+ be greater than 0.
+
+ |
+
+ *Overload 3:*
+ Creates an interval var with a fixed duration, and performed_variable.
+ The duration must be greater than 0.
+ """
+ return_pywrapcp.Solver_FixedDurationIntervalVar(self,*args)
+
+ defFixedInterval(self,start:"int64_t",duration:"int64_t",name:"std::string const &")->"operations_research::IntervalVar *":
+ r""" Creates a fixed and performed interval."""
+ return_pywrapcp.Solver_FixedInterval(self,start,duration,name)
+
+ defIntervalVar(self,start_min:"int64_t",start_max:"int64_t",duration_min:"int64_t",duration_max:"int64_t",end_min:"int64_t",end_max:"int64_t",optional:"bool",name:"std::string const &")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var by specifying the bounds on start,
+ duration, and end.
+ """
+ return_pywrapcp.Solver_IntervalVar(self,start_min,start_max,duration_min,duration_max,end_min,end_max,optional,name)
+
+ defMirrorInterval(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var that is the mirror image of the given one, that
+ is, the interval var obtained by reversing the axis.
+ """
+ return_pywrapcp.Solver_MirrorInterval(self,interval_var)
+
+ defFixedDurationStartSyncedOnStartIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose start is
+ synchronized with the start of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationStartSyncedOnStartIntervalVar(self,interval_var,duration,offset)
+
+ defFixedDurationStartSyncedOnEndIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose start is
+ synchronized with the end of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationStartSyncedOnEndIntervalVar(self,interval_var,duration,offset)
+
+ defFixedDurationEndSyncedOnStartIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose end is
+ synchronized with the start of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationEndSyncedOnStartIntervalVar(self,interval_var,duration,offset)
+
+ defFixedDurationEndSyncedOnEndIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose end is
+ synchronized with the end of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationEndSyncedOnEndIntervalVar(self,interval_var,duration,offset)
+
+ defIntervalRelaxedMin(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates and returns an interval variable that wraps around the given one,
+ relaxing the min start and end. Relaxing means making unbounded when
+ optional. If the variable is non-optional, this method returns
+ interval_var.
+
+ More precisely, such an interval variable behaves as follows:
+ When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+ When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the min side;
+ When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+ This is very useful to implement propagators that may only modify
+ the start max or end max.
+ """
+ return_pywrapcp.Solver_IntervalRelaxedMin(self,interval_var)
+
+ defIntervalRelaxedMax(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates and returns an interval variable that wraps around the given one,
+ relaxing the max start and end. Relaxing means making unbounded when
+ optional. If the variable is non optional, this method returns
+ interval_var.
+
+ More precisely, such an interval variable behaves as follows:
+ When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+ When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the max side;
+ When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+ This is very useful for implementing propagators that may only modify
+ the start min or end min.
+ """
+ return_pywrapcp.Solver_IntervalRelaxedMax(self,interval_var)
+
+ defTemporalDisjunction(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This constraint implements a temporal disjunction between two
+ interval vars t1 and t2. 'alt' indicates which alternative was
+ chosen (alt == 0 is equivalent to t1 before t2).
+
+ |
+
+ *Overload 2:*
+ This constraint implements a temporal disjunction between two
+ interval vars.
+ """
+ return_pywrapcp.Solver_TemporalDisjunction(self,*args)
+
+ defDisjunctiveConstraint(self,intervals:"std::vector< operations_research::IntervalVar * > const &",name:"std::string const &")->"operations_research::DisjunctiveConstraint *":
+ r"""
+ This constraint forces all interval vars into an non-overlapping
+ sequence. Intervals with zero duration can be scheduled anywhere.
+ """
+ return_pywrapcp.Solver_DisjunctiveConstraint(self,intervals,name)
+
+ defCumulative(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 2:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 3:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 4:*
+ This constraint enforces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 5:*
+ This constraint enforces that, for any integer t, the sum of demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should be positive.
+
+ |
+
+ *Overload 6:*
+ This constraint enforces that, for any integer t, the sum of demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should be positive.
+ """
+ return_pywrapcp.Solver_Cumulative(self,*args)
+
+ defCover(self,vars:"std::vector< operations_research::IntervalVar * > const &",target_var:"IntervalVar")->"operations_research::Constraint *":
+ r"""
+ This constraint states that the target_var is the convex hull of
+ the intervals. If none of the interval variables is performed,
+ then the target var is unperformed too. Also, if the target
+ variable is unperformed, then all the intervals variables are
+ unperformed too.
+ """
+ return_pywrapcp.Solver_Cover(self,vars,target_var)
+
+ defAssignment(self,*args)->"operations_research::Assignment *":
+ r"""
+ *Overload 1:*
+ This method creates an empty assignment.
+
+ |
+
+ *Overload 2:*
+ This method creates an assignment which is a copy of 'a'.
+ """
+ return_pywrapcp.Solver_Assignment(self,*args)
+
+ defFirstSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the first solution of the search.
+
+ |
+
+ *Overload 2:*
+ Collect the first solution of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_FirstSolutionCollector(self,*args)
+
+ defLastSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the last solution of the search.
+
+ |
+
+ *Overload 2:*
+ Collect the last solution of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_LastSolutionCollector(self,*args)
+
+ defBestValueSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the solution corresponding to the optimal value of the objective
+ of 'assignment'; if 'assignment' does not have an objective no solution is
+ collected. This collector only collects one solution corresponding to the
+ best objective value (the first one found).
+
+ |
+
+ *Overload 2:*
+ Collect the solution corresponding to the optimal value of the
+ objective of 'assignment'; if 'assignment' does not have an objective no
+ solution is collected. This collector only collects one solution
+ corresponding to the best objective value (the first one
+ found). The variables will need to be added later.
+ """
+ return_pywrapcp.Solver_BestValueSolutionCollector(self,*args)
+
+ defAllSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect all solutions of the search.
+
+ |
+
+ *Overload 2:*
+ Collect all solutions of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_AllSolutionCollector(self,*args)
+
+ defMinimize(self,v:"IntVar",step:"int64_t")->"operations_research::OptimizeVar *":
+ r""" Creates a minimization objective."""
+ return_pywrapcp.Solver_Minimize(self,v,step)
+
+ defMaximize(self,v:"IntVar",step:"int64_t")->"operations_research::OptimizeVar *":
+ r""" Creates a maximization objective."""
+ return_pywrapcp.Solver_Maximize(self,v,step)
+
+ defOptimize(self,maximize:"bool",v:"IntVar",step:"int64_t")->"operations_research::OptimizeVar *":
+ r""" Creates a objective with a given sense (true = maximization)."""
+ return_pywrapcp.Solver_Optimize(self,maximize,v,step)
+
+ defWeightedMinimize(self,*args)->"operations_research::OptimizeVar *":
+ r"""
+ *Overload 1:*
+ Creates a minimization weighted objective. The actual objective is
+ scalar_prod(sub_objectives, weights).
+
+ |
+
+ *Overload 2:*
+ Creates a minimization weighted objective. The actual objective is
+ scalar_prod(sub_objectives, weights).
+ """
+ return_pywrapcp.Solver_WeightedMinimize(self,*args)
+
+ defWeightedMaximize(self,*args)->"operations_research::OptimizeVar *":
+ r"""
+ *Overload 1:*
+ Creates a maximization weigthed objective.
+
+ |
+
+ *Overload 2:*
+ Creates a maximization weigthed objective.
+ """
+ return_pywrapcp.Solver_WeightedMaximize(self,*args)
+
+ defWeightedOptimize(self,*args)->"operations_research::OptimizeVar *":
+ r"""
+ *Overload 1:*
+ Creates a weighted objective with a given sense (true = maximization).
+
+ |
+
+ *Overload 2:*
+ Creates a weighted objective with a given sense (true = maximization).
+ """
+ return_pywrapcp.Solver_WeightedOptimize(self,*args)
+
+ defTabuSearch(self,maximize:"bool",v:"IntVar",step:"int64_t",vars:"std::vector< operations_research::IntVar * > const &",keep_tenure:"int64_t",forbid_tenure:"int64_t",tabu_factor:"double")->"operations_research::SearchMonitor *":
+ r"""
+ MetaHeuristics which try to get the search out of local optima.
+ Creates a Tabu Search monitor.
+ In the context of local search the behavior is similar to MakeOptimize(),
+ creating an objective in a given sense. The behavior differs once a local
+ optimum is reached: thereafter solutions which degrade the value of the
+ objective are allowed if they are not "tabu". A solution is "tabu" if it
+ doesn't respect the following rules:
+ - improving the best solution found so far
+ - variables in the "keep" list must keep their value, variables in the
+ "forbid" list must not take the value they have in the list.
+ Variables with new values enter the tabu lists after each new solution
+ found and leave the lists after a given number of iterations (called
+ tenure). Only the variables passed to the method can enter the lists.
+ The tabu criterion is softened by the tabu factor which gives the number
+ of "tabu" violations which is tolerated; a factor of 1 means no violations
+ allowed; a factor of 0 means all violations are allowed.
+ """
+ return_pywrapcp.Solver_TabuSearch(self,maximize,v,step,vars,keep_tenure,forbid_tenure,tabu_factor)
+
+ defSimulatedAnnealing(self,maximize:"bool",v:"IntVar",step:"int64_t",initial_temperature:"int64_t")->"operations_research::SearchMonitor *":
+ r""" Creates a Simulated Annealing monitor."""
+ return_pywrapcp.Solver_SimulatedAnnealing(self,maximize,v,step,initial_temperature)
+
+ defLubyRestart(self,scale_factor:"int")->"operations_research::SearchMonitor *":
+ r"""
+ This search monitor will restart the search periodically.
+ At the iteration n, it will restart after scale_factor * Luby(n) failures
+ where Luby is the Luby Strategy (i.e. 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8...).
+ """
+ return_pywrapcp.Solver_LubyRestart(self,scale_factor)
+
+ defConstantRestart(self,frequency:"int")->"operations_research::SearchMonitor *":
+ r"""
+ This search monitor will restart the search periodically after 'frequency'
+ failures.
+ """
+ return_pywrapcp.Solver_ConstantRestart(self,frequency)
+
+ defTimeLimit(self,*args)->"operations_research::RegularLimit *":
+ return_pywrapcp.Solver_TimeLimit(self,*args)
+
+ defBranchesLimit(self,branches:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of branches
+ explored in the search tree.
+ """
+ return_pywrapcp.Solver_BranchesLimit(self,branches)
+
+ defFailuresLimit(self,failures:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of failures
+ that can happen when exploring the search tree.
+ """
+ return_pywrapcp.Solver_FailuresLimit(self,failures)
+
+ defSolutionsLimit(self,solutions:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of solutions found
+ during the search.
+ """
+ return_pywrapcp.Solver_SolutionsLimit(self,solutions)
+
+ defLimit(self,*args)->"operations_research::SearchLimit *":
+ r"""
+ *Overload 1:*
+ Limits the search with the 'time', 'branches', 'failures' and
+ 'solutions' limits. 'smart_time_check' reduces the calls to the wall
+
+ |
+
+ *Overload 2:*
+ Creates a search limit from its protobuf description
+
+ |
+
+ *Overload 3:*
+ Creates a search limit that is reached when either of the underlying limit
+ is reached. That is, the returned limit is more stringent than both
+ argument limits.
+ """
+ return_pywrapcp.Solver_Limit(self,*args)
+
+ defCustomLimit(self,limiter:"std::function< bool () >")->"operations_research::SearchLimit *":
+ r"""
+ Callback-based search limit. Search stops when limiter returns true; if
+ this happens at a leaf the corresponding solution will be rejected.
+ """
+ return_pywrapcp.Solver_CustomLimit(self,limiter)
+
+ defSearchLog(self,*args)->"operations_research::SearchMonitor *":
+ return_pywrapcp.Solver_SearchLog(self,*args)
+
+ defSearchTrace(self,prefix:"std::string const &")->"operations_research::SearchMonitor *":
+ r"""
+ Creates a search monitor that will trace precisely the behavior of the
+ search. Use this only for low level debugging.
+ """
+ return_pywrapcp.Solver_SearchTrace(self,prefix)
+
+ defPrintModelVisitor(self)->"operations_research::ModelVisitor *":
+ r""" Prints the model."""
+ return_pywrapcp.Solver_PrintModelVisitor(self)
+
+ defStatisticsModelVisitor(self)->"operations_research::ModelVisitor *":
+ r""" Displays some nice statistics on the model."""
+ return_pywrapcp.Solver_StatisticsModelVisitor(self)
+
+ defAssignVariableValue(self,var:"IntVar",val:"int64_t")->"operations_research::Decision *":
+ r""" Decisions."""
+ return_pywrapcp.Solver_AssignVariableValue(self,var,val)
+
+ defVariableLessOrEqualValue(self,var:"IntVar",value:"int64_t")->"operations_research::Decision *":
+ return_pywrapcp.Solver_VariableLessOrEqualValue(self,var,value)
+
+ defVariableGreaterOrEqualValue(self,var:"IntVar",value:"int64_t")->"operations_research::Decision *":
+ return_pywrapcp.Solver_VariableGreaterOrEqualValue(self,var,value)
+
+ defSplitVariableDomain(self,var:"IntVar",val:"int64_t",start_with_lower_half:"bool")->"operations_research::Decision *":
+ return_pywrapcp.Solver_SplitVariableDomain(self,var,val,start_with_lower_half)
+
+ defAssignVariableValueOrFail(self,var:"IntVar",value:"int64_t")->"operations_research::Decision *":
+ return_pywrapcp.Solver_AssignVariableValueOrFail(self,var,value)
+
+ defAssignVariablesValues(self,vars:"std::vector< operations_research::IntVar * > const &",values:"std::vector< int64_t > const &")->"operations_research::Decision *":
+ return_pywrapcp.Solver_AssignVariablesValues(self,vars,values)
+
+ defFailDecision(self)->"operations_research::Decision *":
+ return_pywrapcp.Solver_FailDecision(self)
+
+ defDecision(self,apply:"operations_research::Solver::Action",refute:"operations_research::Solver::Action")->"operations_research::Decision *":
+ return_pywrapcp.Solver_Decision(self,apply,refute)
+
+ defCompose(self,dbs:"std::vector< operations_research::DecisionBuilder * > const &")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_Compose(self,dbs)
+
+ defTry(self,dbs:"std::vector< operations_research::DecisionBuilder * > const &")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_Try(self,dbs)
+
+ defDefaultPhase(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_DefaultPhase(self,*args)
+
+ defScheduleOrPostpone(self,var:"IntervalVar",est:"int64_t",marker:"int64_t *const")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to schedule a task at a given time.
+ On the Apply branch, it will set that interval var as performed and set
+ its start to 'est'. On the Refute branch, it will just update the
+ 'marker' to 'est' + 1. This decision is used in the
+ INTERVAL_SET_TIMES_FORWARD strategy.
+ """
+ return_pywrapcp.Solver_ScheduleOrPostpone(self,var,est,marker)
+
+ defScheduleOrExpedite(self,var:"IntervalVar",est:"int64_t",marker:"int64_t *const")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to schedule a task at a given time.
+ On the Apply branch, it will set that interval var as performed and set
+ its end to 'est'. On the Refute branch, it will just update the
+ 'marker' to 'est' - 1. This decision is used in the
+ INTERVAL_SET_TIMES_BACKWARD strategy.
+ """
+ return_pywrapcp.Solver_ScheduleOrExpedite(self,var,est,marker)
+
+ defRankFirstInterval(self,sequence:"SequenceVar",index:"int")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to rank first the ith interval var
+ in the sequence variable.
+ """
+ return_pywrapcp.Solver_RankFirstInterval(self,sequence,index)
+
+ defRankLastInterval(self,sequence:"SequenceVar",index:"int")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to rank last the ith interval var
+ in the sequence variable.
+ """
+ return_pywrapcp.Solver_RankLastInterval(self,sequence,index)
+
+ defPhase(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_Phase(self,*args)
+
+ defDecisionBuilderFromAssignment(self,assignment:"Assignment",db:"DecisionBuilder",vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a decision builder for which the left-most leaf corresponds
+ to assignment, the rest of the tree being explored using 'db'.
+ """
+ return_pywrapcp.Solver_DecisionBuilderFromAssignment(self,assignment,db,vars)
+
+ defConstraintAdder(self,ct:"Constraint")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a decision builder that will add the given constraint to
+ the model.
+ """
+ return_pywrapcp.Solver_ConstraintAdder(self,ct)
+
+ defSolveOnce(self,db:"DecisionBuilder",monitors:"std::vector< operations_research::SearchMonitor * > const &")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_SolveOnce(self,db,monitors)
+
+ defNestedOptimize(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_NestedOptimize(self,*args)
+
+ defRestoreAssignment(self,assignment:"Assignment")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a DecisionBuilder which restores an Assignment
+ (calls void Assignment::Restore())
+ """
+ return_pywrapcp.Solver_RestoreAssignment(self,assignment)
+
+ defStoreAssignment(self,assignment:"Assignment")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a DecisionBuilder which stores an Assignment
+ (calls void Assignment::Store())
+ """
+ return_pywrapcp.Solver_StoreAssignment(self,assignment)
+
+ defOperator(self,*args)->"operations_research::LocalSearchOperator *":
+ return_pywrapcp.Solver_Operator(self,*args)
+
+ defRandomLnsOperator(self,*args)->"operations_research::LocalSearchOperator *":
+ return_pywrapcp.Solver_RandomLnsOperator(self,*args)
+
+ defMoveTowardTargetOperator(self,*args)->"operations_research::LocalSearchOperator *":
+ r"""
+ *Overload 1:*
+ Creates a local search operator that tries to move the assignment of some
+ variables toward a target. The target is given as an Assignment. This
+ operator generates neighbors in which the only difference compared to the
+ current state is that one variable that belongs to the target assignment
+ is set to its target value.
+
+ |
+
+ *Overload 2:*
+ Creates a local search operator that tries to move the assignment of some
+ variables toward a target. The target is given either as two vectors: a
+ vector of variables and a vector of associated target values. The two
+ vectors should be of the same length. This operator generates neighbors in
+ which the only difference compared to the current state is that one
+ variable that belongs to the given vector is set to its target value.
+ """
+ return_pywrapcp.Solver_MoveTowardTargetOperator(self,*args)
+
+ defConcatenateOperators(self,*args)->"operations_research::LocalSearchOperator *":
+ return_pywrapcp.Solver_ConcatenateOperators(self,*args)
+
+ defRandomConcatenateOperators(self,*args)->"operations_research::LocalSearchOperator *":
+ r"""
+ *Overload 1:*
+ Randomized version of local search concatenator; calls a random operator
+ at each call to MakeNextNeighbor().
+
+ |
+
+ *Overload 2:*
+ Randomized version of local search concatenator; calls a random operator
+ at each call to MakeNextNeighbor(). The provided seed is used to
+ initialize the random number generator.
+ """
+ return_pywrapcp.Solver_RandomConcatenateOperators(self,*args)
+
+ defNeighborhoodLimit(self,op:"LocalSearchOperator",limit:"int64_t")->"operations_research::LocalSearchOperator *":
+ r"""
+ Creates a local search operator that wraps another local search
+ operator and limits the number of neighbors explored (i.e., calls
+ to MakeNextNeighbor from the current solution (between two calls
+ to Start()). When this limit is reached, MakeNextNeighbor()
+ returns false. The counter is cleared when Start() is called.
+ """
+ return_pywrapcp.Solver_NeighborhoodLimit(self,op,limit)
+
+ defLocalSearchPhase(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_LocalSearchPhase(self,*args)
+
+ defLocalSearchPhaseParameters(self,*args)->"operations_research::LocalSearchPhaseParameters *":
+ return_pywrapcp.Solver_LocalSearchPhaseParameters(self,*args)
+
+ defSearchDepth(self)->"int":
+ r"""
+ Gets the search depth of the current active search. Returns -1 if
+ there is no active search opened.
+ """
+ return_pywrapcp.Solver_SearchDepth(self)
+
+ defSearchLeftDepth(self)->"int":
+ r"""
+ Gets the search left depth of the current active search. Returns -1 if
+ there is no active search opened.
+ """
+ return_pywrapcp.Solver_SearchLeftDepth(self)
+
+ defSolveDepth(self)->"int":
+ r"""
+ Gets the number of nested searches. It returns 0 outside search,
+ 1 during the top level search, 2 or more in case of nested searches.
+ """
+ return_pywrapcp.Solver_SolveDepth(self)
+
+ defRand64(self,size:"int64_t")->"int64_t":
+ r""" Returns a random value between 0 and 'size' - 1;"""
+ return_pywrapcp.Solver_Rand64(self,size)
+
+ defRand32(self,size:"int32_t")->"int32_t":
+ r""" Returns a random value between 0 and 'size' - 1;"""
+ return_pywrapcp.Solver_Rand32(self,size)
+
+ defReSeed(self,seed:"int32_t")->"void":
+ r""" Reseed the solver random generator."""
+ return_pywrapcp.Solver_ReSeed(self,seed)
+
+ defLocalSearchProfile(self)->"std::string":
+ r""" Returns local search profiling information in a human readable format."""
+ return_pywrapcp.Solver_LocalSearchProfile(self)
+
+ defConstraints(self)->"int":
+ r"""
+ Counts the number of constraints that have been added
+ to the solver before the search.
+ """
+ return_pywrapcp.Solver_Constraints(self)
+
+ defAccept(self,visitor:"operations_research::ModelVisitor *const")->"void":
+ r""" Accepts the given model visitor."""
+ return_pywrapcp.Solver_Accept(self,visitor)
+
+ defFinishCurrentSearch(self)->"void":
+ r""" Tells the solver to kill or restart the current search."""
+ return_pywrapcp.Solver_FinishCurrentSearch(self)
+
+ defRestartCurrentSearch(self)->"void":
+ return_pywrapcp.Solver_RestartCurrentSearch(self)
+
+ defShouldFail(self)->"void":
+ r"""
+ These methods are only useful for the SWIG wrappers, which need a way
+ to externally cause the Solver to fail.
+ """
+ return_pywrapcp.Solver_ShouldFail(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.Solver___str__(self)
+
+ defAdd(self,ct):
+ ifisinstance(ct,PyConstraint):
+ self.__python_constraints.append(ct)
+ self.AddConstraint(ct)
+
+
+ defTreeNoCycle(self,nexts:"std::vector< operations_research::IntVar * > const &",active:"std::vector< operations_research::IntVar * > const &",callback:"operations_research::Solver::IndexFilter1"=0)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_TreeNoCycle(self,nexts,active,callback)
+
+ defSearchLogWithCallback(self,period:"int",callback:"std::function< std::string () >")->"operations_research::SearchMonitor *":
+ return_pywrapcp.Solver_SearchLogWithCallback(self,period,callback)
+
+ defElementFunction(self,values:"std::function< int64_t (int64_t) >",index:"IntVar")->"operations_research::IntExpr *":
+ return_pywrapcp.Solver_ElementFunction(self,values,index)
+
+ defVarEvalValStrPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_evaluator:"std::function< int64_t (int64_t) >",val_str:"operations_research::Solver::IntValueStrategy")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarEvalValStrPhase(self,vars,var_evaluator,val_str)
+
+ defVarStrValEvalPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_str:"operations_research::Solver::IntVarStrategy",val_eval:"operations_research::Solver::IndexEvaluator2")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarStrValEvalPhase(self,vars,var_str,val_eval)
+
+ defVarEvalValEvalPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_eval:"std::function< int64_t (int64_t) >",val_eval:"operations_research::Solver::IndexEvaluator2")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarEvalValEvalPhase(self,vars,var_eval,val_eval)
+
+ defVarStrValEvalTieBreakPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_str:"operations_research::Solver::IntVarStrategy",val_eval:"operations_research::Solver::IndexEvaluator2",tie_breaker:"std::function< int64_t (int64_t) >")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarStrValEvalTieBreakPhase(self,vars,var_str,val_eval,tie_breaker)
+
+ defVarEvalValEvalTieBreakPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_eval:"std::function< int64_t (int64_t) >",val_eval:"operations_research::Solver::IndexEvaluator2",tie_breaker:"std::function< int64_t (int64_t) >")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarEvalValEvalTieBreakPhase(self,vars,var_eval,val_eval,tie_breaker)
+
+ defEvalEvalStrPhase(self,vars:"std::vector< operations_research::IntVar * > const &",evaluator:"operations_research::Solver::IndexEvaluator2",str:"operations_research::Solver::EvaluatorStrategy")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_EvalEvalStrPhase(self,vars,evaluator,str)
+
+ defEvalEvalStrTieBreakPhase(self,vars:"std::vector< operations_research::IntVar * > const &",evaluator:"operations_research::Solver::IndexEvaluator2",tie_breaker:"operations_research::Solver::IndexEvaluator1",str:"operations_research::Solver::EvaluatorStrategy")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_EvalEvalStrTieBreakPhase(self,vars,evaluator,tie_breaker,str)
+
+ defGuidedLocalSearch(self,*args)->"operations_research::SearchMonitor *":
+ return_pywrapcp.Solver_GuidedLocalSearch(self,*args)
+
+ defSumObjectiveFilter(self,vars:"std::vector< operations_research::IntVar * > const &",values:"operations_research::Solver::IndexEvaluator2",filter_enum:"operations_research::Solver::LocalSearchFilterBound")->"operations_research::LocalSearchFilter *":
+ return_pywrapcp.Solver_SumObjectiveFilter(self,vars,values,filter_enum)
+
+# Register Solver in _pywrapcp:
+_pywrapcp.Solver_swigregister(Solver)
+
+defSolver_DefaultSolverParameters()->"operations_research::ConstraintSolverParameters":
+ r""" Create a ConstraintSolverParameters proto with all the default values."""
+ return_pywrapcp.Solver_DefaultSolverParameters()
+
+defSolver_MemoryUsage()->"int64_t":
+ r""" Current memory usage in bytes"""
+ return_pywrapcp.Solver_MemoryUsage()
+
+classBaseObject(object):
+ r"""
+ A BaseObject is the root of all reversibly allocated objects.
+ A DebugString method and the associated << operator are implemented
+ as a convenience.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self):
+ ifself.__class__==BaseObject:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.BaseObject_swiginit(self,_pywrapcp.new_BaseObject(_self,))
+ __swig_destroy__=_pywrapcp.delete_BaseObject
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.BaseObject_DebugString(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.BaseObject___str__(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.BaseObject___repr__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_BaseObject(self)
+ returnweakref.proxy(self)
+
+# Register BaseObject in _pywrapcp:
+_pywrapcp.BaseObject_swigregister(BaseObject)
+
+classPropagationBaseObject(BaseObject):
+ r"""
+ NOLINT
+ The PropagationBaseObject is a subclass of BaseObject that is also
+ friend to the Solver class. It allows accessing methods useful when
+ writing new constraints or new expressions.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,s:"Solver"):
+ ifself.__class__==PropagationBaseObject:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.PropagationBaseObject_swiginit(self,_pywrapcp.new_PropagationBaseObject(_self,s))
+ __swig_destroy__=_pywrapcp.delete_PropagationBaseObject
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.PropagationBaseObject_DebugString(self)
+
+ defsolver(self)->"operations_research::Solver *":
+ return_pywrapcp.PropagationBaseObject_solver(self)
+
+ defName(self)->"std::string":
+ r""" Object naming."""
+ return_pywrapcp.PropagationBaseObject_Name(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_PropagationBaseObject(self)
+ returnweakref.proxy(self)
+
+# Register PropagationBaseObject in _pywrapcp:
+_pywrapcp.PropagationBaseObject_swigregister(PropagationBaseObject)
+
+classDecision(BaseObject):
+ r"""
+ A Decision represents a choice point in the search tree. The two main
+ methods are Apply() to go left, or Refute() to go right.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self):
+ ifself.__class__==Decision:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.Decision_swiginit(self,_pywrapcp.new_Decision(_self,))
+ __swig_destroy__=_pywrapcp.delete_Decision
+
+ defApplyWrapper(self,s:"Solver")->"void":
+ r""" Apply will be called first when the decision is executed."""
+ return_pywrapcp.Decision_ApplyWrapper(self,s)
+
+ defRefuteWrapper(self,s:"Solver")->"void":
+ r""" Refute will be called after a backtrack."""
+ return_pywrapcp.Decision_RefuteWrapper(self,s)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Decision_DebugString(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.Decision___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.Decision___str__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_Decision(self)
+ returnweakref.proxy(self)
+
+# Register Decision in _pywrapcp:
+_pywrapcp.Decision_swigregister(Decision)
+
+classDecisionBuilder(BaseObject):
+ r"""
+ A DecisionBuilder is responsible for creating the search tree. The
+ important method is Next(), which returns the next decision to execute.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self):
+ ifself.__class__==DecisionBuilder:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.DecisionBuilder_swiginit(self,_pywrapcp.new_DecisionBuilder(_self,))
+ __swig_destroy__=_pywrapcp.delete_DecisionBuilder
+
+ defNextWrapper(self,s:"Solver")->"operations_research::Decision *":
+ r"""
+ This is the main method of the decision builder class. It must
+ return a decision (an instance of the class Decision). If it
+ returns nullptr, this means that the decision builder has finished
+ its work.
+ """
+ return_pywrapcp.DecisionBuilder_NextWrapper(self,s)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.DecisionBuilder_DebugString(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.DecisionBuilder___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.DecisionBuilder___str__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_DecisionBuilder(self)
+ returnweakref.proxy(self)
+
+# Register DecisionBuilder in _pywrapcp:
+_pywrapcp.DecisionBuilder_swigregister(DecisionBuilder)
+
+classDemon(BaseObject):
+ r"""
+ A Demon is the base element of a propagation queue. It is the main
+ object responsible for implementing the actual propagation
+ of the constraint and pruning the inconsistent values in the domains
+ of the variables. The main concept is that demons are listeners that are
+ attached to the variables and listen to their modifications.
+ There are two methods:
+ - Run() is the actual method called when the demon is processed.
+ - priority() returns its priority. Standard priorities are slow, normal
+ or fast. "immediate" is reserved for variables and is treated separately.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self):
+ r"""
+ This indicates the priority of a demon. Immediate demons are treated
+ separately and corresponds to variables.
+ """
+ ifself.__class__==Demon:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.Demon_swiginit(self,_pywrapcp.new_Demon(_self,))
+ __swig_destroy__=_pywrapcp.delete_Demon
+
+ defRunWrapper(self,s:"Solver")->"void":
+ r""" This is the main callback of the demon."""
+ return_pywrapcp.Demon_RunWrapper(self,s)
+
+ defPriority(self)->"operations_research::Solver::DemonPriority":
+ r"""
+ This method returns the priority of the demon. Usually a demon is
+ fast, slow or normal. Immediate demons are reserved for internal
+ use to maintain variables.
+ """
+ return_pywrapcp.Demon_Priority(self)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Demon_DebugString(self)
+
+ defInhibit(self,s:"Solver")->"void":
+ r"""
+ This method inhibits the demon in the search tree below the
+ current position.
+ """
+ return_pywrapcp.Demon_Inhibit(self,s)
+
+ defDesinhibit(self,s:"Solver")->"void":
+ r""" This method un-inhibits the demon that was previously inhibited."""
+ return_pywrapcp.Demon_Desinhibit(self,s)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_Demon(self)
+ returnweakref.proxy(self)
+
+# Register Demon in _pywrapcp:
+_pywrapcp.Demon_swigregister(Demon)
+
+classConstraint(PropagationBaseObject):
+ r"""
+ A constraint is the main modeling object. It provides two methods:
+ - Post() is responsible for creating the demons and attaching them to
+ immediate demons().
+ - InitialPropagate() is called once just after Post and performs
+ the initial propagation. The subsequent propagations will be performed
+ by the demons Posted during the post() method.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,solver:"Solver"):
+ ifself.__class__==Constraint:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.Constraint_swiginit(self,_pywrapcp.new_Constraint(_self,solver))
+ __swig_destroy__=_pywrapcp.delete_Constraint
+
+ defPost(self)->"void":
+ r"""
+ This method is called when the constraint is processed by the
+ solver. Its main usage is to attach demons to variables.
+ """
+ return_pywrapcp.Constraint_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ r"""
+ This method performs the initial propagation of the
+ constraint. It is called just after the post.
+ """
+ return_pywrapcp.Constraint_InitialPropagateWrapper(self)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Constraint_DebugString(self)
+
+ defVar(self)->"operations_research::IntVar *":
+ r"""
+ Creates a Boolean variable representing the status of the constraint
+ (false = constraint is violated, true = constraint is satisfied). It
+ returns nullptr if the constraint does not support this API.
+ """
+ return_pywrapcp.Constraint_Var(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.Constraint___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.Constraint___str__(self)
+
+ def__add__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___add__(self,*args)
+
+ def__radd__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___radd__(self,v)
+
+ def__sub__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___sub__(self,*args)
+
+ def__rsub__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___rsub__(self,v)
+
+ def__mul__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___mul__(self,*args)
+
+ def__rmul__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___rmul__(self,v)
+
+ def__floordiv__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___floordiv__(self,v)
+
+ def__neg__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___neg__(self)
+
+ def__abs__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___abs__(self)
+
+ defSquare(self)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint_Square(self)
+
+ def__eq__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___eq__(self,*args)
+
+ def__ne__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___ne__(self,*args)
+
+ def__ge__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___ge__(self,*args)
+
+ def__gt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___gt__(self,*args)
+
+ def__le__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___le__(self,*args)
+
+ def__lt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___lt__(self,*args)
+
+ defMapTo(self,vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ return_pywrapcp.Constraint_MapTo(self,vars)
+
+ defIndexOf(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint_IndexOf(self,*args)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_Constraint(self)
+ returnweakref.proxy(self)
+
+# Register Constraint in _pywrapcp:
+_pywrapcp.Constraint_swigregister(Constraint)
+
+classSearchMonitor(BaseObject):
+ r""" A search monitor is a simple set of callbacks to monitor all search events"""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,s:"Solver"):
+ ifself.__class__==SearchMonitor:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.SearchMonitor_swiginit(self,_pywrapcp.new_SearchMonitor(_self,s))
+ __swig_destroy__=_pywrapcp.delete_SearchMonitor
+
+ defEnterSearch(self)->"void":
+ r""" Beginning of the search."""
+ return_pywrapcp.SearchMonitor_EnterSearch(self)
+
+ defRestartSearch(self)->"void":
+ r""" Restart the search."""
+ return_pywrapcp.SearchMonitor_RestartSearch(self)
+
+ defExitSearch(self)->"void":
+ r""" End of the search."""
+ return_pywrapcp.SearchMonitor_ExitSearch(self)
+
+ defBeginNextDecision(self,b:"DecisionBuilder")->"void":
+ r""" Before calling DecisionBuilder::Next."""
+ return_pywrapcp.SearchMonitor_BeginNextDecision(self,b)
+
+ defEndNextDecision(self,b:"DecisionBuilder",d:"Decision")->"void":
+ r""" After calling DecisionBuilder::Next, along with the returned decision."""
+ return_pywrapcp.SearchMonitor_EndNextDecision(self,b,d)
+
+ defApplyDecision(self,d:"Decision")->"void":
+ r""" Before applying the decision."""
+ return_pywrapcp.SearchMonitor_ApplyDecision(self,d)
+
+ defRefuteDecision(self,d:"Decision")->"void":
+ r""" Before refuting the decision."""
+ return_pywrapcp.SearchMonitor_RefuteDecision(self,d)
+
+ defAfterDecision(self,d:"Decision",apply:"bool")->"void":
+ r"""
+ Just after refuting or applying the decision, apply is true after Apply.
+ This is called only if the Apply() or Refute() methods have not failed.
+ """
+ return_pywrapcp.SearchMonitor_AfterDecision(self,d,apply)
+
+ defBeginFail(self)->"void":
+ r""" Just when the failure occurs."""
+ return_pywrapcp.SearchMonitor_BeginFail(self)
+
+ defEndFail(self)->"void":
+ r""" After completing the backtrack."""
+ return_pywrapcp.SearchMonitor_EndFail(self)
+
+ defBeginInitialPropagation(self)->"void":
+ r""" Before the initial propagation."""
+ return_pywrapcp.SearchMonitor_BeginInitialPropagation(self)
+
+ defEndInitialPropagation(self)->"void":
+ r""" After the initial propagation."""
+ return_pywrapcp.SearchMonitor_EndInitialPropagation(self)
+
+ defAcceptSolution(self)->"bool":
+ r"""
+ This method is called when a solution is found. It asserts whether the
+ solution is valid. A value of false indicates that the solution
+ should be discarded.
+ """
+ return_pywrapcp.SearchMonitor_AcceptSolution(self)
+
+ defAtSolution(self)->"bool":
+ r"""
+ This method is called when a valid solution is found. If the
+ return value is true, then search will resume after. If the result
+ is false, then search will stop there.
+ """
+ return_pywrapcp.SearchMonitor_AtSolution(self)
+
+ defNoMoreSolutions(self)->"void":
+ r""" When the search tree is finished."""
+ return_pywrapcp.SearchMonitor_NoMoreSolutions(self)
+
+ defLocalOptimum(self)->"bool":
+ r"""
+ When a local optimum is reached. If 'true' is returned, the last solution
+ is discarded and the search proceeds with the next one.
+ """
+ return_pywrapcp.SearchMonitor_LocalOptimum(self)
+
+ defAcceptDelta(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+
+ return_pywrapcp.SearchMonitor_AcceptDelta(self,delta,deltadelta)
+
+ defAcceptNeighbor(self)->"void":
+ r""" After accepting a neighbor during local search."""
+ return_pywrapcp.SearchMonitor_AcceptNeighbor(self)
+
+ defsolver(self)->"operations_research::Solver *":
+ return_pywrapcp.SearchMonitor_solver(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.SearchMonitor___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.SearchMonitor___str__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_SearchMonitor(self)
+ returnweakref.proxy(self)
+
+# Register SearchMonitor in _pywrapcp:
+_pywrapcp.SearchMonitor_swigregister(SearchMonitor)
+
+classIntExpr(PropagationBaseObject):
+ r"""
+ The class IntExpr is the base of all integer expressions in
+ constraint programming.
+ It contains the basic protocol for an expression:
+ - setting and modifying its bound
+ - querying if it is bound
+ - listening to events modifying its bounds
+ - casting it into a variable (instance of IntVar)
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+
+ defMin(self)->"int64_t":
+ return_pywrapcp.IntExpr_Min(self)
+
+ defSetMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntExpr_SetMin(self,m)
+
+ defMax(self)->"int64_t":
+ return_pywrapcp.IntExpr_Max(self)
+
+ defSetMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntExpr_SetMax(self,m)
+
+ defSetRange(self,l:"int64_t",u:"int64_t")->"void":
+ r""" This method sets both the min and the max of the expression."""
+ return_pywrapcp.IntExpr_SetRange(self,l,u)
+
+ defSetValue(self,v:"int64_t")->"void":
+ r""" This method sets the value of the expression."""
+ return_pywrapcp.IntExpr_SetValue(self,v)
+
+ defBound(self)->"bool":
+ r""" Returns true if the min and the max of the expression are equal."""
+ return_pywrapcp.IntExpr_Bound(self)
+
+ defIsVar(self)->"bool":
+ r""" Returns true if the expression is indeed a variable."""
+ return_pywrapcp.IntExpr_IsVar(self)
+
+ defVar(self)->"operations_research::IntVar *":
+ r""" Creates a variable from the expression."""
+ return_pywrapcp.IntExpr_Var(self)
+
+ defVarWithName(self,name:"std::string const &")->"operations_research::IntVar *":
+ r"""
+ Creates a variable from the expression and set the name of the
+ resulting var. If the expression is already a variable, then it
+ will set the name of the expression, possibly overwriting it.
+ This is just a shortcut to Var() followed by set_name().
+ """
+ return_pywrapcp.IntExpr_VarWithName(self,name)
+
+ defWhenRange(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Attach a demon that will watch the min or the max of the expression.
+
+ |
+
+ *Overload 2:*
+ Attach a demon that will watch the min or the max of the expression.
+ """
+ return_pywrapcp.IntExpr_WhenRange(self,*args)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.IntExpr___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.IntExpr___str__(self)
+
+ def__add__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___add__(self,*args)
+
+ def__radd__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___radd__(self,v)
+
+ def__sub__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___sub__(self,*args)
+
+ def__rsub__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___rsub__(self,v)
+
+ def__mul__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___mul__(self,*args)
+
+ def__rmul__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___rmul__(self,v)
+
+ def__floordiv__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___floordiv__(self,*args)
+
+ def__mod__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___mod__(self,*args)
+
+ def__neg__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___neg__(self)
+
+ def__abs__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___abs__(self)
+
+ defSquare(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr_Square(self)
+
+ def__eq__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___eq__(self,*args)
+
+ def__ne__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___ne__(self,*args)
+
+ def__ge__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___ge__(self,*args)
+
+ def__gt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___gt__(self,*args)
+
+ def__le__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___le__(self,*args)
+
+ def__lt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___lt__(self,*args)
+
+ defMapTo(self,vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr_MapTo(self,vars)
+
+ defIndexOf(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr_IndexOf(self,*args)
+
+ defIsMember(self,values:"std::vector< int64_t > const &")->"operations_research::IntVar *":
+ return_pywrapcp.IntExpr_IsMember(self,values)
+
+ defMember(self,values:"std::vector< int64_t > const &")->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr_Member(self,values)
+
+ defNotMember(self,starts:"std::vector< int64_t > const &",ends:"std::vector< int64_t > const &")->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr_NotMember(self,starts,ends)
+
+# Register IntExpr in _pywrapcp:
+_pywrapcp.IntExpr_swigregister(IntExpr)
+
+classIntVarIterator(BaseObject):
+ r"""
+ The class Iterator has two direct subclasses. HoleIterators
+ iterates over all holes, that is value removed between the
+ current min and max of the variable since the last time the
+ variable was processed in the queue. DomainIterators iterates
+ over all elements of the variable domain. Both iterators are not
+ robust to domain changes. Hole iterators can also report values outside
+ the current min and max of the variable.
+ HoleIterators should only be called from a demon attached to the
+ variable that has created this iterator.
+ IntVar* current_var;
+ std::unique_ptr<IntVarIterator> it(current_var->MakeHoleIterator(false));
+ for (const int64_t hole : InitAndGetValues(it)) {
+ use the hole
+ }
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defInit(self)->"void":
+ r""" This method must be called before each loop."""
+ return_pywrapcp.IntVarIterator_Init(self)
+
+ defOk(self)->"bool":
+ r""" This method indicates if we can call Value() or not."""
+ return_pywrapcp.IntVarIterator_Ok(self)
+
+ defValue(self)->"int64_t":
+ r""" This method returns the current value of the iterator."""
+ return_pywrapcp.IntVarIterator_Value(self)
+
+ defNext(self)->"void":
+ r""" This method moves the iterator to the next value."""
+ return_pywrapcp.IntVarIterator_Next(self)
+
+ defDebugString(self)->"std::string":
+ r""" Pretty Print."""
+ return_pywrapcp.IntVarIterator_DebugString(self)
+
+ def__iter__(self):
+ self.Init()
+ returnself
+
+ defnext(self):
+ ifself.Ok():
+ result=self.Value()
+ self.Next()
+ returnresult
+ else:
+ raiseStopIteration()
+
+ def__next__(self):
+ returnself.next()
+
+
+# Register IntVarIterator in _pywrapcp:
+_pywrapcp.IntVarIterator_swigregister(IntVarIterator)
+
+classIntVar(IntExpr):
+ r"""
+ The class IntVar is a subset of IntExpr. In addition to the
+ IntExpr protocol, it offers persistence, removing values from the domains,
+ and a finer model for events.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+
+ defIsVar(self)->"bool":
+ return_pywrapcp.IntVar_IsVar(self)
+
+ defVar(self)->"operations_research::IntVar *":
+ return_pywrapcp.IntVar_Var(self)
+
+ defValue(self)->"int64_t":
+ r"""
+ This method returns the value of the variable. This method checks
+ before that the variable is bound.
+ """
+ return_pywrapcp.IntVar_Value(self)
+
+ defRemoveValue(self,v:"int64_t")->"void":
+ r""" This method removes the value 'v' from the domain of the variable."""
+ return_pywrapcp.IntVar_RemoveValue(self,v)
+
+ defRemoveInterval(self,l:"int64_t",u:"int64_t")->"void":
+ r"""
+ This method removes the interval 'l' .. 'u' from the domain of
+ the variable. It assumes that 'l' <= 'u'.
+ """
+ return_pywrapcp.IntVar_RemoveInterval(self,l,u)
+
+ defRemoveValues(self,values:"std::vector< int64_t > const &")->"void":
+ r""" This method remove the values from the domain of the variable."""
+ return_pywrapcp.IntVar_RemoveValues(self,values)
+
+ defSetValues(self,values:"std::vector< int64_t > const &")->"void":
+ r""" This method intersects the current domain with the values in the array."""
+ return_pywrapcp.IntVar_SetValues(self,values)
+
+ defWhenBound(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This method attaches a demon that will be awakened when the
+ variable is bound.
+
+ |
+
+ *Overload 2:*
+ This method attaches a closure that will be awakened when the
+ variable is bound.
+ """
+ return_pywrapcp.IntVar_WhenBound(self,*args)
+
+ defWhenDomain(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This method attaches a demon that will watch any domain
+ modification of the domain of the variable.
+
+ |
+
+ *Overload 2:*
+ This method attaches a closure that will watch any domain
+ modification of the domain of the variable.
+ """
+ return_pywrapcp.IntVar_WhenDomain(self,*args)
+
+ defSize(self)->"uint64_t":
+ r""" This method returns the number of values in the domain of the variable."""
+ return_pywrapcp.IntVar_Size(self)
+
+ defContains(self,v:"int64_t")->"bool":
+ r"""
+ This method returns whether the value 'v' is in the domain of the
+ variable.
+ """
+ return_pywrapcp.IntVar_Contains(self,v)
+
+ defHoleIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ r"""
+ Creates a hole iterator. When 'reversible' is false, the returned
+ object is created on the normal C++ heap and the solver does NOT
+ take ownership of the object.
+ """
+ return_pywrapcp.IntVar_HoleIteratorAux(self,reversible)
+
+ defDomainIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ r"""
+ Creates a domain iterator. When 'reversible' is false, the
+ returned object is created on the normal C++ heap and the solver
+ does NOT take ownership of the object.
+ """
+ return_pywrapcp.IntVar_DomainIteratorAux(self,reversible)
+
+ defOldMin(self)->"int64_t":
+ r""" Returns the previous min."""
+ return_pywrapcp.IntVar_OldMin(self)
+
+ defOldMax(self)->"int64_t":
+ r""" Returns the previous max."""
+ return_pywrapcp.IntVar_OldMax(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.IntVar___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.IntVar___str__(self)
+
+ defDomainIterator(self):
+ returniter(self.DomainIteratorAux(False))
+
+ defHoleIterator(self):
+ returniter(self.HoleIteratorAux(False))
+
+
+# Register IntVar in _pywrapcp:
+_pywrapcp.IntVar_swigregister(IntVar)
+
+classSolutionCollector(SearchMonitor):
+ r"""
+ This class is the root class of all solution collectors.
+ It implements a basic query API to be used independently
+ of the collector used.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.SolutionCollector_DebugString(self)
+
+ defAdd(self,*args)->"void":
+ return_pywrapcp.SolutionCollector_Add(self,*args)
+
+ defAddObjective(self,objective:"IntVar")->"void":
+ return_pywrapcp.SolutionCollector_AddObjective(self,objective)
+
+ defEnterSearch(self)->"void":
+ r""" Beginning of the search."""
+ return_pywrapcp.SolutionCollector_EnterSearch(self)
+
+ defSolutionCount(self)->"int":
+ r""" Returns how many solutions were stored during the search."""
+ return_pywrapcp.SolutionCollector_SolutionCount(self)
+
+ defSolution(self,n:"int")->"operations_research::Assignment *":
+ r""" Returns the nth solution."""
+ return_pywrapcp.SolutionCollector_Solution(self,n)
+
+ defWallTime(self,n:"int")->"int64_t":
+ r""" Returns the wall time in ms for the nth solution."""
+ return_pywrapcp.SolutionCollector_WallTime(self,n)
+
+ defBranches(self,n:"int")->"int64_t":
+ r""" Returns the number of branches when the nth solution was found."""
+ return_pywrapcp.SolutionCollector_Branches(self,n)
+
+ defFailures(self,n:"int")->"int64_t":
+ r"""
+ Returns the number of failures encountered at the time of the nth
+ solution.
+ """
+ return_pywrapcp.SolutionCollector_Failures(self,n)
+
+ defObjectiveValue(self,n:"int")->"int64_t":
+ r""" Returns the objective value of the nth solution."""
+ return_pywrapcp.SolutionCollector_ObjectiveValue(self,n)
+
+ defValue(self,n:"int",var:"IntVar")->"int64_t":
+ r""" This is a shortcut to get the Value of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_Value(self,n,var)
+
+ defStartValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the StartValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_StartValue(self,n,var)
+
+ defEndValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the EndValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_EndValue(self,n,var)
+
+ defDurationValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the DurationValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_DurationValue(self,n,var)
+
+ defPerformedValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the PerformedValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_PerformedValue(self,n,var)
+
+ defForwardSequence(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the ForwardSequence of 'var' in the
+ nth solution. The forward sequence is the list of ranked interval
+ variables starting from the start of the sequence.
+ """
+ return_pywrapcp.SolutionCollector_ForwardSequence(self,n,var)
+
+ defBackwardSequence(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the BackwardSequence of 'var' in the
+ nth solution. The backward sequence is the list of ranked interval
+ variables starting from the end of the sequence.
+ """
+ return_pywrapcp.SolutionCollector_BackwardSequence(self,n,var)
+
+ defUnperformed(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the list of unperformed of 'var' in the
+ nth solution.
+ """
+ return_pywrapcp.SolutionCollector_Unperformed(self,n,var)
+
+# Register SolutionCollector in _pywrapcp:
+_pywrapcp.SolutionCollector_swigregister(SolutionCollector)
+
+classOptimizeVar(SearchMonitor):
+ r"""
+ This class encapsulates an objective. It requires the direction
+ (minimize or maximize), the variable to optimize, and the
+ improvement step.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defBest(self)->"int64_t":
+ r""" Returns the best value found during search."""
+ return_pywrapcp.OptimizeVar_Best(self)
+
+ defVar(self)->"operations_research::IntVar *":
+ r""" Returns the variable that is optimized."""
+ return_pywrapcp.OptimizeVar_Var(self)
+
+ defAcceptDelta(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+ r""" Internal methods."""
+ return_pywrapcp.OptimizeVar_AcceptDelta(self,delta,deltadelta)
+
+ defEnterSearch(self)->"void":
+ return_pywrapcp.OptimizeVar_EnterSearch(self)
+
+ defBeginNextDecision(self,db:"DecisionBuilder")->"void":
+ return_pywrapcp.OptimizeVar_BeginNextDecision(self,db)
+
+ defRefuteDecision(self,d:"Decision")->"void":
+ return_pywrapcp.OptimizeVar_RefuteDecision(self,d)
+
+ defAtSolution(self)->"bool":
+ return_pywrapcp.OptimizeVar_AtSolution(self)
+
+ defAcceptSolution(self)->"bool":
+ return_pywrapcp.OptimizeVar_AcceptSolution(self)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.OptimizeVar_DebugString(self)
+
+# Register OptimizeVar in _pywrapcp:
+_pywrapcp.OptimizeVar_swigregister(OptimizeVar)
+
+classSearchLimit(SearchMonitor):
+ r""" Base class of all search limits."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+ __swig_destroy__=_pywrapcp.delete_SearchLimit
+
+ defCrossed(self)->"bool":
+ r""" Returns true if the limit has been crossed."""
+ return_pywrapcp.SearchLimit_Crossed(self)
+
+ defCheck(self)->"bool":
+ r"""
+ This method is called to check the status of the limit. A return
+ value of true indicates that we have indeed crossed the limit. In
+ that case, this method will not be called again and the remaining
+ search will be discarded.
+ """
+ return_pywrapcp.SearchLimit_Check(self)
+
+ defInit(self)->"void":
+ r""" This method is called when the search limit is initialized."""
+ return_pywrapcp.SearchLimit_Init(self)
+
+ defEnterSearch(self)->"void":
+ r""" Internal methods."""
+ return_pywrapcp.SearchLimit_EnterSearch(self)
+
+ defBeginNextDecision(self,b:"DecisionBuilder")->"void":
+ return_pywrapcp.SearchLimit_BeginNextDecision(self,b)
+
+ defRefuteDecision(self,d:"Decision")->"void":
+ return_pywrapcp.SearchLimit_RefuteDecision(self,d)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.SearchLimit_DebugString(self)
+
+# Register SearchLimit in _pywrapcp:
+_pywrapcp.SearchLimit_swigregister(SearchLimit)
+
+classIntervalVar(PropagationBaseObject):
+ r"""
+ Interval variables are often used in scheduling. The main characteristics
+ of an IntervalVar are the start position, duration, and end
+ date. All these characteristics can be queried and set, and demons can
+ be posted on their modifications.
+
+ An important aspect is optionality: an IntervalVar can be performed or not.
+ If unperformed, then it simply does not exist, and its characteristics
+ cannot be accessed any more. An interval var is automatically marked
+ as unperformed when it is not consistent anymore (start greater
+ than end, duration < 0...)
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+
+ defStartMin(self)->"int64_t":
+ r"""
+ These methods query, set, and watch the start position of the
+ interval var.
+ """
+ return_pywrapcp.IntervalVar_StartMin(self)
+
+ defStartMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_StartMax(self)
+
+ defSetStartMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetStartMin(self,m)
+
+ defSetStartMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetStartMax(self,m)
+
+ defSetStartRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetStartRange(self,mi,ma)
+
+ defOldStartMin(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldStartMin(self)
+
+ defOldStartMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldStartMax(self)
+
+ defWhenStartRange(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenStartRange(self,*args)
+
+ defWhenStartBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenStartBound(self,*args)
+
+ defDurationMin(self)->"int64_t":
+ r""" These methods query, set, and watch the duration of the interval var."""
+ return_pywrapcp.IntervalVar_DurationMin(self)
+
+ defDurationMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_DurationMax(self)
+
+ defSetDurationMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetDurationMin(self,m)
+
+ defSetDurationMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetDurationMax(self,m)
+
+ defSetDurationRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetDurationRange(self,mi,ma)
+
+ defOldDurationMin(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldDurationMin(self)
+
+ defOldDurationMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldDurationMax(self)
+
+ defWhenDurationRange(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenDurationRange(self,*args)
+
+ defWhenDurationBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenDurationBound(self,*args)
+
+ defEndMin(self)->"int64_t":
+ r""" These methods query, set, and watch the end position of the interval var."""
+ return_pywrapcp.IntervalVar_EndMin(self)
+
+ defEndMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_EndMax(self)
+
+ defSetEndMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetEndMin(self,m)
+
+ defSetEndMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetEndMax(self,m)
+
+ defSetEndRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetEndRange(self,mi,ma)
+
+ defOldEndMin(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldEndMin(self)
+
+ defOldEndMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldEndMax(self)
+
+ defWhenEndRange(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenEndRange(self,*args)
+
+ defWhenEndBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenEndBound(self,*args)
+
+ defMustBePerformed(self)->"bool":
+ r"""
+ These methods query, set, and watch the performed status of the
+ interval var.
+ """
+ return_pywrapcp.IntervalVar_MustBePerformed(self)
+
+ defMayBePerformed(self)->"bool":
+ return_pywrapcp.IntervalVar_MayBePerformed(self)
+
+ defCannotBePerformed(self)->"bool":
+ return_pywrapcp.IntervalVar_CannotBePerformed(self)
+
+ defIsPerformedBound(self)->"bool":
+ return_pywrapcp.IntervalVar_IsPerformedBound(self)
+
+ defSetPerformed(self,val:"bool")->"void":
+ return_pywrapcp.IntervalVar_SetPerformed(self,val)
+
+ defWasPerformedBound(self)->"bool":
+ return_pywrapcp.IntervalVar_WasPerformedBound(self)
+
+ defWhenPerformedBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenPerformedBound(self,*args)
+
+ defWhenAnything(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Attaches a demon awakened when anything about this interval changes.
+
+ |
+
+ *Overload 2:*
+ Attaches a closure awakened when anything about this interval changes.
+ """
+ return_pywrapcp.IntervalVar_WhenAnything(self,*args)
+
+ defStartExpr(self)->"operations_research::IntExpr *":
+ r"""
+ These methods create expressions encapsulating the start, end
+ and duration of the interval var. Please note that these must not
+ be used if the interval var is unperformed.
+ """
+ return_pywrapcp.IntervalVar_StartExpr(self)
+
+ defDurationExpr(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_DurationExpr(self)
+
+ defEndExpr(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_EndExpr(self)
+
+ defPerformedExpr(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_PerformedExpr(self)
+
+ defSafeStartExpr(self,unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ These methods create expressions encapsulating the start, end
+ and duration of the interval var. If the interval var is
+ unperformed, they will return the unperformed_value.
+ """
+ return_pywrapcp.IntervalVar_SafeStartExpr(self,unperformed_value)
+
+ defSafeDurationExpr(self,unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_SafeDurationExpr(self,unperformed_value)
+
+ defSafeEndExpr(self,unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_SafeEndExpr(self,unperformed_value)
+
+ defEndsAfterEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterEnd(self,other)
+
+ defEndsAfterEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterEndWithDelay(self,other,delay)
+
+ defEndsAfterStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterStart(self,other)
+
+ defEndsAfterStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterStartWithDelay(self,other,delay)
+
+ defEndsAtEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtEnd(self,other)
+
+ defEndsAtEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtEndWithDelay(self,other,delay)
+
+ defEndsAtStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtStart(self,other)
+
+ defEndsAtStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtStartWithDelay(self,other,delay)
+
+ defStartsAfterEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterEnd(self,other)
+
+ defStartsAfterEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterEndWithDelay(self,other,delay)
+
+ defStartsAfterStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterStart(self,other)
+
+ defStartsAfterStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterStartWithDelay(self,other,delay)
+
+ defStartsAtEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtEnd(self,other)
+
+ defStartsAtEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtEndWithDelay(self,other,delay)
+
+ defStartsAtStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtStart(self,other)
+
+ defStartsAtStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtStartWithDelay(self,other,delay)
+
+ defStaysInSync(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StaysInSync(self,other)
+
+ defStaysInSyncWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StaysInSyncWithDelay(self,other,delay)
+
+ defEndsAfter(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfter(self,date)
+
+ defEndsAt(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAt(self,date)
+
+ defEndsBefore(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsBefore(self,date)
+
+ defStartsAfter(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfter(self,date)
+
+ defStartsAt(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAt(self,date)
+
+ defStartsBefore(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsBefore(self,date)
+
+ defCrossesDate(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_CrossesDate(self,date)
+
+ defAvoidsDate(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_AvoidsDate(self,date)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.IntervalVar___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.IntervalVar___str__(self)
+
+# Register IntervalVar in _pywrapcp:
+_pywrapcp.IntervalVar_swigregister(IntervalVar)
+
+classSequenceVar(PropagationBaseObject):
+ r"""
+ A sequence variable is a variable whose domain is a set of possible
+ orderings of the interval variables. It allows ordering of tasks. It
+ has two sets of methods: ComputePossibleFirstsAndLasts(), which
+ returns the list of interval variables that can be ranked first or
+ last; and RankFirst/RankNotFirst/RankLast/RankNotLast, which can be
+ used to create the search decision.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.SequenceVar_DebugString(self)
+
+ defRankFirst(self,index:"int")->"void":
+ r"""
+ Ranks the index_th interval var first of all unranked interval
+ vars. After that, it will no longer be considered ranked.
+ """
+ return_pywrapcp.SequenceVar_RankFirst(self,index)
+
+ defRankNotFirst(self,index:"int")->"void":
+ r"""
+ Indicates that the index_th interval var will not be ranked first
+ of all currently unranked interval vars.
+ """
+ return_pywrapcp.SequenceVar_RankNotFirst(self,index)
+
+ defRankLast(self,index:"int")->"void":
+ r"""
+ Ranks the index_th interval var first of all unranked interval
+ vars. After that, it will no longer be considered ranked.
+ """
+ return_pywrapcp.SequenceVar_RankLast(self,index)
+
+ defRankNotLast(self,index:"int")->"void":
+ r"""
+ Indicates that the index_th interval var will not be ranked first
+ of all currently unranked interval vars.
+ """
+ return_pywrapcp.SequenceVar_RankNotLast(self,index)
+
+ defInterval(self,index:"int")->"operations_research::IntervalVar *":
+ r""" Returns the index_th interval of the sequence."""
+ return_pywrapcp.SequenceVar_Interval(self,index)
+
+ defNext(self,index:"int")->"operations_research::IntVar *":
+ r""" Returns the next of the index_th interval of the sequence."""
+ return_pywrapcp.SequenceVar_Next(self,index)
+
+ defSize(self)->"int64_t":
+ r""" Returns the number of interval vars in the sequence."""
+ return_pywrapcp.SequenceVar_Size(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.SequenceVar___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.SequenceVar___str__(self)
+
+# Register SequenceVar in _pywrapcp:
+_pywrapcp.SequenceVar_swigregister(SequenceVar)
+
+classAssignmentElement(object):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defActivate(self)->"void":
+ return_pywrapcp.AssignmentElement_Activate(self)
+
+ defDeactivate(self)->"void":
+ return_pywrapcp.AssignmentElement_Deactivate(self)
+
+ defActivated(self)->"bool":
+ return_pywrapcp.AssignmentElement_Activated(self)
+ __swig_destroy__=_pywrapcp.delete_AssignmentElement
+
+# Register AssignmentElement in _pywrapcp:
+_pywrapcp.AssignmentElement_swigregister(AssignmentElement)
+
+classIntVarElement(AssignmentElement):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defVar(self)->"operations_research::IntVar *":
+ return_pywrapcp.IntVarElement_Var(self)
+
+ defMin(self)->"int64_t":
+ return_pywrapcp.IntVarElement_Min(self)
+
+ defSetMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntVarElement_SetMin(self,m)
+
+ defMax(self)->"int64_t":
+ return_pywrapcp.IntVarElement_Max(self)
+
+ defSetMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntVarElement_SetMax(self,m)
+
+ defValue(self)->"int64_t":
+ return_pywrapcp.IntVarElement_Value(self)
+
+ defBound(self)->"bool":
+ return_pywrapcp.IntVarElement_Bound(self)
+
+ defSetRange(self,l:"int64_t",u:"int64_t")->"void":
+ return_pywrapcp.IntVarElement_SetRange(self,l,u)
+
+ defSetValue(self,v:"int64_t")->"void":
+ return_pywrapcp.IntVarElement_SetValue(self,v)
+
+ def__eq__(self,element:"IntVarElement")->"bool":
+ return_pywrapcp.IntVarElement___eq__(self,element)
+
+ def__ne__(self,element:"IntVarElement")->"bool":
+ return_pywrapcp.IntVarElement___ne__(self,element)
+ __swig_destroy__=_pywrapcp.delete_IntVarElement
+
+# Register IntVarElement in _pywrapcp:
+_pywrapcp.IntVarElement_swigregister(IntVarElement)
+
+classIntervalVarElement(AssignmentElement):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defVar(self)->"operations_research::IntervalVar *":
+ return_pywrapcp.IntervalVarElement_Var(self)
+
+ defStartMin(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_StartMin(self)
+
+ defStartMax(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_StartMax(self)
+
+ defStartValue(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_StartValue(self)
+
+ defDurationMin(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_DurationMin(self)
+
+ defDurationMax(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_DurationMax(self)
+
+ defDurationValue(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_DurationValue(self)
+
+ defEndMin(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_EndMin(self)
+
+ defEndMax(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_EndMax(self)
+
+ defEndValue(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_EndValue(self)
+
+ defPerformedMin(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_PerformedMin(self)
+
+ defPerformedMax(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_PerformedMax(self)
+
+ defPerformedValue(self)->"int64_t":
+ return_pywrapcp.IntervalVarElement_PerformedValue(self)
+
+ defSetStartMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetStartMin(self,m)
+
+ defSetStartMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetStartMax(self,m)
+
+ defSetStartRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetStartRange(self,mi,ma)
+
+ defSetStartValue(self,v:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetStartValue(self,v)
+
+ defSetDurationMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetDurationMin(self,m)
+
+ defSetDurationMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetDurationMax(self,m)
+
+ defSetDurationRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetDurationRange(self,mi,ma)
+
+ defSetDurationValue(self,v:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetDurationValue(self,v)
+
+ defSetEndMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetEndMin(self,m)
+
+ defSetEndMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetEndMax(self,m)
+
+ defSetEndRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetEndRange(self,mi,ma)
+
+ defSetEndValue(self,v:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetEndValue(self,v)
+
+ defSetPerformedMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetPerformedMin(self,m)
+
+ defSetPerformedMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetPerformedMax(self,m)
+
+ defSetPerformedRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetPerformedRange(self,mi,ma)
+
+ defSetPerformedValue(self,v:"int64_t")->"void":
+ return_pywrapcp.IntervalVarElement_SetPerformedValue(self,v)
+
+ def__eq__(self,element:"IntervalVarElement")->"bool":
+ return_pywrapcp.IntervalVarElement___eq__(self,element)
+
+ def__ne__(self,element:"IntervalVarElement")->"bool":
+ return_pywrapcp.IntervalVarElement___ne__(self,element)
+ __swig_destroy__=_pywrapcp.delete_IntervalVarElement
+
+# Register IntervalVarElement in _pywrapcp:
+_pywrapcp.IntervalVarElement_swigregister(IntervalVarElement)
+
+classSequenceVarElement(AssignmentElement):
+ r"""
+ The SequenceVarElement stores a partial representation of ranked
+ interval variables in the underlying sequence variable.
+ This representation consists of three vectors:
+ - the forward sequence. That is the list of interval variables
+ ranked first in the sequence. The first element of the backward
+ sequence is the first interval in the sequence variable.
+ - the backward sequence. That is the list of interval variables
+ ranked last in the sequence. The first element of the backward
+ sequence is the last interval in the sequence variable.
+ - The list of unperformed interval variables.
+ Furthermore, if all performed variables are ranked, then by
+ convention, the forward_sequence will contain all such variables
+ and the backward_sequence will be empty.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defVar(self)->"operations_research::SequenceVar *":
+ return_pywrapcp.SequenceVarElement_Var(self)
+
+ defForwardSequence(self)->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarElement_ForwardSequence(self)
+
+ defBackwardSequence(self)->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarElement_BackwardSequence(self)
+
+ defUnperformed(self)->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarElement_Unperformed(self)
+
+ defSetSequence(self,forward_sequence:"std::vector< int > const &",backward_sequence:"std::vector< int > const &",unperformed:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetSequence(self,forward_sequence,backward_sequence,unperformed)
+
+ defSetForwardSequence(self,forward_sequence:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetForwardSequence(self,forward_sequence)
+
+ defSetBackwardSequence(self,backward_sequence:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetBackwardSequence(self,backward_sequence)
+
+ defSetUnperformed(self,unperformed:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetUnperformed(self,unperformed)
+
+ def__eq__(self,element:"SequenceVarElement")->"bool":
+ return_pywrapcp.SequenceVarElement___eq__(self,element)
+
+ def__ne__(self,element:"SequenceVarElement")->"bool":
+ return_pywrapcp.SequenceVarElement___ne__(self,element)
+ __swig_destroy__=_pywrapcp.delete_SequenceVarElement
+
+# Register SequenceVarElement in _pywrapcp:
+_pywrapcp.SequenceVarElement_swigregister(SequenceVarElement)
+
+classAssignment(PropagationBaseObject):
+ r"""
+ An Assignment is a variable -> domains mapping, used
+ to report solutions to the user.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defClear(self)->"void":
+ return_pywrapcp.Assignment_Clear(self)
+
+ defEmpty(self)->"bool":
+ return_pywrapcp.Assignment_Empty(self)
+
+ defSize(self)->"int":
+ return_pywrapcp.Assignment_Size(self)
+
+ defNumIntVars(self)->"int":
+ return_pywrapcp.Assignment_NumIntVars(self)
+
+ defNumIntervalVars(self)->"int":
+ return_pywrapcp.Assignment_NumIntervalVars(self)
+
+ defNumSequenceVars(self)->"int":
+ return_pywrapcp.Assignment_NumSequenceVars(self)
+
+ defStore(self)->"void":
+ return_pywrapcp.Assignment_Store(self)
+
+ defRestore(self)->"void":
+ return_pywrapcp.Assignment_Restore(self)
+
+ defLoad(self,*args)->"void":
+ return_pywrapcp.Assignment_Load(self,*args)
+
+ defSave(self,*args)->"void":
+ return_pywrapcp.Assignment_Save(self,*args)
+
+ defAddObjective(self,v:"IntVar")->"void":
+ return_pywrapcp.Assignment_AddObjective(self,v)
+
+ defObjective(self)->"operations_research::IntVar *":
+ return_pywrapcp.Assignment_Objective(self)
+
+ defHasObjective(self)->"bool":
+ return_pywrapcp.Assignment_HasObjective(self)
+
+ defObjectiveMin(self)->"int64_t":
+ return_pywrapcp.Assignment_ObjectiveMin(self)
+
+ defObjectiveMax(self)->"int64_t":
+ return_pywrapcp.Assignment_ObjectiveMax(self)
+
+ defObjectiveValue(self)->"int64_t":
+ return_pywrapcp.Assignment_ObjectiveValue(self)
+
+ defObjectiveBound(self)->"bool":
+ return_pywrapcp.Assignment_ObjectiveBound(self)
+
+ defSetObjectiveMin(self,m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetObjectiveMin(self,m)
+
+ defSetObjectiveMax(self,m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetObjectiveMax(self,m)
+
+ defSetObjectiveValue(self,value:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetObjectiveValue(self,value)
+
+ defSetObjectiveRange(self,l:"int64_t",u:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetObjectiveRange(self,l,u)
+
+ defMin(self,var:"IntVar")->"int64_t":
+ return_pywrapcp.Assignment_Min(self,var)
+
+ defMax(self,var:"IntVar")->"int64_t":
+ return_pywrapcp.Assignment_Max(self,var)
+
+ defValue(self,var:"IntVar")->"int64_t":
+ return_pywrapcp.Assignment_Value(self,var)
+
+ defBound(self,var:"IntVar")->"bool":
+ return_pywrapcp.Assignment_Bound(self,var)
+
+ defSetMin(self,var:"IntVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetMin(self,var,m)
+
+ defSetMax(self,var:"IntVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetMax(self,var,m)
+
+ defSetRange(self,var:"IntVar",l:"int64_t",u:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetRange(self,var,l,u)
+
+ defSetValue(self,var:"IntVar",value:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetValue(self,var,value)
+
+ defStartMin(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_StartMin(self,var)
+
+ defStartMax(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_StartMax(self,var)
+
+ defStartValue(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_StartValue(self,var)
+
+ defDurationMin(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_DurationMin(self,var)
+
+ defDurationMax(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_DurationMax(self,var)
+
+ defDurationValue(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_DurationValue(self,var)
+
+ defEndMin(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_EndMin(self,var)
+
+ defEndMax(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_EndMax(self,var)
+
+ defEndValue(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_EndValue(self,var)
+
+ defPerformedMin(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_PerformedMin(self,var)
+
+ defPerformedMax(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_PerformedMax(self,var)
+
+ defPerformedValue(self,var:"IntervalVar")->"int64_t":
+ return_pywrapcp.Assignment_PerformedValue(self,var)
+
+ defSetStartMin(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetStartMin(self,var,m)
+
+ defSetStartMax(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetStartMax(self,var,m)
+
+ defSetStartRange(self,var:"IntervalVar",mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetStartRange(self,var,mi,ma)
+
+ defSetStartValue(self,var:"IntervalVar",value:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetStartValue(self,var,value)
+
+ defSetDurationMin(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetDurationMin(self,var,m)
+
+ defSetDurationMax(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetDurationMax(self,var,m)
+
+ defSetDurationRange(self,var:"IntervalVar",mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetDurationRange(self,var,mi,ma)
+
+ defSetDurationValue(self,var:"IntervalVar",value:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetDurationValue(self,var,value)
+
+ defSetEndMin(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetEndMin(self,var,m)
+
+ defSetEndMax(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetEndMax(self,var,m)
+
+ defSetEndRange(self,var:"IntervalVar",mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetEndRange(self,var,mi,ma)
+
+ defSetEndValue(self,var:"IntervalVar",value:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetEndValue(self,var,value)
+
+ defSetPerformedMin(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetPerformedMin(self,var,m)
+
+ defSetPerformedMax(self,var:"IntervalVar",m:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetPerformedMax(self,var,m)
+
+ defSetPerformedRange(self,var:"IntervalVar",mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetPerformedRange(self,var,mi,ma)
+
+ defSetPerformedValue(self,var:"IntervalVar",value:"int64_t")->"void":
+ return_pywrapcp.Assignment_SetPerformedValue(self,var,value)
+
+ defAdd(self,*args)->"void":
+ return_pywrapcp.Assignment_Add(self,*args)
+
+ defForwardSequence(self,var:"SequenceVar")->"std::vector< int > const &":
+ return_pywrapcp.Assignment_ForwardSequence(self,var)
+
+ defBackwardSequence(self,var:"SequenceVar")->"std::vector< int > const &":
+ return_pywrapcp.Assignment_BackwardSequence(self,var)
+
+ defUnperformed(self,var:"SequenceVar")->"std::vector< int > const &":
+ return_pywrapcp.Assignment_Unperformed(self,var)
+
+ defSetSequence(self,var:"SequenceVar",forward_sequence:"std::vector< int > const &",backward_sequence:"std::vector< int > const &",unperformed:"std::vector< int > const &")->"void":
+ return_pywrapcp.Assignment_SetSequence(self,var,forward_sequence,backward_sequence,unperformed)
+
+ defSetForwardSequence(self,var:"SequenceVar",forward_sequence:"std::vector< int > const &")->"void":
+ return_pywrapcp.Assignment_SetForwardSequence(self,var,forward_sequence)
+
+ defSetBackwardSequence(self,var:"SequenceVar",backward_sequence:"std::vector< int > const &")->"void":
+ return_pywrapcp.Assignment_SetBackwardSequence(self,var,backward_sequence)
+
+ defSetUnperformed(self,var:"SequenceVar",unperformed:"std::vector< int > const &")->"void":
+ return_pywrapcp.Assignment_SetUnperformed(self,var,unperformed)
+
+ defActivate(self,*args)->"void":
+ return_pywrapcp.Assignment_Activate(self,*args)
+
+ defDeactivate(self,*args)->"void":
+ return_pywrapcp.Assignment_Deactivate(self,*args)
+
+ defActivated(self,*args)->"bool":
+ return_pywrapcp.Assignment_Activated(self,*args)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Assignment_DebugString(self)
+
+ defIntVarContainer(self)->"operations_research::Assignment::IntContainer const &":
+ return_pywrapcp.Assignment_IntVarContainer(self)
+
+ defMutableIntVarContainer(self)->"operations_research::Assignment::IntContainer *":
+ return_pywrapcp.Assignment_MutableIntVarContainer(self)
+
+ defIntervalVarContainer(self)->"operations_research::Assignment::IntervalContainer const &":
+ return_pywrapcp.Assignment_IntervalVarContainer(self)
+
+ defMutableIntervalVarContainer(self)->"operations_research::Assignment::IntervalContainer *":
+ return_pywrapcp.Assignment_MutableIntervalVarContainer(self)
+
+ defSequenceVarContainer(self)->"operations_research::Assignment::SequenceContainer const &":
+ return_pywrapcp.Assignment_SequenceVarContainer(self)
+
+ defMutableSequenceVarContainer(self)->"operations_research::Assignment::SequenceContainer *":
+ return_pywrapcp.Assignment_MutableSequenceVarContainer(self)
+
+ def__eq__(self,assignment:"Assignment")->"bool":
+ return_pywrapcp.Assignment___eq__(self,assignment)
+
+ def__ne__(self,assignment:"Assignment")->"bool":
+ return_pywrapcp.Assignment___ne__(self,assignment)
+
+# Register Assignment in _pywrapcp:
+_pywrapcp.Assignment_swigregister(Assignment)
+
+
+def__lshift__(*args)->"std::ostream &":
+ return_pywrapcp.__lshift__(*args)
+classPack(Constraint):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defAddWeightedSumLessOrEqualConstantDimension(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Dimensions are additional constraints than can restrict what is
+ possible with the pack constraint. It can be used to set capacity
+ limits, to count objects per bin, to compute unassigned
+ penalties...
+ This dimension imposes that for all bins b, the weighted sum
+ (weights[i]) of all objects i assigned to 'b' is less or equal
+ 'bounds[b]'.
+
+ |
+
+ *Overload 2:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i)) of all objects i assigned to 'b' is less or
+ equal to 'bounds[b]'. Ownership of the callback is transferred to
+ the pack constraint.
+
+ |
+
+ *Overload 3:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i, b) of all objects i assigned to 'b' is less or
+ equal to 'bounds[b]'. Ownership of the callback is transferred to
+ the pack constraint.
+ """
+ return_pywrapcp.Pack_AddWeightedSumLessOrEqualConstantDimension(self,*args)
+
+ defAddWeightedSumEqualVarDimension(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights[i]) of all objects i assigned to 'b' is equal to loads[b].
+
+ |
+
+ *Overload 2:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i, b)) of all objects i assigned to 'b' is equal to
+ loads[b].
+ """
+ return_pywrapcp.Pack_AddWeightedSumEqualVarDimension(self,*args)
+
+ defAddSumVariableWeightsLessOrEqualConstantDimension(self,usage:"std::vector< operations_research::IntVar * > const &",capacity:"std::vector< int64_t > const &")->"void":
+ r"""
+ This dimension imposes:
+ forall b in bins,
+ sum (i in items: usage[i] * is_assigned(i, b)) <= capacity[b]
+ where is_assigned(i, b) is true if and only if item i is assigned
+ to the bin b.
+
+ This can be used to model shapes of items by linking variables of
+ the same item on parallel dimensions with an allowed assignment
+ constraint.
+ """
+ return_pywrapcp.Pack_AddSumVariableWeightsLessOrEqualConstantDimension(self,usage,capacity)
+
+ defAddWeightedSumOfAssignedDimension(self,weights:"std::vector< int64_t > const &",cost_var:"IntVar")->"void":
+ r"""
+ This dimension enforces that cost_var == sum of weights[i] for
+ all objects 'i' assigned to a bin.
+ """
+ return_pywrapcp.Pack_AddWeightedSumOfAssignedDimension(self,weights,cost_var)
+
+ defAddCountUsedBinDimension(self,count_var:"IntVar")->"void":
+ r"""
+ This dimension links 'count_var' to the actual number of bins used in the
+ pack.
+ """
+ return_pywrapcp.Pack_AddCountUsedBinDimension(self,count_var)
+
+ defAddCountAssignedItemsDimension(self,count_var:"IntVar")->"void":
+ r"""
+ This dimension links 'count_var' to the actual number of items
+ assigned to a bin in the pack.
+ """
+ return_pywrapcp.Pack_AddCountAssignedItemsDimension(self,count_var)
+
+ defPost(self)->"void":
+ return_pywrapcp.Pack_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ return_pywrapcp.Pack_InitialPropagateWrapper(self)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Pack_DebugString(self)
+
+# Register Pack in _pywrapcp:
+_pywrapcp.Pack_swigregister(Pack)
+
+classDisjunctiveConstraint(Constraint):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defSequenceVar(self)->"operations_research::SequenceVar *":
+ r""" Creates a sequence variable from the constraint."""
+ return_pywrapcp.DisjunctiveConstraint_SequenceVar(self)
+
+ defSetTransitionTime(self,transition_time:"operations_research::Solver::IndexEvaluator2")->"void":
+ r"""
+ Add a transition time between intervals. It forces the distance between
+ the end of interval a and start of interval b that follows it to be at
+ least transition_time(a, b). This function must always return
+ a positive or null value.
+ """
+ return_pywrapcp.DisjunctiveConstraint_SetTransitionTime(self,transition_time)
+
+ defTransitionTime(self,before_index:"int",after_index:"int")->"int64_t":
+ return_pywrapcp.DisjunctiveConstraint_TransitionTime(self,before_index,after_index)
+
+# Register DisjunctiveConstraint in _pywrapcp:
+_pywrapcp.DisjunctiveConstraint_swigregister(DisjunctiveConstraint)
+
+classRevInteger(object):
+ r"""
+ This class adds reversibility to a POD type.
+ It contains the stamp optimization. i.e. the SaveValue call is done
+ only once per node of the search tree. Please note that actual
+ stamps always starts at 1, thus an initial value of 0 will always
+ trigger the first SaveValue.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,val:"long const &"):
+ _pywrapcp.RevInteger_swiginit(self,_pywrapcp.new_RevInteger(val))
+
+ defValue(self)->"long const &":
+ return_pywrapcp.RevInteger_Value(self)
+
+ defSetValue(self,s:"Solver",val:"long const &")->"void":
+ return_pywrapcp.RevInteger_SetValue(self,s,val)
+ __swig_destroy__=_pywrapcp.delete_RevInteger
+
+# Register RevInteger in _pywrapcp:
+_pywrapcp.RevInteger_swigregister(RevInteger)
+
+classNumericalRevInteger(RevInteger):
+ r""" Subclass of Rev<T> which adds numerical operations."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,val:"long const &"):
+ _pywrapcp.NumericalRevInteger_swiginit(self,_pywrapcp.new_NumericalRevInteger(val))
+
+ defAdd(self,s:"Solver",to_add:"long const &")->"void":
+ return_pywrapcp.NumericalRevInteger_Add(self,s,to_add)
+
+ defIncr(self,s:"Solver")->"void":
+ return_pywrapcp.NumericalRevInteger_Incr(self,s)
+
+ defDecr(self,s:"Solver")->"void":
+ return_pywrapcp.NumericalRevInteger_Decr(self,s)
+ __swig_destroy__=_pywrapcp.delete_NumericalRevInteger
+
+# Register NumericalRevInteger in _pywrapcp:
+_pywrapcp.NumericalRevInteger_swigregister(NumericalRevInteger)
+
+classRevBool(object):
+ r"""
+ This class adds reversibility to a POD type.
+ It contains the stamp optimization. i.e. the SaveValue call is done
+ only once per node of the search tree. Please note that actual
+ stamps always starts at 1, thus an initial value of 0 will always
+ trigger the first SaveValue.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,val:"bool const &"):
+ _pywrapcp.RevBool_swiginit(self,_pywrapcp.new_RevBool(val))
+
+ defValue(self)->"bool const &":
+ return_pywrapcp.RevBool_Value(self)
+
+ defSetValue(self,s:"Solver",val:"bool const &")->"void":
+ return_pywrapcp.RevBool_SetValue(self,s,val)
+ __swig_destroy__=_pywrapcp.delete_RevBool
+
+# Register RevBool in _pywrapcp:
+_pywrapcp.RevBool_swigregister(RevBool)
+
+classIntVarContainer(object):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defContains(self,var:"IntVar")->"bool":
+ return_pywrapcp.IntVarContainer_Contains(self,var)
+
+ defElement(self,index:"int")->"operations_research::IntVarElement *":
+ return_pywrapcp.IntVarContainer_Element(self,index)
+
+ defSize(self)->"int":
+ return_pywrapcp.IntVarContainer_Size(self)
+
+ defStore(self)->"void":
+ return_pywrapcp.IntVarContainer_Store(self)
+
+ defRestore(self)->"void":
+ return_pywrapcp.IntVarContainer_Restore(self)
+
+ def__eq__(self,container:"IntVarContainer")->"bool":
+ r"""
+ Returns true if this and 'container' both represent the same V* -> E map.
+ Runs in linear time; requires that the == operator on the type E is well
+ defined.
+ """
+ return_pywrapcp.IntVarContainer___eq__(self,container)
+
+ def__ne__(self,container:"IntVarContainer")->"bool":
+ return_pywrapcp.IntVarContainer___ne__(self,container)
+ __swig_destroy__=_pywrapcp.delete_IntVarContainer
+
+# Register IntVarContainer in _pywrapcp:
+_pywrapcp.IntVarContainer_swigregister(IntVarContainer)
+
+classIntervalVarContainer(object):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defContains(self,var:"IntervalVar")->"bool":
+ return_pywrapcp.IntervalVarContainer_Contains(self,var)
+
+ defElement(self,index:"int")->"operations_research::IntervalVarElement *":
+ return_pywrapcp.IntervalVarContainer_Element(self,index)
+
+ defSize(self)->"int":
+ return_pywrapcp.IntervalVarContainer_Size(self)
+
+ defStore(self)->"void":
+ return_pywrapcp.IntervalVarContainer_Store(self)
+
+ defRestore(self)->"void":
+ return_pywrapcp.IntervalVarContainer_Restore(self)
+
+ def__eq__(self,container:"IntervalVarContainer")->"bool":
+ r"""
+ Returns true if this and 'container' both represent the same V* -> E map.
+ Runs in linear time; requires that the == operator on the type E is well
+ defined.
+ """
+ return_pywrapcp.IntervalVarContainer___eq__(self,container)
+
+ def__ne__(self,container:"IntervalVarContainer")->"bool":
+ return_pywrapcp.IntervalVarContainer___ne__(self,container)
+ __swig_destroy__=_pywrapcp.delete_IntervalVarContainer
+
+# Register IntervalVarContainer in _pywrapcp:
+_pywrapcp.IntervalVarContainer_swigregister(IntervalVarContainer)
+
+classSequenceVarContainer(object):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defContains(self,var:"SequenceVar")->"bool":
+ return_pywrapcp.SequenceVarContainer_Contains(self,var)
+
+ defElement(self,index:"int")->"operations_research::SequenceVarElement *":
+ return_pywrapcp.SequenceVarContainer_Element(self,index)
+
+ defSize(self)->"int":
+ return_pywrapcp.SequenceVarContainer_Size(self)
+
+ defStore(self)->"void":
+ return_pywrapcp.SequenceVarContainer_Store(self)
+
+ defRestore(self)->"void":
+ return_pywrapcp.SequenceVarContainer_Restore(self)
+
+ def__eq__(self,container:"SequenceVarContainer")->"bool":
+ r"""
+ Returns true if this and 'container' both represent the same V* -> E map.
+ Runs in linear time; requires that the == operator on the type E is well
+ defined.
+ """
+ return_pywrapcp.SequenceVarContainer___eq__(self,container)
+
+ def__ne__(self,container:"SequenceVarContainer")->"bool":
+ return_pywrapcp.SequenceVarContainer___ne__(self,container)
+ __swig_destroy__=_pywrapcp.delete_SequenceVarContainer
+
+# Register SequenceVarContainer in _pywrapcp:
+_pywrapcp.SequenceVarContainer_swigregister(SequenceVarContainer)
+
+classLocalSearchOperator(BaseObject):
+ r"""
+ This class represent a reversible FIFO structure.
+ The main difference w.r.t a standard FIFO structure is that a Solver is
+ given as parameter to the modifiers such that the solver can store the
+ backtrack information
+ Iterator's traversing order should not be changed, as some algorithm
+ depend on it to be consistent.
+ It's main use is to store a list of demons in the various classes of
+ variables.
+ The base class for all local search operators.
+
+ A local search operator is an object that defines the neighborhood of a
+ solution. In other words, a neighborhood is the set of solutions which can
+ be reached from a given solution using an operator.
+
+ The behavior of the LocalSearchOperator class is similar to iterators.
+ The operator is synchronized with an assignment (gives the
+ current values of the variables); this is done in the Start() method.
+
+ Then one can iterate over the neighbors using the MakeNextNeighbor method.
+ This method returns an assignment which represents the incremental changes
+ to the current solution. It also returns a second assignment representing
+ the changes to the last solution defined by the neighborhood operator; this
+ assignment is empty if the neighborhood operator cannot track this
+ information.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defNextNeighbor(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+ return_pywrapcp.LocalSearchOperator_NextNeighbor(self,delta,deltadelta)
+
+ defStart(self,assignment:"Assignment")->"void":
+ return_pywrapcp.LocalSearchOperator_Start(self,assignment)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_LocalSearchOperator(self)
+ returnweakref.proxy(self)
+
+# Register LocalSearchOperator in _pywrapcp:
+_pywrapcp.LocalSearchOperator_swigregister(LocalSearchOperator)
+
+classIntVarLocalSearchOperatorTemplate(LocalSearchOperator):
+ r""" Base operator class for operators manipulating variables."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defStart(self,assignment:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnStart() instead which is
+ called before exiting this method.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Start(self,assignment)
+
+ defIsIncremental(self)->"bool":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_IsIncremental(self)
+
+ defSize(self)->"int":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Size(self)
+
+ defValue(self,index:"int64_t")->"long const &":
+ r"""
+ Returns the value in the current assignment of the variable of given
+ index.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Value(self,index)
+
+ defOldValue(self,index:"int64_t")->"long const &":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_OldValue(self,index)
+
+ defSetValue(self,index:"int64_t",value:"long const &")->"void":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_SetValue(self,index,value)
+
+ defOnStart(self)->"void":
+ r"""
+ Called by Start() after synchronizing the operator with the current
+ assignment. Should be overridden instead of Start() to avoid calling
+ VarLocalSearchOperator::Start explicitly.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_OnStart(self)
+
+# Register IntVarLocalSearchOperatorTemplate in _pywrapcp:
+_pywrapcp.IntVarLocalSearchOperatorTemplate_swigregister(IntVarLocalSearchOperatorTemplate)
+
+classIntVarLocalSearchOperator(IntVarLocalSearchOperatorTemplate):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,*args):
+ ifself.__class__==IntVarLocalSearchOperator:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.IntVarLocalSearchOperator_swiginit(self,_pywrapcp.new_IntVarLocalSearchOperator(_self,*args))
+ __swig_destroy__=_pywrapcp.delete_IntVarLocalSearchOperator
+
+ defNextNeighbor(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+ r"""
+ Redefines MakeNextNeighbor to export a simpler interface. The calls to
+ ApplyChanges() and RevertChanges() are factored in this method, hiding
+ both delta and deltadelta from subclasses which only need to override
+ MakeOneNeighbor().
+ Therefore this method should not be overridden. Override MakeOneNeighbor()
+ instead.
+ """
+ return_pywrapcp.IntVarLocalSearchOperator_NextNeighbor(self,delta,deltadelta)
+
+ defOneNeighbor(self)->"bool":
+ r"""
+ Creates a new neighbor. It returns false when the neighborhood is
+ completely explored.
+ MakeNextNeighbor() in a subclass of IntVarLocalSearchOperator.
+ """
+ return_pywrapcp.IntVarLocalSearchOperator_OneNeighbor(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_IntVarLocalSearchOperator(self)
+ returnweakref.proxy(self)
+
+# Register IntVarLocalSearchOperator in _pywrapcp:
+_pywrapcp.IntVarLocalSearchOperator_swigregister(IntVarLocalSearchOperator)
+
+classSequenceVarLocalSearchOperatorTemplate(LocalSearchOperator):
+ r""" Base operator class for operators manipulating variables."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defStart(self,assignment:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnStart() instead which is
+ called before exiting this method.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Start(self,assignment)
+
+ defIsIncremental(self)->"bool":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_IsIncremental(self)
+
+ defSize(self)->"int":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Size(self)
+
+ defValue(self,index:"int64_t")->"std::vector< int > const &":
+ r"""
+ Returns the value in the current assignment of the variable of given
+ index.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Value(self,index)
+
+ defOldValue(self,index:"int64_t")->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_OldValue(self,index)
+
+ defSetValue(self,index:"int64_t",value:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_SetValue(self,index,value)
+
+ defOnStart(self)->"void":
+ r"""
+ Called by Start() after synchronizing the operator with the current
+ assignment. Should be overridden instead of Start() to avoid calling
+ VarLocalSearchOperator::Start explicitly.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_OnStart(self)
+
+# Register SequenceVarLocalSearchOperatorTemplate in _pywrapcp:
+_pywrapcp.SequenceVarLocalSearchOperatorTemplate_swigregister(SequenceVarLocalSearchOperatorTemplate)
+
+classSequenceVarLocalSearchOperator(SequenceVarLocalSearchOperatorTemplate):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+# Register SequenceVarLocalSearchOperator in _pywrapcp:
+_pywrapcp.SequenceVarLocalSearchOperator_swigregister(SequenceVarLocalSearchOperator)
+
+classBaseLns(IntVarLocalSearchOperator):
+ r"""
+ This is the base class for building an Lns operator. An Lns fragment is a
+ collection of variables which will be relaxed. Fragments are built with
+ NextFragment(), which returns false if there are no more fragments to build.
+ Optionally one can override InitFragments, which is called from
+ LocalSearchOperator::Start to initialize fragment data.
+
+ Here's a sample relaxing one variable at a time:
+
+ class OneVarLns : public BaseLns {
+ public:
+ OneVarLns(const std::vector<IntVar*>& vars) : BaseLns(vars), index_(0) {}
+ virtual ~OneVarLns() {}
+ virtual void InitFragments() { index_ = 0; }
+ virtual bool NextFragment() {
+ const int size = Size();
+ if (index_ < size) {
+ AppendToFragment(index_);
+ ++index_;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ int index_;
+ };
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,vars:"std::vector< operations_research::IntVar * > const &"):
+ ifself.__class__==BaseLns:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.BaseLns_swiginit(self,_pywrapcp.new_BaseLns(_self,vars))
+ __swig_destroy__=_pywrapcp.delete_BaseLns
+
+ defInitFragments(self)->"void":
+ return_pywrapcp.BaseLns_InitFragments(self)
+
+ defNextFragment(self)->"bool":
+ return_pywrapcp.BaseLns_NextFragment(self)
+
+ defAppendToFragment(self,index:"int")->"void":
+ return_pywrapcp.BaseLns_AppendToFragment(self,index)
+
+ defFragmentSize(self)->"int":
+ return_pywrapcp.BaseLns_FragmentSize(self)
+
+ def__getitem__(self,index:"int")->"int64_t":
+ return_pywrapcp.BaseLns___getitem__(self,index)
+
+ def__len__(self)->"int":
+ return_pywrapcp.BaseLns___len__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_BaseLns(self)
+ returnweakref.proxy(self)
+
+# Register BaseLns in _pywrapcp:
+_pywrapcp.BaseLns_swigregister(BaseLns)
+
+classChangeValue(IntVarLocalSearchOperator):
+ r"""
+ Defines operators which change the value of variables;
+ each neighbor corresponds to *one* modified variable.
+ Sub-classes have to define ModifyValue which determines what the new
+ variable value is going to be (given the current value and the variable).
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,vars:"std::vector< operations_research::IntVar * > const &"):
+ ifself.__class__==ChangeValue:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.ChangeValue_swiginit(self,_pywrapcp.new_ChangeValue(_self,vars))
+ __swig_destroy__=_pywrapcp.delete_ChangeValue
+
+ defModifyValue(self,index:"int64_t",value:"int64_t")->"int64_t":
+ return_pywrapcp.ChangeValue_ModifyValue(self,index,value)
+
+ defOneNeighbor(self)->"bool":
+ r""" This method should not be overridden. Override ModifyValue() instead."""
+ return_pywrapcp.ChangeValue_OneNeighbor(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_ChangeValue(self)
+ returnweakref.proxy(self)
+
+# Register ChangeValue in _pywrapcp:
+_pywrapcp.ChangeValue_swigregister(ChangeValue)
+
+classPathOperator(IntVarLocalSearchOperator):
+ r"""
+ Base class of the local search operators dedicated to path modifications
+ (a path is a set of nodes linked together by arcs).
+ This family of neighborhoods supposes they are handling next variables
+ representing the arcs (var[i] represents the node immediately after i on
+ a path).
+ Several services are provided:
+ - arc manipulators (SetNext(), ReverseChain(), MoveChain())
+ - path inspectors (Next(), Prev(), IsPathEnd())
+ - path iterators: operators need a given number of nodes to define a
+ neighbor; this class provides the iteration on a given number of (base)
+ nodes which can be used to define a neighbor (through the BaseNode method)
+ Subclasses only need to override MakeNeighbor to create neighbors using
+ the services above (no direct manipulation of assignments).
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defNeighbor(self)->"bool":
+ return_pywrapcp.PathOperator_Neighbor(self)
+
+# Register PathOperator in _pywrapcp:
+_pywrapcp.PathOperator_swigregister(PathOperator)
+
+classLocalSearchFilter(BaseObject):
+ r"""
+ Classes to which this template function can be applied to as of 04/2014.
+ Usage: LocalSearchOperator* op = MakeLocalSearchOperator<Relocate>(...);
+ class TwoOpt;
+ class Relocate;
+ class Exchange;
+ class Cross;
+ class MakeActiveOperator;
+ class MakeInactiveOperator;
+ class MakeChainInactiveOperator;
+ class SwapActiveOperator;
+ class ExtendedSwapActiveOperator;
+ class MakeActiveAndRelocate;
+ class RelocateAndMakeActiveOperator;
+ class RelocateAndMakeInactiveOperator;
+ Local Search Filters are used for fast neighbor pruning.
+ Filtering a move is done in several phases:
+ - in the Relax phase, filters determine which parts of their internals
+ will be changed by the candidate, and modify intermediary State
+ - in the Accept phase, filters check that the candidate is feasible,
+ - if the Accept phase succeeds, the solver may decide to trigger a
+ Synchronize phase that makes filters change their internal representation
+ to the last candidate,
+ - otherwise (Accept fails or the solver does not want to synchronize),
+ a Revert phase makes filters erase any intermediary State generated by the
+ Relax and Accept phases.
+ A given filter has phases called with the following pattern:
+ (Relax.Accept.Synchronize | Relax.Accept.Revert | Relax.Revert)*.
+ Filters's Revert() is always called in the reverse order their Accept() was
+ called, to allow late filters to use state done/undone by early filters'
+ Accept()/Revert().
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defAccept(self,delta:"Assignment",deltadelta:"Assignment",objective_min:"int64_t",objective_max:"int64_t")->"bool":
+ r"""
+ Accepts a "delta" given the assignment with which the filter has been
+ synchronized; the delta holds the variables which have been modified and
+ their new value.
+ If the filter represents a part of the global objective, its contribution
+ must be between objective_min and objective_max.
+ Sample: supposing one wants to maintain a[0,1] + b[0,1] <= 1,
+ for the assignment (a,1), (b,0), the delta (b,1) will be rejected
+ but the delta (a,0) will be accepted.
+ TODO(user): Remove arguments when there are no more need for those.
+ """
+ return_pywrapcp.LocalSearchFilter_Accept(self,delta,deltadelta,objective_min,objective_max)
+
+ defIsIncremental(self)->"bool":
+ return_pywrapcp.LocalSearchFilter_IsIncremental(self)
+
+ defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r"""
+ Synchronizes the filter with the current solution, delta being the
+ difference with the solution passed to the previous call to Synchronize()
+ or IncrementalSynchronize(). 'delta' can be used to incrementally
+ synchronizing the filter with the new solution by only considering the
+ changes in delta.
+ """
+ return_pywrapcp.LocalSearchFilter_Synchronize(self,assignment,delta)
+ __swig_destroy__=_pywrapcp.delete_LocalSearchFilter
+
+# Register LocalSearchFilter in _pywrapcp:
+_pywrapcp.LocalSearchFilter_swigregister(LocalSearchFilter)
+
+classLocalSearchFilterManager(BaseObject):
+ r"""
+ Filter manager: when a move is made, filters are executed to decide whether
+ the solution is feasible and compute parts of the new cost. This class
+ schedules filter execution and composes costs as a sum.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.LocalSearchFilterManager_DebugString(self)
+
+ def__init__(self,*args):
+ _pywrapcp.LocalSearchFilterManager_swiginit(self,_pywrapcp.new_LocalSearchFilterManager(*args))
+
+ defAccept(self,monitor:"operations_research::LocalSearchMonitor *const",delta:"Assignment",deltadelta:"Assignment",objective_min:"int64_t",objective_max:"int64_t")->"bool":
+ r"""
+ Returns true iff all filters return true, and the sum of their accepted
+ objectives is between objective_min and objective_max.
+ The monitor has its Begin/EndFiltering events triggered.
+ """
+ return_pywrapcp.LocalSearchFilterManager_Accept(self,monitor,delta,deltadelta,objective_min,objective_max)
+
+ defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r""" Synchronizes all filters to assignment."""
+ return_pywrapcp.LocalSearchFilterManager_Synchronize(self,assignment,delta)
+ __swig_destroy__=_pywrapcp.delete_LocalSearchFilterManager
+
+# Register LocalSearchFilterManager in _pywrapcp:
+_pywrapcp.LocalSearchFilterManager_swigregister(LocalSearchFilterManager)
+
+classIntVarLocalSearchFilter(LocalSearchFilter):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,vars:"std::vector< operations_research::IntVar * > const &"):
+ ifself.__class__==IntVarLocalSearchFilter:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.IntVarLocalSearchFilter_swiginit(self,_pywrapcp.new_IntVarLocalSearchFilter(_self,vars))
+ __swig_destroy__=_pywrapcp.delete_IntVarLocalSearchFilter
+
+ defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnSynchronize() instead
+ which is called before exiting this method.
+ """
+ return_pywrapcp.IntVarLocalSearchFilter_Synchronize(self,assignment,delta)
+
+ defSize(self)->"int":
+ return_pywrapcp.IntVarLocalSearchFilter_Size(self)
+
+ defValue(self,index:"int")->"int64_t":
+ return_pywrapcp.IntVarLocalSearchFilter_Value(self,index)
+
+ defIndexFromVar(self,var:"IntVar")->"int64_t":
+ return_pywrapcp.IntVarLocalSearchFilter_IndexFromVar(self,var)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_IntVarLocalSearchFilter(self)
+ returnweakref.proxy(self)
+
+# Register IntVarLocalSearchFilter in _pywrapcp:
+_pywrapcp.IntVarLocalSearchFilter_swigregister(IntVarLocalSearchFilter)
+
+classBooleanVar(IntVar):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defMin(self)->"int64_t":
+ return_pywrapcp.BooleanVar_Min(self)
+
+ defSetMin(self,m:"int64_t")->"void":
+ return_pywrapcp.BooleanVar_SetMin(self,m)
+
+ defMax(self)->"int64_t":
+ return_pywrapcp.BooleanVar_Max(self)
+
+ defSetMax(self,m:"int64_t")->"void":
+ return_pywrapcp.BooleanVar_SetMax(self,m)
+
+ defSetRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.BooleanVar_SetRange(self,mi,ma)
+
+ defBound(self)->"bool":
+ return_pywrapcp.BooleanVar_Bound(self)
+
+ defValue(self)->"int64_t":
+ return_pywrapcp.BooleanVar_Value(self)
+
+ defRemoveValue(self,v:"int64_t")->"void":
+ return_pywrapcp.BooleanVar_RemoveValue(self,v)
+
+ defRemoveInterval(self,l:"int64_t",u:"int64_t")->"void":
+ return_pywrapcp.BooleanVar_RemoveInterval(self,l,u)
+
+ defWhenBound(self,d:"Demon")->"void":
+ return_pywrapcp.BooleanVar_WhenBound(self,d)
+
+ defWhenRange(self,d:"Demon")->"void":
+ return_pywrapcp.BooleanVar_WhenRange(self,d)
+
+ defWhenDomain(self,d:"Demon")->"void":
+ return_pywrapcp.BooleanVar_WhenDomain(self,d)
+
+ defSize(self)->"uint64_t":
+ return_pywrapcp.BooleanVar_Size(self)
+
+ defContains(self,v:"int64_t")->"bool":
+ return_pywrapcp.BooleanVar_Contains(self,v)
+
+ defHoleIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ return_pywrapcp.BooleanVar_HoleIteratorAux(self,reversible)
+
+ defDomainIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ return_pywrapcp.BooleanVar_DomainIteratorAux(self,reversible)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.BooleanVar_DebugString(self)
+
+# Register BooleanVar in _pywrapcp:
+_pywrapcp.BooleanVar_swigregister(BooleanVar)
+
+
+classPyDecision(Decision):
+
+ def__init__(self):
+ Decision.__init__(self)
+
+ defApplyWrapper(self,solver):
+ try:
+ self.Apply(solver)
+ exceptExceptionase:
+ if'CP Solver fail'instr(e):
+ solver.ShouldFail()
+ else:
+ raise
+
+ defRefuteWrapper(self,solver):
+ try:
+ self.Refute(solver)
+ exceptExceptionase:
+ if'CP Solver fail'instr(e):
+ solver.ShouldFail()
+ else:
+ raise
+
+ defDebugString(self):
+ return"PyDecision"
+
+
+classPyDecisionBuilder(DecisionBuilder):
+
+ def__init__(self):
+ DecisionBuilder.__init__(self)
+
+ defNextWrapper(self,solver):
+ try:
+ returnself.Next(solver)
+ exceptExceptionase:
+ if'CP Solver fail'instr(e):
+ returnsolver.FailDecision()
+ else:
+ raise
+
+ defDebugString(self):
+ return"PyDecisionBuilder"
+
+
+classPyDemon(Demon):
+
+ defRunWrapper(self,solver):
+ try:
+ self.Run(solver)
+ exceptExceptionase:
+ if'CP Solver fail'instr(e):
+ solver.ShouldFail()
+ else:
+ raise
+
+ defDebugString(self):
+ return"PyDemon"
+
+
+classPyConstraintDemon(PyDemon):
+
+ def__init__(self,ct,method,delayed,*args):
+ PyDemon.__init__(self)
+ self.__constraint=ct
+ self.__method=method
+ self.__delayed=delayed
+ self.__args=args
+
+ defRun(self,solver):
+ self.__method(self.__constraint,*self.__args)
+
+ defPriority(self):
+ returnSolver.DELAYED_PRIORITYifself.__delayedelseSolver.NORMAL_PRIORITY
+
+ defDebugString(self):
+ return'PyConstraintDemon'
+
+
+classPyConstraint(Constraint):
+
+ def__init__(self,solver):
+ Constraint.__init__(self,solver)
+ self.__demons=[]
+
+ defDemon(self,method,*args):
+ demon=PyConstraintDemon(self,method,False,*args)
+ self.__demons.append(demon)
+ returndemon
+
+ defDelayedDemon(self,method,*args):
+ demon=PyConstraintDemon(self,method,True,*args)
+ self.__demons.append(demon)
+ returndemon
+
+ defInitialPropagateDemon(self):
+ returnself.solver().ConstraintInitialPropagateCallback(self)
+
+ defDelayedInitialPropagateDemon(self):
+ returnself.solver().DelayedConstraintInitialPropagateCallback(self)
+
+ defInitialPropagateWrapper(self):
+ try:
+ self.InitialPropagate()
+ exceptExceptionase:
+ if'CP Solver fail'instr(e):
+ self.solver().ShouldFail()
+ else:
+ raise
+
+ defDebugString(self):
+ return"PyConstraint"
+
+
+
+classRoutingIndexManager(object):
+ r"""
+ Manager for any NodeIndex <-> variable index conversion. The routing solver
+ uses variable indices internally and through its API. These variable indices
+ are tricky to manage directly because one Node can correspond to a multitude
+ of variables, depending on the number of times they appear in the model, and
+ if they're used as start and/or end points. This class aims to simplify
+ variable index usage, allowing users to use NodeIndex instead.
+
+ Usage:
+
+ .. code-block:: c++
+
+ auto starts_ends = ...; /// These are NodeIndex.
+ RoutingIndexManager manager(10, 4, starts_ends); // 10 nodes, 4 vehicles.
+ RoutingModel model(manager);
+
+ Then, use 'manager.NodeToIndex(node)' whenever model requires a variable
+ index.
+
+ Note: the mapping between node indices and variables indices is subject to
+ change so no assumption should be made on it. The only guarantee is that
+ indices range between 0 and n-1, where n = number of vehicles * 2 (for start
+ and end nodes) + number of non-start or end nodes.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,*args):
+ _pywrapcp.RoutingIndexManager_swiginit(self,_pywrapcp.new_RoutingIndexManager(*args))
+ __swig_destroy__=_pywrapcp.delete_RoutingIndexManager
+
+ defGetNumberOfNodes(self)->"int":
+ return_pywrapcp.RoutingIndexManager_GetNumberOfNodes(self)
+
+ defGetNumberOfVehicles(self)->"int":
+ return_pywrapcp.RoutingIndexManager_GetNumberOfVehicles(self)
+
+ defGetNumberOfIndices(self)->"int":
+ return_pywrapcp.RoutingIndexManager_GetNumberOfIndices(self)
+
+ defGetStartIndex(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingIndexManager_GetStartIndex(self,vehicle)
+
+ defGetEndIndex(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingIndexManager_GetEndIndex(self,vehicle)
+
+ defNodeToIndex(self,node:"operations_research::RoutingIndexManager::NodeIndex")->"int64_t":
+ return_pywrapcp.RoutingIndexManager_NodeToIndex(self,node)
+
+ defIndexToNode(self,index:"int64_t")->"operations_research::RoutingIndexManager::NodeIndex":
+ return_pywrapcp.RoutingIndexManager_IndexToNode(self,index)
+
+# Register RoutingIndexManager in _pywrapcp:
+_pywrapcp.RoutingIndexManager_swigregister(RoutingIndexManager)
+
+
+defDefaultRoutingModelParameters()->"operations_research::RoutingModelParameters":
+ return_pywrapcp.DefaultRoutingModelParameters()
+
+defDefaultRoutingSearchParameters()->"operations_research::RoutingSearchParameters":
+ return_pywrapcp.DefaultRoutingSearchParameters()
+
+defFindErrorInRoutingSearchParameters(search_parameters:"operations_research::RoutingSearchParameters const &")->"std::string":
+ r"""
+ Returns an empty std::string if the routing search parameters are valid, and
+ a non-empty, human readable error description if they're not.
+ """
+ return_pywrapcp.FindErrorInRoutingSearchParameters(search_parameters)
+BOOL_UNSPECIFIED=_pywrapcp.BOOL_UNSPECIFIED
+BOOL_FALSE=_pywrapcp.BOOL_FALSE
+BOOL_TRUE=_pywrapcp.BOOL_TRUE
+classRoutingModel(object):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ ROUTING_NOT_SOLVED=_pywrapcp.RoutingModel_ROUTING_NOT_SOLVED
+ r""" Problem not solved yet (before calling RoutingModel::Solve())."""
+ ROUTING_SUCCESS=_pywrapcp.RoutingModel_ROUTING_SUCCESS
+ r""" Problem solved successfully after calling RoutingModel::Solve()."""
+ ROUTING_FAIL=_pywrapcp.RoutingModel_ROUTING_FAIL
+ r""" No solution found to the problem after calling RoutingModel::Solve()."""
+ ROUTING_FAIL_TIMEOUT=_pywrapcp.RoutingModel_ROUTING_FAIL_TIMEOUT
+ r""" Time limit reached before finding a solution with RoutingModel::Solve()."""
+ ROUTING_INVALID=_pywrapcp.RoutingModel_ROUTING_INVALID
+ r""" Model, model parameters or flags are not valid."""
+ ROUTING_INFEASIBLE=_pywrapcp.RoutingModel_ROUTING_INFEASIBLE
+ r""" Problem proven to be infeasible."""
+ PICKUP_AND_DELIVERY_NO_ORDER=_pywrapcp.RoutingModel_PICKUP_AND_DELIVERY_NO_ORDER
+ r""" Any precedence is accepted."""
+ PICKUP_AND_DELIVERY_LIFO=_pywrapcp.RoutingModel_PICKUP_AND_DELIVERY_LIFO
+ r""" Deliveries must be performed in reverse order of pickups."""
+ PICKUP_AND_DELIVERY_FIFO=_pywrapcp.RoutingModel_PICKUP_AND_DELIVERY_FIFO
+ r""" Deliveries must be performed in the same order as pickups."""
+
+ def__init__(self,*args):
+ _pywrapcp.RoutingModel_swiginit(self,_pywrapcp.new_RoutingModel(*args))
+ __swig_destroy__=_pywrapcp.delete_RoutingModel
+
+ defRegisterUnaryTransitVector(self,values:"std::vector< int64_t >")->"int":
+ r""" Registers 'callback' and returns its index."""
+ return_pywrapcp.RoutingModel_RegisterUnaryTransitVector(self,values)
+
+ defRegisterUnaryTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback1")->"int":
+ return_pywrapcp.RoutingModel_RegisterUnaryTransitCallback(self,callback)
+
+ defRegisterPositiveUnaryTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback1")->"int":
+ return_pywrapcp.RoutingModel_RegisterPositiveUnaryTransitCallback(self,callback)
+
+ defRegisterTransitMatrix(self,values:"std::vector< std::vector< int64_t > >")->"int":
+ return_pywrapcp.RoutingModel_RegisterTransitMatrix(self,values)
+
+ defRegisterTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback2")->"int":
+ return_pywrapcp.RoutingModel_RegisterTransitCallback(self,callback)
+
+ defRegisterPositiveTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback2")->"int":
+ return_pywrapcp.RoutingModel_RegisterPositiveTransitCallback(self,callback)
+
+ defTransitCallback(self,callback_index:"int")->"operations_research::RoutingModel::TransitCallback2 const &":
+ return_pywrapcp.RoutingModel_TransitCallback(self,callback_index)
+
+ defUnaryTransitCallbackOrNull(self,callback_index:"int")->"operations_research::RoutingModel::TransitCallback1 const &":
+ return_pywrapcp.RoutingModel_UnaryTransitCallbackOrNull(self,callback_index)
+
+ defAddDimension(self,evaluator_index:"int",slack_max:"int64_t",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ r"""
+ Model creation
+ Methods to add dimensions to routes; dimensions represent quantities
+ accumulated at nodes along the routes. They represent quantities such as
+ weights or volumes carried along the route, or distance or times.
+ Quantities at a node are represented by "cumul" variables and the increase
+ or decrease of quantities between nodes are represented by "transit"
+ variables. These variables are linked as follows:
+ if j == next(i), cumul(j) = cumul(i) + transit(i) + slack(i)
+ where slack is a positive slack variable (can represent waiting times for
+ a time dimension).
+ Setting the value of fix_start_cumul_to_zero to true will force the
+ "cumul" variable of the start node of all vehicles to be equal to 0.
+ Creates a dimension where the transit variable is constrained to be
+ equal to evaluator(i, next(i)); 'slack_max' is the upper bound of the
+ slack variable and 'capacity' is the upper bound of the cumul variables.
+ 'name' is the name used to reference the dimension; this name is used to
+ get cumul and transit variables from the routing model.
+ Returns false if a dimension with the same name has already been created
+ (and doesn't create the new dimension).
+ Takes ownership of the callback 'evaluator'.
+ """
+ return_pywrapcp.RoutingModel_AddDimension(self,evaluator_index,slack_max,capacity,fix_start_cumul_to_zero,name)
+
+ defAddDimensionWithVehicleTransits(self,evaluator_indices:"std::vector< int > const &",slack_max:"int64_t",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ return_pywrapcp.RoutingModel_AddDimensionWithVehicleTransits(self,evaluator_indices,slack_max,capacity,fix_start_cumul_to_zero,name)
+
+ defAddDimensionWithVehicleCapacity(self,evaluator_index:"int",slack_max:"int64_t",vehicle_capacities:"std::vector< int64_t >",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ return_pywrapcp.RoutingModel_AddDimensionWithVehicleCapacity(self,evaluator_index,slack_max,vehicle_capacities,fix_start_cumul_to_zero,name)
+
+ defAddDimensionWithVehicleTransitAndCapacity(self,evaluator_indices:"std::vector< int > const &",slack_max:"int64_t",vehicle_capacities:"std::vector< int64_t >",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ return_pywrapcp.RoutingModel_AddDimensionWithVehicleTransitAndCapacity(self,evaluator_indices,slack_max,vehicle_capacities,fix_start_cumul_to_zero,name)
+
+ defAddConstantDimensionWithSlack(self,value:"int64_t",capacity:"int64_t",slack_max:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'value'; 'capacity' is the upper bound of the cumul variables.
+ 'name' is the name used to reference the dimension; this name is used to
+ get cumul and transit variables from the routing model.
+ Returns a pair consisting of an index to the registered unary transit
+ callback and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddConstantDimensionWithSlack(self,value,capacity,slack_max,fix_start_cumul_to_zero,name)
+
+ defAddConstantDimension(self,value:"int64_t",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ return_pywrapcp.RoutingModel_AddConstantDimension(self,value,capacity,fix_start_cumul_to_zero,name)
+
+ defAddVectorDimension(self,values:"std::vector< int64_t >",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'values[i]' for node i; 'capacity' is the upper bound of
+ the cumul variables. 'name' is the name used to reference the dimension;
+ this name is used to get cumul and transit variables from the routing
+ model.
+ Returns a pair consisting of an index to the registered unary transit
+ callback and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddVectorDimension(self,values,capacity,fix_start_cumul_to_zero,name)
+
+ defAddMatrixDimension(self,values:"std::vector< std::vector< int64_t > >",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'values[i][next(i)]' for node i; 'capacity' is the upper bound of
+ the cumul variables. 'name' is the name used to reference the dimension;
+ this name is used to get cumul and transit variables from the routing
+ model.
+ Returns a pair consisting of an index to the registered transit callback
+ and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddMatrixDimension(self,values,capacity,fix_start_cumul_to_zero,name)
+
+ defMakePathSpansAndTotalSlacks(self,dimension:"RoutingDimension",spans:"std::vector< operations_research::IntVar * >",total_slacks:"std::vector< operations_research::IntVar * >")->"operations_research::Constraint *":
+ r"""
+ For every vehicle of the routing model:
+ - if total_slacks[vehicle] is not nullptr, constrains it to be the sum of
+ slacks on that vehicle, that is,
+ dimension->CumulVar(end) - dimension->CumulVar(start) -
+ sum_{node in path of vehicle} dimension->FixedTransitVar(node).
+ - if spans[vehicle] is not nullptr, constrains it to be
+ dimension->CumulVar(end) - dimension->CumulVar(start)
+ This does stronger propagation than a decomposition, and takes breaks into
+ account.
+ """
+ return_pywrapcp.RoutingModel_MakePathSpansAndTotalSlacks(self,dimension,spans,total_slacks)
+
+ defGetAllDimensionNames(self)->"std::vector< std::string >":
+ r""" Outputs the names of all dimensions added to the routing engine."""
+ return_pywrapcp.RoutingModel_GetAllDimensionNames(self)
+
+ defGetDimensions(self)->"std::vector< operations_research::RoutingDimension * > const &":
+ r""" Returns all dimensions of the model."""
+ return_pywrapcp.RoutingModel_GetDimensions(self)
+
+ defGetDimensionsWithSoftOrSpanCosts(self)->"std::vector< operations_research::RoutingDimension * >":
+ r""" Returns dimensions with soft or vehicle span costs."""
+ return_pywrapcp.RoutingModel_GetDimensionsWithSoftOrSpanCosts(self)
+
+ defGetGlobalDimensionCumulOptimizers(self)->"std::vector< std::unique_ptr< operations_research::GlobalDimensionCumulOptimizer > > const &":
+ r"""
+ Returns [global|local]_dimension_optimizers_, which are empty if the model
+ has not been closed.
+ """
+ return_pywrapcp.RoutingModel_GetGlobalDimensionCumulOptimizers(self)
+
+ defGetGlobalDimensionCumulMPOptimizers(self)->"std::vector< std::unique_ptr< operations_research::GlobalDimensionCumulOptimizer > > const &":
+ return_pywrapcp.RoutingModel_GetGlobalDimensionCumulMPOptimizers(self)
+
+ defGetLocalDimensionCumulOptimizers(self)->"std::vector< std::unique_ptr< operations_research::LocalDimensionCumulOptimizer > > const &":
+ return_pywrapcp.RoutingModel_GetLocalDimensionCumulOptimizers(self)
+
+ defGetLocalDimensionCumulMPOptimizers(self)->"std::vector< std::unique_ptr< operations_research::LocalDimensionCumulOptimizer > > const &":
+ return_pywrapcp.RoutingModel_GetLocalDimensionCumulMPOptimizers(self)
+
+ defGetMutableGlobalCumulOptimizer(self,dimension:"RoutingDimension")->"operations_research::GlobalDimensionCumulOptimizer *":
+ r"""
+ Returns the global/local dimension cumul optimizer for a given dimension,
+ or nullptr if there is none.
+ """
+ return_pywrapcp.RoutingModel_GetMutableGlobalCumulOptimizer(self,dimension)
+
+ defGetMutableGlobalCumulMPOptimizer(self,dimension:"RoutingDimension")->"operations_research::GlobalDimensionCumulOptimizer *":
+ return_pywrapcp.RoutingModel_GetMutableGlobalCumulMPOptimizer(self,dimension)
+
+ defGetMutableLocalCumulOptimizer(self,dimension:"RoutingDimension")->"operations_research::LocalDimensionCumulOptimizer *":
+ return_pywrapcp.RoutingModel_GetMutableLocalCumulOptimizer(self,dimension)
+
+ defGetMutableLocalCumulMPOptimizer(self,dimension:"RoutingDimension")->"operations_research::LocalDimensionCumulOptimizer *":
+ return_pywrapcp.RoutingModel_GetMutableLocalCumulMPOptimizer(self,dimension)
+
+ defHasDimension(self,dimension_name:"std::string const &")->"bool":
+ r""" Returns true if a dimension exists for a given dimension name."""
+ return_pywrapcp.RoutingModel_HasDimension(self,dimension_name)
+
+ defGetDimensionOrDie(self,dimension_name:"std::string const &")->"operations_research::RoutingDimension const &":
+ r""" Returns a dimension from its name. Dies if the dimension does not exist."""
+ return_pywrapcp.RoutingModel_GetDimensionOrDie(self,dimension_name)
+
+ defGetMutableDimension(self,dimension_name:"std::string const &")->"operations_research::RoutingDimension *":
+ r"""
+ Returns a dimension from its name. Returns nullptr if the dimension does
+ not exist.
+ """
+ return_pywrapcp.RoutingModel_GetMutableDimension(self,dimension_name)
+
+ defSetPrimaryConstrainedDimension(self,dimension_name:"std::string const &")->"void":
+ r"""
+ Set the given dimension as "primary constrained". As of August 2013, this
+ is only used by ArcIsMoreConstrainedThanArc().
+ "dimension" must be the name of an existing dimension, or be empty, in
+ which case there will not be a primary dimension after this call.
+ """
+ return_pywrapcp.RoutingModel_SetPrimaryConstrainedDimension(self,dimension_name)
+
+ defGetPrimaryConstrainedDimension(self)->"std::string const &":
+ r""" Get the primary constrained dimension, or an empty string if it is unset."""
+ return_pywrapcp.RoutingModel_GetPrimaryConstrainedDimension(self)
+
+ defAddResourceGroup(self)->"int":
+ r"""
+ Adds a resource group to the routing model. Returns its index in
+ resource_groups_.
+ """
+ return_pywrapcp.RoutingModel_AddResourceGroup(self)
+
+ defGetDimensionResourceGroupIndices(self,dimension:"RoutingDimension")->"std::vector< int > const &":
+ r"""
+ Returns the indices of resource groups for this dimension. This method can
+ only be called after the model has been closed.
+ """
+ return_pywrapcp.RoutingModel_GetDimensionResourceGroupIndices(self,dimension)
+
+ defGetDimensionResourceGroupIndex(self,dimension:"RoutingDimension")->"int":
+ r"""
+ Returns the index of the resource group attached to the dimension.
+ DCHECKS that there's exactly one resource group for this dimension.
+ """
+ return_pywrapcp.RoutingModel_GetDimensionResourceGroupIndex(self,dimension)
+
+ defAddDisjunction(self,*args)->"operations_research::RoutingModel::DisjunctionIndex":
+ r"""
+ Adds a disjunction constraint on the indices: exactly 'max_cardinality' of
+ the indices are active. Start and end indices of any vehicle cannot be
+ part of a disjunction.
+
+ If a penalty is given, at most 'max_cardinality' of the indices can be
+ active, and if less are active, 'penalty' is payed per inactive index.
+ This is equivalent to adding the constraint:
+ p + Sum(i)active[i] == max_cardinality
+ where p is an integer variable, and the following cost to the cost
+ function:
+ p * penalty.
+ 'penalty' must be positive to make the disjunction optional; a negative
+ penalty will force 'max_cardinality' indices of the disjunction to be
+ performed, and therefore p == 0.
+ Note: passing a vector with a single index will model an optional index
+ with a penalty cost if it is not visited.
+ """
+ return_pywrapcp.RoutingModel_AddDisjunction(self,*args)
+
+ defGetDisjunctionIndices(self,index:"int64_t")->"std::vector< operations_research::RoutingModel::DisjunctionIndex > const &":
+ r""" Returns the indices of the disjunctions to which an index belongs."""
+ return_pywrapcp.RoutingModel_GetDisjunctionIndices(self,index)
+
+ defGetDisjunctionPenalty(self,index:"operations_research::RoutingModel::DisjunctionIndex")->"int64_t":
+ r""" Returns the penalty of the node disjunction of index 'index'."""
+ return_pywrapcp.RoutingModel_GetDisjunctionPenalty(self,index)
+
+ defGetDisjunctionMaxCardinality(self,index:"operations_research::RoutingModel::DisjunctionIndex")->"int64_t":
+ r"""
+ Returns the maximum number of possible active nodes of the node
+ disjunction of index 'index'.
+ """
+ return_pywrapcp.RoutingModel_GetDisjunctionMaxCardinality(self,index)
+
+ defGetNumberOfDisjunctions(self)->"int":
+ r""" Returns the number of node disjunctions in the model."""
+ return_pywrapcp.RoutingModel_GetNumberOfDisjunctions(self)
+
+ defHasMandatoryDisjunctions(self)->"bool":
+ r"""
+ Returns true if the model contains mandatory disjunctions (ones with
+ kNoPenalty as penalty).
+ """
+ return_pywrapcp.RoutingModel_HasMandatoryDisjunctions(self)
+
+ defHasMaxCardinalityConstrainedDisjunctions(self)->"bool":
+ r"""
+ Returns true if the model contains at least one disjunction which is
+ constrained by its max_cardinality.
+ """
+ return_pywrapcp.RoutingModel_HasMaxCardinalityConstrainedDisjunctions(self)
+
+ defGetPerfectBinaryDisjunctions(self)->"std::vector< std::pair< int64_t,int64_t > >":
+ r"""
+ Returns the list of all perfect binary disjunctions, as pairs of variable
+ indices: a disjunction is "perfect" when its variables do not appear in
+ any other disjunction. Each pair is sorted (lowest variable index first),
+ and the output vector is also sorted (lowest pairs first).
+ """
+ return_pywrapcp.RoutingModel_GetPerfectBinaryDisjunctions(self)
+
+ defIgnoreDisjunctionsAlreadyForcedToZero(self)->"void":
+ r"""
+ SPECIAL: Makes the solver ignore all the disjunctions whose active
+ variables are all trivially zero (i.e. Max() == 0), by setting their
+ max_cardinality to 0.
+ This can be useful when using the BaseBinaryDisjunctionNeighborhood
+ operators, in the context of arc-based routing.
+ """
+ return_pywrapcp.RoutingModel_IgnoreDisjunctionsAlreadyForcedToZero(self)
+
+ defAddSoftSameVehicleConstraint(self,indices:"std::vector< int64_t > const &",cost:"int64_t")->"void":
+ r"""
+ Adds a soft constraint to force a set of variable indices to be on the
+ same vehicle. If all nodes are not on the same vehicle, each extra vehicle
+ used adds 'cost' to the cost function.
+ """
+ return_pywrapcp.RoutingModel_AddSoftSameVehicleConstraint(self,indices,cost)
+
+ defSetAllowedVehiclesForIndex(self,vehicles:"std::vector< int > const &",index:"int64_t")->"void":
+ r"""
+ Sets the vehicles which can visit a given node. If the node is in a
+ disjunction, this will not prevent it from being unperformed.
+ Specifying an empty vector of vehicles has no effect (all vehicles
+ will be allowed to visit the node).
+ """
+ return_pywrapcp.RoutingModel_SetAllowedVehiclesForIndex(self,vehicles,index)
+
+ defIsVehicleAllowedForIndex(self,vehicle:"int",index:"int64_t")->"bool":
+ r""" Returns true if a vehicle is allowed to visit a given node."""
+ return_pywrapcp.RoutingModel_IsVehicleAllowedForIndex(self,vehicle,index)
+
+ defAddPickupAndDelivery(self,pickup:"int64_t",delivery:"int64_t")->"void":
+ r"""
+ Notifies that index1 and index2 form a pair of nodes which should belong
+ to the same route. This methods helps the search find better solutions,
+ especially in the local search phase.
+ It should be called each time you have an equality constraint linking
+ the vehicle variables of two node (including for instance pickup and
+ delivery problems):
+ Solver* const solver = routing.solver();
+ int64_t index1 = manager.NodeToIndex(node1);
+ int64_t index2 = manager.NodeToIndex(node2);
+ solver->AddConstraint(solver->MakeEquality(
+ routing.VehicleVar(index1),
+ routing.VehicleVar(index2)));
+ routing.AddPickupAndDelivery(index1, index2);
+ """
+ return_pywrapcp.RoutingModel_AddPickupAndDelivery(self,pickup,delivery)
+
+ defAddPickupAndDeliverySets(self,pickup_disjunction:"operations_research::RoutingModel::DisjunctionIndex",delivery_disjunction:"operations_research::RoutingModel::DisjunctionIndex")->"void":
+ r"""
+ Same as AddPickupAndDelivery but notifying that the performed node from
+ the disjunction of index 'pickup_disjunction' is on the same route as the
+ performed node from the disjunction of index 'delivery_disjunction'.
+ """
+ return_pywrapcp.RoutingModel_AddPickupAndDeliverySets(self,pickup_disjunction,delivery_disjunction)
+
+ defGetPickupIndexPairs(self,node_index:"int64_t")->"std::vector< std::pair< int,int > > const &":
+ r"""
+ Returns pairs for which the node is a pickup; the first element of each
+ pair is the index in the pickup and delivery pairs list in which the
+ pickup appears, the second element is its index in the pickups list.
+ """
+ return_pywrapcp.RoutingModel_GetPickupIndexPairs(self,node_index)
+
+ defGetDeliveryIndexPairs(self,node_index:"int64_t")->"std::vector< std::pair< int,int > > const &":
+ r""" Same as above for deliveries."""
+ return_pywrapcp.RoutingModel_GetDeliveryIndexPairs(self,node_index)
+
+ defSetPickupAndDeliveryPolicyOfAllVehicles(self,policy:"operations_research::RoutingModel::PickupAndDeliveryPolicy")->"void":
+ r"""
+ Sets the Pickup and delivery policy of all vehicles. It is equivalent to
+ calling SetPickupAndDeliveryPolicyOfVehicle on all vehicles.
+ """
+ return_pywrapcp.RoutingModel_SetPickupAndDeliveryPolicyOfAllVehicles(self,policy)
+
+ defSetPickupAndDeliveryPolicyOfVehicle(self,policy:"operations_research::RoutingModel::PickupAndDeliveryPolicy",vehicle:"int")->"void":
+ return_pywrapcp.RoutingModel_SetPickupAndDeliveryPolicyOfVehicle(self,policy,vehicle)
+
+ defGetPickupAndDeliveryPolicyOfVehicle(self,vehicle:"int")->"operations_research::RoutingModel::PickupAndDeliveryPolicy":
+ return_pywrapcp.RoutingModel_GetPickupAndDeliveryPolicyOfVehicle(self,vehicle)
+
+ defGetNumOfSingletonNodes(self)->"int":
+ r"""
+ Returns the number of non-start/end nodes which do not appear in a
+ pickup/delivery pair.
+ """
+ return_pywrapcp.RoutingModel_GetNumOfSingletonNodes(self)
+ TYPE_ADDED_TO_VEHICLE=_pywrapcp.RoutingModel_TYPE_ADDED_TO_VEHICLE
+ r""" When visited, the number of types 'T' on the vehicle increases by one."""
+ ADDED_TYPE_REMOVED_FROM_VEHICLE=_pywrapcp.RoutingModel_ADDED_TYPE_REMOVED_FROM_VEHICLE
+ r"""
+ When visited, one instance of type 'T' previously added to the route
+ (TYPE_ADDED_TO_VEHICLE), if any, is removed from the vehicle.
+ If the type was not previously added to the route or all added instances
+ have already been removed, this visit has no effect on the types.
+ """
+ TYPE_ON_VEHICLE_UP_TO_VISIT=_pywrapcp.RoutingModel_TYPE_ON_VEHICLE_UP_TO_VISIT
+ r"""
+ With the following policy, the visit enforces that type 'T' is
+ considered on the route from its start until this node is visited.
+ """
+ TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED=_pywrapcp.RoutingModel_TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED
+ r"""
+ The visit doesn't have an impact on the number of types 'T' on the
+ route, as it's (virtually) added and removed directly.
+ This policy can be used for visits which are part of an incompatibility
+ or requirement set without affecting the type count on the route.
+ """
+
+ defSetVisitType(self,index:"int64_t",type:"int",type_policy:"operations_research::RoutingModel::VisitTypePolicy")->"void":
+ return_pywrapcp.RoutingModel_SetVisitType(self,index,type,type_policy)
+
+ defGetVisitType(self,index:"int64_t")->"int":
+ return_pywrapcp.RoutingModel_GetVisitType(self,index)
+
+ defGetSingleNodesOfType(self,type:"int")->"std::vector< int > const &":
+ return_pywrapcp.RoutingModel_GetSingleNodesOfType(self,type)
+
+ defGetPairIndicesOfType(self,type:"int")->"std::vector< int > const &":
+ return_pywrapcp.RoutingModel_GetPairIndicesOfType(self,type)
+
+ defGetVisitTypePolicy(self,index:"int64_t")->"operations_research::RoutingModel::VisitTypePolicy":
+ return_pywrapcp.RoutingModel_GetVisitTypePolicy(self,index)
+
+ defCloseVisitTypes(self)->"void":
+ r"""
+ This function should be called once all node visit types have been set and
+ prior to adding any incompatibilities/requirements.
+ "close" types.
+ """
+ return_pywrapcp.RoutingModel_CloseVisitTypes(self)
+
+ defGetNumberOfVisitTypes(self)->"int":
+ return_pywrapcp.RoutingModel_GetNumberOfVisitTypes(self)
+
+ defAddHardTypeIncompatibility(self,type1:"int",type2:"int")->"void":
+ r"""
+ Incompatibilities:
+ Two nodes with "hard" incompatible types cannot share the same route at
+ all, while with a "temporal" incompatibility they can't be on the same
+ route at the same time.
+ """
+ return_pywrapcp.RoutingModel_AddHardTypeIncompatibility(self,type1,type2)
+
+ defAddTemporalTypeIncompatibility(self,type1:"int",type2:"int")->"void":
+ return_pywrapcp.RoutingModel_AddTemporalTypeIncompatibility(self,type1,type2)
+
+ defGetHardTypeIncompatibilitiesOfType(self,type:"int")->"absl::flat_hash_set< int > const &":
+ r""" Returns visit types incompatible with a given type."""
+ return_pywrapcp.RoutingModel_GetHardTypeIncompatibilitiesOfType(self,type)
+
+ defGetTemporalTypeIncompatibilitiesOfType(self,type:"int")->"absl::flat_hash_set< int > const &":
+ return_pywrapcp.RoutingModel_GetTemporalTypeIncompatibilitiesOfType(self,type)
+
+ defHasHardTypeIncompatibilities(self)->"bool":
+ r"""
+ Returns true iff any hard (resp. temporal) type incompatibilities have
+ been added to the model.
+ """
+ return_pywrapcp.RoutingModel_HasHardTypeIncompatibilities(self)
+
+ defHasTemporalTypeIncompatibilities(self)->"bool":
+ return_pywrapcp.RoutingModel_HasTemporalTypeIncompatibilities(self)
+
+ defAddSameVehicleRequiredTypeAlternatives(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ Requirements:
+ NOTE: As of 2019-04, cycles in the requirement graph are not supported,
+ and lead to the dependent nodes being skipped if possible (otherwise
+ the model is considered infeasible).
+ The following functions specify that "dependent_type" requires at least
+ one of the types in "required_type_alternatives".
+
+ For same-vehicle requirements, a node of dependent type type_D requires at
+ least one node of type type_R among the required alternatives on the same
+ route.
+ """
+ return_pywrapcp.RoutingModel_AddSameVehicleRequiredTypeAlternatives(self,dependent_type,required_type_alternatives)
+
+ defAddRequiredTypeAlternativesWhenAddingType(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ If type_D depends on type_R when adding type_D, any node_D of type_D and
+ VisitTypePolicy TYPE_ADDED_TO_VEHICLE or
+ TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED requires at least one type_R on its
+ vehicle at the time node_D is visited.
+ """
+ return_pywrapcp.RoutingModel_AddRequiredTypeAlternativesWhenAddingType(self,dependent_type,required_type_alternatives)
+
+ defAddRequiredTypeAlternativesWhenRemovingType(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ The following requirements apply when visiting dependent nodes that remove
+ their type from the route, i.e. type_R must be on the vehicle when type_D
+ of VisitTypePolicy ADDED_TYPE_REMOVED_FROM_VEHICLE,
+ TYPE_ON_VEHICLE_UP_TO_VISIT or TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED is
+ visited.
+ """
+ return_pywrapcp.RoutingModel_AddRequiredTypeAlternativesWhenRemovingType(self,dependent_type,required_type_alternatives)
+
+ defGetSameVehicleRequiredTypeAlternativesOfType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r"""
+ Returns the set of same-vehicle requirement alternatives for the given
+ type.
+ """
+ return_pywrapcp.RoutingModel_GetSameVehicleRequiredTypeAlternativesOfType(self,type)
+
+ defGetRequiredTypeAlternativesWhenAddingType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r""" Returns the set of requirement alternatives when adding the given type."""
+ return_pywrapcp.RoutingModel_GetRequiredTypeAlternativesWhenAddingType(self,type)
+
+ defGetRequiredTypeAlternativesWhenRemovingType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r""" Returns the set of requirement alternatives when removing the given type."""
+ return_pywrapcp.RoutingModel_GetRequiredTypeAlternativesWhenRemovingType(self,type)
+
+ defHasSameVehicleTypeRequirements(self)->"bool":
+ r"""
+ Returns true iff any same-route (resp. temporal) type requirements have
+ been added to the model.
+ """
+ return_pywrapcp.RoutingModel_HasSameVehicleTypeRequirements(self)
+
+ defHasTemporalTypeRequirements(self)->"bool":
+ return_pywrapcp.RoutingModel_HasTemporalTypeRequirements(self)
+
+ defHasTypeRegulations(self)->"bool":
+ r"""
+ Returns true iff the model has any incompatibilities or requirements set
+ on node types.
+ """
+ return_pywrapcp.RoutingModel_HasTypeRegulations(self)
+
+ defUnperformedPenalty(self,var_index:"int64_t")->"int64_t":
+ r"""
+ Get the "unperformed" penalty of a node. This is only well defined if the
+ node is only part of a single Disjunction, and that disjunction has a
+ penalty. For forced active nodes returns max int64_t. In all other cases,
+ this returns 0.
+ """
+ return_pywrapcp.RoutingModel_UnperformedPenalty(self,var_index)
+
+ defUnperformedPenaltyOrValue(self,default_value:"int64_t",var_index:"int64_t")->"int64_t":
+ r"""
+ Same as above except that it returns default_value instead of 0 when
+ penalty is not well defined (default value is passed as first argument to
+ simplify the usage of the method in a callback).
+ """
+ return_pywrapcp.RoutingModel_UnperformedPenaltyOrValue(self,default_value,var_index)
+
+ defGetDepot(self)->"int64_t":
+ r"""
+ Returns the variable index of the first starting or ending node of all
+ routes. If all routes start and end at the same node (single depot), this
+ is the node returned.
+ """
+ return_pywrapcp.RoutingModel_GetDepot(self)
+
+ defSetMaximumNumberOfActiveVehicles(self,max_active_vehicles:"int")->"void":
+ r"""
+ Constrains the maximum number of active vehicles, aka the number of
+ vehicles which do not have an empty route. For instance, this can be used
+ to limit the number of routes in the case where there are fewer drivers
+ than vehicles and that the fleet of vehicle is heterogeneous.
+ """
+ return_pywrapcp.RoutingModel_SetMaximumNumberOfActiveVehicles(self,max_active_vehicles)
+
+ defGetMaximumNumberOfActiveVehicles(self)->"int":
+ r""" Returns the maximum number of active vehicles."""
+ return_pywrapcp.RoutingModel_GetMaximumNumberOfActiveVehicles(self)
+
+ defSetArcCostEvaluatorOfAllVehicles(self,evaluator_index:"int")->"void":
+ r"""
+ Sets the cost function of the model such that the cost of a segment of a
+ route between node 'from' and 'to' is evaluator(from, to), whatever the
+ route or vehicle performing the route.
+ """
+ return_pywrapcp.RoutingModel_SetArcCostEvaluatorOfAllVehicles(self,evaluator_index)
+
+ defSetArcCostEvaluatorOfVehicle(self,evaluator_index:"int",vehicle:"int")->"void":
+ r""" Sets the cost function for a given vehicle route."""
+ return_pywrapcp.RoutingModel_SetArcCostEvaluatorOfVehicle(self,evaluator_index,vehicle)
+
+ defSetFixedCostOfAllVehicles(self,cost:"int64_t")->"void":
+ r"""
+ Sets the fixed cost of all vehicle routes. It is equivalent to calling
+ SetFixedCostOfVehicle on all vehicle routes.
+ """
+ return_pywrapcp.RoutingModel_SetFixedCostOfAllVehicles(self,cost)
+
+ defSetFixedCostOfVehicle(self,cost:"int64_t",vehicle:"int")->"void":
+ r""" Sets the fixed cost of one vehicle route."""
+ return_pywrapcp.RoutingModel_SetFixedCostOfVehicle(self,cost,vehicle)
+
+ defGetFixedCostOfVehicle(self,vehicle:"int")->"int64_t":
+ r"""
+ Returns the route fixed cost taken into account if the route of the
+ vehicle is not empty, aka there's at least one node on the route other
+ than the first and last nodes.
+ """
+ return_pywrapcp.RoutingModel_GetFixedCostOfVehicle(self,vehicle)
+
+ defSetAmortizedCostFactorsOfAllVehicles(self,linear_cost_factor:"int64_t",quadratic_cost_factor:"int64_t")->"void":
+ r"""
+ The following methods set the linear and quadratic cost factors of
+ vehicles (must be positive values). The default value of these parameters
+ is zero for all vehicles.
+
+ When set, the cost_ of the model will contain terms aiming at reducing the
+ number of vehicles used in the model, by adding the following to the
+ objective for every vehicle v:
+ INDICATOR(v used in the model) *
+ [linear_cost_factor_of_vehicle_[v]
+ - quadratic_cost_factor_of_vehicle_[v]*(square of length of route v)]
+ i.e. for every used vehicle, we add the linear factor as fixed cost, and
+ subtract the square of the route length multiplied by the quadratic
+ factor. This second term aims at making the routes as dense as possible.
+
+ Sets the linear and quadratic cost factor of all vehicles.
+ """
+ return_pywrapcp.RoutingModel_SetAmortizedCostFactorsOfAllVehicles(self,linear_cost_factor,quadratic_cost_factor)
+
+ defSetAmortizedCostFactorsOfVehicle(self,linear_cost_factor:"int64_t",quadratic_cost_factor:"int64_t",vehicle:"int")->"void":
+ r""" Sets the linear and quadratic cost factor of the given vehicle."""
+ return_pywrapcp.RoutingModel_SetAmortizedCostFactorsOfVehicle(self,linear_cost_factor,quadratic_cost_factor,vehicle)
+
+ defGetAmortizedLinearCostFactorOfVehicles(self)->"std::vector< int64_t > const &":
+ return_pywrapcp.RoutingModel_GetAmortizedLinearCostFactorOfVehicles(self)
+
+ defGetAmortizedQuadraticCostFactorOfVehicles(self)->"std::vector< int64_t > const &":
+ return_pywrapcp.RoutingModel_GetAmortizedQuadraticCostFactorOfVehicles(self)
+
+ defSetVehicleUsedWhenEmpty(self,is_used:"bool",vehicle:"int")->"void":
+ return_pywrapcp.RoutingModel_SetVehicleUsedWhenEmpty(self,is_used,vehicle)
+
+ defIsVehicleUsedWhenEmpty(self,vehicle:"int")->"bool":
+ return_pywrapcp.RoutingModel_IsVehicleUsedWhenEmpty(self,vehicle)
+
+ defSetFirstSolutionEvaluator(self,evaluator:"operations_research::Solver::IndexEvaluator2")->"void":
+ r"""
+ Gets/sets the evaluator used during the search. Only relevant when
+ RoutingSearchParameters.first_solution_strategy = EVALUATOR_STRATEGY.
+ Takes ownership of evaluator.
+ """
+ return_pywrapcp.RoutingModel_SetFirstSolutionEvaluator(self,evaluator)
+
+ defAddLocalSearchOperator(self,ls_operator:"LocalSearchOperator")->"void":
+ r"""
+ Adds a local search operator to the set of operators used to solve the
+ vehicle routing problem.
+ """
+ return_pywrapcp.RoutingModel_AddLocalSearchOperator(self,ls_operator)
+
+ defAddSearchMonitor(self,monitor:"SearchMonitor")->"void":
+ r""" Adds a search monitor to the search used to solve the routing model."""
+ return_pywrapcp.RoutingModel_AddSearchMonitor(self,monitor)
+
+ defAddAtSolutionCallback(self,callback:"std::function< void () >")->"void":
+ r"""
+ Adds a callback called each time a solution is found during the search.
+ This is a shortcut to creating a monitor to call the callback on
+ AtSolution() and adding it with AddSearchMonitor.
+ """
+ return_pywrapcp.RoutingModel_AddAtSolutionCallback(self,callback)
+
+ defAddVariableMinimizedByFinalizer(self,var:"IntVar")->"void":
+ r"""
+ Adds a variable to minimize in the solution finalizer. The solution
+ finalizer is called each time a solution is found during the search and
+ allows to instantiate secondary variables (such as dimension cumul
+ variables).
+ """
+ return_pywrapcp.RoutingModel_AddVariableMinimizedByFinalizer(self,var)
+
+ defAddVariableMaximizedByFinalizer(self,var:"IntVar")->"void":
+ r"""
+ Adds a variable to maximize in the solution finalizer (see above for
+ information on the solution finalizer).
+ """
+ return_pywrapcp.RoutingModel_AddVariableMaximizedByFinalizer(self,var)
+
+ defAddWeightedVariableMinimizedByFinalizer(self,var:"IntVar",cost:"int64_t")->"void":
+ r"""
+ Adds a variable to minimize in the solution finalizer, with a weighted
+ priority: the higher the more priority it has.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableMinimizedByFinalizer(self,var,cost)
+
+ defAddWeightedVariableMaximizedByFinalizer(self,var:"IntVar",cost:"int64_t")->"void":
+ r"""
+ Adds a variable to maximize in the solution finalizer, with a weighted
+ priority: the higher the more priority it has.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableMaximizedByFinalizer(self,var,cost)
+
+ defAddVariableTargetToFinalizer(self,var:"IntVar",target:"int64_t")->"void":
+ r"""
+ Add a variable to set the closest possible to the target value in the
+ solution finalizer.
+ """
+ return_pywrapcp.RoutingModel_AddVariableTargetToFinalizer(self,var,target)
+
+ defAddWeightedVariableTargetToFinalizer(self,var:"IntVar",target:"int64_t",cost:"int64_t")->"void":
+ r"""
+ Same as above with a weighted priority: the higher the cost, the more
+ priority it has to be set close to the target value.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableTargetToFinalizer(self,var,target,cost)
+
+ defCloseModel(self)->"void":
+ r"""
+ Closes the current routing model; after this method is called, no
+ modification to the model can be done, but RoutesToAssignment becomes
+ available. Note that CloseModel() is automatically called by Solve() and
+ other methods that produce solution.
+ This is equivalent to calling
+ CloseModelWithParameters(DefaultRoutingSearchParameters()).
+ """
+ return_pywrapcp.RoutingModel_CloseModel(self)
+
+ defCloseModelWithParameters(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"void":
+ r"""
+ Same as above taking search parameters (as of 10/2015 some the parameters
+ have to be set when closing the model).
+ """
+ return_pywrapcp.RoutingModel_CloseModelWithParameters(self,search_parameters)
+
+ defSolve(self,assignment:"Assignment"=None)->"operations_research::Assignment const *":
+ r"""
+ Solves the current routing model; closes the current model.
+ This is equivalent to calling
+ SolveWithParameters(DefaultRoutingSearchParameters())
+ or
+ SolveFromAssignmentWithParameters(assignment,
+ DefaultRoutingSearchParameters()).
+ """
+ return_pywrapcp.RoutingModel_Solve(self,assignment)
+
+ defSolveWithParameters(self,search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Solves the current routing model with the given parameters. If 'solutions'
+ is specified, it will contain the k best solutions found during the search
+ (from worst to best, including the one returned by this method), where k
+ corresponds to the 'number_of_solutions_to_collect' in
+ 'search_parameters'. Note that the Assignment returned by the method and
+ the ones in solutions are owned by the underlying solver and should not be
+ deleted.
+ """
+ return_pywrapcp.RoutingModel_SolveWithParameters(self,search_parameters,solutions)
+
+ defSolveFromAssignmentWithParameters(self,assignment:"Assignment",search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Same as above, except that if assignment is not null, it will be used as
+ the initial solution.
+ """
+ return_pywrapcp.RoutingModel_SolveFromAssignmentWithParameters(self,assignment,search_parameters,solutions)
+
+ defSolveFromAssignmentsWithParameters(self,assignments:"std::vector< operations_research::Assignment const * > const &",search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Same as above but will try all assignments in order as first solutions
+ until one succeeds.
+ """
+ return_pywrapcp.RoutingModel_SolveFromAssignmentsWithParameters(self,assignments,search_parameters,solutions)
+
+ defSetAssignmentFromOtherModelAssignment(self,target_assignment:"Assignment",source_model:"RoutingModel",source_assignment:"Assignment")->"void":
+ r"""
+ Given a "source_model" and its "source_assignment", resets
+ "target_assignment" with the IntVar variables (nexts_, and vehicle_vars_
+ if costs aren't homogeneous across vehicles) of "this" model, with the
+ values set according to those in "other_assignment".
+ The objective_element of target_assignment is set to this->cost_.
+ """
+ return_pywrapcp.RoutingModel_SetAssignmentFromOtherModelAssignment(self,target_assignment,source_model,source_assignment)
+
+ defComputeLowerBound(self)->"int64_t":
+ r"""
+ Computes a lower bound to the routing problem solving a linear assignment
+ problem. The routing model must be closed before calling this method.
+ Note that problems with node disjunction constraints (including optional
+ nodes) and non-homogenous costs are not supported (the method returns 0 in
+ these cases).
+ """
+ return_pywrapcp.RoutingModel_ComputeLowerBound(self)
+
+ defstatus(self)->"operations_research::RoutingModel::Status":
+ r""" Returns the current status of the routing model."""
+ return_pywrapcp.RoutingModel_status(self)
+
+ defApplyLocks(self,locks:"std::vector< int64_t > const &")->"operations_research::IntVar *":
+ r"""
+ Applies a lock chain to the next search. 'locks' represents an ordered
+ vector of nodes representing a partial route which will be fixed during
+ the next search; it will constrain next variables such that:
+ next[locks[i]] == locks[i+1].
+
+ Returns the next variable at the end of the locked chain; this variable is
+ not locked. An assignment containing the locks can be obtained by calling
+ PreAssignment().
+ """
+ return_pywrapcp.RoutingModel_ApplyLocks(self,locks)
+
+ defApplyLocksToAllVehicles(self,locks:"std::vector< std::vector< int64_t > > const &",close_routes:"bool")->"bool":
+ r"""
+ Applies lock chains to all vehicles to the next search, such that locks[p]
+ is the lock chain for route p. Returns false if the locks do not contain
+ valid routes; expects that the routes do not contain the depots,
+ i.e. there are empty vectors in place of empty routes.
+ If close_routes is set to true, adds the end nodes to the route of each
+ vehicle and deactivates other nodes.
+ An assignment containing the locks can be obtained by calling
+ PreAssignment().
+ """
+ return_pywrapcp.RoutingModel_ApplyLocksToAllVehicles(self,locks,close_routes)
+
+ defPreAssignment(self)->"operations_research::Assignment const *const":
+ r"""
+ Returns an assignment used to fix some of the variables of the problem.
+ In practice, this assignment locks partial routes of the problem. This
+ can be used in the context of locking the parts of the routes which have
+ already been driven in online routing problems.
+ """
+ return_pywrapcp.RoutingModel_PreAssignment(self)
+
+ defMutablePreAssignment(self)->"operations_research::Assignment *":
+ return_pywrapcp.RoutingModel_MutablePreAssignment(self)
+
+ defWriteAssignment(self,file_name:"std::string const &")->"bool":
+ r"""
+ Writes the current solution to a file containing an AssignmentProto.
+ Returns false if the file cannot be opened or if there is no current
+ solution.
+ """
+ return_pywrapcp.RoutingModel_WriteAssignment(self,file_name)
+
+ defReadAssignment(self,file_name:"std::string const &")->"operations_research::Assignment *":
+ r"""
+ Reads an assignment from a file and returns the current solution.
+ Returns nullptr if the file cannot be opened or if the assignment is not
+ valid.
+ """
+ return_pywrapcp.RoutingModel_ReadAssignment(self,file_name)
+
+ defRestoreAssignment(self,solution:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Restores an assignment as a solution in the routing model and returns the
+ new solution. Returns nullptr if the assignment is not valid.
+ """
+ return_pywrapcp.RoutingModel_RestoreAssignment(self,solution)
+
+ defReadAssignmentFromRoutes(self,routes:"std::vector< std::vector< int64_t > > const &",ignore_inactive_indices:"bool")->"operations_research::Assignment *":
+ r"""
+ Restores the routes as the current solution. Returns nullptr if the
+ solution cannot be restored (routes do not contain a valid solution). Note
+ that calling this method will run the solver to assign values to the
+ dimension variables; this may take considerable amount of time, especially
+ when using dimensions with slack.
+ """
+ return_pywrapcp.RoutingModel_ReadAssignmentFromRoutes(self,routes,ignore_inactive_indices)
+
+ defRoutesToAssignment(self,routes:"std::vector< std::vector< int64_t > > const &",ignore_inactive_indices:"bool",close_routes:"bool",assignment:"Assignment")->"bool":
+ r"""
+ Fills an assignment from a specification of the routes of the
+ vehicles. The routes are specified as lists of variable indices that
+ appear on the routes of the vehicles. The indices of the outer vector in
+ 'routes' correspond to vehicles IDs, the inner vector contains the
+ variable indices on the routes for the given vehicle. The inner vectors
+ must not contain the start and end indices, as these are determined by the
+ routing model. Sets the value of NextVars in the assignment, adding the
+ variables to the assignment if necessary. The method does not touch other
+ variables in the assignment. The method can only be called after the model
+ is closed. With ignore_inactive_indices set to false, this method will
+ fail (return nullptr) in case some of the route contain indices that are
+ deactivated in the model; when set to true, these indices will be
+ skipped. Returns true if routes were successfully
+ loaded. However, such assignment still might not be a valid
+ solution to the routing problem due to more complex constraints;
+ it is advisible to call solver()->CheckSolution() afterwards.
+ """
+ return_pywrapcp.RoutingModel_RoutesToAssignment(self,routes,ignore_inactive_indices,close_routes,assignment)
+
+ defAssignmentToRoutes(self,assignment:"Assignment",routes:"std::vector< std::vector< int64_t > > *const")->"void":
+ r"""
+ Converts the solution in the given assignment to routes for all vehicles.
+ Expects that assignment contains a valid solution (i.e. routes for all
+ vehicles end with an end index for that vehicle).
+ """
+ return_pywrapcp.RoutingModel_AssignmentToRoutes(self,assignment,routes)
+
+ defCompactAssignment(self,assignment:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Converts the solution in the given assignment to routes for all vehicles.
+ If the returned vector is route_indices, route_indices[i][j] is the index
+ for jth location visited on route i. Note that contrary to
+ AssignmentToRoutes, the vectors do include start and end locations.
+ Returns a compacted version of the given assignment, in which all vehicles
+ with id lower or equal to some N have non-empty routes, and all vehicles
+ with id greater than N have empty routes. Does not take ownership of the
+ returned object.
+ If found, the cost of the compact assignment is the same as in the
+ original assignment and it preserves the values of 'active' variables.
+ Returns nullptr if a compact assignment was not found.
+ This method only works in homogenous mode, and it only swaps equivalent
+ vehicles (vehicles with the same start and end nodes). When creating the
+ compact assignment, the empty plan is replaced by the route assigned to
+ the compatible vehicle with the highest id. Note that with more complex
+ constraints on vehicle variables, this method might fail even if a compact
+ solution exists.
+ This method changes the vehicle and dimension variables as necessary.
+ While compacting the solution, only basic checks on vehicle variables are
+ performed; if one of these checks fails no attempts to repair it are made
+ (instead, the method returns nullptr).
+ """
+ return_pywrapcp.RoutingModel_CompactAssignment(self,assignment)
+
+ defCompactAndCheckAssignment(self,assignment:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Same as CompactAssignment() but also checks the validity of the final
+ compact solution; if it is not valid, no attempts to repair it are made
+ (instead, the method returns nullptr).
+ """
+ return_pywrapcp.RoutingModel_CompactAndCheckAssignment(self,assignment)
+
+ defAddToAssignment(self,var:"IntVar")->"void":
+ r""" Adds an extra variable to the vehicle routing assignment."""
+ return_pywrapcp.RoutingModel_AddToAssignment(self,var)
+
+ defAddIntervalToAssignment(self,interval:"IntervalVar")->"void":
+ return_pywrapcp.RoutingModel_AddIntervalToAssignment(self,interval)
+
+ defPackCumulsOfOptimizerDimensionsFromAssignment(self,original_assignment:"Assignment",duration_limit:"absl::Duration")->"operations_research::Assignment const *":
+ r"""
+ For every dimension in the model with an optimizer in
+ local/global_dimension_optimizers_, this method tries to pack the cumul
+ values of the dimension, such that:
+ - The cumul costs (span costs, soft lower and upper bound costs, etc) are
+ minimized.
+ - The cumuls of the ends of the routes are minimized for this given
+ minimal cumul cost.
+ - Given these minimal end cumuls, the route start cumuls are maximized.
+ Returns the assignment resulting from allocating these packed cumuls with
+ the solver, and nullptr if these cumuls could not be set by the solver.
+ """
+ return_pywrapcp.RoutingModel_PackCumulsOfOptimizerDimensionsFromAssignment(self,original_assignment,duration_limit)
+
+ defAddLocalSearchFilter(self,filter:"LocalSearchFilter")->"void":
+ r"""
+ Adds a custom local search filter to the list of filters used to speed up
+ local search by pruning unfeasible variable assignments.
+ Calling this method after the routing model has been closed (CloseModel()
+ or Solve() has been called) has no effect.
+ The routing model does not take ownership of the filter.
+ """
+ return_pywrapcp.RoutingModel_AddLocalSearchFilter(self,filter)
+
+ defStart(self,vehicle:"int")->"int64_t":
+ r"""
+ Model inspection.
+ Returns the variable index of the starting node of a vehicle route.
+ """
+ return_pywrapcp.RoutingModel_Start(self,vehicle)
+
+ defEnd(self,vehicle:"int")->"int64_t":
+ r""" Returns the variable index of the ending node of a vehicle route."""
+ return_pywrapcp.RoutingModel_End(self,vehicle)
+
+ defIsStart(self,index:"int64_t")->"bool":
+ r""" Returns true if 'index' represents the first node of a route."""
+ return_pywrapcp.RoutingModel_IsStart(self,index)
+
+ defIsEnd(self,index:"int64_t")->"bool":
+ r""" Returns true if 'index' represents the last node of a route."""
+ return_pywrapcp.RoutingModel_IsEnd(self,index)
+
+ defVehicleIndex(self,index:"int64_t")->"int":
+ r"""
+ Returns the vehicle of the given start/end index, and -1 if the given
+ index is not a vehicle start/end.
+ """
+ return_pywrapcp.RoutingModel_VehicleIndex(self,index)
+
+ defNext(self,assignment:"Assignment",index:"int64_t")->"int64_t":
+ r"""
+ Assignment inspection
+ Returns the variable index of the node directly after the node
+ corresponding to 'index' in 'assignment'.
+ """
+ return_pywrapcp.RoutingModel_Next(self,assignment,index)
+
+ defIsVehicleUsed(self,assignment:"Assignment",vehicle:"int")->"bool":
+ r""" Returns true if the route of 'vehicle' is non empty in 'assignment'."""
+ return_pywrapcp.RoutingModel_IsVehicleUsed(self,assignment,vehicle)
+
+ defNextVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Returns the next variable of the node corresponding to index. Note that
+ NextVar(index) == index is equivalent to ActiveVar(index) == 0.
+ """
+ return_pywrapcp.RoutingModel_NextVar(self,index)
+
+ defActiveVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r""" Returns the active variable of the node corresponding to index."""
+ return_pywrapcp.RoutingModel_ActiveVar(self,index)
+
+ defActiveVehicleVar(self,vehicle:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the active variable of the vehicle. It will be equal to 1 iff the
+ route of the vehicle is not empty, 0 otherwise.
+ """
+ return_pywrapcp.RoutingModel_ActiveVehicleVar(self,vehicle)
+
+ defVehicleRouteConsideredVar(self,vehicle:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the variable specifying whether or not the given vehicle route is
+ considered for costs and constraints. It will be equal to 1 iff the route
+ of the vehicle is not empty OR vehicle_used_when_empty_[vehicle] is true.
+ """
+ return_pywrapcp.RoutingModel_VehicleRouteConsideredVar(self,vehicle)
+
+ defVehicleVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Returns the vehicle variable of the node corresponding to index. Note that
+ VehicleVar(index) == -1 is equivalent to ActiveVar(index) == 0.
+ """
+ return_pywrapcp.RoutingModel_VehicleVar(self,index)
+
+ defResourceVar(self,vehicle:"int",resource_group:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the resource variable for the given vehicle index in the given
+ resource group. If a vehicle doesn't require a resource from the
+ corresponding resource group, then ResourceVar(v, r_g) == -1.
+ """
+ return_pywrapcp.RoutingModel_ResourceVar(self,vehicle,resource_group)
+
+ defCostVar(self)->"operations_research::IntVar *":
+ r""" Returns the global cost variable which is being minimized."""
+ return_pywrapcp.RoutingModel_CostVar(self)
+
+ defGetArcCostForVehicle(self,from_index:"int64_t",to_index:"int64_t",vehicle:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the transit arc between two nodes for a given vehicle.
+ Input are variable indices of node. This returns 0 if vehicle < 0.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForVehicle(self,from_index,to_index,vehicle)
+
+ defCostsAreHomogeneousAcrossVehicles(self)->"bool":
+ r""" Whether costs are homogeneous across all vehicles."""
+ return_pywrapcp.RoutingModel_CostsAreHomogeneousAcrossVehicles(self)
+
+ defGetHomogeneousCost(self,from_index:"int64_t",to_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the segment between two nodes supposing all vehicle
+ costs are the same (returns the cost for the first vehicle otherwise).
+ """
+ return_pywrapcp.RoutingModel_GetHomogeneousCost(self,from_index,to_index)
+
+ defGetArcCostForFirstSolution(self,from_index:"int64_t",to_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the arc in the context of the first solution strategy.
+ This is typically a simplification of the actual cost; see the .cc.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForFirstSolution(self,from_index,to_index)
+
+ defGetArcCostForClass(self,from_index:"int64_t",to_index:"int64_t",cost_class_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the segment between two nodes for a given cost
+ class. Input are variable indices of nodes and the cost class.
+ Unlike GetArcCostForVehicle(), if cost_class is kNoCost, then the
+ returned cost won't necessarily be zero: only some of the components
+ of the cost that depend on the cost class will be omited. See the code
+ for details.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForClass(self,from_index,to_index,cost_class_index)
+
+ defGetCostClassIndexOfVehicle(self,vehicle:"int64_t")->"operations_research::RoutingModel::CostClassIndex":
+ r""" Get the cost class index of the given vehicle."""
+ return_pywrapcp.RoutingModel_GetCostClassIndexOfVehicle(self,vehicle)
+
+ defHasVehicleWithCostClassIndex(self,cost_class_index:"operations_research::RoutingModel::CostClassIndex")->"bool":
+ r"""
+ Returns true iff the model contains a vehicle with the given
+ cost_class_index.
+ """
+ return_pywrapcp.RoutingModel_HasVehicleWithCostClassIndex(self,cost_class_index)
+
+ defGetCostClassesCount(self)->"int":
+ r""" Returns the number of different cost classes in the model."""
+ return_pywrapcp.RoutingModel_GetCostClassesCount(self)
+
+ defGetNonZeroCostClassesCount(self)->"int":
+ r""" Ditto, minus the 'always zero', built-in cost class."""
+ return_pywrapcp.RoutingModel_GetNonZeroCostClassesCount(self)
+
+ defGetVehicleClassIndexOfVehicle(self,vehicle:"int64_t")->"operations_research::RoutingModel::VehicleClassIndex":
+ return_pywrapcp.RoutingModel_GetVehicleClassIndexOfVehicle(self,vehicle)
+
+ defGetVehicleOfClass(self,vehicle_class:"operations_research::RoutingModel::VehicleClassIndex")->"int":
+ r"""
+ Returns a vehicle of the given vehicle class, and -1 if there are no
+ vehicles for this class.
+ """
+ return_pywrapcp.RoutingModel_GetVehicleOfClass(self,vehicle_class)
+
+ defGetVehicleClassesCount(self)->"int":
+ r""" Returns the number of different vehicle classes in the model."""
+ return_pywrapcp.RoutingModel_GetVehicleClassesCount(self)
+
+ defGetSameVehicleIndicesOfIndex(self,node:"int")->"std::vector< int > const &":
+ r""" Returns variable indices of nodes constrained to be on the same route."""
+ return_pywrapcp.RoutingModel_GetSameVehicleIndicesOfIndex(self,node)
+
+ defGetVehicleTypeContainer(self)->"operations_research::RoutingModel::VehicleTypeContainer const &":
+ return_pywrapcp.RoutingModel_GetVehicleTypeContainer(self)
+
+ defArcIsMoreConstrainedThanArc(self,_from:"int64_t",to1:"int64_t",to2:"int64_t")->"bool":
+ r"""
+ Returns whether the arc from->to1 is more constrained than from->to2,
+ taking into account, in order:
+ - whether the destination node isn't an end node
+ - whether the destination node is mandatory
+ - whether the destination node is bound to the same vehicle as the source
+ - the "primary constrained" dimension (see SetPrimaryConstrainedDimension)
+ It then breaks ties using, in order:
+ - the arc cost (taking unperformed penalties into account)
+ - the size of the vehicle vars of "to1" and "to2" (lowest size wins)
+ - the value: the lowest value of the indices to1 and to2 wins.
+ See the .cc for details.
+ The more constrained arc is typically preferable when building a
+ first solution. This method is intended to be used as a callback for the
+ BestValueByComparisonSelector value selector.
+ Args:
+ from: the variable index of the source node
+ to1: the variable index of the first candidate destination node.
+ to2: the variable index of the second candidate destination node.
+ """
+ return_pywrapcp.RoutingModel_ArcIsMoreConstrainedThanArc(self,_from,to1,to2)
+
+ defDebugOutputAssignment(self,solution_assignment:"Assignment",dimension_to_print:"std::string const &")->"std::string":
+ r"""
+ Print some debugging information about an assignment, including the
+ feasible intervals of the CumulVar for dimension "dimension_to_print"
+ at each step of the routes.
+ If "dimension_to_print" is omitted, all dimensions will be printed.
+ """
+ return_pywrapcp.RoutingModel_DebugOutputAssignment(self,solution_assignment,dimension_to_print)
+
+ defsolver(self)->"operations_research::Solver *":
+ r"""
+ Returns a vector cumul_bounds, for which cumul_bounds[i][j] is a pair
+ containing the minimum and maximum of the CumulVar of the jth node on
+ route i.
+ - cumul_bounds[i][j].first is the minimum.
+ - cumul_bounds[i][j].second is the maximum.
+ Returns the underlying constraint solver. Can be used to add extra
+ constraints and/or modify search algorithms.
+ """
+ return_pywrapcp.RoutingModel_solver(self)
+
+ defCheckLimit(self)->"bool":
+ r""" Returns true if the search limit has been crossed."""
+ return_pywrapcp.RoutingModel_CheckLimit(self)
+
+ defRemainingTime(self)->"absl::Duration":
+ r""" Returns the time left in the search limit."""
+ return_pywrapcp.RoutingModel_RemainingTime(self)
+
+ defnodes(self)->"int":
+ r"""
+ Sizes and indices
+ Returns the number of nodes in the model.
+ """
+ return_pywrapcp.RoutingModel_nodes(self)
+
+ defvehicles(self)->"int":
+ r""" Returns the number of vehicle routes in the model."""
+ return_pywrapcp.RoutingModel_vehicles(self)
+
+ defSize(self)->"int64_t":
+ r""" Returns the number of next variables in the model."""
+ return_pywrapcp.RoutingModel_Size(self)
+
+ defGetNumberOfDecisionsInFirstSolution(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"int64_t":
+ r"""
+ Returns statistics on first solution search, number of decisions sent to
+ filters, number of decisions rejected by filters.
+ """
+ return_pywrapcp.RoutingModel_GetNumberOfDecisionsInFirstSolution(self,search_parameters)
+
+ defGetNumberOfRejectsInFirstSolution(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"int64_t":
+ return_pywrapcp.RoutingModel_GetNumberOfRejectsInFirstSolution(self,search_parameters)
+
+ defGetAutomaticFirstSolutionStrategy(self)->"operations_research::FirstSolutionStrategy::Value":
+ r""" Returns the automatic first solution strategy selected."""
+ return_pywrapcp.RoutingModel_GetAutomaticFirstSolutionStrategy(self)
+
+ defIsMatchingModel(self)->"bool":
+ r""" Returns true if a vehicle/node matching problem is detected."""
+ return_pywrapcp.RoutingModel_IsMatchingModel(self)
+
+ defMakeGuidedSlackFinalizer(self,dimension:"RoutingDimension",initializer:"std::function< int64_t (int64_t) >")->"operations_research::DecisionBuilder *":
+ r"""
+ The next few members are in the public section only for testing purposes.
+
+ MakeGuidedSlackFinalizer creates a DecisionBuilder for the slacks of a
+ dimension using a callback to choose which values to start with.
+ The finalizer works only when all next variables in the model have
+ been fixed. It has the following two characteristics:
+ 1. It follows the routes defined by the nexts variables when choosing a
+ variable to make a decision on.
+ 2. When it comes to choose a value for the slack of node i, the decision
+ builder first calls the callback with argument i, and supposingly the
+ returned value is x it creates decisions slack[i] = x, slack[i] = x +
+ 1, slack[i] = x - 1, slack[i] = x + 2, etc.
+ """
+ return_pywrapcp.RoutingModel_MakeGuidedSlackFinalizer(self,dimension,initializer)
+
+ defMakeSelfDependentDimensionFinalizer(self,dimension:"RoutingDimension")->"operations_research::DecisionBuilder *":
+ r"""
+ MakeSelfDependentDimensionFinalizer is a finalizer for the slacks of a
+ self-dependent dimension. It makes an extensive use of the caches of the
+ state dependent transits.
+ In detail, MakeSelfDependentDimensionFinalizer returns a composition of a
+ local search decision builder with a greedy descent operator for the cumul
+ of the start of each route and a guided slack finalizer. Provided there
+ are no time windows and the maximum slacks are large enough, once the
+ cumul of the start of route is fixed, the guided finalizer can find
+ optimal values of the slacks for the rest of the route in time
+ proportional to the length of the route. Therefore the composed finalizer
+ generally works in time O(log(t)*n*m), where t is the latest possible
+ departute time, n is the number of nodes in the network and m is the
+ number of vehicles.
+ """
+ return_pywrapcp.RoutingModel_MakeSelfDependentDimensionFinalizer(self,dimension)
+
+# Register RoutingModel in _pywrapcp:
+_pywrapcp.RoutingModel_swigregister(RoutingModel)
+cvar=_pywrapcp.cvar
+RoutingModel.kNoPenalty=_pywrapcp.cvar.RoutingModel_kNoPenalty
+RoutingModel.kNoDisjunction=_pywrapcp.cvar.RoutingModel_kNoDisjunction
+RoutingModel.kNoDimension=_pywrapcp.cvar.RoutingModel_kNoDimension
+
+classRoutingModelVisitor(BaseObject):
+ r""" Routing model visitor."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self):
+ _pywrapcp.RoutingModelVisitor_swiginit(self,_pywrapcp.new_RoutingModelVisitor())
+ __swig_destroy__=_pywrapcp.delete_RoutingModelVisitor
+
+# Register RoutingModelVisitor in _pywrapcp:
+_pywrapcp.RoutingModelVisitor_swigregister(RoutingModelVisitor)
+RoutingModelVisitor.kLightElement=_pywrapcp.cvar.RoutingModelVisitor_kLightElement
+RoutingModelVisitor.kLightElement2=_pywrapcp.cvar.RoutingModelVisitor_kLightElement2
+RoutingModelVisitor.kRemoveValues=_pywrapcp.cvar.RoutingModelVisitor_kRemoveValues
+
+classGlobalVehicleBreaksConstraint(Constraint):
+ r"""
+ GlobalVehicleBreaksConstraint ensures breaks constraints are enforced on
+ all vehicles in the dimension passed to its constructor.
+ It is intended to be used for dimensions representing time.
+ A break constraint ensures break intervals fit on the route of a vehicle.
+ For a given vehicle, it forces break intervals to be disjoint from visit
+ intervals, where visit intervals start at CumulVar(node) and last for
+ node_visit_transit[node]. Moreover, it ensures that there is enough time
+ between two consecutive nodes of a route to do transit and vehicle breaks,
+ i.e. if Next(nodeA) = nodeB, CumulVar(nodeA) = tA and CumulVar(nodeB) = tB,
+ then SlackVar(nodeA) >= sum_{breaks [tA, tB)} duration(break).
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,dimension:"RoutingDimension"):
+ _pywrapcp.GlobalVehicleBreaksConstraint_swiginit(self,_pywrapcp.new_GlobalVehicleBreaksConstraint(dimension))
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.GlobalVehicleBreaksConstraint_DebugString(self)
+
+ defPost(self)->"void":
+ return_pywrapcp.GlobalVehicleBreaksConstraint_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ return_pywrapcp.GlobalVehicleBreaksConstraint_InitialPropagateWrapper(self)
+ __swig_destroy__=_pywrapcp.delete_GlobalVehicleBreaksConstraint
+
+# Register GlobalVehicleBreaksConstraint in _pywrapcp:
+_pywrapcp.GlobalVehicleBreaksConstraint_swigregister(GlobalVehicleBreaksConstraint)
+
+classTypeRegulationsChecker(object):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+ __swig_destroy__=_pywrapcp.delete_TypeRegulationsChecker
+
+ defCheckVehicle(self,vehicle:"int",next_accessor:"std::function< int64_t (int64_t) > const &")->"bool":
+ return_pywrapcp.TypeRegulationsChecker_CheckVehicle(self,vehicle,next_accessor)
+
+# Register TypeRegulationsChecker in _pywrapcp:
+_pywrapcp.TypeRegulationsChecker_swigregister(TypeRegulationsChecker)
+
+classTypeIncompatibilityChecker(TypeRegulationsChecker):
+ r""" Checker for type incompatibilities."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,model:"RoutingModel",check_hard_incompatibilities:"bool"):
+ _pywrapcp.TypeIncompatibilityChecker_swiginit(self,_pywrapcp.new_TypeIncompatibilityChecker(model,check_hard_incompatibilities))
+ __swig_destroy__=_pywrapcp.delete_TypeIncompatibilityChecker
+
+# Register TypeIncompatibilityChecker in _pywrapcp:
+_pywrapcp.TypeIncompatibilityChecker_swigregister(TypeIncompatibilityChecker)
+
+classTypeRequirementChecker(TypeRegulationsChecker):
+ r""" Checker for type requirements."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,model:"RoutingModel"):
+ _pywrapcp.TypeRequirementChecker_swiginit(self,_pywrapcp.new_TypeRequirementChecker(model))
+ __swig_destroy__=_pywrapcp.delete_TypeRequirementChecker
+
+# Register TypeRequirementChecker in _pywrapcp:
+_pywrapcp.TypeRequirementChecker_swigregister(TypeRequirementChecker)
+
+classTypeRegulationsConstraint(Constraint):
+ r"""
+ The following constraint ensures that incompatibilities and requirements
+ between types are respected.
+
+ It verifies both "hard" and "temporal" incompatibilities.
+ Two nodes with hard incompatible types cannot be served by the same vehicle
+ at all, while with a temporal incompatibility they can't be on the same
+ route at the same time.
+ The VisitTypePolicy of a node determines how visiting it impacts the type
+ count on the route.
+
+ For example, for
+ - three temporally incompatible types T1 T2 and T3
+ - 2 pairs of nodes a1/r1 and a2/r2 of type T1 and T2 respectively, with
+ - a1 and a2 of VisitTypePolicy TYPE_ADDED_TO_VEHICLE
+ - r1 and r2 of policy ADDED_TYPE_REMOVED_FROM_VEHICLE
+ - 3 nodes A, UV and AR of type T3, respectively with type policies
+ TYPE_ADDED_TO_VEHICLE, TYPE_ON_VEHICLE_UP_TO_VISIT and
+ TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED
+ the configurations
+ UV --> a1 --> r1 --> a2 --> r2, a1 --> r1 --> a2 --> r2 --> A and
+ a1 --> r1 --> AR --> a2 --> r2 are acceptable, whereas the configurations
+ a1 --> a2 --> r1 --> ..., or A --> a1 --> r1 --> ..., or
+ a1 --> r1 --> UV --> ... are not feasible.
+
+ It also verifies same-vehicle and temporal type requirements.
+ A node of type T_d with a same-vehicle requirement for type T_r needs to be
+ served by the same vehicle as a node of type T_r.
+ Temporal requirements, on the other hand, can take effect either when the
+ dependent type is being added to the route or when it's removed from it,
+ which is determined by the dependent node's VisitTypePolicy.
+ In the above example:
+ - If T3 is required on the same vehicle as T1, A, AR or UV must be on the
+ same vehicle as a1.
+ - If T2 is required when adding T1, a2 must be visited *before* a1, and if
+ r2 is also visited on the route, it must be *after* a1, i.e. T2 must be on
+ the vehicle when a1 is visited:
+ ... --> a2 --> ... --> a1 --> ... --> r2 --> ...
+ - If T3 is required when removing T1, T3 needs to be on the vehicle when
+ r1 is visited:
+ ... --> A --> ... --> r1 --> ... OR ... --> r1 --> ... --> UV --> ...
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,model:"RoutingModel"):
+ _pywrapcp.TypeRegulationsConstraint_swiginit(self,_pywrapcp.new_TypeRegulationsConstraint(model))
+
+ defPost(self)->"void":
+ return_pywrapcp.TypeRegulationsConstraint_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ return_pywrapcp.TypeRegulationsConstraint_InitialPropagateWrapper(self)
+ __swig_destroy__=_pywrapcp.delete_TypeRegulationsConstraint
+
+# Register TypeRegulationsConstraint in _pywrapcp:
+_pywrapcp.TypeRegulationsConstraint_swigregister(TypeRegulationsConstraint)
+
+classRoutingDimension(object):
+ r"""
+ Dimensions represent quantities accumulated at nodes along the routes. They
+ represent quantities such as weights or volumes carried along the route, or
+ distance or times.
+
+ Quantities at a node are represented by "cumul" variables and the increase
+ or decrease of quantities between nodes are represented by "transit"
+ variables. These variables are linked as follows:
+
+ if j == next(i),
+ cumuls(j) = cumuls(i) + transits(i) + slacks(i) +
+ state_dependent_transits(i)
+
+ where slack is a positive slack variable (can represent waiting times for
+ a time dimension), and state_dependent_transits is a non-purely functional
+ version of transits_. Favour transits over state_dependent_transits when
+ possible, because purely functional callbacks allow more optimisations and
+ make the model faster and easier to solve.
+ for a given vehicle, it is passed as an external vector, it would be better
+ to have this information here.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+ __swig_destroy__=_pywrapcp.delete_RoutingDimension
+
+ defmodel(self)->"operations_research::RoutingModel *":
+ r""" Returns the model on which the dimension was created."""
+ return_pywrapcp.RoutingDimension_model(self)
+
+ defGetTransitValue(self,from_index:"int64_t",to_index:"int64_t",vehicle:"int64_t")->"int64_t":
+ r"""
+ Returns the transition value for a given pair of nodes (as var index);
+ this value is the one taken by the corresponding transit variable when
+ the 'next' variable for 'from_index' is bound to 'to_index'.
+ """
+ return_pywrapcp.RoutingDimension_GetTransitValue(self,from_index,to_index,vehicle)
+
+ defGetTransitValueFromClass(self,from_index:"int64_t",to_index:"int64_t",vehicle_class:"int64_t")->"int64_t":
+ r"""
+ Same as above but taking a vehicle class of the dimension instead of a
+ vehicle (the class of a vehicle can be obtained with vehicle_to_class()).
+ """
+ return_pywrapcp.RoutingDimension_GetTransitValueFromClass(self,from_index,to_index,vehicle_class)
+
+ defCumulVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Get the cumul, transit and slack variables for the given node (given as
+ int64_t var index).
+ """
+ return_pywrapcp.RoutingDimension_CumulVar(self,index)
+
+ defTransitVar(self,index:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.RoutingDimension_TransitVar(self,index)
+
+ defFixedTransitVar(self,index:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.RoutingDimension_FixedTransitVar(self,index)
+
+ defSlackVar(self,index:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.RoutingDimension_SlackVar(self,index)
+
+ defSetSpanUpperBoundForVehicle(self,upper_bound:"int64_t",vehicle:"int")->"void":
+ r"""
+ Sets an upper bound on the dimension span on a given vehicle. This is the
+ preferred way to limit the "length" of the route of a vehicle according to
+ a dimension.
+ """
+ return_pywrapcp.RoutingDimension_SetSpanUpperBoundForVehicle(self,upper_bound,vehicle)
+
+ defSetSpanCostCoefficientForVehicle(self,coefficient:"int64_t",vehicle:"int")->"void":
+ r"""
+ Sets a cost proportional to the dimension span on a given vehicle,
+ or on all vehicles at once. "coefficient" must be nonnegative.
+ This is handy to model costs proportional to idle time when the dimension
+ represents time.
+ The cost for a vehicle is
+ span_cost = coefficient * (dimension end value - dimension start value).
+ """
+ return_pywrapcp.RoutingDimension_SetSpanCostCoefficientForVehicle(self,coefficient,vehicle)
+
+ defSetSpanCostCoefficientForAllVehicles(self,coefficient:"int64_t")->"void":
+ return_pywrapcp.RoutingDimension_SetSpanCostCoefficientForAllVehicles(self,coefficient)
+
+ defSetGlobalSpanCostCoefficient(self,coefficient:"int64_t")->"void":
+ r"""
+ Sets a cost proportional to the *global* dimension span, that is the
+ difference between the largest value of route end cumul variables and
+ the smallest value of route start cumul variables.
+ In other words:
+ global_span_cost =
+ coefficient * (Max(dimension end value) - Min(dimension start value)).
+ """
+ return_pywrapcp.RoutingDimension_SetGlobalSpanCostCoefficient(self,coefficient)
+
+ defSetCumulVarSoftUpperBound(self,index:"int64_t",upper_bound:"int64_t",coefficient:"int64_t")->"void":
+ r"""
+ Sets a soft upper bound to the cumul variable of a given variable index.
+ If the value of the cumul variable is greater than the bound, a cost
+ proportional to the difference between this value and the bound is added
+ to the cost function of the model:
+ cumulVar <= upper_bound -> cost = 0
+ cumulVar > upper_bound -> cost = coefficient * (cumulVar - upper_bound)
+ This is also handy to model tardiness costs when the dimension represents
+ time.
+ """
+ return_pywrapcp.RoutingDimension_SetCumulVarSoftUpperBound(self,index,upper_bound,coefficient)
+
+ defHasCumulVarSoftUpperBound(self,index:"int64_t")->"bool":
+ r"""
+ Returns true if a soft upper bound has been set for a given variable
+ index.
+ """
+ return_pywrapcp.RoutingDimension_HasCumulVarSoftUpperBound(self,index)
+
+ defGetCumulVarSoftUpperBound(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the soft upper bound of a cumul variable for a given variable
+ index. The "hard" upper bound of the variable is returned if no soft upper
+ bound has been set.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftUpperBound(self,index)
+
+ defGetCumulVarSoftUpperBoundCoefficient(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost coefficient of the soft upper bound of a cumul variable
+ for a given variable index. If no soft upper bound has been set, 0 is
+ returned.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftUpperBoundCoefficient(self,index)
+
+ defSetCumulVarSoftLowerBound(self,index:"int64_t",lower_bound:"int64_t",coefficient:"int64_t")->"void":
+ r"""
+ Sets a soft lower bound to the cumul variable of a given variable index.
+ If the value of the cumul variable is less than the bound, a cost
+ proportional to the difference between this value and the bound is added
+ to the cost function of the model:
+ cumulVar > lower_bound -> cost = 0
+ cumulVar <= lower_bound -> cost = coefficient * (lower_bound -
+ cumulVar).
+ This is also handy to model earliness costs when the dimension represents
+ time.
+ """
+ return_pywrapcp.RoutingDimension_SetCumulVarSoftLowerBound(self,index,lower_bound,coefficient)
+
+ defHasCumulVarSoftLowerBound(self,index:"int64_t")->"bool":
+ r"""
+ Returns true if a soft lower bound has been set for a given variable
+ index.
+ """
+ return_pywrapcp.RoutingDimension_HasCumulVarSoftLowerBound(self,index)
+
+ defGetCumulVarSoftLowerBound(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the soft lower bound of a cumul variable for a given variable
+ index. The "hard" lower bound of the variable is returned if no soft lower
+ bound has been set.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftLowerBound(self,index)
+
+ defGetCumulVarSoftLowerBoundCoefficient(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost coefficient of the soft lower bound of a cumul variable
+ for a given variable index. If no soft lower bound has been set, 0 is
+ returned.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftLowerBoundCoefficient(self,index)
+
+ defSetBreakIntervalsOfVehicle(self,breaks:"std::vector< operations_research::IntervalVar * >",vehicle:"int",node_visit_transits:"std::vector< int64_t >")->"void":
+ r"""
+ Sets the breaks for a given vehicle. Breaks are represented by
+ IntervalVars. They may interrupt transits between nodes and increase
+ the value of corresponding slack variables.
+ A break may take place before the start of a vehicle, after the end of
+ a vehicle, or during a travel i -> j.
+
+ In that case, the interval [break.Start(), break.End()) must be a subset
+ of [CumulVar(i) + pre_travel(i, j), CumulVar(j) - post_travel(i, j)). In
+ other words, a break may not overlap any node n's visit, given by
+ [CumulVar(n) - post_travel(_, n), CumulVar(n) + pre_travel(n, _)).
+ This formula considers post_travel(_, start) and pre_travel(end, _) to be
+ 0; pre_travel will never be called on any (_, start) and post_travel will
+ never we called on any (end, _). If pre_travel_evaluator or
+ post_travel_evaluator is -1, it will be taken as a function that always
+ returns 0.
+ Deprecated, sets pre_travel(i, j) = node_visit_transit[i].
+ """
+ return_pywrapcp.RoutingDimension_SetBreakIntervalsOfVehicle(self,breaks,vehicle,node_visit_transits)
+
+ defSetBreakDistanceDurationOfVehicle(self,distance:"int64_t",duration:"int64_t",vehicle:"int")->"void":
+ r"""
+ With breaks supposed to be consecutive, this forces the distance between
+ breaks of size at least minimum_break_duration to be at most distance.
+ This supposes that the time until route start and after route end are
+ infinite breaks.
+ """
+ return_pywrapcp.RoutingDimension_SetBreakDistanceDurationOfVehicle(self,distance,duration,vehicle)
+
+ defInitializeBreaks(self)->"void":
+ r"""
+ Sets up vehicle_break_intervals_, vehicle_break_distance_duration_,
+ pre_travel_evaluators and post_travel_evaluators.
+ """
+ return_pywrapcp.RoutingDimension_InitializeBreaks(self)
+
+ defHasBreakConstraints(self)->"bool":
+ r""" Returns true if any break interval or break distance was defined."""
+ return_pywrapcp.RoutingDimension_HasBreakConstraints(self)
+
+ defGetPreTravelEvaluatorOfVehicle(self,vehicle:"int")->"int":
+ return_pywrapcp.RoutingDimension_GetPreTravelEvaluatorOfVehicle(self,vehicle)
+
+ defGetPostTravelEvaluatorOfVehicle(self,vehicle:"int")->"int":
+ return_pywrapcp.RoutingDimension_GetPostTravelEvaluatorOfVehicle(self,vehicle)
+
+ defbase_dimension(self)->"operations_research::RoutingDimension const *":
+ r""" Returns the parent in the dependency tree if any or nullptr otherwise."""
+ return_pywrapcp.RoutingDimension_base_dimension(self)
+
+ defShortestTransitionSlack(self,node:"int64_t")->"int64_t":
+ r"""
+ It makes sense to use the function only for self-dependent dimension.
+ For such dimensions the value of the slack of a node determines the
+ transition cost of the next transit. Provided that
+ 1. cumul[node] is fixed,
+ 2. next[node] and next[next[node]] (if exists) are fixed,
+ the value of slack[node] for which cumul[next[node]] + transit[next[node]]
+ is minimized can be found in O(1) using this function.
+ """
+ return_pywrapcp.RoutingDimension_ShortestTransitionSlack(self,node)
+
+ defname(self)->"std::string const &":
+ r""" Returns the name of the dimension."""
+ return_pywrapcp.RoutingDimension_name(self)
+
+ defSetPickupToDeliveryLimitFunctionForPair(self,limit_function:"operations_research::RoutingDimension::PickupToDeliveryLimitFunction",pair_index:"int")->"void":
+ return_pywrapcp.RoutingDimension_SetPickupToDeliveryLimitFunctionForPair(self,limit_function,pair_index)
+
+ defHasPickupToDeliveryLimits(self)->"bool":
+ return_pywrapcp.RoutingDimension_HasPickupToDeliveryLimits(self)
+
+ defAddNodePrecedence(self,first_node:"int64_t",second_node:"int64_t",offset:"int64_t")->"void":
+ return_pywrapcp.RoutingDimension_AddNodePrecedence(self,first_node,second_node,offset)
+
+ defGetSpanUpperBoundForVehicle(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingDimension_GetSpanUpperBoundForVehicle(self,vehicle)
+
+ defGetSpanCostCoefficientForVehicle(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingDimension_GetSpanCostCoefficientForVehicle(self,vehicle)
+
+ defglobal_span_cost_coefficient(self)->"int64_t":
+ return_pywrapcp.RoutingDimension_global_span_cost_coefficient(self)
+
+ defGetGlobalOptimizerOffset(self)->"int64_t":
+ return_pywrapcp.RoutingDimension_GetGlobalOptimizerOffset(self)
+
+ defGetLocalOptimizerOffsetForVehicle(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingDimension_GetLocalOptimizerOffsetForVehicle(self,vehicle)
+
+# Register RoutingDimension in _pywrapcp:
+_pywrapcp.RoutingDimension_swigregister(RoutingDimension)
+
+
+defMakeSetValuesFromTargets(solver:"Solver",variables:"std::vector< operations_research::IntVar * >",targets:"std::vector< int64_t >")->"operations_research::DecisionBuilder *":
+ r"""
+ A decision builder which tries to assign values to variables as close as
+ possible to target values first.
+ """
+ return_pywrapcp.MakeSetValuesFromTargets(solver,variables,targets)
+
+defSolveModelWithSat(model:"RoutingModel",search_parameters:"operations_research::RoutingSearchParameters const &",initial_solution:"Assignment",solution:"Assignment")->"bool":
+ r"""
+ Attempts to solve the model using the cp-sat solver. As of 5/2019, will
+ solve the TSP corresponding to the model if it has a single vehicle.
+ Therefore the resulting solution might not actually be feasible. Will return
+ false if a solution could not be found.
+ """
+ return_pywrapcp.SolveModelWithSat(model,search_parameters,initial_solution,solution)
+
classDefaultPhaseParameters(object):
+ r"""
+ This struct holds all parameters for the default search.
+ DefaultPhaseParameters is only used by Solver::MakeDefaultPhase methods.
+ Note this is for advanced users only.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ CHOOSE_MAX_SUM_IMPACT=_pywrapcp.DefaultPhaseParameters_CHOOSE_MAX_SUM_IMPACT
+ CHOOSE_MAX_AVERAGE_IMPACT=_pywrapcp.DefaultPhaseParameters_CHOOSE_MAX_AVERAGE_IMPACT
+ CHOOSE_MAX_VALUE_IMPACT=_pywrapcp.DefaultPhaseParameters_CHOOSE_MAX_VALUE_IMPACT
+ SELECT_MIN_IMPACT=_pywrapcp.DefaultPhaseParameters_SELECT_MIN_IMPACT
+ SELECT_MAX_IMPACT=_pywrapcp.DefaultPhaseParameters_SELECT_MAX_IMPACT
+ NONE=_pywrapcp.DefaultPhaseParameters_NONE
+ NORMAL=_pywrapcp.DefaultPhaseParameters_NORMAL
+ VERBOSE=_pywrapcp.DefaultPhaseParameters_VERBOSE
+ var_selection_schema=property(_pywrapcp.DefaultPhaseParameters_var_selection_schema_get,_pywrapcp.DefaultPhaseParameters_var_selection_schema_set,doc=r"""
+ This parameter describes how the next variable to instantiate
+ will be chosen.
+ """)
+ value_selection_schema=property(_pywrapcp.DefaultPhaseParameters_value_selection_schema_get,_pywrapcp.DefaultPhaseParameters_value_selection_schema_set,doc=r""" This parameter describes which value to select for a given var.""")
+ initialization_splits=property(_pywrapcp.DefaultPhaseParameters_initialization_splits_get,_pywrapcp.DefaultPhaseParameters_initialization_splits_set,doc=r"""
+ Maximum number of intervals that the initialization of impacts will scan
+ per variable.
+ """)
+ run_all_heuristics=property(_pywrapcp.DefaultPhaseParameters_run_all_heuristics_get,_pywrapcp.DefaultPhaseParameters_run_all_heuristics_set,doc=r"""
+ The default phase will run heuristics periodically. This parameter
+ indicates if we should run all heuristics, or a randomly selected
+ one.
+ """)
+ heuristic_period=property(_pywrapcp.DefaultPhaseParameters_heuristic_period_get,_pywrapcp.DefaultPhaseParameters_heuristic_period_set,doc=r"""
+ The distance in nodes between each run of the heuristics. A
+ negative or null value will mean that we will not run heuristics
+ at all.
+ """)
+ heuristic_num_failures_limit=property(_pywrapcp.DefaultPhaseParameters_heuristic_num_failures_limit_get,_pywrapcp.DefaultPhaseParameters_heuristic_num_failures_limit_set,doc=r""" The failure limit for each heuristic that we run.""")
+ persistent_impact=property(_pywrapcp.DefaultPhaseParameters_persistent_impact_get,_pywrapcp.DefaultPhaseParameters_persistent_impact_set,doc=r"""
+ Whether to keep the impact from the first search for other searches,
+ or to recompute the impact for each new search.
+ """)
+ random_seed=property(_pywrapcp.DefaultPhaseParameters_random_seed_get,_pywrapcp.DefaultPhaseParameters_random_seed_set,doc=r""" Seed used to initialize the random part in some heuristics.""")
+ display_level=property(_pywrapcp.DefaultPhaseParameters_display_level_get,_pywrapcp.DefaultPhaseParameters_display_level_set,doc=r"""
+ This represents the amount of information displayed by the default search.
+ NONE means no display, VERBOSE means extra information.
+ """)
+ decision_builder=property(_pywrapcp.DefaultPhaseParameters_decision_builder_get,_pywrapcp.DefaultPhaseParameters_decision_builder_set,doc=r""" When defined, this overrides the default impact based decision builder.""")
+
+ def__init__(self):
+ _pywrapcp.DefaultPhaseParameters_swiginit(self,_pywrapcp.new_DefaultPhaseParameters())
+ __swig_destroy__=_pywrapcp.delete_DefaultPhaseParameters
+
+
+
+
+
This struct holds all parameters for the default search.
+DefaultPhaseParameters is only used by Solver::MakeDefaultPhase methods.
+Note this is for advanced users only.
classSolver(object):
+ r"""
+ Solver Class
+
+ A solver represents the main computation engine. It implements the entire
+ range of Constraint Programming protocols:
+ - Reversibility
+ - Propagation
+ - Search
+
+ Usually, Constraint Programming code consists of
+ - the creation of the Solver,
+ - the creation of the decision variables of the model,
+ - the creation of the constraints of the model and their addition to the
+ solver() through the AddConstraint() method,
+ - the creation of the main DecisionBuilder class,
+ - the launch of the solve() method with the decision builder.
+
+ For the time being, Solver is neither MT_SAFE nor MT_HOT.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ INT_VAR_DEFAULT=_pywrapcp.Solver_INT_VAR_DEFAULT
+ r""" The default behavior is CHOOSE_FIRST_UNBOUND."""
+ INT_VAR_SIMPLE=_pywrapcp.Solver_INT_VAR_SIMPLE
+ r""" The simple selection is CHOOSE_FIRST_UNBOUND."""
+ CHOOSE_FIRST_UNBOUND=_pywrapcp.Solver_CHOOSE_FIRST_UNBOUND
+ r"""
+ Select the first unbound variable.
+ Variables are considered in the order of the vector of IntVars used
+ to create the selector.
+ """
+ CHOOSE_RANDOM=_pywrapcp.Solver_CHOOSE_RANDOM
+ r""" Randomly select one of the remaining unbound variables."""
+ CHOOSE_MIN_SIZE_LOWEST_MIN=_pywrapcp.Solver_CHOOSE_MIN_SIZE_LOWEST_MIN
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variables is the one with the lowest min
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE_HIGHEST_MIN=_pywrapcp.Solver_CHOOSE_MIN_SIZE_HIGHEST_MIN
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variable is the one with the highest min
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE_LOWEST_MAX=_pywrapcp.Solver_CHOOSE_MIN_SIZE_LOWEST_MAX
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variables is the one with the lowest max
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE_HIGHEST_MAX=_pywrapcp.Solver_CHOOSE_MIN_SIZE_HIGHEST_MAX
+ r"""
+ Among unbound variables, select the variable with the smallest size,
+ i.e., the smallest number of possible values.
+ In case of a tie, the selected variable is the one with the highest max
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_LOWEST_MIN=_pywrapcp.Solver_CHOOSE_LOWEST_MIN
+ r"""
+ Among unbound variables, select the variable with the smallest minimal
+ value.
+ In case of a tie, the first one is selected, "first" defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_HIGHEST_MAX=_pywrapcp.Solver_CHOOSE_HIGHEST_MAX
+ r"""
+ Among unbound variables, select the variable with the highest maximal
+ value.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MIN_SIZE=_pywrapcp.Solver_CHOOSE_MIN_SIZE
+ r"""
+ Among unbound variables, select the variable with the smallest size.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MAX_SIZE=_pywrapcp.Solver_CHOOSE_MAX_SIZE
+ r"""
+ Among unbound variables, select the variable with the highest size.
+ In case of a tie, the first one is selected, first being defined by the
+ order in the vector of IntVars used to create the selector.
+ """
+ CHOOSE_MAX_REGRET_ON_MIN=_pywrapcp.Solver_CHOOSE_MAX_REGRET_ON_MIN
+ r"""
+ Among unbound variables, select the variable with the largest
+ gap between the first and the second values of the domain.
+ """
+ CHOOSE_PATH=_pywrapcp.Solver_CHOOSE_PATH
+ r"""
+ Selects the next unbound variable on a path, the path being defined by
+ the variables: var[i] corresponds to the index of the next of i.
+ """
+ INT_VALUE_DEFAULT=_pywrapcp.Solver_INT_VALUE_DEFAULT
+ r""" The default behavior is ASSIGN_MIN_VALUE."""
+ INT_VALUE_SIMPLE=_pywrapcp.Solver_INT_VALUE_SIMPLE
+ r""" The simple selection is ASSIGN_MIN_VALUE."""
+ ASSIGN_MIN_VALUE=_pywrapcp.Solver_ASSIGN_MIN_VALUE
+ r""" Selects the min value of the selected variable."""
+ ASSIGN_MAX_VALUE=_pywrapcp.Solver_ASSIGN_MAX_VALUE
+ r""" Selects the max value of the selected variable."""
+ ASSIGN_RANDOM_VALUE=_pywrapcp.Solver_ASSIGN_RANDOM_VALUE
+ r""" Selects randomly one of the possible values of the selected variable."""
+ ASSIGN_CENTER_VALUE=_pywrapcp.Solver_ASSIGN_CENTER_VALUE
+ r"""
+ Selects the first possible value which is the closest to the center
+ of the domain of the selected variable.
+ The center is defined as (min + max) / 2.
+ """
+ SPLIT_LOWER_HALF=_pywrapcp.Solver_SPLIT_LOWER_HALF
+ r"""
+ Split the domain in two around the center, and choose the lower
+ part first.
+ """
+ SPLIT_UPPER_HALF=_pywrapcp.Solver_SPLIT_UPPER_HALF
+ r"""
+ Split the domain in two around the center, and choose the lower
+ part first.
+ """
+ SEQUENCE_DEFAULT=_pywrapcp.Solver_SEQUENCE_DEFAULT
+ SEQUENCE_SIMPLE=_pywrapcp.Solver_SEQUENCE_SIMPLE
+ CHOOSE_MIN_SLACK_RANK_FORWARD=_pywrapcp.Solver_CHOOSE_MIN_SLACK_RANK_FORWARD
+ CHOOSE_RANDOM_RANK_FORWARD=_pywrapcp.Solver_CHOOSE_RANDOM_RANK_FORWARD
+ INTERVAL_DEFAULT=_pywrapcp.Solver_INTERVAL_DEFAULT
+ r""" The default is INTERVAL_SET_TIMES_FORWARD."""
+ INTERVAL_SIMPLE=_pywrapcp.Solver_INTERVAL_SIMPLE
+ r""" The simple is INTERVAL_SET_TIMES_FORWARD."""
+ INTERVAL_SET_TIMES_FORWARD=_pywrapcp.Solver_INTERVAL_SET_TIMES_FORWARD
+ r"""
+ Selects the variable with the lowest starting time of all variables,
+ and fixes its starting time to this lowest value.
+ """
+ INTERVAL_SET_TIMES_BACKWARD=_pywrapcp.Solver_INTERVAL_SET_TIMES_BACKWARD
+ r"""
+ Selects the variable with the highest ending time of all variables,
+ and fixes the ending time to this highest values.
+ """
+ TWOOPT=_pywrapcp.Solver_TWOOPT
+ r"""
+ Operator which reverses a sub-chain of a path. It is called TwoOpt
+ because it breaks two arcs on the path; resulting paths are called
+ two-optimal.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5
+ (where (1, 5) are first and last nodes of the path and can therefore not
+ be moved):
+ 1 -> [3 -> 2] -> 4 -> 5
+ 1 -> [4 -> 3 -> 2] -> 5
+ 1 -> 2 -> [4 -> 3] -> 5
+ """
+ OROPT=_pywrapcp.Solver_OROPT
+ r"""
+ Relocate: OROPT and RELOCATE.
+ Operator which moves a sub-chain of a path to another position; the
+ specified chain length is the fixed length of the chains being moved.
+ When this length is 1, the operator simply moves a node to another
+ position.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5, for a chain
+ length of 2 (where (1, 5) are first and last nodes of the path and can
+ therefore not be moved):
+ 1 -> 4 -> [2 -> 3] -> 5
+ 1 -> [3 -> 4] -> 2 -> 5
+
+ Using Relocate with chain lengths of 1, 2 and 3 together is equivalent
+ to the OrOpt operator on a path. The OrOpt operator is a limited
+ version of 3Opt (breaks 3 arcs on a path).
+ """
+ RELOCATE=_pywrapcp.Solver_RELOCATE
+ r""" Relocate neighborhood with length of 1 (see OROPT comment)."""
+ EXCHANGE=_pywrapcp.Solver_EXCHANGE
+ r"""
+ Operator which exchanges the positions of two nodes.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5
+ (where (1, 5) are first and last nodes of the path and can therefore not
+ be moved):
+ 1 -> [3] -> [2] -> 4 -> 5
+ 1 -> [4] -> 3 -> [2] -> 5
+ 1 -> 2 -> [4] -> [3] -> 5
+ """
+ CROSS=_pywrapcp.Solver_CROSS
+ r"""
+ Operator which cross exchanges the starting chains of 2 paths, including
+ exchanging the whole paths.
+ First and last nodes are not moved.
+ Possible neighbors for the paths 1 -> 2 -> 3 -> 4 -> 5 and 6 -> 7 -> 8
+ (where (1, 5) and (6, 8) are first and last nodes of the paths and can
+ therefore not be moved):
+ 1 -> [7] -> 3 -> 4 -> 5 6 -> [2] -> 8
+ 1 -> [7] -> 4 -> 5 6 -> [2 -> 3] -> 8
+ 1 -> [7] -> 5 6 -> [2 -> 3 -> 4] -> 8
+ """
+ MAKEACTIVE=_pywrapcp.Solver_MAKEACTIVE
+ r"""
+ Operator which inserts an inactive node into a path.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+ (where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 2 -> 3 -> 4
+ 1 -> 2 -> [5] -> 3 -> 4
+ 1 -> 2 -> 3 -> [5] -> 4
+ """
+ MAKEINACTIVE=_pywrapcp.Solver_MAKEINACTIVE
+ r"""
+ Operator which makes path nodes inactive.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 (where 1 and 4 are
+ first and last nodes of the path) are:
+ 1 -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> 4 with 3 inactive
+ """
+ MAKECHAININACTIVE=_pywrapcp.Solver_MAKECHAININACTIVE
+ r"""
+ Operator which makes a "chain" of path nodes inactive.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 (where 1 and 4 are
+ first and last nodes of the path) are:
+ 1 -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> 4 with 3 inactive
+ 1 -> 4 with 2 and 3 inactive
+ """
+ SWAPACTIVE=_pywrapcp.Solver_SWAPACTIVE
+ r"""
+ Operator which replaces an active node by an inactive one.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+ (where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> [5] -> 4 with 3 inactive
+ """
+ EXTENDEDSWAPACTIVE=_pywrapcp.Solver_EXTENDEDSWAPACTIVE
+ r"""
+ Operator which makes an inactive node active and an active one inactive.
+ It is similar to SwapActiveOperator except that it tries to insert the
+ inactive node in all possible positions instead of just the position of
+ the node made inactive.
+ Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+ (where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 3 -> 4 with 2 inactive
+ 1 -> 3 -> [5] -> 4 with 2 inactive
+ 1 -> [5] -> 2 -> 4 with 3 inactive
+ 1 -> 2 -> [5] -> 4 with 3 inactive
+ """
+ PATHLNS=_pywrapcp.Solver_PATHLNS
+ r"""
+ Operator which relaxes two sub-chains of three consecutive arcs each.
+ Each sub-chain is defined by a start node and the next three arcs. Those
+ six arcs are relaxed to build a new neighbor.
+ PATHLNS explores all possible pairs of starting nodes and so defines
+ n^2 neighbors, n being the number of nodes.
+ Note that the two sub-chains can be part of the same path; they even may
+ overlap.
+ """
+ FULLPATHLNS=_pywrapcp.Solver_FULLPATHLNS
+ r"""
+ Operator which relaxes one entire path and all inactive nodes, thus
+ defining num_paths neighbors.
+ """
+ UNACTIVELNS=_pywrapcp.Solver_UNACTIVELNS
+ r"""
+ Operator which relaxes all inactive nodes and one sub-chain of six
+ consecutive arcs. That way the path can be improved by inserting
+ inactive nodes or swapping arcs.
+ """
+ INCREMENT=_pywrapcp.Solver_INCREMENT
+ r"""
+ Operator which defines one neighbor per variable. Each neighbor tries to
+ increment by one the value of the corresponding variable. When a new
+ solution is found the neighborhood is rebuilt from scratch, i.e., tries
+ to increment values in the variable order.
+ Consider for instance variables x and y. x is incremented one by one to
+ its max, and when it is not possible to increment x anymore, y is
+ incremented once. If this is a solution, then next neighbor tries to
+ increment x.
+ """
+ DECREMENT=_pywrapcp.Solver_DECREMENT
+ r"""
+ Operator which defines a neighborhood to decrement values.
+ The behavior is the same as INCREMENT, except values are decremented
+ instead of incremented.
+ """
+ SIMPLELNS=_pywrapcp.Solver_SIMPLELNS
+ r"""
+ Operator which defines one neighbor per variable. Each neighbor relaxes
+ one variable.
+ When a new solution is found the neighborhood is rebuilt from scratch.
+ Consider for instance variables x and y. First x is relaxed and the
+ solver is looking for the best possible solution (with only x relaxed).
+ Then y is relaxed, and the solver is looking for a new solution.
+ If a new solution is found, then the next variable to be relaxed is x.
+ """
+ GE=_pywrapcp.Solver_GE
+ r""" Move is accepted when the current objective value >= objective.Min."""
+ LE=_pywrapcp.Solver_LE
+ r""" Move is accepted when the current objective value <= objective.Max."""
+ EQ=_pywrapcp.Solver_EQ
+ r"""
+ Move is accepted when the current objective value is in the interval
+ objective.Min .. objective.Max.
+ """
+ DELAYED_PRIORITY=_pywrapcp.Solver_DELAYED_PRIORITY
+ r"""
+ DELAYED_PRIORITY is the lowest priority: Demons will be processed after
+ VAR_PRIORITY and NORMAL_PRIORITY demons.
+ """
+ VAR_PRIORITY=_pywrapcp.Solver_VAR_PRIORITY
+ r""" VAR_PRIORITY is between DELAYED_PRIORITY and NORMAL_PRIORITY."""
+ NORMAL_PRIORITY=_pywrapcp.Solver_NORMAL_PRIORITY
+ r""" NORMAL_PRIORITY is the highest priority: Demons will be processed first."""
+
+ def__init__(self,*args):
+ _pywrapcp.Solver_swiginit(self,_pywrapcp.new_Solver(*args))
+
+ self.__python_constraints=[]
+
+
+
+ __swig_destroy__=_pywrapcp.delete_Solver
+
+ defParameters(self)->"operations_research::ConstraintSolverParameters":
+ r""" Stored Parameters."""
+ return_pywrapcp.Solver_Parameters(self)
+
+ @staticmethod
+ defDefaultSolverParameters()->"operations_research::ConstraintSolverParameters":
+ r""" Create a ConstraintSolverParameters proto with all the default values."""
+ return_pywrapcp.Solver_DefaultSolverParameters()
+
+ defAddConstraint(self,c:"Constraint")->"void":
+ r"""
+ Adds the constraint 'c' to the model.
+
+ After calling this method, and until there is a backtrack that undoes the
+ addition, any assignment of variables to values must satisfy the given
+ constraint in order to be considered feasible. There are two fairly
+ different use cases:
+
+ - the most common use case is modeling: the given constraint is really
+ part of the problem that the user is trying to solve. In this use case,
+ AddConstraint is called outside of search (i.e., with state() ==
+ OUTSIDE_SEARCH). Most users should only use AddConstraint in this
+ way. In this case, the constraint will belong to the model forever: it
+ cannot not be removed by backtracking.
+
+ - a rarer use case is that 'c' is not a real constraint of the model. It
+ may be a constraint generated by a branching decision (a constraint whose
+ goal is to restrict the search space), a symmetry breaking constraint (a
+ constraint that does restrict the search space, but in a way that cannot
+ have an impact on the quality of the solutions in the subtree), or an
+ inferred constraint that, while having no semantic value to the model (it
+ does not restrict the set of solutions), is worth having because we
+ believe it may strengthen the propagation. In these cases, it happens
+ that the constraint is added during the search (i.e., with state() ==
+ IN_SEARCH or state() == IN_ROOT_NODE). When a constraint is
+ added during a search, it applies only to the subtree of the search tree
+ rooted at the current node, and will be automatically removed by
+ backtracking.
+
+ This method does not take ownership of the constraint. If the constraint
+ has been created by any factory method (Solver::MakeXXX), it will
+ automatically be deleted. However, power users who implement their own
+ constraints should do: solver.AddConstraint(solver.RevAlloc(new
+ MyConstraint(...));
+ """
+ return_pywrapcp.Solver_AddConstraint(self,c)
+
+ defSolve(self,*args)->"bool":
+ return_pywrapcp.Solver_Solve(self,*args)
+
+ defNewSearch(self,*args)->"void":
+ return_pywrapcp.Solver_NewSearch(self,*args)
+
+ defNextSolution(self)->"bool":
+ return_pywrapcp.Solver_NextSolution(self)
+
+ defRestartSearch(self)->"void":
+ return_pywrapcp.Solver_RestartSearch(self)
+
+ defEndSearch(self)->"void":
+ return_pywrapcp.Solver_EndSearch(self)
+
+ defSolveAndCommit(self,*args)->"bool":
+ return_pywrapcp.Solver_SolveAndCommit(self,*args)
+
+ defCheckAssignment(self,solution:"Assignment")->"bool":
+ r""" Checks whether the given assignment satisfies all relevant constraints."""
+ return_pywrapcp.Solver_CheckAssignment(self,solution)
+
+ defCheckConstraint(self,ct:"Constraint")->"bool":
+ r"""
+ Checks whether adding this constraint will lead to an immediate
+ failure. It will return false if the model is already inconsistent, or if
+ adding the constraint makes it inconsistent.
+ """
+ return_pywrapcp.Solver_CheckConstraint(self,ct)
+
+ defFail(self)->"void":
+ r""" Abandon the current branch in the search tree. A backtrack will follow."""
+ return_pywrapcp.Solver_Fail(self)
+
+ @staticmethod
+ defMemoryUsage()->"int64_t":
+ r""" Current memory usage in bytes"""
+ return_pywrapcp.Solver_MemoryUsage()
+
+ defWallTime(self)->"int64_t":
+ r"""
+ DEPRECATED: Use Now() instead.
+ Time elapsed, in ms since the creation of the solver.
+ """
+ return_pywrapcp.Solver_WallTime(self)
+
+ defBranches(self)->"int64_t":
+ r""" The number of branches explored since the creation of the solver."""
+ return_pywrapcp.Solver_Branches(self)
+
+ defSolutions(self)->"int64_t":
+ r""" The number of solutions found since the start of the search."""
+ return_pywrapcp.Solver_Solutions(self)
+
+ defFailures(self)->"int64_t":
+ r""" The number of failures encountered since the creation of the solver."""
+ return_pywrapcp.Solver_Failures(self)
+
+ defAcceptedNeighbors(self)->"int64_t":
+ r""" The number of accepted neighbors."""
+ return_pywrapcp.Solver_AcceptedNeighbors(self)
+
+ defStamp(self)->"uint64_t":
+ r"""
+ The stamp indicates how many moves in the search tree we have performed.
+ It is useful to detect if we need to update same lazy structures.
+ """
+ return_pywrapcp.Solver_Stamp(self)
+
+ defFailStamp(self)->"uint64_t":
+ r""" The fail_stamp() is incremented after each backtrack."""
+ return_pywrapcp.Solver_FailStamp(self)
+
+ defIntVar(self,*args)->"operations_research::IntVar *":
+ r"""
+ *Overload 1:*
+ MakeIntVar will create the best range based int var for the bounds given.
+
+ |
+
+ *Overload 2:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 3:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 4:*
+ MakeIntVar will create the best range based int var for the bounds given.
+
+ |
+
+ *Overload 5:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 6:*
+ MakeIntVar will create a variable with the given sparse domain.
+ """
+ return_pywrapcp.Solver_IntVar(self,*args)
+
+ defBoolVar(self,*args)->"operations_research::IntVar *":
+ r"""
+ *Overload 1:*
+ MakeBoolVar will create a variable with a {0, 1} domain.
+
+ |
+
+ *Overload 2:*
+ MakeBoolVar will create a variable with a {0, 1} domain.
+ """
+ return_pywrapcp.Solver_BoolVar(self,*args)
+
+ defIntConst(self,*args)->"operations_research::IntVar *":
+ r"""
+ *Overload 1:*
+ IntConst will create a constant expression.
+
+ |
+
+ *Overload 2:*
+ IntConst will create a constant expression.
+ """
+ return_pywrapcp.Solver_IntConst(self,*args)
+
+ defSum(self,vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::IntExpr *":
+ r""" sum of all vars."""
+ return_pywrapcp.Solver_Sum(self,vars)
+
+ defScalProd(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ scalar product
+
+ |
+
+ *Overload 2:*
+ scalar product
+ """
+ return_pywrapcp.Solver_ScalProd(self,*args)
+
+ defMonotonicElement(self,values:"operations_research::Solver::IndexEvaluator1",increasing:"bool",index:"IntVar")->"operations_research::IntExpr *":
+ r"""
+ Function based element. The constraint takes ownership of the
+ callback. The callback must be monotonic. It must be able to
+ cope with any possible value in the domain of 'index'
+ (potentially negative ones too). Furtermore, monotonicity is not
+ checked. Thus giving a non-monotonic function, or specifying an
+ incorrect increasing parameter will result in undefined behavior.
+ """
+ return_pywrapcp.Solver_MonotonicElement(self,values,increasing,index)
+
+ defElement(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ values[index]
+
+ |
+
+ *Overload 2:*
+ values[index]
+
+ |
+
+ *Overload 3:*
+ Function-based element. The constraint takes ownership of the
+ callback. The callback must be able to cope with any possible
+ value in the domain of 'index' (potentially negative ones too).
+
+ |
+
+ *Overload 4:*
+ 2D version of function-based element expression, values(expr1, expr2).
+
+ |
+
+ *Overload 5:*
+ vars[expr]
+ """
+ return_pywrapcp.Solver_Element(self,*args)
+
+ defIndexExpression(self,vars:"std::vector< operations_research::IntVar * > const &",value:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ Returns the expression expr such that vars[expr] == value.
+ It assumes that vars are all different.
+ """
+ return_pywrapcp.Solver_IndexExpression(self,vars,value)
+
+ defMin(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ std::min(vars)
+
+ |
+
+ *Overload 2:*
+ std::min (left, right)
+
+ |
+
+ *Overload 3:*
+ std::min(expr, value)
+
+ |
+
+ *Overload 4:*
+ std::min(expr, value)
+ """
+ return_pywrapcp.Solver_Min(self,*args)
+
+ defMax(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ std::max(vars)
+
+ |
+
+ *Overload 2:*
+ std::max(left, right)
+
+ |
+
+ *Overload 3:*
+ std::max(expr, value)
+
+ |
+
+ *Overload 4:*
+ std::max(expr, value)
+ """
+ return_pywrapcp.Solver_Max(self,*args)
+
+ defConvexPiecewiseExpr(self,expr:"IntExpr",early_cost:"int64_t",early_date:"int64_t",late_date:"int64_t",late_cost:"int64_t")->"operations_research::IntExpr *":
+ r""" Convex piecewise function."""
+ return_pywrapcp.Solver_ConvexPiecewiseExpr(self,expr,early_cost,early_date,late_date,late_cost)
+
+ defSemiContinuousExpr(self,expr:"IntExpr",fixed_charge:"int64_t",step:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ Semi continuous Expression (x <= 0 -> f(x) = 0; x > 0 -> f(x) = ax + b)
+ a >= 0 and b >= 0
+ """
+ return_pywrapcp.Solver_SemiContinuousExpr(self,expr,fixed_charge,step)
+
+ defConditionalExpression(self,condition:"IntVar",expr:"IntExpr",unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ r""" Conditional Expr condition ? expr : unperformed_value"""
+ return_pywrapcp.Solver_ConditionalExpression(self,condition,expr,unperformed_value)
+
+ defTrueConstraint(self)->"operations_research::Constraint *":
+ r""" This constraint always succeeds."""
+ return_pywrapcp.Solver_TrueConstraint(self)
+
+ defFalseConstraint(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_FalseConstraint(self,*args)
+
+ defIsEqualCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var == value)"""
+ return_pywrapcp.Solver_IsEqualCstCt(self,var,value,boolvar)
+
+ defIsEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var == value)"""
+ return_pywrapcp.Solver_IsEqualCstVar(self,var,value)
+
+ defIsEqualCt(self,v1:"IntExpr",v2:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v1 == v2)"""
+ return_pywrapcp.Solver_IsEqualCt(self,v1,v2,b)
+
+ defIsEqualVar(self,v1:"IntExpr",v2:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (v1 == v2)"""
+ return_pywrapcp.Solver_IsEqualVar(self,v1,v2)
+
+ defIsDifferentCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var != value)"""
+ return_pywrapcp.Solver_IsDifferentCstCt(self,var,value,boolvar)
+
+ defIsDifferentCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var != value)"""
+ return_pywrapcp.Solver_IsDifferentCstVar(self,var,value)
+
+ defIsDifferentVar(self,v1:"IntExpr",v2:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (v1 != v2)"""
+ return_pywrapcp.Solver_IsDifferentVar(self,v1,v2)
+
+ defIsDifferentCt(self,v1:"IntExpr",v2:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v1 != v2)"""
+ return_pywrapcp.Solver_IsDifferentCt(self,v1,v2,b)
+
+ defIsLessOrEqualCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var <= value)"""
+ return_pywrapcp.Solver_IsLessOrEqualCstCt(self,var,value,boolvar)
+
+ defIsLessOrEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var <= value)"""
+ return_pywrapcp.Solver_IsLessOrEqualCstVar(self,var,value)
+
+ defIsLessOrEqualVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left <= right)"""
+ return_pywrapcp.Solver_IsLessOrEqualVar(self,left,right)
+
+ defIsLessOrEqualCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left <= right)"""
+ return_pywrapcp.Solver_IsLessOrEqualCt(self,left,right,b)
+
+ defIsGreaterOrEqualCstCt(self,var:"IntExpr",value:"int64_t",boolvar:"IntVar")->"operations_research::Constraint *":
+ r""" boolvar == (var >= value)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualCstCt(self,var,value,boolvar)
+
+ defIsGreaterOrEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var >= value)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualCstVar(self,var,value)
+
+ defIsGreaterOrEqualVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left >= right)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualVar(self,left,right)
+
+ defIsGreaterOrEqualCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left >= right)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualCt(self,left,right,b)
+
+ defIsGreaterCstCt(self,v:"IntExpr",c:"int64_t",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v > c)"""
+ return_pywrapcp.Solver_IsGreaterCstCt(self,v,c,b)
+
+ defIsGreaterCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var > value)"""
+ return_pywrapcp.Solver_IsGreaterCstVar(self,var,value)
+
+ defIsGreaterVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left > right)"""
+ return_pywrapcp.Solver_IsGreaterVar(self,left,right)
+
+ defIsGreaterCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left > right)"""
+ return_pywrapcp.Solver_IsGreaterCt(self,left,right,b)
+
+ defIsLessCstCt(self,v:"IntExpr",c:"int64_t",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (v < c)"""
+ return_pywrapcp.Solver_IsLessCstCt(self,v,c,b)
+
+ defIsLessCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var < value)"""
+ return_pywrapcp.Solver_IsLessCstVar(self,var,value)
+
+ defIsLessVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left < right)"""
+ return_pywrapcp.Solver_IsLessVar(self,left,right)
+
+ defIsLessCt(self,left:"IntExpr",right:"IntExpr",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (left < right)"""
+ return_pywrapcp.Solver_IsLessCt(self,left,right,b)
+
+ defSumLessOrEqual(self,vars:"std::vector< operations_research::IntVar * > const &",cst:"int64_t")->"operations_research::Constraint *":
+ r""" Variation on arrays."""
+ return_pywrapcp.Solver_SumLessOrEqual(self,vars,cst)
+
+ defSumGreaterOrEqual(self,vars:"std::vector< operations_research::IntVar * > const &",cst:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.Solver_SumGreaterOrEqual(self,vars,cst)
+
+ defSumEquality(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_SumEquality(self,*args)
+
+ defScalProdEquality(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ScalProdEquality(self,*args)
+
+ defScalProdGreaterOrEqual(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ScalProdGreaterOrEqual(self,*args)
+
+ defScalProdLessOrEqual(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ScalProdLessOrEqual(self,*args)
+
+ defMinEquality(self,vars:"std::vector< operations_research::IntVar * > const &",min_var:"IntVar")->"operations_research::Constraint *":
+ return_pywrapcp.Solver_MinEquality(self,vars,min_var)
+
+ defMaxEquality(self,vars:"std::vector< operations_research::IntVar * > const &",max_var:"IntVar")->"operations_research::Constraint *":
+ return_pywrapcp.Solver_MaxEquality(self,vars,max_var)
+
+ defElementEquality(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_ElementEquality(self,*args)
+
+ defAbsEquality(self,var:"IntVar",abs_var:"IntVar")->"operations_research::Constraint *":
+ r""" Creates the constraint abs(var) == abs_var."""
+ return_pywrapcp.Solver_AbsEquality(self,var,abs_var)
+
+ defIndexOfConstraint(self,vars:"std::vector< operations_research::IntVar * > const &",index:"IntVar",target:"int64_t")->"operations_research::Constraint *":
+ r"""
+ This constraint is a special case of the element constraint with
+ an array of integer variables, where the variables are all
+ different and the index variable is constrained such that
+ vars[index] == target.
+ """
+ return_pywrapcp.Solver_IndexOfConstraint(self,vars,index,target)
+
+ defConstraintInitialPropagateCallback(self,ct:"Constraint")->"operations_research::Demon *":
+ r"""
+ This method is a specialized case of the MakeConstraintDemon
+ method to call the InitiatePropagate of the constraint 'ct'.
+ """
+ return_pywrapcp.Solver_ConstraintInitialPropagateCallback(self,ct)
+
+ defDelayedConstraintInitialPropagateCallback(self,ct:"Constraint")->"operations_research::Demon *":
+ r"""
+ This method is a specialized case of the MakeConstraintDemon
+ method to call the InitiatePropagate of the constraint 'ct' with
+ low priority.
+ """
+ return_pywrapcp.Solver_DelayedConstraintInitialPropagateCallback(self,ct)
+
+ defClosureDemon(self,closure:"operations_research::Solver::Closure")->"operations_research::Demon *":
+ r""" Creates a demon from a closure."""
+ return_pywrapcp.Solver_ClosureDemon(self,closure)
+
+ defBetweenCt(self,expr:"IntExpr",l:"int64_t",u:"int64_t")->"operations_research::Constraint *":
+ r""" (l <= expr <= u)"""
+ return_pywrapcp.Solver_BetweenCt(self,expr,l,u)
+
+ defIsBetweenCt(self,expr:"IntExpr",l:"int64_t",u:"int64_t",b:"IntVar")->"operations_research::Constraint *":
+ r""" b == (l <= expr <= u)"""
+ return_pywrapcp.Solver_IsBetweenCt(self,expr,l,u,b)
+
+ defIsBetweenVar(self,v:"IntExpr",l:"int64_t",u:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.Solver_IsBetweenVar(self,v,l,u)
+
+ defMemberCt(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_MemberCt(self,*args)
+
+ defNotMemberCt(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ expr not in set.
+
+ |
+
+ *Overload 2:*
+ expr should not be in the list of forbidden intervals [start[i]..end[i]].
+
+ |
+
+ *Overload 3:*
+ expr should not be in the list of forbidden intervals [start[i]..end[i]].
+ """
+ return_pywrapcp.Solver_NotMemberCt(self,*args)
+
+ defIsMemberCt(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_IsMemberCt(self,*args)
+
+ defIsMemberVar(self,*args)->"operations_research::IntVar *":
+ return_pywrapcp.Solver_IsMemberVar(self,*args)
+
+ defCount(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ |{i | vars[i] == value}| == max_count
+
+ |
+
+ *Overload 2:*
+ |{i | vars[i] == value}| == max_count
+ """
+ return_pywrapcp.Solver_Count(self,*args)
+
+ defDistribute(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ Aggregated version of count: |{i | v[i] == values[j]}| == cards[j]
+
+ |
+
+ *Overload 2:*
+ Aggregated version of count: |{i | v[i] == values[j]}| == cards[j]
+
+ |
+
+ *Overload 3:*
+ Aggregated version of count: |{i | v[i] == j}| == cards[j]
+
+ |
+
+ *Overload 4:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1: card_min <= |{i | v[i] == j}| <= card_max
+
+ |
+
+ *Overload 5:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == j}| <= card_max[j]
+
+ |
+
+ *Overload 6:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == j}| <= card_max[j]
+
+ |
+
+ *Overload 7:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == values[j]}| <= card_max[j]
+
+ |
+
+ *Overload 8:*
+ Aggregated version of count with bounded cardinalities:
+ forall j in 0 .. card_size - 1:
+ card_min[j] <= |{i | v[i] == values[j]}| <= card_max[j]
+ """
+ return_pywrapcp.Solver_Distribute(self,*args)
+
+ defDeviation(self,vars:"std::vector< operations_research::IntVar * > const &",deviation_var:"IntVar",total_sum:"int64_t")->"operations_research::Constraint *":
+ r"""
+ Deviation constraint:
+ sum_i |n * vars[i] - total_sum| <= deviation_var and
+ sum_i vars[i] == total_sum
+ n = #vars
+ """
+ return_pywrapcp.Solver_Deviation(self,vars,deviation_var,total_sum)
+
+ defAllDifferent(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ All variables are pairwise different. This corresponds to the
+ stronger version of the propagation algorithm.
+
+ |
+
+ *Overload 2:*
+ All variables are pairwise different. If 'stronger_propagation'
+ is true, stronger, and potentially slower propagation will
+ occur. This API will be deprecated in the future.
+ """
+ return_pywrapcp.Solver_AllDifferent(self,*args)
+
+ defAllDifferentExcept(self,vars:"std::vector< operations_research::IntVar * > const &",escape_value:"int64_t")->"operations_research::Constraint *":
+ r"""
+ All variables are pairwise different, unless they are assigned to
+ the escape value.
+ """
+ return_pywrapcp.Solver_AllDifferentExcept(self,vars,escape_value)
+
+ defSortingConstraint(self,vars:"std::vector< operations_research::IntVar * > const &",sorted:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint binding the arrays of variables "vars" and
+ "sorted_vars": sorted_vars[0] must be equal to the minimum of all
+ variables in vars, and so on: the value of sorted_vars[i] must be
+ equal to the i-th value of variables invars.
+
+ This constraint propagates in both directions: from "vars" to
+ "sorted_vars" and vice-versa.
+
+ Behind the scenes, this constraint maintains that:
+ - sorted is always increasing.
+ - whatever the values of vars, there exists a permutation that
+ injects its values into the sorted variables.
+
+ For more info, please have a look at:
+ https://mpi-inf.mpg.de/~mehlhorn/ftp/Mehlhorn-Thiel.pdf
+ """
+ return_pywrapcp.Solver_SortingConstraint(self,vars,sorted)
+
+ defLexicalLess(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that left is lexicographically less
+ than right.
+ """
+ return_pywrapcp.Solver_LexicalLess(self,left,right)
+
+ defLexicalLessOrEqual(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that left is lexicographically less
+ than or equal to right.
+ """
+ return_pywrapcp.Solver_LexicalLessOrEqual(self,left,right)
+
+ defInversePermutationConstraint(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that 'left' and 'right' both
+ represent permutations of [0..left.size()-1], and that 'right' is
+ the inverse permutation of 'left', i.e. for all i in
+ [0..left.size()-1], right[left[i]] = i.
+ """
+ return_pywrapcp.Solver_InversePermutationConstraint(self,left,right)
+
+ defNullIntersect(self,first_vars:"std::vector< operations_research::IntVar * > const &",second_vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that states that all variables in the first
+ vector are different from all variables in the second
+ group. Thus the set of values in the first vector does not
+ intersect with the set of values in the second vector.
+ """
+ return_pywrapcp.Solver_NullIntersect(self,first_vars,second_vars)
+
+ defNullIntersectExcept(self,first_vars:"std::vector< operations_research::IntVar * > const &",second_vars:"std::vector< operations_research::IntVar * > const &",escape_value:"int64_t")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that states that all variables in the first
+ vector are different from all variables from the second group,
+ unless they are assigned to the escape value. Thus the set of
+ values in the first vector minus the escape value does not
+ intersect with the set of values in the second vector.
+ """
+ return_pywrapcp.Solver_NullIntersectExcept(self,first_vars,second_vars,escape_value)
+
+ defCircuit(self,nexts:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r""" Force the "nexts" variable to create a complete Hamiltonian path."""
+ return_pywrapcp.Solver_Circuit(self,nexts)
+
+ defSubCircuit(self,nexts:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Force the "nexts" variable to create a complete Hamiltonian path
+ for those that do not loop upon themselves.
+ """
+ return_pywrapcp.Solver_SubCircuit(self,nexts)
+
+ defDelayedPathCumul(self,nexts:"std::vector< operations_research::IntVar * > const &",active:"std::vector< operations_research::IntVar * > const &",cumuls:"std::vector< operations_research::IntVar * > const &",transits:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Delayed version of the same constraint: propagation on the nexts variables
+ is delayed until all constraints have propagated.
+ """
+ return_pywrapcp.Solver_DelayedPathCumul(self,nexts,active,cumuls,transits)
+
+ defPathCumul(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transits[i].
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+
+ |
+
+ *Overload 2:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]).
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+ Ownership of transit_evaluator is taken and it must be a repeatable
+ callback.
+
+ |
+
+ *Overload 3:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]) + slacks[i].
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+ Ownership of transit_evaluator is taken and it must be a repeatable
+ callback.
+ """
+ return_pywrapcp.Solver_PathCumul(self,*args)
+
+ defAllowedAssignments(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This method creates a constraint where the graph of the relation
+ between the variables is given in extension. There are 'arity'
+ variables involved in the relation and the graph is given by a
+ integer tuple set.
+
+ |
+
+ *Overload 2:*
+ Compatibility layer for Python API.
+ """
+ return_pywrapcp.Solver_AllowedAssignments(self,*args)
+
+ defTransitionConstraint(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_TransitionConstraint(self,*args)
+
+ defNonOverlappingBoxesConstraint(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_NonOverlappingBoxesConstraint(self,*args)
+
+ defPack(self,vars:"std::vector< operations_research::IntVar * > const &",number_of_bins:"int")->"operations_research::Pack *":
+ r"""
+ This constraint packs all variables onto 'number_of_bins'
+ variables. For any given variable, a value of 'number_of_bins'
+ indicates that the variable is not assigned to any bin.
+ Dimensions, i.e., cumulative constraints on this packing, can be
+ added directly from the pack class.
+ """
+ return_pywrapcp.Solver_Pack(self,vars,number_of_bins)
+
+ defFixedDurationIntervalVar(self,*args)->"operations_research::IntervalVar *":
+ r"""
+ *Overload 1:*
+ Creates an interval var with a fixed duration. The duration must
+ be greater than 0. If optional is true, then the interval can be
+ performed or unperformed. If optional is false, then the interval
+ is always performed.
+
+ |
+
+ *Overload 2:*
+ Creates a performed interval var with a fixed duration. The duration must
+ be greater than 0.
+
+ |
+
+ *Overload 3:*
+ Creates an interval var with a fixed duration, and performed_variable.
+ The duration must be greater than 0.
+ """
+ return_pywrapcp.Solver_FixedDurationIntervalVar(self,*args)
+
+ defFixedInterval(self,start:"int64_t",duration:"int64_t",name:"std::string const &")->"operations_research::IntervalVar *":
+ r""" Creates a fixed and performed interval."""
+ return_pywrapcp.Solver_FixedInterval(self,start,duration,name)
+
+ defIntervalVar(self,start_min:"int64_t",start_max:"int64_t",duration_min:"int64_t",duration_max:"int64_t",end_min:"int64_t",end_max:"int64_t",optional:"bool",name:"std::string const &")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var by specifying the bounds on start,
+ duration, and end.
+ """
+ return_pywrapcp.Solver_IntervalVar(self,start_min,start_max,duration_min,duration_max,end_min,end_max,optional,name)
+
+ defMirrorInterval(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var that is the mirror image of the given one, that
+ is, the interval var obtained by reversing the axis.
+ """
+ return_pywrapcp.Solver_MirrorInterval(self,interval_var)
+
+ defFixedDurationStartSyncedOnStartIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose start is
+ synchronized with the start of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationStartSyncedOnStartIntervalVar(self,interval_var,duration,offset)
+
+ defFixedDurationStartSyncedOnEndIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose start is
+ synchronized with the end of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationStartSyncedOnEndIntervalVar(self,interval_var,duration,offset)
+
+ defFixedDurationEndSyncedOnStartIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose end is
+ synchronized with the start of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationEndSyncedOnStartIntervalVar(self,interval_var,duration,offset)
+
+ defFixedDurationEndSyncedOnEndIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose end is
+ synchronized with the end of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationEndSyncedOnEndIntervalVar(self,interval_var,duration,offset)
+
+ defIntervalRelaxedMin(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates and returns an interval variable that wraps around the given one,
+ relaxing the min start and end. Relaxing means making unbounded when
+ optional. If the variable is non-optional, this method returns
+ interval_var.
+
+ More precisely, such an interval variable behaves as follows:
+ When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+ When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the min side;
+ When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+ This is very useful to implement propagators that may only modify
+ the start max or end max.
+ """
+ return_pywrapcp.Solver_IntervalRelaxedMin(self,interval_var)
+
+ defIntervalRelaxedMax(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates and returns an interval variable that wraps around the given one,
+ relaxing the max start and end. Relaxing means making unbounded when
+ optional. If the variable is non optional, this method returns
+ interval_var.
+
+ More precisely, such an interval variable behaves as follows:
+ When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+ When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the max side;
+ When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+ This is very useful for implementing propagators that may only modify
+ the start min or end min.
+ """
+ return_pywrapcp.Solver_IntervalRelaxedMax(self,interval_var)
+
+ defTemporalDisjunction(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This constraint implements a temporal disjunction between two
+ interval vars t1 and t2. 'alt' indicates which alternative was
+ chosen (alt == 0 is equivalent to t1 before t2).
+
+ |
+
+ *Overload 2:*
+ This constraint implements a temporal disjunction between two
+ interval vars.
+ """
+ return_pywrapcp.Solver_TemporalDisjunction(self,*args)
+
+ defDisjunctiveConstraint(self,intervals:"std::vector< operations_research::IntervalVar * > const &",name:"std::string const &")->"operations_research::DisjunctiveConstraint *":
+ r"""
+ This constraint forces all interval vars into an non-overlapping
+ sequence. Intervals with zero duration can be scheduled anywhere.
+ """
+ return_pywrapcp.Solver_DisjunctiveConstraint(self,intervals,name)
+
+ defCumulative(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 2:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 3:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 4:*
+ This constraint enforces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 5:*
+ This constraint enforces that, for any integer t, the sum of demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should be positive.
+
+ |
+
+ *Overload 6:*
+ This constraint enforces that, for any integer t, the sum of demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should be positive.
+ """
+ return_pywrapcp.Solver_Cumulative(self,*args)
+
+ defCover(self,vars:"std::vector< operations_research::IntervalVar * > const &",target_var:"IntervalVar")->"operations_research::Constraint *":
+ r"""
+ This constraint states that the target_var is the convex hull of
+ the intervals. If none of the interval variables is performed,
+ then the target var is unperformed too. Also, if the target
+ variable is unperformed, then all the intervals variables are
+ unperformed too.
+ """
+ return_pywrapcp.Solver_Cover(self,vars,target_var)
+
+ defAssignment(self,*args)->"operations_research::Assignment *":
+ r"""
+ *Overload 1:*
+ This method creates an empty assignment.
+
+ |
+
+ *Overload 2:*
+ This method creates an assignment which is a copy of 'a'.
+ """
+ return_pywrapcp.Solver_Assignment(self,*args)
+
+ defFirstSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the first solution of the search.
+
+ |
+
+ *Overload 2:*
+ Collect the first solution of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_FirstSolutionCollector(self,*args)
+
+ defLastSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the last solution of the search.
+
+ |
+
+ *Overload 2:*
+ Collect the last solution of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_LastSolutionCollector(self,*args)
+
+ defBestValueSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the solution corresponding to the optimal value of the objective
+ of 'assignment'; if 'assignment' does not have an objective no solution is
+ collected. This collector only collects one solution corresponding to the
+ best objective value (the first one found).
+
+ |
+
+ *Overload 2:*
+ Collect the solution corresponding to the optimal value of the
+ objective of 'assignment'; if 'assignment' does not have an objective no
+ solution is collected. This collector only collects one solution
+ corresponding to the best objective value (the first one
+ found). The variables will need to be added later.
+ """
+ return_pywrapcp.Solver_BestValueSolutionCollector(self,*args)
+
+ defAllSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect all solutions of the search.
+
+ |
+
+ *Overload 2:*
+ Collect all solutions of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_AllSolutionCollector(self,*args)
+
+ defMinimize(self,v:"IntVar",step:"int64_t")->"operations_research::OptimizeVar *":
+ r""" Creates a minimization objective."""
+ return_pywrapcp.Solver_Minimize(self,v,step)
+
+ defMaximize(self,v:"IntVar",step:"int64_t")->"operations_research::OptimizeVar *":
+ r""" Creates a maximization objective."""
+ return_pywrapcp.Solver_Maximize(self,v,step)
+
+ defOptimize(self,maximize:"bool",v:"IntVar",step:"int64_t")->"operations_research::OptimizeVar *":
+ r""" Creates a objective with a given sense (true = maximization)."""
+ return_pywrapcp.Solver_Optimize(self,maximize,v,step)
+
+ defWeightedMinimize(self,*args)->"operations_research::OptimizeVar *":
+ r"""
+ *Overload 1:*
+ Creates a minimization weighted objective. The actual objective is
+ scalar_prod(sub_objectives, weights).
+
+ |
+
+ *Overload 2:*
+ Creates a minimization weighted objective. The actual objective is
+ scalar_prod(sub_objectives, weights).
+ """
+ return_pywrapcp.Solver_WeightedMinimize(self,*args)
+
+ defWeightedMaximize(self,*args)->"operations_research::OptimizeVar *":
+ r"""
+ *Overload 1:*
+ Creates a maximization weigthed objective.
+
+ |
+
+ *Overload 2:*
+ Creates a maximization weigthed objective.
+ """
+ return_pywrapcp.Solver_WeightedMaximize(self,*args)
+
+ defWeightedOptimize(self,*args)->"operations_research::OptimizeVar *":
+ r"""
+ *Overload 1:*
+ Creates a weighted objective with a given sense (true = maximization).
+
+ |
+
+ *Overload 2:*
+ Creates a weighted objective with a given sense (true = maximization).
+ """
+ return_pywrapcp.Solver_WeightedOptimize(self,*args)
+
+ defTabuSearch(self,maximize:"bool",v:"IntVar",step:"int64_t",vars:"std::vector< operations_research::IntVar * > const &",keep_tenure:"int64_t",forbid_tenure:"int64_t",tabu_factor:"double")->"operations_research::SearchMonitor *":
+ r"""
+ MetaHeuristics which try to get the search out of local optima.
+ Creates a Tabu Search monitor.
+ In the context of local search the behavior is similar to MakeOptimize(),
+ creating an objective in a given sense. The behavior differs once a local
+ optimum is reached: thereafter solutions which degrade the value of the
+ objective are allowed if they are not "tabu". A solution is "tabu" if it
+ doesn't respect the following rules:
+ - improving the best solution found so far
+ - variables in the "keep" list must keep their value, variables in the
+ "forbid" list must not take the value they have in the list.
+ Variables with new values enter the tabu lists after each new solution
+ found and leave the lists after a given number of iterations (called
+ tenure). Only the variables passed to the method can enter the lists.
+ The tabu criterion is softened by the tabu factor which gives the number
+ of "tabu" violations which is tolerated; a factor of 1 means no violations
+ allowed; a factor of 0 means all violations are allowed.
+ """
+ return_pywrapcp.Solver_TabuSearch(self,maximize,v,step,vars,keep_tenure,forbid_tenure,tabu_factor)
+
+ defSimulatedAnnealing(self,maximize:"bool",v:"IntVar",step:"int64_t",initial_temperature:"int64_t")->"operations_research::SearchMonitor *":
+ r""" Creates a Simulated Annealing monitor."""
+ return_pywrapcp.Solver_SimulatedAnnealing(self,maximize,v,step,initial_temperature)
+
+ defLubyRestart(self,scale_factor:"int")->"operations_research::SearchMonitor *":
+ r"""
+ This search monitor will restart the search periodically.
+ At the iteration n, it will restart after scale_factor * Luby(n) failures
+ where Luby is the Luby Strategy (i.e. 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8...).
+ """
+ return_pywrapcp.Solver_LubyRestart(self,scale_factor)
+
+ defConstantRestart(self,frequency:"int")->"operations_research::SearchMonitor *":
+ r"""
+ This search monitor will restart the search periodically after 'frequency'
+ failures.
+ """
+ return_pywrapcp.Solver_ConstantRestart(self,frequency)
+
+ defTimeLimit(self,*args)->"operations_research::RegularLimit *":
+ return_pywrapcp.Solver_TimeLimit(self,*args)
+
+ defBranchesLimit(self,branches:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of branches
+ explored in the search tree.
+ """
+ return_pywrapcp.Solver_BranchesLimit(self,branches)
+
+ defFailuresLimit(self,failures:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of failures
+ that can happen when exploring the search tree.
+ """
+ return_pywrapcp.Solver_FailuresLimit(self,failures)
+
+ defSolutionsLimit(self,solutions:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of solutions found
+ during the search.
+ """
+ return_pywrapcp.Solver_SolutionsLimit(self,solutions)
+
+ defLimit(self,*args)->"operations_research::SearchLimit *":
+ r"""
+ *Overload 1:*
+ Limits the search with the 'time', 'branches', 'failures' and
+ 'solutions' limits. 'smart_time_check' reduces the calls to the wall
+
+ |
+
+ *Overload 2:*
+ Creates a search limit from its protobuf description
+
+ |
+
+ *Overload 3:*
+ Creates a search limit that is reached when either of the underlying limit
+ is reached. That is, the returned limit is more stringent than both
+ argument limits.
+ """
+ return_pywrapcp.Solver_Limit(self,*args)
+
+ defCustomLimit(self,limiter:"std::function< bool () >")->"operations_research::SearchLimit *":
+ r"""
+ Callback-based search limit. Search stops when limiter returns true; if
+ this happens at a leaf the corresponding solution will be rejected.
+ """
+ return_pywrapcp.Solver_CustomLimit(self,limiter)
+
+ defSearchLog(self,*args)->"operations_research::SearchMonitor *":
+ return_pywrapcp.Solver_SearchLog(self,*args)
+
+ defSearchTrace(self,prefix:"std::string const &")->"operations_research::SearchMonitor *":
+ r"""
+ Creates a search monitor that will trace precisely the behavior of the
+ search. Use this only for low level debugging.
+ """
+ return_pywrapcp.Solver_SearchTrace(self,prefix)
+
+ defPrintModelVisitor(self)->"operations_research::ModelVisitor *":
+ r""" Prints the model."""
+ return_pywrapcp.Solver_PrintModelVisitor(self)
+
+ defStatisticsModelVisitor(self)->"operations_research::ModelVisitor *":
+ r""" Displays some nice statistics on the model."""
+ return_pywrapcp.Solver_StatisticsModelVisitor(self)
+
+ defAssignVariableValue(self,var:"IntVar",val:"int64_t")->"operations_research::Decision *":
+ r""" Decisions."""
+ return_pywrapcp.Solver_AssignVariableValue(self,var,val)
+
+ defVariableLessOrEqualValue(self,var:"IntVar",value:"int64_t")->"operations_research::Decision *":
+ return_pywrapcp.Solver_VariableLessOrEqualValue(self,var,value)
+
+ defVariableGreaterOrEqualValue(self,var:"IntVar",value:"int64_t")->"operations_research::Decision *":
+ return_pywrapcp.Solver_VariableGreaterOrEqualValue(self,var,value)
+
+ defSplitVariableDomain(self,var:"IntVar",val:"int64_t",start_with_lower_half:"bool")->"operations_research::Decision *":
+ return_pywrapcp.Solver_SplitVariableDomain(self,var,val,start_with_lower_half)
+
+ defAssignVariableValueOrFail(self,var:"IntVar",value:"int64_t")->"operations_research::Decision *":
+ return_pywrapcp.Solver_AssignVariableValueOrFail(self,var,value)
+
+ defAssignVariablesValues(self,vars:"std::vector< operations_research::IntVar * > const &",values:"std::vector< int64_t > const &")->"operations_research::Decision *":
+ return_pywrapcp.Solver_AssignVariablesValues(self,vars,values)
+
+ defFailDecision(self)->"operations_research::Decision *":
+ return_pywrapcp.Solver_FailDecision(self)
+
+ defDecision(self,apply:"operations_research::Solver::Action",refute:"operations_research::Solver::Action")->"operations_research::Decision *":
+ return_pywrapcp.Solver_Decision(self,apply,refute)
+
+ defCompose(self,dbs:"std::vector< operations_research::DecisionBuilder * > const &")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_Compose(self,dbs)
+
+ defTry(self,dbs:"std::vector< operations_research::DecisionBuilder * > const &")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_Try(self,dbs)
+
+ defDefaultPhase(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_DefaultPhase(self,*args)
+
+ defScheduleOrPostpone(self,var:"IntervalVar",est:"int64_t",marker:"int64_t *const")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to schedule a task at a given time.
+ On the Apply branch, it will set that interval var as performed and set
+ its start to 'est'. On the Refute branch, it will just update the
+ 'marker' to 'est' + 1. This decision is used in the
+ INTERVAL_SET_TIMES_FORWARD strategy.
+ """
+ return_pywrapcp.Solver_ScheduleOrPostpone(self,var,est,marker)
+
+ defScheduleOrExpedite(self,var:"IntervalVar",est:"int64_t",marker:"int64_t *const")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to schedule a task at a given time.
+ On the Apply branch, it will set that interval var as performed and set
+ its end to 'est'. On the Refute branch, it will just update the
+ 'marker' to 'est' - 1. This decision is used in the
+ INTERVAL_SET_TIMES_BACKWARD strategy.
+ """
+ return_pywrapcp.Solver_ScheduleOrExpedite(self,var,est,marker)
+
+ defRankFirstInterval(self,sequence:"SequenceVar",index:"int")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to rank first the ith interval var
+ in the sequence variable.
+ """
+ return_pywrapcp.Solver_RankFirstInterval(self,sequence,index)
+
+ defRankLastInterval(self,sequence:"SequenceVar",index:"int")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to rank last the ith interval var
+ in the sequence variable.
+ """
+ return_pywrapcp.Solver_RankLastInterval(self,sequence,index)
+
+ defPhase(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_Phase(self,*args)
+
+ defDecisionBuilderFromAssignment(self,assignment:"Assignment",db:"DecisionBuilder",vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a decision builder for which the left-most leaf corresponds
+ to assignment, the rest of the tree being explored using 'db'.
+ """
+ return_pywrapcp.Solver_DecisionBuilderFromAssignment(self,assignment,db,vars)
+
+ defConstraintAdder(self,ct:"Constraint")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a decision builder that will add the given constraint to
+ the model.
+ """
+ return_pywrapcp.Solver_ConstraintAdder(self,ct)
+
+ defSolveOnce(self,db:"DecisionBuilder",monitors:"std::vector< operations_research::SearchMonitor * > const &")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_SolveOnce(self,db,monitors)
+
+ defNestedOptimize(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_NestedOptimize(self,*args)
+
+ defRestoreAssignment(self,assignment:"Assignment")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a DecisionBuilder which restores an Assignment
+ (calls void Assignment::Restore())
+ """
+ return_pywrapcp.Solver_RestoreAssignment(self,assignment)
+
+ defStoreAssignment(self,assignment:"Assignment")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a DecisionBuilder which stores an Assignment
+ (calls void Assignment::Store())
+ """
+ return_pywrapcp.Solver_StoreAssignment(self,assignment)
+
+ defOperator(self,*args)->"operations_research::LocalSearchOperator *":
+ return_pywrapcp.Solver_Operator(self,*args)
+
+ defRandomLnsOperator(self,*args)->"operations_research::LocalSearchOperator *":
+ return_pywrapcp.Solver_RandomLnsOperator(self,*args)
+
+ defMoveTowardTargetOperator(self,*args)->"operations_research::LocalSearchOperator *":
+ r"""
+ *Overload 1:*
+ Creates a local search operator that tries to move the assignment of some
+ variables toward a target. The target is given as an Assignment. This
+ operator generates neighbors in which the only difference compared to the
+ current state is that one variable that belongs to the target assignment
+ is set to its target value.
+
+ |
+
+ *Overload 2:*
+ Creates a local search operator that tries to move the assignment of some
+ variables toward a target. The target is given either as two vectors: a
+ vector of variables and a vector of associated target values. The two
+ vectors should be of the same length. This operator generates neighbors in
+ which the only difference compared to the current state is that one
+ variable that belongs to the given vector is set to its target value.
+ """
+ return_pywrapcp.Solver_MoveTowardTargetOperator(self,*args)
+
+ defConcatenateOperators(self,*args)->"operations_research::LocalSearchOperator *":
+ return_pywrapcp.Solver_ConcatenateOperators(self,*args)
+
+ defRandomConcatenateOperators(self,*args)->"operations_research::LocalSearchOperator *":
+ r"""
+ *Overload 1:*
+ Randomized version of local search concatenator; calls a random operator
+ at each call to MakeNextNeighbor().
+
+ |
+
+ *Overload 2:*
+ Randomized version of local search concatenator; calls a random operator
+ at each call to MakeNextNeighbor(). The provided seed is used to
+ initialize the random number generator.
+ """
+ return_pywrapcp.Solver_RandomConcatenateOperators(self,*args)
+
+ defNeighborhoodLimit(self,op:"LocalSearchOperator",limit:"int64_t")->"operations_research::LocalSearchOperator *":
+ r"""
+ Creates a local search operator that wraps another local search
+ operator and limits the number of neighbors explored (i.e., calls
+ to MakeNextNeighbor from the current solution (between two calls
+ to Start()). When this limit is reached, MakeNextNeighbor()
+ returns false. The counter is cleared when Start() is called.
+ """
+ return_pywrapcp.Solver_NeighborhoodLimit(self,op,limit)
+
+ defLocalSearchPhase(self,*args)->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_LocalSearchPhase(self,*args)
+
+ defLocalSearchPhaseParameters(self,*args)->"operations_research::LocalSearchPhaseParameters *":
+ return_pywrapcp.Solver_LocalSearchPhaseParameters(self,*args)
+
+ defSearchDepth(self)->"int":
+ r"""
+ Gets the search depth of the current active search. Returns -1 if
+ there is no active search opened.
+ """
+ return_pywrapcp.Solver_SearchDepth(self)
+
+ defSearchLeftDepth(self)->"int":
+ r"""
+ Gets the search left depth of the current active search. Returns -1 if
+ there is no active search opened.
+ """
+ return_pywrapcp.Solver_SearchLeftDepth(self)
+
+ defSolveDepth(self)->"int":
+ r"""
+ Gets the number of nested searches. It returns 0 outside search,
+ 1 during the top level search, 2 or more in case of nested searches.
+ """
+ return_pywrapcp.Solver_SolveDepth(self)
+
+ defRand64(self,size:"int64_t")->"int64_t":
+ r""" Returns a random value between 0 and 'size' - 1;"""
+ return_pywrapcp.Solver_Rand64(self,size)
+
+ defRand32(self,size:"int32_t")->"int32_t":
+ r""" Returns a random value between 0 and 'size' - 1;"""
+ return_pywrapcp.Solver_Rand32(self,size)
+
+ defReSeed(self,seed:"int32_t")->"void":
+ r""" Reseed the solver random generator."""
+ return_pywrapcp.Solver_ReSeed(self,seed)
+
+ defLocalSearchProfile(self)->"std::string":
+ r""" Returns local search profiling information in a human readable format."""
+ return_pywrapcp.Solver_LocalSearchProfile(self)
+
+ defConstraints(self)->"int":
+ r"""
+ Counts the number of constraints that have been added
+ to the solver before the search.
+ """
+ return_pywrapcp.Solver_Constraints(self)
+
+ defAccept(self,visitor:"operations_research::ModelVisitor *const")->"void":
+ r""" Accepts the given model visitor."""
+ return_pywrapcp.Solver_Accept(self,visitor)
+
+ defFinishCurrentSearch(self)->"void":
+ r""" Tells the solver to kill or restart the current search."""
+ return_pywrapcp.Solver_FinishCurrentSearch(self)
+
+ defRestartCurrentSearch(self)->"void":
+ return_pywrapcp.Solver_RestartCurrentSearch(self)
+
+ defShouldFail(self)->"void":
+ r"""
+ These methods are only useful for the SWIG wrappers, which need a way
+ to externally cause the Solver to fail.
+ """
+ return_pywrapcp.Solver_ShouldFail(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.Solver___str__(self)
+
+ defAdd(self,ct):
+ ifisinstance(ct,PyConstraint):
+ self.__python_constraints.append(ct)
+ self.AddConstraint(ct)
+
+
+ defTreeNoCycle(self,nexts:"std::vector< operations_research::IntVar * > const &",active:"std::vector< operations_research::IntVar * > const &",callback:"operations_research::Solver::IndexFilter1"=0)->"operations_research::Constraint *":
+ return_pywrapcp.Solver_TreeNoCycle(self,nexts,active,callback)
+
+ defSearchLogWithCallback(self,period:"int",callback:"std::function< std::string () >")->"operations_research::SearchMonitor *":
+ return_pywrapcp.Solver_SearchLogWithCallback(self,period,callback)
+
+ defElementFunction(self,values:"std::function< int64_t (int64_t) >",index:"IntVar")->"operations_research::IntExpr *":
+ return_pywrapcp.Solver_ElementFunction(self,values,index)
+
+ defVarEvalValStrPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_evaluator:"std::function< int64_t (int64_t) >",val_str:"operations_research::Solver::IntValueStrategy")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarEvalValStrPhase(self,vars,var_evaluator,val_str)
+
+ defVarStrValEvalPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_str:"operations_research::Solver::IntVarStrategy",val_eval:"operations_research::Solver::IndexEvaluator2")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarStrValEvalPhase(self,vars,var_str,val_eval)
+
+ defVarEvalValEvalPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_eval:"std::function< int64_t (int64_t) >",val_eval:"operations_research::Solver::IndexEvaluator2")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarEvalValEvalPhase(self,vars,var_eval,val_eval)
+
+ defVarStrValEvalTieBreakPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_str:"operations_research::Solver::IntVarStrategy",val_eval:"operations_research::Solver::IndexEvaluator2",tie_breaker:"std::function< int64_t (int64_t) >")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarStrValEvalTieBreakPhase(self,vars,var_str,val_eval,tie_breaker)
+
+ defVarEvalValEvalTieBreakPhase(self,vars:"std::vector< operations_research::IntVar * > const &",var_eval:"std::function< int64_t (int64_t) >",val_eval:"operations_research::Solver::IndexEvaluator2",tie_breaker:"std::function< int64_t (int64_t) >")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_VarEvalValEvalTieBreakPhase(self,vars,var_eval,val_eval,tie_breaker)
+
+ defEvalEvalStrPhase(self,vars:"std::vector< operations_research::IntVar * > const &",evaluator:"operations_research::Solver::IndexEvaluator2",str:"operations_research::Solver::EvaluatorStrategy")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_EvalEvalStrPhase(self,vars,evaluator,str)
+
+ defEvalEvalStrTieBreakPhase(self,vars:"std::vector< operations_research::IntVar * > const &",evaluator:"operations_research::Solver::IndexEvaluator2",tie_breaker:"operations_research::Solver::IndexEvaluator1",str:"operations_research::Solver::EvaluatorStrategy")->"operations_research::DecisionBuilder *":
+ return_pywrapcp.Solver_EvalEvalStrTieBreakPhase(self,vars,evaluator,tie_breaker,str)
+
+ defGuidedLocalSearch(self,*args)->"operations_research::SearchMonitor *":
+ return_pywrapcp.Solver_GuidedLocalSearch(self,*args)
+
+ defSumObjectiveFilter(self,vars:"std::vector< operations_research::IntVar * > const &",values:"operations_research::Solver::IndexEvaluator2",filter_enum:"operations_research::Solver::LocalSearchFilterBound")->"operations_research::LocalSearchFilter *":
+ return_pywrapcp.Solver_SumObjectiveFilter(self,vars,values,filter_enum)
+
+
+
+
+
Solver Class
+
+
A solver represents the main computation engine. It implements the entire
+range of Constraint Programming protocols:
+
+
+
Reversibility
+
Propagation
+
Search
+
+
+
Usually, Constraint Programming code consists of
+
+
+
the creation of the Solver,
+
the creation of the decision variables of the model,
+
the creation of the constraints of the model and their addition to the
+solver() through the AddConstraint() method,
+
the creation of the main DecisionBuilder class,
+
the launch of the solve() method with the decision builder.
+
+
+
For the time being, Solver is neither MT_SAFE nor MT_HOT.
Among unbound variables, select the variable with the smallest size,
+i.e., the smallest number of possible values.
+In case of a tie, the selected variables is the one with the lowest min
+value.
+In case of a tie, the first one is selected, first being defined by the
+order in the vector of IntVars used to create the selector.
Among unbound variables, select the variable with the smallest size,
+i.e., the smallest number of possible values.
+In case of a tie, the selected variable is the one with the highest min
+value.
+In case of a tie, the first one is selected, first being defined by the
+order in the vector of IntVars used to create the selector.
Among unbound variables, select the variable with the smallest size,
+i.e., the smallest number of possible values.
+In case of a tie, the selected variables is the one with the lowest max
+value.
+In case of a tie, the first one is selected, first being defined by the
+order in the vector of IntVars used to create the selector.
Among unbound variables, select the variable with the smallest size,
+i.e., the smallest number of possible values.
+In case of a tie, the selected variable is the one with the highest max
+value.
+In case of a tie, the first one is selected, first being defined by the
+order in the vector of IntVars used to create the selector.
Among unbound variables, select the variable with the smallest minimal
+value.
+In case of a tie, the first one is selected, "first" defined by the
+order in the vector of IntVars used to create the selector.
Among unbound variables, select the variable with the highest maximal
+value.
+In case of a tie, the first one is selected, first being defined by the
+order in the vector of IntVars used to create the selector.
Among unbound variables, select the variable with the smallest size.
+In case of a tie, the first one is selected, first being defined by the
+order in the vector of IntVars used to create the selector.
Among unbound variables, select the variable with the highest size.
+In case of a tie, the first one is selected, first being defined by the
+order in the vector of IntVars used to create the selector.
Selects the first possible value which is the closest to the center
+of the domain of the selected variable.
+The center is defined as (min + max) / 2.
Operator which reverses a sub-chain of a path. It is called TwoOpt
+because it breaks two arcs on the path; resulting paths are called
+two-optimal.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5
+(where (1, 5) are first and last nodes of the path and can therefore not
+be moved):
+ 1 -> [3 -> 2] -> 4 -> 5
+ 1 -> [4 -> 3 -> 2] -> 5
+ 1 -> 2 -> [4 -> 3] -> 5
Relocate: OROPT and RELOCATE.
+Operator which moves a sub-chain of a path to another position; the
+specified chain length is the fixed length of the chains being moved.
+When this length is 1, the operator simply moves a node to another
+position.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5, for a chain
+length of 2 (where (1, 5) are first and last nodes of the path and can
+therefore not be moved):
+ 1 -> 4 -> [2 -> 3] -> 5
+ 1 -> [3 -> 4] -> 2 -> 5
+
+
Using Relocate with chain lengths of 1, 2 and 3 together is equivalent
+to the OrOpt operator on a path. The OrOpt operator is a limited
+ version of 3Opt (breaks 3 arcs on a path).
Operator which exchanges the positions of two nodes.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 -> 5
+(where (1, 5) are first and last nodes of the path and can therefore not
+be moved):
+ 1 -> [3] -> [2] -> 4 -> 5
+ 1 -> [4] -> 3 -> [2] -> 5
+ 1 -> 2 -> [4] -> [3] -> 5
Operator which cross exchanges the starting chains of 2 paths, including
+exchanging the whole paths.
+First and last nodes are not moved.
+Possible neighbors for the paths 1 -> 2 -> 3 -> 4 -> 5 and 6 -> 7 -> 8
+(where (1, 5) and (6, 8) are first and last nodes of the paths and can
+therefore not be moved):
+ 1 -> [7] -> 3 -> 4 -> 5 6 -> [2] -> 8
+ 1 -> [7] -> 4 -> 5 6 -> [2 -> 3] -> 8
+ 1 -> [7] -> 5 6 -> [2 -> 3 -> 4] -> 8
Operator which inserts an inactive node into a path.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+(where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 2 -> 3 -> 4
+ 1 -> 2 -> [5] -> 3 -> 4
+ 1 -> 2 -> 3 -> [5] -> 4
Operator which makes path nodes inactive.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 (where 1 and 4 are
+first and last nodes of the path) are:
+ 1 -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> 4 with 3 inactive
Operator which makes a "chain" of path nodes inactive.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 (where 1 and 4 are
+first and last nodes of the path) are:
+ 1 -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> 4 with 3 inactive
+ 1 -> 4 with 2 and 3 inactive
Operator which replaces an active node by an inactive one.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+(where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 3 -> 4 with 2 inactive
+ 1 -> 2 -> [5] -> 4 with 3 inactive
Operator which makes an inactive node active and an active one inactive.
+It is similar to SwapActiveOperator except that it tries to insert the
+inactive node in all possible positions instead of just the position of
+the node made inactive.
+Possible neighbors for the path 1 -> 2 -> 3 -> 4 with 5 inactive
+(where 1 and 4 are first and last nodes of the path) are:
+ 1 -> [5] -> 3 -> 4 with 2 inactive
+ 1 -> 3 -> [5] -> 4 with 2 inactive
+ 1 -> [5] -> 2 -> 4 with 3 inactive
+ 1 -> 2 -> [5] -> 4 with 3 inactive
Operator which relaxes two sub-chains of three consecutive arcs each.
+Each sub-chain is defined by a start node and the next three arcs. Those
+six arcs are relaxed to build a new neighbor.
+PATHLNS explores all possible pairs of starting nodes and so defines
+n^2 neighbors, n being the number of nodes.
+Note that the two sub-chains can be part of the same path; they even may
+overlap.
Operator which relaxes all inactive nodes and one sub-chain of six
+consecutive arcs. That way the path can be improved by inserting
+inactive nodes or swapping arcs.
Operator which defines one neighbor per variable. Each neighbor tries to
+increment by one the value of the corresponding variable. When a new
+solution is found the neighborhood is rebuilt from scratch, i.e., tries
+to increment values in the variable order.
+Consider for instance variables x and y. x is incremented one by one to
+its max, and when it is not possible to increment x anymore, y is
+incremented once. If this is a solution, then next neighbor tries to
+increment x.
Operator which defines a neighborhood to decrement values.
+The behavior is the same as INCREMENT, except values are decremented
+instead of incremented.
Operator which defines one neighbor per variable. Each neighbor relaxes
+one variable.
+When a new solution is found the neighborhood is rebuilt from scratch.
+Consider for instance variables x and y. First x is relaxed and the
+solver is looking for the best possible solution (with only x relaxed).
+Then y is relaxed, and the solver is looking for a new solution.
+If a new solution is found, then the next variable to be relaxed is x.
@staticmethod
+ defDefaultSolverParameters()->"operations_research::ConstraintSolverParameters":
+ r""" Create a ConstraintSolverParameters proto with all the default values."""
+ return_pywrapcp.Solver_DefaultSolverParameters()
+
+
+
+
+
Create a ConstraintSolverParameters proto with all the default values.
defAddConstraint(self,c:"Constraint")->"void":
+ r"""
+ Adds the constraint 'c' to the model.
+
+ After calling this method, and until there is a backtrack that undoes the
+ addition, any assignment of variables to values must satisfy the given
+ constraint in order to be considered feasible. There are two fairly
+ different use cases:
+
+ - the most common use case is modeling: the given constraint is really
+ part of the problem that the user is trying to solve. In this use case,
+ AddConstraint is called outside of search (i.e., with state() ==
+ OUTSIDE_SEARCH). Most users should only use AddConstraint in this
+ way. In this case, the constraint will belong to the model forever: it
+ cannot not be removed by backtracking.
+
+ - a rarer use case is that 'c' is not a real constraint of the model. It
+ may be a constraint generated by a branching decision (a constraint whose
+ goal is to restrict the search space), a symmetry breaking constraint (a
+ constraint that does restrict the search space, but in a way that cannot
+ have an impact on the quality of the solutions in the subtree), or an
+ inferred constraint that, while having no semantic value to the model (it
+ does not restrict the set of solutions), is worth having because we
+ believe it may strengthen the propagation. In these cases, it happens
+ that the constraint is added during the search (i.e., with state() ==
+ IN_SEARCH or state() == IN_ROOT_NODE). When a constraint is
+ added during a search, it applies only to the subtree of the search tree
+ rooted at the current node, and will be automatically removed by
+ backtracking.
+
+ This method does not take ownership of the constraint. If the constraint
+ has been created by any factory method (Solver::MakeXXX), it will
+ automatically be deleted. However, power users who implement their own
+ constraints should do: solver.AddConstraint(solver.RevAlloc(new
+ MyConstraint(...));
+ """
+ return_pywrapcp.Solver_AddConstraint(self,c)
+
+
+
+
+
Adds the constraint 'c' to the model.
+
+
After calling this method, and until there is a backtrack that undoes the
+addition, any assignment of variables to values must satisfy the given
+constraint in order to be considered feasible. There are two fairly
+different use cases:
+
+
+
the most common use case is modeling: the given constraint is really
+part of the problem that the user is trying to solve. In this use case,
+AddConstraint is called outside of search (i.e., with state() ==
+OUTSIDE_SEARCH). Most users should only use AddConstraint in this
+way. In this case, the constraint will belong to the model forever: it
+cannot not be removed by backtracking.
+
a rarer use case is that 'c' is not a real constraint of the model. It
+may be a constraint generated by a branching decision (a constraint whose
+goal is to restrict the search space), a symmetry breaking constraint (a
+constraint that does restrict the search space, but in a way that cannot
+have an impact on the quality of the solutions in the subtree), or an
+inferred constraint that, while having no semantic value to the model (it
+does not restrict the set of solutions), is worth having because we
+believe it may strengthen the propagation. In these cases, it happens
+that the constraint is added during the search (i.e., with state() ==
+IN_SEARCH or state() == IN_ROOT_NODE). When a constraint is
+added during a search, it applies only to the subtree of the search tree
+rooted at the current node, and will be automatically removed by
+backtracking.
+
+
+
This method does not take ownership of the constraint. If the constraint
+has been created by any factory method (Solver::MakeXXX), it will
+automatically be deleted. However, power users who implement their own
+constraints should do: solver.AddConstraint(solver.RevAlloc(new
+MyConstraint(...));
defCheckAssignment(self,solution:"Assignment")->"bool":
+ r""" Checks whether the given assignment satisfies all relevant constraints."""
+ return_pywrapcp.Solver_CheckAssignment(self,solution)
+
+
+
+
+
Checks whether the given assignment satisfies all relevant constraints.
defCheckConstraint(self,ct:"Constraint")->"bool":
+ r"""
+ Checks whether adding this constraint will lead to an immediate
+ failure. It will return false if the model is already inconsistent, or if
+ adding the constraint makes it inconsistent.
+ """
+ return_pywrapcp.Solver_CheckConstraint(self,ct)
+
+
+
+
+
Checks whether adding this constraint will lead to an immediate
+failure. It will return false if the model is already inconsistent, or if
+adding the constraint makes it inconsistent.
defWallTime(self)->"int64_t":
+ r"""
+ DEPRECATED: Use Now() instead.
+ Time elapsed, in ms since the creation of the solver.
+ """
+ return_pywrapcp.Solver_WallTime(self)
+
+
+
+
+
DEPRECATED: Use Now() instead.
+Time elapsed, in ms since the creation of the solver.
defStamp(self)->"uint64_t":
+ r"""
+ The stamp indicates how many moves in the search tree we have performed.
+ It is useful to detect if we need to update same lazy structures.
+ """
+ return_pywrapcp.Solver_Stamp(self)
+
+
+
+
+
The stamp indicates how many moves in the search tree we have performed.
+It is useful to detect if we need to update same lazy structures.
defIntVar(self,*args)->"operations_research::IntVar *":
+ r"""
+ *Overload 1:*
+ MakeIntVar will create the best range based int var for the bounds given.
+
+ |
+
+ *Overload 2:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 3:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 4:*
+ MakeIntVar will create the best range based int var for the bounds given.
+
+ |
+
+ *Overload 5:*
+ MakeIntVar will create a variable with the given sparse domain.
+
+ |
+
+ *Overload 6:*
+ MakeIntVar will create a variable with the given sparse domain.
+ """
+ return_pywrapcp.Solver_IntVar(self,*args)
+
+
+
+
+
Overload 1:
+MakeIntVar will create the best range based int var for the bounds given.
+
+
|
+
+
Overload 2:
+MakeIntVar will create a variable with the given sparse domain.
+
+
|
+
+
Overload 3:
+MakeIntVar will create a variable with the given sparse domain.
+
+
|
+
+
Overload 4:
+MakeIntVar will create the best range based int var for the bounds given.
+
+
|
+
+
Overload 5:
+MakeIntVar will create a variable with the given sparse domain.
+
+
|
+
+
Overload 6:
+MakeIntVar will create a variable with the given sparse domain.
defMonotonicElement(self,values:"operations_research::Solver::IndexEvaluator1",increasing:"bool",index:"IntVar")->"operations_research::IntExpr *":
+ r"""
+ Function based element. The constraint takes ownership of the
+ callback. The callback must be monotonic. It must be able to
+ cope with any possible value in the domain of 'index'
+ (potentially negative ones too). Furtermore, monotonicity is not
+ checked. Thus giving a non-monotonic function, or specifying an
+ incorrect increasing parameter will result in undefined behavior.
+ """
+ return_pywrapcp.Solver_MonotonicElement(self,values,increasing,index)
+
+
+
+
+
Function based element. The constraint takes ownership of the
+callback. The callback must be monotonic. It must be able to
+cope with any possible value in the domain of 'index'
+(potentially negative ones too). Furtermore, monotonicity is not
+checked. Thus giving a non-monotonic function, or specifying an
+incorrect increasing parameter will result in undefined behavior.
defElement(self,*args)->"operations_research::IntExpr *":
+ r"""
+ *Overload 1:*
+ values[index]
+
+ |
+
+ *Overload 2:*
+ values[index]
+
+ |
+
+ *Overload 3:*
+ Function-based element. The constraint takes ownership of the
+ callback. The callback must be able to cope with any possible
+ value in the domain of 'index' (potentially negative ones too).
+
+ |
+
+ *Overload 4:*
+ 2D version of function-based element expression, values(expr1, expr2).
+
+ |
+
+ *Overload 5:*
+ vars[expr]
+ """
+ return_pywrapcp.Solver_Element(self,*args)
+
+
+
+
+
Overload 1:
+values[index]
+
+
|
+
+
Overload 2:
+values[index]
+
+
|
+
+
Overload 3:
+Function-based element. The constraint takes ownership of the
+callback. The callback must be able to cope with any possible
+value in the domain of 'index' (potentially negative ones too).
+
+
|
+
+
Overload 4:
+2D version of function-based element expression, values(expr1, expr2).
defIndexExpression(self,vars:"std::vector< operations_research::IntVar * > const &",value:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ Returns the expression expr such that vars[expr] == value.
+ It assumes that vars are all different.
+ """
+ return_pywrapcp.Solver_IndexExpression(self,vars,value)
+
+
+
+
+
Returns the expression expr such that vars[expr] == value.
+It assumes that vars are all different.
defIsEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var == value)"""
+ return_pywrapcp.Solver_IsEqualCstVar(self,var,value)
+
defIsEqualVar(self,v1:"IntExpr",v2:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (v1 == v2)"""
+ return_pywrapcp.Solver_IsEqualVar(self,v1,v2)
+
defIsDifferentCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var != value)"""
+ return_pywrapcp.Solver_IsDifferentCstVar(self,var,value)
+
defIsDifferentVar(self,v1:"IntExpr",v2:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (v1 != v2)"""
+ return_pywrapcp.Solver_IsDifferentVar(self,v1,v2)
+
defIsLessOrEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var <= value)"""
+ return_pywrapcp.Solver_IsLessOrEqualCstVar(self,var,value)
+
defIsLessOrEqualVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left <= right)"""
+ return_pywrapcp.Solver_IsLessOrEqualVar(self,left,right)
+
defIsGreaterOrEqualCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var >= value)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualCstVar(self,var,value)
+
defIsGreaterOrEqualVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left >= right)"""
+ return_pywrapcp.Solver_IsGreaterOrEqualVar(self,left,right)
+
defIsGreaterCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var > value)"""
+ return_pywrapcp.Solver_IsGreaterCstVar(self,var,value)
+
defIsGreaterVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left > right)"""
+ return_pywrapcp.Solver_IsGreaterVar(self,left,right)
+
defIsLessCstVar(self,var:"IntExpr",value:"int64_t")->"operations_research::IntVar *":
+ r""" status var of (var < value)"""
+ return_pywrapcp.Solver_IsLessCstVar(self,var,value)
+
defIsLessVar(self,left:"IntExpr",right:"IntExpr")->"operations_research::IntVar *":
+ r""" status var of (left < right)"""
+ return_pywrapcp.Solver_IsLessVar(self,left,right)
+
defIndexOfConstraint(self,vars:"std::vector< operations_research::IntVar * > const &",index:"IntVar",target:"int64_t")->"operations_research::Constraint *":
+ r"""
+ This constraint is a special case of the element constraint with
+ an array of integer variables, where the variables are all
+ different and the index variable is constrained such that
+ vars[index] == target.
+ """
+ return_pywrapcp.Solver_IndexOfConstraint(self,vars,index,target)
+
+
+
+
+
This constraint is a special case of the element constraint with
+an array of integer variables, where the variables are all
+different and the index variable is constrained such that
+vars[index] == target.
defConstraintInitialPropagateCallback(self,ct:"Constraint")->"operations_research::Demon *":
+ r"""
+ This method is a specialized case of the MakeConstraintDemon
+ method to call the InitiatePropagate of the constraint 'ct'.
+ """
+ return_pywrapcp.Solver_ConstraintInitialPropagateCallback(self,ct)
+
+
+
+
+
This method is a specialized case of the MakeConstraintDemon
+method to call the InitiatePropagate of the constraint 'ct'.
defDelayedConstraintInitialPropagateCallback(self,ct:"Constraint")->"operations_research::Demon *":
+ r"""
+ This method is a specialized case of the MakeConstraintDemon
+ method to call the InitiatePropagate of the constraint 'ct' with
+ low priority.
+ """
+ return_pywrapcp.Solver_DelayedConstraintInitialPropagateCallback(self,ct)
+
+
+
+
+
This method is a specialized case of the MakeConstraintDemon
+method to call the InitiatePropagate of the constraint 'ct' with
+low priority.
defClosureDemon(self,closure:"operations_research::Solver::Closure")->"operations_research::Demon *":
+ r""" Creates a demon from a closure."""
+ return_pywrapcp.Solver_ClosureDemon(self,closure)
+
defNotMemberCt(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ expr not in set.
+
+ |
+
+ *Overload 2:*
+ expr should not be in the list of forbidden intervals [start[i]..end[i]].
+
+ |
+
+ *Overload 3:*
+ expr should not be in the list of forbidden intervals [start[i]..end[i]].
+ """
+ return_pywrapcp.Solver_NotMemberCt(self,*args)
+
+
+
+
+
Overload 1:
+expr not in set.
+
+
|
+
+
Overload 2:
+expr should not be in the list of forbidden intervals [start[i]..end[i]].
+
+
|
+
+
Overload 3:
+expr should not be in the list of forbidden intervals [start[i]..end[i]].
defAllDifferent(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ All variables are pairwise different. This corresponds to the
+ stronger version of the propagation algorithm.
+
+ |
+
+ *Overload 2:*
+ All variables are pairwise different. If 'stronger_propagation'
+ is true, stronger, and potentially slower propagation will
+ occur. This API will be deprecated in the future.
+ """
+ return_pywrapcp.Solver_AllDifferent(self,*args)
+
+
+
+
+
Overload 1:
+All variables are pairwise different. This corresponds to the
+stronger version of the propagation algorithm.
+
+
|
+
+
Overload 2:
+All variables are pairwise different. If 'stronger_propagation'
+is true, stronger, and potentially slower propagation will
+occur. This API will be deprecated in the future.
defAllDifferentExcept(self,vars:"std::vector< operations_research::IntVar * > const &",escape_value:"int64_t")->"operations_research::Constraint *":
+ r"""
+ All variables are pairwise different, unless they are assigned to
+ the escape value.
+ """
+ return_pywrapcp.Solver_AllDifferentExcept(self,vars,escape_value)
+
+
+
+
+
All variables are pairwise different, unless they are assigned to
+the escape value.
defSortingConstraint(self,vars:"std::vector< operations_research::IntVar * > const &",sorted:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint binding the arrays of variables "vars" and
+ "sorted_vars": sorted_vars[0] must be equal to the minimum of all
+ variables in vars, and so on: the value of sorted_vars[i] must be
+ equal to the i-th value of variables invars.
+
+ This constraint propagates in both directions: from "vars" to
+ "sorted_vars" and vice-versa.
+
+ Behind the scenes, this constraint maintains that:
+ - sorted is always increasing.
+ - whatever the values of vars, there exists a permutation that
+ injects its values into the sorted variables.
+
+ For more info, please have a look at:
+ https://mpi-inf.mpg.de/~mehlhorn/ftp/Mehlhorn-Thiel.pdf
+ """
+ return_pywrapcp.Solver_SortingConstraint(self,vars,sorted)
+
+
+
+
+
Creates a constraint binding the arrays of variables "vars" and
+"sorted_vars": sorted_vars[0] must be equal to the minimum of all
+variables in vars, and so on: the value of sorted_vars[i] must be
+equal to the i-th value of variables invars.
+
+
This constraint propagates in both directions: from "vars" to
+"sorted_vars" and vice-versa.
+
+
Behind the scenes, this constraint maintains that:
+
+
+
sorted is always increasing.
+
whatever the values of vars, there exists a permutation that
+injects its values into the sorted variables.
+
+
+
For more info, please have a look at:
+ https://mpi-inf.mpg.de/~mehlhorn/ftp/Mehlhorn-Thiel.pdf
defLexicalLess(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that left is lexicographically less
+ than right.
+ """
+ return_pywrapcp.Solver_LexicalLess(self,left,right)
+
+
+
+
+
Creates a constraint that enforces that left is lexicographically less
+than right.
defLexicalLessOrEqual(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that left is lexicographically less
+ than or equal to right.
+ """
+ return_pywrapcp.Solver_LexicalLessOrEqual(self,left,right)
+
+
+
+
+
Creates a constraint that enforces that left is lexicographically less
+than or equal to right.
defInversePermutationConstraint(self,left:"std::vector< operations_research::IntVar * > const &",right:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that enforces that 'left' and 'right' both
+ represent permutations of [0..left.size()-1], and that 'right' is
+ the inverse permutation of 'left', i.e. for all i in
+ [0..left.size()-1], right[left[i]] = i.
+ """
+ return_pywrapcp.Solver_InversePermutationConstraint(self,left,right)
+
+
+
+
+
Creates a constraint that enforces that 'left' and 'right' both
+represent permutations of [0..left.size()-1], and that 'right' is
+the inverse permutation of 'left', i.e. for all i in
+[0..left.size()-1], right[left[i]] = i.
defNullIntersect(self,first_vars:"std::vector< operations_research::IntVar * > const &",second_vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that states that all variables in the first
+ vector are different from all variables in the second
+ group. Thus the set of values in the first vector does not
+ intersect with the set of values in the second vector.
+ """
+ return_pywrapcp.Solver_NullIntersect(self,first_vars,second_vars)
+
+
+
+
+
Creates a constraint that states that all variables in the first
+vector are different from all variables in the second
+group. Thus the set of values in the first vector does not
+intersect with the set of values in the second vector.
defNullIntersectExcept(self,first_vars:"std::vector< operations_research::IntVar * > const &",second_vars:"std::vector< operations_research::IntVar * > const &",escape_value:"int64_t")->"operations_research::Constraint *":
+ r"""
+ Creates a constraint that states that all variables in the first
+ vector are different from all variables from the second group,
+ unless they are assigned to the escape value. Thus the set of
+ values in the first vector minus the escape value does not
+ intersect with the set of values in the second vector.
+ """
+ return_pywrapcp.Solver_NullIntersectExcept(self,first_vars,second_vars,escape_value)
+
+
+
+
+
Creates a constraint that states that all variables in the first
+vector are different from all variables from the second group,
+unless they are assigned to the escape value. Thus the set of
+values in the first vector minus the escape value does not
+intersect with the set of values in the second vector.
defSubCircuit(self,nexts:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Force the "nexts" variable to create a complete Hamiltonian path
+ for those that do not loop upon themselves.
+ """
+ return_pywrapcp.Solver_SubCircuit(self,nexts)
+
+
+
+
+
Force the "nexts" variable to create a complete Hamiltonian path
+for those that do not loop upon themselves.
defDelayedPathCumul(self,nexts:"std::vector< operations_research::IntVar * > const &",active:"std::vector< operations_research::IntVar * > const &",cumuls:"std::vector< operations_research::IntVar * > const &",transits:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ r"""
+ Delayed version of the same constraint: propagation on the nexts variables
+ is delayed until all constraints have propagated.
+ """
+ return_pywrapcp.Solver_DelayedPathCumul(self,nexts,active,cumuls,transits)
+
+
+
+
+
Delayed version of the same constraint: propagation on the nexts variables
+is delayed until all constraints have propagated.
defPathCumul(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transits[i].
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+
+ |
+
+ *Overload 2:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]).
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+ Ownership of transit_evaluator is taken and it must be a repeatable
+ callback.
+
+ |
+
+ *Overload 3:*
+ Creates a constraint which accumulates values along a path such that:
+ cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]) + slacks[i].
+ Active variables indicate if the corresponding next variable is active;
+ this could be useful to model unperformed nodes in a routing problem.
+ Ownership of transit_evaluator is taken and it must be a repeatable
+ callback.
+ """
+ return_pywrapcp.Solver_PathCumul(self,*args)
+
+
+
+
+
Overload 1:
+Creates a constraint which accumulates values along a path such that:
+cumuls[next[i]] = cumuls[i] + transits[i].
+Active variables indicate if the corresponding next variable is active;
+this could be useful to model unperformed nodes in a routing problem.
+
+
|
+
+
Overload 2:
+Creates a constraint which accumulates values along a path such that:
+cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]).
+Active variables indicate if the corresponding next variable is active;
+this could be useful to model unperformed nodes in a routing problem.
+Ownership of transit_evaluator is taken and it must be a repeatable
+callback.
+
+
|
+
+
Overload 3:
+Creates a constraint which accumulates values along a path such that:
+cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i]) + slacks[i].
+Active variables indicate if the corresponding next variable is active;
+this could be useful to model unperformed nodes in a routing problem.
+Ownership of transit_evaluator is taken and it must be a repeatable
+callback.
defAllowedAssignments(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This method creates a constraint where the graph of the relation
+ between the variables is given in extension. There are 'arity'
+ variables involved in the relation and the graph is given by a
+ integer tuple set.
+
+ |
+
+ *Overload 2:*
+ Compatibility layer for Python API.
+ """
+ return_pywrapcp.Solver_AllowedAssignments(self,*args)
+
+
+
+
+
Overload 1:
+This method creates a constraint where the graph of the relation
+between the variables is given in extension. There are 'arity'
+variables involved in the relation and the graph is given by a
+integer tuple set.
defPack(self,vars:"std::vector< operations_research::IntVar * > const &",number_of_bins:"int")->"operations_research::Pack *":
+ r"""
+ This constraint packs all variables onto 'number_of_bins'
+ variables. For any given variable, a value of 'number_of_bins'
+ indicates that the variable is not assigned to any bin.
+ Dimensions, i.e., cumulative constraints on this packing, can be
+ added directly from the pack class.
+ """
+ return_pywrapcp.Solver_Pack(self,vars,number_of_bins)
+
+
+
+
+
This constraint packs all variables onto 'number_of_bins'
+variables. For any given variable, a value of 'number_of_bins'
+indicates that the variable is not assigned to any bin.
+Dimensions, i.e., cumulative constraints on this packing, can be
+added directly from the pack class.
defFixedDurationIntervalVar(self,*args)->"operations_research::IntervalVar *":
+ r"""
+ *Overload 1:*
+ Creates an interval var with a fixed duration. The duration must
+ be greater than 0. If optional is true, then the interval can be
+ performed or unperformed. If optional is false, then the interval
+ is always performed.
+
+ |
+
+ *Overload 2:*
+ Creates a performed interval var with a fixed duration. The duration must
+ be greater than 0.
+
+ |
+
+ *Overload 3:*
+ Creates an interval var with a fixed duration, and performed_variable.
+ The duration must be greater than 0.
+ """
+ return_pywrapcp.Solver_FixedDurationIntervalVar(self,*args)
+
+
+
+
+
Overload 1:
+Creates an interval var with a fixed duration. The duration must
+be greater than 0. If optional is true, then the interval can be
+performed or unperformed. If optional is false, then the interval
+is always performed.
+
+
|
+
+
Overload 2:
+Creates a performed interval var with a fixed duration. The duration must
+be greater than 0.
+
+
|
+
+
Overload 3:
+Creates an interval var with a fixed duration, and performed_variable.
+The duration must be greater than 0.
defFixedInterval(self,start:"int64_t",duration:"int64_t",name:"std::string const &")->"operations_research::IntervalVar *":
+ r""" Creates a fixed and performed interval."""
+ return_pywrapcp.Solver_FixedInterval(self,start,duration,name)
+
defIntervalVar(self,start_min:"int64_t",start_max:"int64_t",duration_min:"int64_t",duration_max:"int64_t",end_min:"int64_t",end_max:"int64_t",optional:"bool",name:"std::string const &")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var by specifying the bounds on start,
+ duration, and end.
+ """
+ return_pywrapcp.Solver_IntervalVar(self,start_min,start_max,duration_min,duration_max,end_min,end_max,optional,name)
+
+
+
+
+
Creates an interval var by specifying the bounds on start,
+duration, and end.
defMirrorInterval(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var that is the mirror image of the given one, that
+ is, the interval var obtained by reversing the axis.
+ """
+ return_pywrapcp.Solver_MirrorInterval(self,interval_var)
+
+
+
+
+
Creates an interval var that is the mirror image of the given one, that
+is, the interval var obtained by reversing the axis.
defFixedDurationStartSyncedOnStartIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose start is
+ synchronized with the start of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationStartSyncedOnStartIntervalVar(self,interval_var,duration,offset)
+
+
+
+
+
Creates an interval var with a fixed duration whose start is
+synchronized with the start of another interval, with a given
+offset. The performed status is also in sync with the performed
+status of the given interval variable.
defFixedDurationStartSyncedOnEndIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose start is
+ synchronized with the end of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationStartSyncedOnEndIntervalVar(self,interval_var,duration,offset)
+
+
+
+
+
Creates an interval var with a fixed duration whose start is
+synchronized with the end of another interval, with a given
+offset. The performed status is also in sync with the performed
+status of the given interval variable.
defFixedDurationEndSyncedOnStartIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose end is
+ synchronized with the start of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationEndSyncedOnStartIntervalVar(self,interval_var,duration,offset)
+
+
+
+
+
Creates an interval var with a fixed duration whose end is
+synchronized with the start of another interval, with a given
+offset. The performed status is also in sync with the performed
+status of the given interval variable.
defFixedDurationEndSyncedOnEndIntervalVar(self,interval_var:"IntervalVar",duration:"int64_t",offset:"int64_t")->"operations_research::IntervalVar *":
+ r"""
+ Creates an interval var with a fixed duration whose end is
+ synchronized with the end of another interval, with a given
+ offset. The performed status is also in sync with the performed
+ status of the given interval variable.
+ """
+ return_pywrapcp.Solver_FixedDurationEndSyncedOnEndIntervalVar(self,interval_var,duration,offset)
+
+
+
+
+
Creates an interval var with a fixed duration whose end is
+synchronized with the end of another interval, with a given
+offset. The performed status is also in sync with the performed
+status of the given interval variable.
defIntervalRelaxedMin(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates and returns an interval variable that wraps around the given one,
+ relaxing the min start and end. Relaxing means making unbounded when
+ optional. If the variable is non-optional, this method returns
+ interval_var.
+
+ More precisely, such an interval variable behaves as follows:
+ When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+ When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the min side;
+ When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+ This is very useful to implement propagators that may only modify
+ the start max or end max.
+ """
+ return_pywrapcp.Solver_IntervalRelaxedMin(self,interval_var)
+
+
+
+
+
Creates and returns an interval variable that wraps around the given one,
+ relaxing the min start and end. Relaxing means making unbounded when
+ optional. If the variable is non-optional, this method returns
+ interval_var.
+
+
More precisely, such an interval variable behaves as follows:
+When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the min side;
+When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+
This is very useful to implement propagators that may only modify
+ the start max or end max.
defIntervalRelaxedMax(self,interval_var:"IntervalVar")->"operations_research::IntervalVar *":
+ r"""
+ Creates and returns an interval variable that wraps around the given one,
+ relaxing the max start and end. Relaxing means making unbounded when
+ optional. If the variable is non optional, this method returns
+ interval_var.
+
+ More precisely, such an interval variable behaves as follows:
+ When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+ When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the max side;
+ When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+ This is very useful for implementing propagators that may only modify
+ the start min or end min.
+ """
+ return_pywrapcp.Solver_IntervalRelaxedMax(self,interval_var)
+
+
+
+
+
Creates and returns an interval variable that wraps around the given one,
+ relaxing the max start and end. Relaxing means making unbounded when
+ optional. If the variable is non optional, this method returns
+ interval_var.
+
+
More precisely, such an interval variable behaves as follows:
+When the underlying must be performed, the returned interval variable
+ behaves exactly as the underlying;
+When the underlying may or may not be performed, the returned interval
+ variable behaves like the underlying, except that it is unbounded on
+ the max side;
+When the underlying cannot be performed, the returned interval variable
+ is of duration 0 and must be performed in an interval unbounded on
+ both sides.
+
+
This is very useful for implementing propagators that may only modify
+ the start min or end min.
defTemporalDisjunction(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This constraint implements a temporal disjunction between two
+ interval vars t1 and t2. 'alt' indicates which alternative was
+ chosen (alt == 0 is equivalent to t1 before t2).
+
+ |
+
+ *Overload 2:*
+ This constraint implements a temporal disjunction between two
+ interval vars.
+ """
+ return_pywrapcp.Solver_TemporalDisjunction(self,*args)
+
+
+
+
+
Overload 1:
+This constraint implements a temporal disjunction between two
+interval vars t1 and t2. 'alt' indicates which alternative was
+chosen (alt == 0 is equivalent to t1 before t2).
+
+
|
+
+
Overload 2:
+This constraint implements a temporal disjunction between two
+interval vars.
defDisjunctiveConstraint(self,intervals:"std::vector< operations_research::IntervalVar * > const &",name:"std::string const &")->"operations_research::DisjunctiveConstraint *":
+ r"""
+ This constraint forces all interval vars into an non-overlapping
+ sequence. Intervals with zero duration can be scheduled anywhere.
+ """
+ return_pywrapcp.Solver_DisjunctiveConstraint(self,intervals,name)
+
+
+
+
+
This constraint forces all interval vars into an non-overlapping
+sequence. Intervals with zero duration can be scheduled anywhere.
defCumulative(self,*args)->"operations_research::Constraint *":
+ r"""
+ *Overload 1:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 2:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 3:*
+ This constraint forces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 4:*
+ This constraint enforces that, for any integer t, the sum of the demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should only contain non-negative values. Zero values are
+ supported, and the corresponding intervals are filtered out, as they
+ neither impact nor are impacted by this constraint.
+
+ |
+
+ *Overload 5:*
+ This constraint enforces that, for any integer t, the sum of demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should be positive.
+
+ |
+
+ *Overload 6:*
+ This constraint enforces that, for any integer t, the sum of demands
+ corresponding to an interval containing t does not exceed the given
+ capacity.
+
+ Intervals and demands should be vectors of equal size.
+
+ Demands should be positive.
+ """
+ return_pywrapcp.Solver_Cumulative(self,*args)
+
+
+
+
+
Overload 1:
+This constraint forces that, for any integer t, the sum of the demands
+corresponding to an interval containing t does not exceed the given
+capacity.
+
+
Intervals and demands should be vectors of equal size.
+
+
Demands should only contain non-negative values. Zero values are
+supported, and the corresponding intervals are filtered out, as they
+neither impact nor are impacted by this constraint.
+
+
|
+
+
Overload 2:
+This constraint forces that, for any integer t, the sum of the demands
+corresponding to an interval containing t does not exceed the given
+capacity.
+
+
Intervals and demands should be vectors of equal size.
+
+
Demands should only contain non-negative values. Zero values are
+supported, and the corresponding intervals are filtered out, as they
+neither impact nor are impacted by this constraint.
+
+
|
+
+
Overload 3:
+This constraint forces that, for any integer t, the sum of the demands
+corresponding to an interval containing t does not exceed the given
+capacity.
+
+
Intervals and demands should be vectors of equal size.
+
+
Demands should only contain non-negative values. Zero values are
+supported, and the corresponding intervals are filtered out, as they
+neither impact nor are impacted by this constraint.
+
+
|
+
+
Overload 4:
+This constraint enforces that, for any integer t, the sum of the demands
+corresponding to an interval containing t does not exceed the given
+capacity.
+
+
Intervals and demands should be vectors of equal size.
+
+
Demands should only contain non-negative values. Zero values are
+supported, and the corresponding intervals are filtered out, as they
+neither impact nor are impacted by this constraint.
+
+
|
+
+
Overload 5:
+This constraint enforces that, for any integer t, the sum of demands
+corresponding to an interval containing t does not exceed the given
+capacity.
+
+
Intervals and demands should be vectors of equal size.
+
+
Demands should be positive.
+
+
|
+
+
Overload 6:
+This constraint enforces that, for any integer t, the sum of demands
+corresponding to an interval containing t does not exceed the given
+capacity.
+
+
Intervals and demands should be vectors of equal size.
defCover(self,vars:"std::vector< operations_research::IntervalVar * > const &",target_var:"IntervalVar")->"operations_research::Constraint *":
+ r"""
+ This constraint states that the target_var is the convex hull of
+ the intervals. If none of the interval variables is performed,
+ then the target var is unperformed too. Also, if the target
+ variable is unperformed, then all the intervals variables are
+ unperformed too.
+ """
+ return_pywrapcp.Solver_Cover(self,vars,target_var)
+
+
+
+
+
This constraint states that the target_var is the convex hull of
+the intervals. If none of the interval variables is performed,
+then the target var is unperformed too. Also, if the target
+variable is unperformed, then all the intervals variables are
+unperformed too.
defAssignment(self,*args)->"operations_research::Assignment *":
+ r"""
+ *Overload 1:*
+ This method creates an empty assignment.
+
+ |
+
+ *Overload 2:*
+ This method creates an assignment which is a copy of 'a'.
+ """
+ return_pywrapcp.Solver_Assignment(self,*args)
+
+
+
+
+
Overload 1:
+This method creates an empty assignment.
+
+
|
+
+
Overload 2:
+This method creates an assignment which is a copy of 'a'.
defFirstSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the first solution of the search.
+
+ |
+
+ *Overload 2:*
+ Collect the first solution of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_FirstSolutionCollector(self,*args)
+
+
+
+
+
Overload 1:
+Collect the first solution of the search.
+
+
|
+
+
Overload 2:
+Collect the first solution of the search. The variables will need to
+be added later.
defLastSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the last solution of the search.
+
+ |
+
+ *Overload 2:*
+ Collect the last solution of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_LastSolutionCollector(self,*args)
+
+
+
+
+
Overload 1:
+Collect the last solution of the search.
+
+
|
+
+
Overload 2:
+Collect the last solution of the search. The variables will need to
+be added later.
defBestValueSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect the solution corresponding to the optimal value of the objective
+ of 'assignment'; if 'assignment' does not have an objective no solution is
+ collected. This collector only collects one solution corresponding to the
+ best objective value (the first one found).
+
+ |
+
+ *Overload 2:*
+ Collect the solution corresponding to the optimal value of the
+ objective of 'assignment'; if 'assignment' does not have an objective no
+ solution is collected. This collector only collects one solution
+ corresponding to the best objective value (the first one
+ found). The variables will need to be added later.
+ """
+ return_pywrapcp.Solver_BestValueSolutionCollector(self,*args)
+
+
+
+
+
Overload 1:
+Collect the solution corresponding to the optimal value of the objective
+of 'assignment'; if 'assignment' does not have an objective no solution is
+collected. This collector only collects one solution corresponding to the
+best objective value (the first one found).
+
+
|
+
+
Overload 2:
+Collect the solution corresponding to the optimal value of the
+objective of 'assignment'; if 'assignment' does not have an objective no
+solution is collected. This collector only collects one solution
+corresponding to the best objective value (the first one
+found). The variables will need to be added later.
defAllSolutionCollector(self,*args)->"operations_research::SolutionCollector *":
+ r"""
+ *Overload 1:*
+ Collect all solutions of the search.
+
+ |
+
+ *Overload 2:*
+ Collect all solutions of the search. The variables will need to
+ be added later.
+ """
+ return_pywrapcp.Solver_AllSolutionCollector(self,*args)
+
+
+
+
+
Overload 1:
+Collect all solutions of the search.
+
+
|
+
+
Overload 2:
+Collect all solutions of the search. The variables will need to
+be added later.
defOptimize(self,maximize:"bool",v:"IntVar",step:"int64_t")->"operations_research::OptimizeVar *":
+ r""" Creates a objective with a given sense (true = maximization)."""
+ return_pywrapcp.Solver_Optimize(self,maximize,v,step)
+
+
+
+
+
Creates a objective with a given sense (true = maximization).
defWeightedOptimize(self,*args)->"operations_research::OptimizeVar *":
+ r"""
+ *Overload 1:*
+ Creates a weighted objective with a given sense (true = maximization).
+
+ |
+
+ *Overload 2:*
+ Creates a weighted objective with a given sense (true = maximization).
+ """
+ return_pywrapcp.Solver_WeightedOptimize(self,*args)
+
+
+
+
+
Overload 1:
+Creates a weighted objective with a given sense (true = maximization).
+
+
|
+
+
Overload 2:
+Creates a weighted objective with a given sense (true = maximization).
defTabuSearch(self,maximize:"bool",v:"IntVar",step:"int64_t",vars:"std::vector< operations_research::IntVar * > const &",keep_tenure:"int64_t",forbid_tenure:"int64_t",tabu_factor:"double")->"operations_research::SearchMonitor *":
+ r"""
+ MetaHeuristics which try to get the search out of local optima.
+ Creates a Tabu Search monitor.
+ In the context of local search the behavior is similar to MakeOptimize(),
+ creating an objective in a given sense. The behavior differs once a local
+ optimum is reached: thereafter solutions which degrade the value of the
+ objective are allowed if they are not "tabu". A solution is "tabu" if it
+ doesn't respect the following rules:
+ - improving the best solution found so far
+ - variables in the "keep" list must keep their value, variables in the
+ "forbid" list must not take the value they have in the list.
+ Variables with new values enter the tabu lists after each new solution
+ found and leave the lists after a given number of iterations (called
+ tenure). Only the variables passed to the method can enter the lists.
+ The tabu criterion is softened by the tabu factor which gives the number
+ of "tabu" violations which is tolerated; a factor of 1 means no violations
+ allowed; a factor of 0 means all violations are allowed.
+ """
+ return_pywrapcp.Solver_TabuSearch(self,maximize,v,step,vars,keep_tenure,forbid_tenure,tabu_factor)
+
+
+
+
+
MetaHeuristics which try to get the search out of local optima.
+Creates a Tabu Search monitor.
+In the context of local search the behavior is similar to MakeOptimize(),
+creating an objective in a given sense. The behavior differs once a local
+optimum is reached: thereafter solutions which degrade the value of the
+objective are allowed if they are not "tabu". A solution is "tabu" if it
+doesn't respect the following rules:
+
+
+
improving the best solution found so far
+
variables in the "keep" list must keep their value, variables in the
+"forbid" list must not take the value they have in the list.
+Variables with new values enter the tabu lists after each new solution
+found and leave the lists after a given number of iterations (called
+tenure). Only the variables passed to the method can enter the lists.
+The tabu criterion is softened by the tabu factor which gives the number
+of "tabu" violations which is tolerated; a factor of 1 means no violations
+allowed; a factor of 0 means all violations are allowed.
defLubyRestart(self,scale_factor:"int")->"operations_research::SearchMonitor *":
+ r"""
+ This search monitor will restart the search periodically.
+ At the iteration n, it will restart after scale_factor * Luby(n) failures
+ where Luby is the Luby Strategy (i.e. 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8...).
+ """
+ return_pywrapcp.Solver_LubyRestart(self,scale_factor)
+
+
+
+
+
This search monitor will restart the search periodically.
+At the iteration n, it will restart after scale_factor * Luby(n) failures
+where Luby is the Luby Strategy (i.e. 1 1 2 1 1 2 4 1 1 2 1 1 2 4 8...).
defBranchesLimit(self,branches:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of branches
+ explored in the search tree.
+ """
+ return_pywrapcp.Solver_BranchesLimit(self,branches)
+
+
+
+
+
Creates a search limit that constrains the number of branches
+explored in the search tree.
defFailuresLimit(self,failures:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of failures
+ that can happen when exploring the search tree.
+ """
+ return_pywrapcp.Solver_FailuresLimit(self,failures)
+
+
+
+
+
Creates a search limit that constrains the number of failures
+that can happen when exploring the search tree.
defSolutionsLimit(self,solutions:"int64_t")->"operations_research::RegularLimit *":
+ r"""
+ Creates a search limit that constrains the number of solutions found
+ during the search.
+ """
+ return_pywrapcp.Solver_SolutionsLimit(self,solutions)
+
+
+
+
+
Creates a search limit that constrains the number of solutions found
+during the search.
defLimit(self,*args)->"operations_research::SearchLimit *":
+ r"""
+ *Overload 1:*
+ Limits the search with the 'time', 'branches', 'failures' and
+ 'solutions' limits. 'smart_time_check' reduces the calls to the wall
+
+ |
+
+ *Overload 2:*
+ Creates a search limit from its protobuf description
+
+ |
+
+ *Overload 3:*
+ Creates a search limit that is reached when either of the underlying limit
+ is reached. That is, the returned limit is more stringent than both
+ argument limits.
+ """
+ return_pywrapcp.Solver_Limit(self,*args)
+
+
+
+
+
Overload 1:
+Limits the search with the 'time', 'branches', 'failures' and
+'solutions' limits. 'smart_time_check' reduces the calls to the wall
+
+
|
+
+
Overload 2:
+Creates a search limit from its protobuf description
+
+
|
+
+
Overload 3:
+Creates a search limit that is reached when either of the underlying limit
+is reached. That is, the returned limit is more stringent than both
+argument limits.
defCustomLimit(self,limiter:"std::function< bool () >")->"operations_research::SearchLimit *":
+ r"""
+ Callback-based search limit. Search stops when limiter returns true; if
+ this happens at a leaf the corresponding solution will be rejected.
+ """
+ return_pywrapcp.Solver_CustomLimit(self,limiter)
+
+
+
+
+
Callback-based search limit. Search stops when limiter returns true; if
+this happens at a leaf the corresponding solution will be rejected.
defSearchTrace(self,prefix:"std::string const &")->"operations_research::SearchMonitor *":
+ r"""
+ Creates a search monitor that will trace precisely the behavior of the
+ search. Use this only for low level debugging.
+ """
+ return_pywrapcp.Solver_SearchTrace(self,prefix)
+
+
+
+
+
Creates a search monitor that will trace precisely the behavior of the
+search. Use this only for low level debugging.
defStatisticsModelVisitor(self)->"operations_research::ModelVisitor *":
+ r""" Displays some nice statistics on the model."""
+ return_pywrapcp.Solver_StatisticsModelVisitor(self)
+
defScheduleOrPostpone(self,var:"IntervalVar",est:"int64_t",marker:"int64_t *const")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to schedule a task at a given time.
+ On the Apply branch, it will set that interval var as performed and set
+ its start to 'est'. On the Refute branch, it will just update the
+ 'marker' to 'est' + 1. This decision is used in the
+ INTERVAL_SET_TIMES_FORWARD strategy.
+ """
+ return_pywrapcp.Solver_ScheduleOrPostpone(self,var,est,marker)
+
+
+
+
+
Returns a decision that tries to schedule a task at a given time.
+On the Apply branch, it will set that interval var as performed and set
+its start to 'est'. On the Refute branch, it will just update the
+'marker' to 'est' + 1. This decision is used in the
+INTERVAL_SET_TIMES_FORWARD strategy.
defScheduleOrExpedite(self,var:"IntervalVar",est:"int64_t",marker:"int64_t *const")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to schedule a task at a given time.
+ On the Apply branch, it will set that interval var as performed and set
+ its end to 'est'. On the Refute branch, it will just update the
+ 'marker' to 'est' - 1. This decision is used in the
+ INTERVAL_SET_TIMES_BACKWARD strategy.
+ """
+ return_pywrapcp.Solver_ScheduleOrExpedite(self,var,est,marker)
+
+
+
+
+
Returns a decision that tries to schedule a task at a given time.
+On the Apply branch, it will set that interval var as performed and set
+its end to 'est'. On the Refute branch, it will just update the
+'marker' to 'est' - 1. This decision is used in the
+INTERVAL_SET_TIMES_BACKWARD strategy.
defRankFirstInterval(self,sequence:"SequenceVar",index:"int")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to rank first the ith interval var
+ in the sequence variable.
+ """
+ return_pywrapcp.Solver_RankFirstInterval(self,sequence,index)
+
+
+
+
+
Returns a decision that tries to rank first the ith interval var
+in the sequence variable.
defRankLastInterval(self,sequence:"SequenceVar",index:"int")->"operations_research::Decision *":
+ r"""
+ Returns a decision that tries to rank last the ith interval var
+ in the sequence variable.
+ """
+ return_pywrapcp.Solver_RankLastInterval(self,sequence,index)
+
+
+
+
+
Returns a decision that tries to rank last the ith interval var
+in the sequence variable.
defDecisionBuilderFromAssignment(self,assignment:"Assignment",db:"DecisionBuilder",vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a decision builder for which the left-most leaf corresponds
+ to assignment, the rest of the tree being explored using 'db'.
+ """
+ return_pywrapcp.Solver_DecisionBuilderFromAssignment(self,assignment,db,vars)
+
+
+
+
+
Returns a decision builder for which the left-most leaf corresponds
+to assignment, the rest of the tree being explored using 'db'.
defConstraintAdder(self,ct:"Constraint")->"operations_research::DecisionBuilder *":
+ r"""
+ Returns a decision builder that will add the given constraint to
+ the model.
+ """
+ return_pywrapcp.Solver_ConstraintAdder(self,ct)
+
+
+
+
+
Returns a decision builder that will add the given constraint to
+the model.
defMoveTowardTargetOperator(self,*args)->"operations_research::LocalSearchOperator *":
+ r"""
+ *Overload 1:*
+ Creates a local search operator that tries to move the assignment of some
+ variables toward a target. The target is given as an Assignment. This
+ operator generates neighbors in which the only difference compared to the
+ current state is that one variable that belongs to the target assignment
+ is set to its target value.
+
+ |
+
+ *Overload 2:*
+ Creates a local search operator that tries to move the assignment of some
+ variables toward a target. The target is given either as two vectors: a
+ vector of variables and a vector of associated target values. The two
+ vectors should be of the same length. This operator generates neighbors in
+ which the only difference compared to the current state is that one
+ variable that belongs to the given vector is set to its target value.
+ """
+ return_pywrapcp.Solver_MoveTowardTargetOperator(self,*args)
+
+
+
+
+
Overload 1:
+Creates a local search operator that tries to move the assignment of some
+variables toward a target. The target is given as an Assignment. This
+operator generates neighbors in which the only difference compared to the
+current state is that one variable that belongs to the target assignment
+is set to its target value.
+
+
|
+
+
Overload 2:
+Creates a local search operator that tries to move the assignment of some
+variables toward a target. The target is given either as two vectors: a
+vector of variables and a vector of associated target values. The two
+vectors should be of the same length. This operator generates neighbors in
+which the only difference compared to the current state is that one
+variable that belongs to the given vector is set to its target value.
defRandomConcatenateOperators(self,*args)->"operations_research::LocalSearchOperator *":
+ r"""
+ *Overload 1:*
+ Randomized version of local search concatenator; calls a random operator
+ at each call to MakeNextNeighbor().
+
+ |
+
+ *Overload 2:*
+ Randomized version of local search concatenator; calls a random operator
+ at each call to MakeNextNeighbor(). The provided seed is used to
+ initialize the random number generator.
+ """
+ return_pywrapcp.Solver_RandomConcatenateOperators(self,*args)
+
+
+
+
+
Overload 1:
+Randomized version of local search concatenator; calls a random operator
+at each call to MakeNextNeighbor().
+
+
|
+
+
Overload 2:
+Randomized version of local search concatenator; calls a random operator
+at each call to MakeNextNeighbor(). The provided seed is used to
+initialize the random number generator.
defNeighborhoodLimit(self,op:"LocalSearchOperator",limit:"int64_t")->"operations_research::LocalSearchOperator *":
+ r"""
+ Creates a local search operator that wraps another local search
+ operator and limits the number of neighbors explored (i.e., calls
+ to MakeNextNeighbor from the current solution (between two calls
+ to Start()). When this limit is reached, MakeNextNeighbor()
+ returns false. The counter is cleared when Start() is called.
+ """
+ return_pywrapcp.Solver_NeighborhoodLimit(self,op,limit)
+
+
+
+
+
Creates a local search operator that wraps another local search
+operator and limits the number of neighbors explored (i.e., calls
+to MakeNextNeighbor from the current solution (between two calls
+to Start()). When this limit is reached, MakeNextNeighbor()
+returns false. The counter is cleared when Start() is called.
defSearchDepth(self)->"int":
+ r"""
+ Gets the search depth of the current active search. Returns -1 if
+ there is no active search opened.
+ """
+ return_pywrapcp.Solver_SearchDepth(self)
+
+
+
+
+
Gets the search depth of the current active search. Returns -1 if
+there is no active search opened.
defSearchLeftDepth(self)->"int":
+ r"""
+ Gets the search left depth of the current active search. Returns -1 if
+ there is no active search opened.
+ """
+ return_pywrapcp.Solver_SearchLeftDepth(self)
+
+
+
+
+
Gets the search left depth of the current active search. Returns -1 if
+there is no active search opened.
defSolveDepth(self)->"int":
+ r"""
+ Gets the number of nested searches. It returns 0 outside search,
+ 1 during the top level search, 2 or more in case of nested searches.
+ """
+ return_pywrapcp.Solver_SolveDepth(self)
+
+
+
+
+
Gets the number of nested searches. It returns 0 outside search,
+1 during the top level search, 2 or more in case of nested searches.
defLocalSearchProfile(self)->"std::string":
+ r""" Returns local search profiling information in a human readable format."""
+ return_pywrapcp.Solver_LocalSearchProfile(self)
+
+
+
+
+
Returns local search profiling information in a human readable format.
defConstraints(self)->"int":
+ r"""
+ Counts the number of constraints that have been added
+ to the solver before the search.
+ """
+ return_pywrapcp.Solver_Constraints(self)
+
+
+
+
+
Counts the number of constraints that have been added
+to the solver before the search.
defAccept(self,visitor:"operations_research::ModelVisitor *const")->"void":
+ r""" Accepts the given model visitor."""
+ return_pywrapcp.Solver_Accept(self,visitor)
+
defFinishCurrentSearch(self)->"void":
+ r""" Tells the solver to kill or restart the current search."""
+ return_pywrapcp.Solver_FinishCurrentSearch(self)
+
+
+
+
+
Tells the solver to kill or restart the current search.
defShouldFail(self)->"void":
+ r"""
+ These methods are only useful for the SWIG wrappers, which need a way
+ to externally cause the Solver to fail.
+ """
+ return_pywrapcp.Solver_ShouldFail(self)
+
+
+
+
+
These methods are only useful for the SWIG wrappers, which need a way
+to externally cause the Solver to fail.
defSolver_DefaultSolverParameters()->"operations_research::ConstraintSolverParameters":
+ r""" Create a ConstraintSolverParameters proto with all the default values."""
+ return_pywrapcp.Solver_DefaultSolverParameters()
+
+
+
+
+
Create a ConstraintSolverParameters proto with all the default values.
classPropagationBaseObject(BaseObject):
+ r"""
+ NOLINT
+ The PropagationBaseObject is a subclass of BaseObject that is also
+ friend to the Solver class. It allows accessing methods useful when
+ writing new constraints or new expressions.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,s:"Solver"):
+ ifself.__class__==PropagationBaseObject:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.PropagationBaseObject_swiginit(self,_pywrapcp.new_PropagationBaseObject(_self,s))
+ __swig_destroy__=_pywrapcp.delete_PropagationBaseObject
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.PropagationBaseObject_DebugString(self)
+
+ defsolver(self)->"operations_research::Solver *":
+ return_pywrapcp.PropagationBaseObject_solver(self)
+
+ defName(self)->"std::string":
+ r""" Object naming."""
+ return_pywrapcp.PropagationBaseObject_Name(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_PropagationBaseObject(self)
+ returnweakref.proxy(self)
+
+
+
+
+
NOLINT
+The PropagationBaseObject is a subclass of BaseObject that is also
+friend to the Solver class. It allows accessing methods useful when
+writing new constraints or new expressions.
classDecision(BaseObject):
+ r"""
+ A Decision represents a choice point in the search tree. The two main
+ methods are Apply() to go left, or Refute() to go right.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self):
+ ifself.__class__==Decision:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.Decision_swiginit(self,_pywrapcp.new_Decision(_self,))
+ __swig_destroy__=_pywrapcp.delete_Decision
+
+ defApplyWrapper(self,s:"Solver")->"void":
+ r""" Apply will be called first when the decision is executed."""
+ return_pywrapcp.Decision_ApplyWrapper(self,s)
+
+ defRefuteWrapper(self,s:"Solver")->"void":
+ r""" Refute will be called after a backtrack."""
+ return_pywrapcp.Decision_RefuteWrapper(self,s)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Decision_DebugString(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.Decision___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.Decision___str__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_Decision(self)
+ returnweakref.proxy(self)
+
+
+
+
+
A Decision represents a choice point in the search tree. The two main
+methods are Apply() to go left, or Refute() to go right.
defApplyWrapper(self,s:"Solver")->"void":
+ r""" Apply will be called first when the decision is executed."""
+ return_pywrapcp.Decision_ApplyWrapper(self,s)
+
+
+
+
+
Apply will be called first when the decision is executed.
classDecisionBuilder(BaseObject):
+ r"""
+ A DecisionBuilder is responsible for creating the search tree. The
+ important method is Next(), which returns the next decision to execute.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self):
+ ifself.__class__==DecisionBuilder:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.DecisionBuilder_swiginit(self,_pywrapcp.new_DecisionBuilder(_self,))
+ __swig_destroy__=_pywrapcp.delete_DecisionBuilder
+
+ defNextWrapper(self,s:"Solver")->"operations_research::Decision *":
+ r"""
+ This is the main method of the decision builder class. It must
+ return a decision (an instance of the class Decision). If it
+ returns nullptr, this means that the decision builder has finished
+ its work.
+ """
+ return_pywrapcp.DecisionBuilder_NextWrapper(self,s)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.DecisionBuilder_DebugString(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.DecisionBuilder___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.DecisionBuilder___str__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_DecisionBuilder(self)
+ returnweakref.proxy(self)
+
+
+
+
+
A DecisionBuilder is responsible for creating the search tree. The
+important method is Next(), which returns the next decision to execute.
defNextWrapper(self,s:"Solver")->"operations_research::Decision *":
+ r"""
+ This is the main method of the decision builder class. It must
+ return a decision (an instance of the class Decision). If it
+ returns nullptr, this means that the decision builder has finished
+ its work.
+ """
+ return_pywrapcp.DecisionBuilder_NextWrapper(self,s)
+
+
+
+
+
This is the main method of the decision builder class. It must
+return a decision (an instance of the class Decision). If it
+returns nullptr, this means that the decision builder has finished
+its work.
classDemon(BaseObject):
+ r"""
+ A Demon is the base element of a propagation queue. It is the main
+ object responsible for implementing the actual propagation
+ of the constraint and pruning the inconsistent values in the domains
+ of the variables. The main concept is that demons are listeners that are
+ attached to the variables and listen to their modifications.
+ There are two methods:
+ - Run() is the actual method called when the demon is processed.
+ - priority() returns its priority. Standard priorities are slow, normal
+ or fast. "immediate" is reserved for variables and is treated separately.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self):
+ r"""
+ This indicates the priority of a demon. Immediate demons are treated
+ separately and corresponds to variables.
+ """
+ ifself.__class__==Demon:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.Demon_swiginit(self,_pywrapcp.new_Demon(_self,))
+ __swig_destroy__=_pywrapcp.delete_Demon
+
+ defRunWrapper(self,s:"Solver")->"void":
+ r""" This is the main callback of the demon."""
+ return_pywrapcp.Demon_RunWrapper(self,s)
+
+ defPriority(self)->"operations_research::Solver::DemonPriority":
+ r"""
+ This method returns the priority of the demon. Usually a demon is
+ fast, slow or normal. Immediate demons are reserved for internal
+ use to maintain variables.
+ """
+ return_pywrapcp.Demon_Priority(self)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Demon_DebugString(self)
+
+ defInhibit(self,s:"Solver")->"void":
+ r"""
+ This method inhibits the demon in the search tree below the
+ current position.
+ """
+ return_pywrapcp.Demon_Inhibit(self,s)
+
+ defDesinhibit(self,s:"Solver")->"void":
+ r""" This method un-inhibits the demon that was previously inhibited."""
+ return_pywrapcp.Demon_Desinhibit(self,s)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_Demon(self)
+ returnweakref.proxy(self)
+
+
+
+
+
A Demon is the base element of a propagation queue. It is the main
+ object responsible for implementing the actual propagation
+ of the constraint and pruning the inconsistent values in the domains
+ of the variables. The main concept is that demons are listeners that are
+ attached to the variables and listen to their modifications.
+
+
There are two methods
+
+
+
+
Run() is the actual method called when the demon is processed.
+
priority() returns its priority. Standard priorities are slow, normal
+ or fast. "immediate" is reserved for variables and is treated separately.
def__init__(self):
+ r"""
+ This indicates the priority of a demon. Immediate demons are treated
+ separately and corresponds to variables.
+ """
+ ifself.__class__==Demon:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.Demon_swiginit(self,_pywrapcp.new_Demon(_self,))
+
+
+
+
+
This indicates the priority of a demon. Immediate demons are treated
+separately and corresponds to variables.
defPriority(self)->"operations_research::Solver::DemonPriority":
+ r"""
+ This method returns the priority of the demon. Usually a demon is
+ fast, slow or normal. Immediate demons are reserved for internal
+ use to maintain variables.
+ """
+ return_pywrapcp.Demon_Priority(self)
+
+
+
+
+
This method returns the priority of the demon. Usually a demon is
+fast, slow or normal. Immediate demons are reserved for internal
+use to maintain variables.
defInhibit(self,s:"Solver")->"void":
+ r"""
+ This method inhibits the demon in the search tree below the
+ current position.
+ """
+ return_pywrapcp.Demon_Inhibit(self,s)
+
+
+
+
+
This method inhibits the demon in the search tree below the
+current position.
defDesinhibit(self,s:"Solver")->"void":
+ r""" This method un-inhibits the demon that was previously inhibited."""
+ return_pywrapcp.Demon_Desinhibit(self,s)
+
+
+
+
+
This method un-inhibits the demon that was previously inhibited.
classConstraint(PropagationBaseObject):
+ r"""
+ A constraint is the main modeling object. It provides two methods:
+ - Post() is responsible for creating the demons and attaching them to
+ immediate demons().
+ - InitialPropagate() is called once just after Post and performs
+ the initial propagation. The subsequent propagations will be performed
+ by the demons Posted during the post() method.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,solver:"Solver"):
+ ifself.__class__==Constraint:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.Constraint_swiginit(self,_pywrapcp.new_Constraint(_self,solver))
+ __swig_destroy__=_pywrapcp.delete_Constraint
+
+ defPost(self)->"void":
+ r"""
+ This method is called when the constraint is processed by the
+ solver. Its main usage is to attach demons to variables.
+ """
+ return_pywrapcp.Constraint_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ r"""
+ This method performs the initial propagation of the
+ constraint. It is called just after the post.
+ """
+ return_pywrapcp.Constraint_InitialPropagateWrapper(self)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Constraint_DebugString(self)
+
+ defVar(self)->"operations_research::IntVar *":
+ r"""
+ Creates a Boolean variable representing the status of the constraint
+ (false = constraint is violated, true = constraint is satisfied). It
+ returns nullptr if the constraint does not support this API.
+ """
+ return_pywrapcp.Constraint_Var(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.Constraint___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.Constraint___str__(self)
+
+ def__add__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___add__(self,*args)
+
+ def__radd__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___radd__(self,v)
+
+ def__sub__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___sub__(self,*args)
+
+ def__rsub__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___rsub__(self,v)
+
+ def__mul__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___mul__(self,*args)
+
+ def__rmul__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___rmul__(self,v)
+
+ def__floordiv__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___floordiv__(self,v)
+
+ def__neg__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___neg__(self)
+
+ def__abs__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint___abs__(self)
+
+ defSquare(self)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint_Square(self)
+
+ def__eq__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___eq__(self,*args)
+
+ def__ne__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___ne__(self,*args)
+
+ def__ge__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___ge__(self,*args)
+
+ def__gt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___gt__(self,*args)
+
+ def__le__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___le__(self,*args)
+
+ def__lt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.Constraint___lt__(self,*args)
+
+ defMapTo(self,vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ return_pywrapcp.Constraint_MapTo(self,vars)
+
+ defIndexOf(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.Constraint_IndexOf(self,*args)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_Constraint(self)
+ returnweakref.proxy(self)
+
+
+
+
+
A constraint is the main modeling object. It provides two methods:
+
+
+
Post() is responsible for creating the demons and attaching them to
+immediate demons().
+
InitialPropagate() is called once just after Post and performs
+the initial propagation. The subsequent propagations will be performed
+by the demons Posted during the post() method.
defPost(self)->"void":
+ r"""
+ This method is called when the constraint is processed by the
+ solver. Its main usage is to attach demons to variables.
+ """
+ return_pywrapcp.Constraint_Post(self)
+
+
+
+
+
This method is called when the constraint is processed by the
+solver. Its main usage is to attach demons to variables.
defInitialPropagateWrapper(self)->"void":
+ r"""
+ This method performs the initial propagation of the
+ constraint. It is called just after the post.
+ """
+ return_pywrapcp.Constraint_InitialPropagateWrapper(self)
+
+
+
+
+
This method performs the initial propagation of the
+constraint. It is called just after the post.
defVar(self)->"operations_research::IntVar *":
+ r"""
+ Creates a Boolean variable representing the status of the constraint
+ (false = constraint is violated, true = constraint is satisfied). It
+ returns nullptr if the constraint does not support this API.
+ """
+ return_pywrapcp.Constraint_Var(self)
+
+
+
+
+
Creates a Boolean variable representing the status of the constraint
+(false = constraint is violated, true = constraint is satisfied). It
+returns nullptr if the constraint does not support this API.
classSearchMonitor(BaseObject):
+ r""" A search monitor is a simple set of callbacks to monitor all search events"""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,s:"Solver"):
+ ifself.__class__==SearchMonitor:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.SearchMonitor_swiginit(self,_pywrapcp.new_SearchMonitor(_self,s))
+ __swig_destroy__=_pywrapcp.delete_SearchMonitor
+
+ defEnterSearch(self)->"void":
+ r""" Beginning of the search."""
+ return_pywrapcp.SearchMonitor_EnterSearch(self)
+
+ defRestartSearch(self)->"void":
+ r""" Restart the search."""
+ return_pywrapcp.SearchMonitor_RestartSearch(self)
+
+ defExitSearch(self)->"void":
+ r""" End of the search."""
+ return_pywrapcp.SearchMonitor_ExitSearch(self)
+
+ defBeginNextDecision(self,b:"DecisionBuilder")->"void":
+ r""" Before calling DecisionBuilder::Next."""
+ return_pywrapcp.SearchMonitor_BeginNextDecision(self,b)
+
+ defEndNextDecision(self,b:"DecisionBuilder",d:"Decision")->"void":
+ r""" After calling DecisionBuilder::Next, along with the returned decision."""
+ return_pywrapcp.SearchMonitor_EndNextDecision(self,b,d)
+
+ defApplyDecision(self,d:"Decision")->"void":
+ r""" Before applying the decision."""
+ return_pywrapcp.SearchMonitor_ApplyDecision(self,d)
+
+ defRefuteDecision(self,d:"Decision")->"void":
+ r""" Before refuting the decision."""
+ return_pywrapcp.SearchMonitor_RefuteDecision(self,d)
+
+ defAfterDecision(self,d:"Decision",apply:"bool")->"void":
+ r"""
+ Just after refuting or applying the decision, apply is true after Apply.
+ This is called only if the Apply() or Refute() methods have not failed.
+ """
+ return_pywrapcp.SearchMonitor_AfterDecision(self,d,apply)
+
+ defBeginFail(self)->"void":
+ r""" Just when the failure occurs."""
+ return_pywrapcp.SearchMonitor_BeginFail(self)
+
+ defEndFail(self)->"void":
+ r""" After completing the backtrack."""
+ return_pywrapcp.SearchMonitor_EndFail(self)
+
+ defBeginInitialPropagation(self)->"void":
+ r""" Before the initial propagation."""
+ return_pywrapcp.SearchMonitor_BeginInitialPropagation(self)
+
+ defEndInitialPropagation(self)->"void":
+ r""" After the initial propagation."""
+ return_pywrapcp.SearchMonitor_EndInitialPropagation(self)
+
+ defAcceptSolution(self)->"bool":
+ r"""
+ This method is called when a solution is found. It asserts whether the
+ solution is valid. A value of false indicates that the solution
+ should be discarded.
+ """
+ return_pywrapcp.SearchMonitor_AcceptSolution(self)
+
+ defAtSolution(self)->"bool":
+ r"""
+ This method is called when a valid solution is found. If the
+ return value is true, then search will resume after. If the result
+ is false, then search will stop there.
+ """
+ return_pywrapcp.SearchMonitor_AtSolution(self)
+
+ defNoMoreSolutions(self)->"void":
+ r""" When the search tree is finished."""
+ return_pywrapcp.SearchMonitor_NoMoreSolutions(self)
+
+ defLocalOptimum(self)->"bool":
+ r"""
+ When a local optimum is reached. If 'true' is returned, the last solution
+ is discarded and the search proceeds with the next one.
+ """
+ return_pywrapcp.SearchMonitor_LocalOptimum(self)
+
+ defAcceptDelta(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+
+ return_pywrapcp.SearchMonitor_AcceptDelta(self,delta,deltadelta)
+
+ defAcceptNeighbor(self)->"void":
+ r""" After accepting a neighbor during local search."""
+ return_pywrapcp.SearchMonitor_AcceptNeighbor(self)
+
+ defsolver(self)->"operations_research::Solver *":
+ return_pywrapcp.SearchMonitor_solver(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.SearchMonitor___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.SearchMonitor___str__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_SearchMonitor(self)
+ returnweakref.proxy(self)
+
+
+
+
+
A search monitor is a simple set of callbacks to monitor all search events
defEndNextDecision(self,b:"DecisionBuilder",d:"Decision")->"void":
+ r""" After calling DecisionBuilder::Next, along with the returned decision."""
+ return_pywrapcp.SearchMonitor_EndNextDecision(self,b,d)
+
+
+
+
+
After calling DecisionBuilder::Next, along with the returned decision.
defAfterDecision(self,d:"Decision",apply:"bool")->"void":
+ r"""
+ Just after refuting or applying the decision, apply is true after Apply.
+ This is called only if the Apply() or Refute() methods have not failed.
+ """
+ return_pywrapcp.SearchMonitor_AfterDecision(self,d,apply)
+
+
+
+
+
Just after refuting or applying the decision, apply is true after Apply.
+This is called only if the Apply() or Refute() methods have not failed.
defAcceptSolution(self)->"bool":
+ r"""
+ This method is called when a solution is found. It asserts whether the
+ solution is valid. A value of false indicates that the solution
+ should be discarded.
+ """
+ return_pywrapcp.SearchMonitor_AcceptSolution(self)
+
+
+
+
+
This method is called when a solution is found. It asserts whether the
+solution is valid. A value of false indicates that the solution
+should be discarded.
defAtSolution(self)->"bool":
+ r"""
+ This method is called when a valid solution is found. If the
+ return value is true, then search will resume after. If the result
+ is false, then search will stop there.
+ """
+ return_pywrapcp.SearchMonitor_AtSolution(self)
+
+
+
+
+
This method is called when a valid solution is found. If the
+return value is true, then search will resume after. If the result
+is false, then search will stop there.
defLocalOptimum(self)->"bool":
+ r"""
+ When a local optimum is reached. If 'true' is returned, the last solution
+ is discarded and the search proceeds with the next one.
+ """
+ return_pywrapcp.SearchMonitor_LocalOptimum(self)
+
+
+
+
+
When a local optimum is reached. If 'true' is returned, the last solution
+is discarded and the search proceeds with the next one.
classIntExpr(PropagationBaseObject):
+ r"""
+ The class IntExpr is the base of all integer expressions in
+ constraint programming.
+ It contains the basic protocol for an expression:
+ - setting and modifying its bound
+ - querying if it is bound
+ - listening to events modifying its bounds
+ - casting it into a variable (instance of IntVar)
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+
+ defMin(self)->"int64_t":
+ return_pywrapcp.IntExpr_Min(self)
+
+ defSetMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntExpr_SetMin(self,m)
+
+ defMax(self)->"int64_t":
+ return_pywrapcp.IntExpr_Max(self)
+
+ defSetMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntExpr_SetMax(self,m)
+
+ defSetRange(self,l:"int64_t",u:"int64_t")->"void":
+ r""" This method sets both the min and the max of the expression."""
+ return_pywrapcp.IntExpr_SetRange(self,l,u)
+
+ defSetValue(self,v:"int64_t")->"void":
+ r""" This method sets the value of the expression."""
+ return_pywrapcp.IntExpr_SetValue(self,v)
+
+ defBound(self)->"bool":
+ r""" Returns true if the min and the max of the expression are equal."""
+ return_pywrapcp.IntExpr_Bound(self)
+
+ defIsVar(self)->"bool":
+ r""" Returns true if the expression is indeed a variable."""
+ return_pywrapcp.IntExpr_IsVar(self)
+
+ defVar(self)->"operations_research::IntVar *":
+ r""" Creates a variable from the expression."""
+ return_pywrapcp.IntExpr_Var(self)
+
+ defVarWithName(self,name:"std::string const &")->"operations_research::IntVar *":
+ r"""
+ Creates a variable from the expression and set the name of the
+ resulting var. If the expression is already a variable, then it
+ will set the name of the expression, possibly overwriting it.
+ This is just a shortcut to Var() followed by set_name().
+ """
+ return_pywrapcp.IntExpr_VarWithName(self,name)
+
+ defWhenRange(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Attach a demon that will watch the min or the max of the expression.
+
+ |
+
+ *Overload 2:*
+ Attach a demon that will watch the min or the max of the expression.
+ """
+ return_pywrapcp.IntExpr_WhenRange(self,*args)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.IntExpr___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.IntExpr___str__(self)
+
+ def__add__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___add__(self,*args)
+
+ def__radd__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___radd__(self,v)
+
+ def__sub__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___sub__(self,*args)
+
+ def__rsub__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___rsub__(self,v)
+
+ def__mul__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___mul__(self,*args)
+
+ def__rmul__(self,v:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___rmul__(self,v)
+
+ def__floordiv__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___floordiv__(self,*args)
+
+ def__mod__(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___mod__(self,*args)
+
+ def__neg__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___neg__(self)
+
+ def__abs__(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr___abs__(self)
+
+ defSquare(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr_Square(self)
+
+ def__eq__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___eq__(self,*args)
+
+ def__ne__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___ne__(self,*args)
+
+ def__ge__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___ge__(self,*args)
+
+ def__gt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___gt__(self,*args)
+
+ def__le__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___le__(self,*args)
+
+ def__lt__(self,*args)->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr___lt__(self,*args)
+
+ defMapTo(self,vars:"std::vector< operations_research::IntVar * > const &")->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr_MapTo(self,vars)
+
+ defIndexOf(self,*args)->"operations_research::IntExpr *":
+ return_pywrapcp.IntExpr_IndexOf(self,*args)
+
+ defIsMember(self,values:"std::vector< int64_t > const &")->"operations_research::IntVar *":
+ return_pywrapcp.IntExpr_IsMember(self,values)
+
+ defMember(self,values:"std::vector< int64_t > const &")->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr_Member(self,values)
+
+ defNotMember(self,starts:"std::vector< int64_t > const &",ends:"std::vector< int64_t > const &")->"operations_research::Constraint *":
+ return_pywrapcp.IntExpr_NotMember(self,starts,ends)
+
+
+
+
+
The class IntExpr is the base of all integer expressions in
+constraint programming.
defSetRange(self,l:"int64_t",u:"int64_t")->"void":
+ r""" This method sets both the min and the max of the expression."""
+ return_pywrapcp.IntExpr_SetRange(self,l,u)
+
+
+
+
+
This method sets both the min and the max of the expression.
defVarWithName(self,name:"std::string const &")->"operations_research::IntVar *":
+ r"""
+ Creates a variable from the expression and set the name of the
+ resulting var. If the expression is already a variable, then it
+ will set the name of the expression, possibly overwriting it.
+ This is just a shortcut to Var() followed by set_name().
+ """
+ return_pywrapcp.IntExpr_VarWithName(self,name)
+
+
+
+
+
Creates a variable from the expression and set the name of the
+resulting var. If the expression is already a variable, then it
+will set the name of the expression, possibly overwriting it.
+This is just a shortcut to Var() followed by set_name().
defWhenRange(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Attach a demon that will watch the min or the max of the expression.
+
+ |
+
+ *Overload 2:*
+ Attach a demon that will watch the min or the max of the expression.
+ """
+ return_pywrapcp.IntExpr_WhenRange(self,*args)
+
+
+
+
+
Overload 1:
+Attach a demon that will watch the min or the max of the expression.
+
+
|
+
+
Overload 2:
+Attach a demon that will watch the min or the max of the expression.
classIntVarIterator(BaseObject):
+ r"""
+ The class Iterator has two direct subclasses. HoleIterators
+ iterates over all holes, that is value removed between the
+ current min and max of the variable since the last time the
+ variable was processed in the queue. DomainIterators iterates
+ over all elements of the variable domain. Both iterators are not
+ robust to domain changes. Hole iterators can also report values outside
+ the current min and max of the variable.
+ HoleIterators should only be called from a demon attached to the
+ variable that has created this iterator.
+ IntVar* current_var;
+ std::unique_ptr<IntVarIterator> it(current_var->MakeHoleIterator(false));
+ for (const int64_t hole : InitAndGetValues(it)) {
+ use the hole
+ }
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defInit(self)->"void":
+ r""" This method must be called before each loop."""
+ return_pywrapcp.IntVarIterator_Init(self)
+
+ defOk(self)->"bool":
+ r""" This method indicates if we can call Value() or not."""
+ return_pywrapcp.IntVarIterator_Ok(self)
+
+ defValue(self)->"int64_t":
+ r""" This method returns the current value of the iterator."""
+ return_pywrapcp.IntVarIterator_Value(self)
+
+ defNext(self)->"void":
+ r""" This method moves the iterator to the next value."""
+ return_pywrapcp.IntVarIterator_Next(self)
+
+ defDebugString(self)->"std::string":
+ r""" Pretty Print."""
+ return_pywrapcp.IntVarIterator_DebugString(self)
+
+ def__iter__(self):
+ self.Init()
+ returnself
+
+ defnext(self):
+ ifself.Ok():
+ result=self.Value()
+ self.Next()
+ returnresult
+ else:
+ raiseStopIteration()
+
+ def__next__(self):
+ returnself.next()
+
+
+
+
+
The class Iterator has two direct subclasses. HoleIterators
+ iterates over all holes, that is value removed between the
+ current min and max of the variable since the last time the
+ variable was processed in the queue. DomainIterators iterates
+ over all elements of the variable domain. Both iterators are not
+ robust to domain changes. Hole iterators can also report values outside
+ the current min and max of the variable.
+ HoleIterators should only be called from a demon attached to the
+ variable that has created this iterator.
+ IntVar* current_var;
+ std::unique_ptr it(current_var->MakeHoleIterator(false));
+ for (const int64_t hole : InitAndGetValues(it)) {
+use the hole
+ }
classIntVar(IntExpr):
+ r"""
+ The class IntVar is a subset of IntExpr. In addition to the
+ IntExpr protocol, it offers persistence, removing values from the domains,
+ and a finer model for events.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+
+ defIsVar(self)->"bool":
+ return_pywrapcp.IntVar_IsVar(self)
+
+ defVar(self)->"operations_research::IntVar *":
+ return_pywrapcp.IntVar_Var(self)
+
+ defValue(self)->"int64_t":
+ r"""
+ This method returns the value of the variable. This method checks
+ before that the variable is bound.
+ """
+ return_pywrapcp.IntVar_Value(self)
+
+ defRemoveValue(self,v:"int64_t")->"void":
+ r""" This method removes the value 'v' from the domain of the variable."""
+ return_pywrapcp.IntVar_RemoveValue(self,v)
+
+ defRemoveInterval(self,l:"int64_t",u:"int64_t")->"void":
+ r"""
+ This method removes the interval 'l' .. 'u' from the domain of
+ the variable. It assumes that 'l' <= 'u'.
+ """
+ return_pywrapcp.IntVar_RemoveInterval(self,l,u)
+
+ defRemoveValues(self,values:"std::vector< int64_t > const &")->"void":
+ r""" This method remove the values from the domain of the variable."""
+ return_pywrapcp.IntVar_RemoveValues(self,values)
+
+ defSetValues(self,values:"std::vector< int64_t > const &")->"void":
+ r""" This method intersects the current domain with the values in the array."""
+ return_pywrapcp.IntVar_SetValues(self,values)
+
+ defWhenBound(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This method attaches a demon that will be awakened when the
+ variable is bound.
+
+ |
+
+ *Overload 2:*
+ This method attaches a closure that will be awakened when the
+ variable is bound.
+ """
+ return_pywrapcp.IntVar_WhenBound(self,*args)
+
+ defWhenDomain(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This method attaches a demon that will watch any domain
+ modification of the domain of the variable.
+
+ |
+
+ *Overload 2:*
+ This method attaches a closure that will watch any domain
+ modification of the domain of the variable.
+ """
+ return_pywrapcp.IntVar_WhenDomain(self,*args)
+
+ defSize(self)->"uint64_t":
+ r""" This method returns the number of values in the domain of the variable."""
+ return_pywrapcp.IntVar_Size(self)
+
+ defContains(self,v:"int64_t")->"bool":
+ r"""
+ This method returns whether the value 'v' is in the domain of the
+ variable.
+ """
+ return_pywrapcp.IntVar_Contains(self,v)
+
+ defHoleIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ r"""
+ Creates a hole iterator. When 'reversible' is false, the returned
+ object is created on the normal C++ heap and the solver does NOT
+ take ownership of the object.
+ """
+ return_pywrapcp.IntVar_HoleIteratorAux(self,reversible)
+
+ defDomainIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ r"""
+ Creates a domain iterator. When 'reversible' is false, the
+ returned object is created on the normal C++ heap and the solver
+ does NOT take ownership of the object.
+ """
+ return_pywrapcp.IntVar_DomainIteratorAux(self,reversible)
+
+ defOldMin(self)->"int64_t":
+ r""" Returns the previous min."""
+ return_pywrapcp.IntVar_OldMin(self)
+
+ defOldMax(self)->"int64_t":
+ r""" Returns the previous max."""
+ return_pywrapcp.IntVar_OldMax(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.IntVar___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.IntVar___str__(self)
+
+ defDomainIterator(self):
+ returniter(self.DomainIteratorAux(False))
+
+ defHoleIterator(self):
+ returniter(self.HoleIteratorAux(False))
+
+
+
+
+
The class IntVar is a subset of IntExpr. In addition to the
+IntExpr protocol, it offers persistence, removing values from the domains,
+and a finer model for events.
defValue(self)->"int64_t":
+ r"""
+ This method returns the value of the variable. This method checks
+ before that the variable is bound.
+ """
+ return_pywrapcp.IntVar_Value(self)
+
+
+
+
+
This method returns the value of the variable. This method checks
+before that the variable is bound.
defRemoveValue(self,v:"int64_t")->"void":
+ r""" This method removes the value 'v' from the domain of the variable."""
+ return_pywrapcp.IntVar_RemoveValue(self,v)
+
+
+
+
+
This method removes the value 'v' from the domain of the variable.
defRemoveInterval(self,l:"int64_t",u:"int64_t")->"void":
+ r"""
+ This method removes the interval 'l' .. 'u' from the domain of
+ the variable. It assumes that 'l' <= 'u'.
+ """
+ return_pywrapcp.IntVar_RemoveInterval(self,l,u)
+
+
+
+
+
This method removes the interval 'l' .. 'u' from the domain of
+the variable. It assumes that 'l' <= 'u'.
defRemoveValues(self,values:"std::vector< int64_t > const &")->"void":
+ r""" This method remove the values from the domain of the variable."""
+ return_pywrapcp.IntVar_RemoveValues(self,values)
+
+
+
+
+
This method remove the values from the domain of the variable.
defSetValues(self,values:"std::vector< int64_t > const &")->"void":
+ r""" This method intersects the current domain with the values in the array."""
+ return_pywrapcp.IntVar_SetValues(self,values)
+
+
+
+
+
This method intersects the current domain with the values in the array.
defWhenBound(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This method attaches a demon that will be awakened when the
+ variable is bound.
+
+ |
+
+ *Overload 2:*
+ This method attaches a closure that will be awakened when the
+ variable is bound.
+ """
+ return_pywrapcp.IntVar_WhenBound(self,*args)
+
+
+
+
+
Overload 1:
+This method attaches a demon that will be awakened when the
+variable is bound.
+
+
|
+
+
Overload 2:
+This method attaches a closure that will be awakened when the
+variable is bound.
defWhenDomain(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This method attaches a demon that will watch any domain
+ modification of the domain of the variable.
+
+ |
+
+ *Overload 2:*
+ This method attaches a closure that will watch any domain
+ modification of the domain of the variable.
+ """
+ return_pywrapcp.IntVar_WhenDomain(self,*args)
+
+
+
+
+
Overload 1:
+This method attaches a demon that will watch any domain
+modification of the domain of the variable.
+
+
|
+
+
Overload 2:
+This method attaches a closure that will watch any domain
+modification of the domain of the variable.
defContains(self,v:"int64_t")->"bool":
+ r"""
+ This method returns whether the value 'v' is in the domain of the
+ variable.
+ """
+ return_pywrapcp.IntVar_Contains(self,v)
+
+
+
+
+
This method returns whether the value 'v' is in the domain of the
+variable.
defHoleIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ r"""
+ Creates a hole iterator. When 'reversible' is false, the returned
+ object is created on the normal C++ heap and the solver does NOT
+ take ownership of the object.
+ """
+ return_pywrapcp.IntVar_HoleIteratorAux(self,reversible)
+
+
+
+
+
Creates a hole iterator. When 'reversible' is false, the returned
+object is created on the normal C++ heap and the solver does NOT
+take ownership of the object.
defDomainIteratorAux(self,reversible:"bool")->"operations_research::IntVarIterator *":
+ r"""
+ Creates a domain iterator. When 'reversible' is false, the
+ returned object is created on the normal C++ heap and the solver
+ does NOT take ownership of the object.
+ """
+ return_pywrapcp.IntVar_DomainIteratorAux(self,reversible)
+
+
+
+
+
Creates a domain iterator. When 'reversible' is false, the
+returned object is created on the normal C++ heap and the solver
+does NOT take ownership of the object.
classSolutionCollector(SearchMonitor):
+ r"""
+ This class is the root class of all solution collectors.
+ It implements a basic query API to be used independently
+ of the collector used.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.SolutionCollector_DebugString(self)
+
+ defAdd(self,*args)->"void":
+ return_pywrapcp.SolutionCollector_Add(self,*args)
+
+ defAddObjective(self,objective:"IntVar")->"void":
+ return_pywrapcp.SolutionCollector_AddObjective(self,objective)
+
+ defEnterSearch(self)->"void":
+ r""" Beginning of the search."""
+ return_pywrapcp.SolutionCollector_EnterSearch(self)
+
+ defSolutionCount(self)->"int":
+ r""" Returns how many solutions were stored during the search."""
+ return_pywrapcp.SolutionCollector_SolutionCount(self)
+
+ defSolution(self,n:"int")->"operations_research::Assignment *":
+ r""" Returns the nth solution."""
+ return_pywrapcp.SolutionCollector_Solution(self,n)
+
+ defWallTime(self,n:"int")->"int64_t":
+ r""" Returns the wall time in ms for the nth solution."""
+ return_pywrapcp.SolutionCollector_WallTime(self,n)
+
+ defBranches(self,n:"int")->"int64_t":
+ r""" Returns the number of branches when the nth solution was found."""
+ return_pywrapcp.SolutionCollector_Branches(self,n)
+
+ defFailures(self,n:"int")->"int64_t":
+ r"""
+ Returns the number of failures encountered at the time of the nth
+ solution.
+ """
+ return_pywrapcp.SolutionCollector_Failures(self,n)
+
+ defObjectiveValue(self,n:"int")->"int64_t":
+ r""" Returns the objective value of the nth solution."""
+ return_pywrapcp.SolutionCollector_ObjectiveValue(self,n)
+
+ defValue(self,n:"int",var:"IntVar")->"int64_t":
+ r""" This is a shortcut to get the Value of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_Value(self,n,var)
+
+ defStartValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the StartValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_StartValue(self,n,var)
+
+ defEndValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the EndValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_EndValue(self,n,var)
+
+ defDurationValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the DurationValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_DurationValue(self,n,var)
+
+ defPerformedValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the PerformedValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_PerformedValue(self,n,var)
+
+ defForwardSequence(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the ForwardSequence of 'var' in the
+ nth solution. The forward sequence is the list of ranked interval
+ variables starting from the start of the sequence.
+ """
+ return_pywrapcp.SolutionCollector_ForwardSequence(self,n,var)
+
+ defBackwardSequence(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the BackwardSequence of 'var' in the
+ nth solution. The backward sequence is the list of ranked interval
+ variables starting from the end of the sequence.
+ """
+ return_pywrapcp.SolutionCollector_BackwardSequence(self,n,var)
+
+ defUnperformed(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the list of unperformed of 'var' in the
+ nth solution.
+ """
+ return_pywrapcp.SolutionCollector_Unperformed(self,n,var)
+
+
+
+
+
This class is the root class of all solution collectors.
+It implements a basic query API to be used independently
+of the collector used.
defSolutionCount(self)->"int":
+ r""" Returns how many solutions were stored during the search."""
+ return_pywrapcp.SolutionCollector_SolutionCount(self)
+
+
+
+
+
Returns how many solutions were stored during the search.
defWallTime(self,n:"int")->"int64_t":
+ r""" Returns the wall time in ms for the nth solution."""
+ return_pywrapcp.SolutionCollector_WallTime(self,n)
+
defBranches(self,n:"int")->"int64_t":
+ r""" Returns the number of branches when the nth solution was found."""
+ return_pywrapcp.SolutionCollector_Branches(self,n)
+
+
+
+
+
Returns the number of branches when the nth solution was found.
defFailures(self,n:"int")->"int64_t":
+ r"""
+ Returns the number of failures encountered at the time of the nth
+ solution.
+ """
+ return_pywrapcp.SolutionCollector_Failures(self,n)
+
+
+
+
+
Returns the number of failures encountered at the time of the nth
+solution.
defObjectiveValue(self,n:"int")->"int64_t":
+ r""" Returns the objective value of the nth solution."""
+ return_pywrapcp.SolutionCollector_ObjectiveValue(self,n)
+
defValue(self,n:"int",var:"IntVar")->"int64_t":
+ r""" This is a shortcut to get the Value of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_Value(self,n,var)
+
+
+
+
+
This is a shortcut to get the Value of 'var' in the nth solution.
defStartValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the StartValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_StartValue(self,n,var)
+
+
+
+
+
This is a shortcut to get the StartValue of 'var' in the nth solution.
defEndValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the EndValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_EndValue(self,n,var)
+
+
+
+
+
This is a shortcut to get the EndValue of 'var' in the nth solution.
defDurationValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the DurationValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_DurationValue(self,n,var)
+
+
+
+
+
This is a shortcut to get the DurationValue of 'var' in the nth solution.
defPerformedValue(self,n:"int",var:"IntervalVar")->"int64_t":
+ r""" This is a shortcut to get the PerformedValue of 'var' in the nth solution."""
+ return_pywrapcp.SolutionCollector_PerformedValue(self,n,var)
+
+
+
+
+
This is a shortcut to get the PerformedValue of 'var' in the nth solution.
defForwardSequence(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the ForwardSequence of 'var' in the
+ nth solution. The forward sequence is the list of ranked interval
+ variables starting from the start of the sequence.
+ """
+ return_pywrapcp.SolutionCollector_ForwardSequence(self,n,var)
+
+
+
+
+
This is a shortcut to get the ForwardSequence of 'var' in the
+nth solution. The forward sequence is the list of ranked interval
+variables starting from the start of the sequence.
defBackwardSequence(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the BackwardSequence of 'var' in the
+ nth solution. The backward sequence is the list of ranked interval
+ variables starting from the end of the sequence.
+ """
+ return_pywrapcp.SolutionCollector_BackwardSequence(self,n,var)
+
+
+
+
+
This is a shortcut to get the BackwardSequence of 'var' in the
+nth solution. The backward sequence is the list of ranked interval
+variables starting from the end of the sequence.
defUnperformed(self,n:"int",var:"SequenceVar")->"std::vector< int > const &":
+ r"""
+ This is a shortcut to get the list of unperformed of 'var' in the
+ nth solution.
+ """
+ return_pywrapcp.SolutionCollector_Unperformed(self,n,var)
+
+
+
+
+
This is a shortcut to get the list of unperformed of 'var' in the
+nth solution.
This method is called when a valid solution is found. If the
+return value is true, then search will resume after. If the result
+is false, then search will stop there.
This method is called when a solution is found. It asserts whether the
+solution is valid. A value of false indicates that the solution
+should be discarded.
classSearchLimit(SearchMonitor):
+ r""" Base class of all search limits."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+ __swig_destroy__=_pywrapcp.delete_SearchLimit
+
+ defCrossed(self)->"bool":
+ r""" Returns true if the limit has been crossed."""
+ return_pywrapcp.SearchLimit_Crossed(self)
+
+ defCheck(self)->"bool":
+ r"""
+ This method is called to check the status of the limit. A return
+ value of true indicates that we have indeed crossed the limit. In
+ that case, this method will not be called again and the remaining
+ search will be discarded.
+ """
+ return_pywrapcp.SearchLimit_Check(self)
+
+ defInit(self)->"void":
+ r""" This method is called when the search limit is initialized."""
+ return_pywrapcp.SearchLimit_Init(self)
+
+ defEnterSearch(self)->"void":
+ r""" Internal methods."""
+ return_pywrapcp.SearchLimit_EnterSearch(self)
+
+ defBeginNextDecision(self,b:"DecisionBuilder")->"void":
+ return_pywrapcp.SearchLimit_BeginNextDecision(self,b)
+
+ defRefuteDecision(self,d:"Decision")->"void":
+ return_pywrapcp.SearchLimit_RefuteDecision(self,d)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.SearchLimit_DebugString(self)
+
defCheck(self)->"bool":
+ r"""
+ This method is called to check the status of the limit. A return
+ value of true indicates that we have indeed crossed the limit. In
+ that case, this method will not be called again and the remaining
+ search will be discarded.
+ """
+ return_pywrapcp.SearchLimit_Check(self)
+
+
+
+
+
This method is called to check the status of the limit. A return
+value of true indicates that we have indeed crossed the limit. In
+that case, this method will not be called again and the remaining
+search will be discarded.
classIntervalVar(PropagationBaseObject):
+ r"""
+ Interval variables are often used in scheduling. The main characteristics
+ of an IntervalVar are the start position, duration, and end
+ date. All these characteristics can be queried and set, and demons can
+ be posted on their modifications.
+
+ An important aspect is optionality: an IntervalVar can be performed or not.
+ If unperformed, then it simply does not exist, and its characteristics
+ cannot be accessed any more. An interval var is automatically marked
+ as unperformed when it is not consistent anymore (start greater
+ than end, duration < 0...)
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+
+ defStartMin(self)->"int64_t":
+ r"""
+ These methods query, set, and watch the start position of the
+ interval var.
+ """
+ return_pywrapcp.IntervalVar_StartMin(self)
+
+ defStartMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_StartMax(self)
+
+ defSetStartMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetStartMin(self,m)
+
+ defSetStartMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetStartMax(self,m)
+
+ defSetStartRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetStartRange(self,mi,ma)
+
+ defOldStartMin(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldStartMin(self)
+
+ defOldStartMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldStartMax(self)
+
+ defWhenStartRange(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenStartRange(self,*args)
+
+ defWhenStartBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenStartBound(self,*args)
+
+ defDurationMin(self)->"int64_t":
+ r""" These methods query, set, and watch the duration of the interval var."""
+ return_pywrapcp.IntervalVar_DurationMin(self)
+
+ defDurationMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_DurationMax(self)
+
+ defSetDurationMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetDurationMin(self,m)
+
+ defSetDurationMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetDurationMax(self,m)
+
+ defSetDurationRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetDurationRange(self,mi,ma)
+
+ defOldDurationMin(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldDurationMin(self)
+
+ defOldDurationMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldDurationMax(self)
+
+ defWhenDurationRange(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenDurationRange(self,*args)
+
+ defWhenDurationBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenDurationBound(self,*args)
+
+ defEndMin(self)->"int64_t":
+ r""" These methods query, set, and watch the end position of the interval var."""
+ return_pywrapcp.IntervalVar_EndMin(self)
+
+ defEndMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_EndMax(self)
+
+ defSetEndMin(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetEndMin(self,m)
+
+ defSetEndMax(self,m:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetEndMax(self,m)
+
+ defSetEndRange(self,mi:"int64_t",ma:"int64_t")->"void":
+ return_pywrapcp.IntervalVar_SetEndRange(self,mi,ma)
+
+ defOldEndMin(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldEndMin(self)
+
+ defOldEndMax(self)->"int64_t":
+ return_pywrapcp.IntervalVar_OldEndMax(self)
+
+ defWhenEndRange(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenEndRange(self,*args)
+
+ defWhenEndBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenEndBound(self,*args)
+
+ defMustBePerformed(self)->"bool":
+ r"""
+ These methods query, set, and watch the performed status of the
+ interval var.
+ """
+ return_pywrapcp.IntervalVar_MustBePerformed(self)
+
+ defMayBePerformed(self)->"bool":
+ return_pywrapcp.IntervalVar_MayBePerformed(self)
+
+ defCannotBePerformed(self)->"bool":
+ return_pywrapcp.IntervalVar_CannotBePerformed(self)
+
+ defIsPerformedBound(self)->"bool":
+ return_pywrapcp.IntervalVar_IsPerformedBound(self)
+
+ defSetPerformed(self,val:"bool")->"void":
+ return_pywrapcp.IntervalVar_SetPerformed(self,val)
+
+ defWasPerformedBound(self)->"bool":
+ return_pywrapcp.IntervalVar_WasPerformedBound(self)
+
+ defWhenPerformedBound(self,*args)->"void":
+ return_pywrapcp.IntervalVar_WhenPerformedBound(self,*args)
+
+ defWhenAnything(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Attaches a demon awakened when anything about this interval changes.
+
+ |
+
+ *Overload 2:*
+ Attaches a closure awakened when anything about this interval changes.
+ """
+ return_pywrapcp.IntervalVar_WhenAnything(self,*args)
+
+ defStartExpr(self)->"operations_research::IntExpr *":
+ r"""
+ These methods create expressions encapsulating the start, end
+ and duration of the interval var. Please note that these must not
+ be used if the interval var is unperformed.
+ """
+ return_pywrapcp.IntervalVar_StartExpr(self)
+
+ defDurationExpr(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_DurationExpr(self)
+
+ defEndExpr(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_EndExpr(self)
+
+ defPerformedExpr(self)->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_PerformedExpr(self)
+
+ defSafeStartExpr(self,unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ These methods create expressions encapsulating the start, end
+ and duration of the interval var. If the interval var is
+ unperformed, they will return the unperformed_value.
+ """
+ return_pywrapcp.IntervalVar_SafeStartExpr(self,unperformed_value)
+
+ defSafeDurationExpr(self,unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_SafeDurationExpr(self,unperformed_value)
+
+ defSafeEndExpr(self,unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ return_pywrapcp.IntervalVar_SafeEndExpr(self,unperformed_value)
+
+ defEndsAfterEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterEnd(self,other)
+
+ defEndsAfterEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterEndWithDelay(self,other,delay)
+
+ defEndsAfterStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterStart(self,other)
+
+ defEndsAfterStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfterStartWithDelay(self,other,delay)
+
+ defEndsAtEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtEnd(self,other)
+
+ defEndsAtEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtEndWithDelay(self,other,delay)
+
+ defEndsAtStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtStart(self,other)
+
+ defEndsAtStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAtStartWithDelay(self,other,delay)
+
+ defStartsAfterEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterEnd(self,other)
+
+ defStartsAfterEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterEndWithDelay(self,other,delay)
+
+ defStartsAfterStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterStart(self,other)
+
+ defStartsAfterStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfterStartWithDelay(self,other,delay)
+
+ defStartsAtEnd(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtEnd(self,other)
+
+ defStartsAtEndWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtEndWithDelay(self,other,delay)
+
+ defStartsAtStart(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtStart(self,other)
+
+ defStartsAtStartWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAtStartWithDelay(self,other,delay)
+
+ defStaysInSync(self,other:"IntervalVar")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StaysInSync(self,other)
+
+ defStaysInSyncWithDelay(self,other:"IntervalVar",delay:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StaysInSyncWithDelay(self,other,delay)
+
+ defEndsAfter(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAfter(self,date)
+
+ defEndsAt(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsAt(self,date)
+
+ defEndsBefore(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_EndsBefore(self,date)
+
+ defStartsAfter(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAfter(self,date)
+
+ defStartsAt(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsAt(self,date)
+
+ defStartsBefore(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_StartsBefore(self,date)
+
+ defCrossesDate(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_CrossesDate(self,date)
+
+ defAvoidsDate(self,date:"int64_t")->"operations_research::Constraint *":
+ return_pywrapcp.IntervalVar_AvoidsDate(self,date)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.IntervalVar___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.IntervalVar___str__(self)
+
+
+
+
+
Interval variables are often used in scheduling. The main characteristics
+of an IntervalVar are the start position, duration, and end
+date. All these characteristics can be queried and set, and demons can
+be posted on their modifications.
+
+
An important aspect is optionality: an IntervalVar can be performed or not.
+If unperformed, then it simply does not exist, and its characteristics
+cannot be accessed any more. An interval var is automatically marked
+as unperformed when it is not consistent anymore (start greater
+than end, duration < 0...)
defStartMin(self)->"int64_t":
+ r"""
+ These methods query, set, and watch the start position of the
+ interval var.
+ """
+ return_pywrapcp.IntervalVar_StartMin(self)
+
+
+
+
+
These methods query, set, and watch the start position of the
+interval var.
defDurationMin(self)->"int64_t":
+ r""" These methods query, set, and watch the duration of the interval var."""
+ return_pywrapcp.IntervalVar_DurationMin(self)
+
+
+
+
+
These methods query, set, and watch the duration of the interval var.
defEndMin(self)->"int64_t":
+ r""" These methods query, set, and watch the end position of the interval var."""
+ return_pywrapcp.IntervalVar_EndMin(self)
+
+
+
+
+
These methods query, set, and watch the end position of the interval var.
defMustBePerformed(self)->"bool":
+ r"""
+ These methods query, set, and watch the performed status of the
+ interval var.
+ """
+ return_pywrapcp.IntervalVar_MustBePerformed(self)
+
+
+
+
+
These methods query, set, and watch the performed status of the
+interval var.
defWhenAnything(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Attaches a demon awakened when anything about this interval changes.
+
+ |
+
+ *Overload 2:*
+ Attaches a closure awakened when anything about this interval changes.
+ """
+ return_pywrapcp.IntervalVar_WhenAnything(self,*args)
+
+
+
+
+
Overload 1:
+Attaches a demon awakened when anything about this interval changes.
+
+
|
+
+
Overload 2:
+Attaches a closure awakened when anything about this interval changes.
defStartExpr(self)->"operations_research::IntExpr *":
+ r"""
+ These methods create expressions encapsulating the start, end
+ and duration of the interval var. Please note that these must not
+ be used if the interval var is unperformed.
+ """
+ return_pywrapcp.IntervalVar_StartExpr(self)
+
+
+
+
+
These methods create expressions encapsulating the start, end
+and duration of the interval var. Please note that these must not
+be used if the interval var is unperformed.
defSafeStartExpr(self,unperformed_value:"int64_t")->"operations_research::IntExpr *":
+ r"""
+ These methods create expressions encapsulating the start, end
+ and duration of the interval var. If the interval var is
+ unperformed, they will return the unperformed_value.
+ """
+ return_pywrapcp.IntervalVar_SafeStartExpr(self,unperformed_value)
+
+
+
+
+
These methods create expressions encapsulating the start, end
+and duration of the interval var. If the interval var is
+unperformed, they will return the unperformed_value.
classSequenceVar(PropagationBaseObject):
+ r"""
+ A sequence variable is a variable whose domain is a set of possible
+ orderings of the interval variables. It allows ordering of tasks. It
+ has two sets of methods: ComputePossibleFirstsAndLasts(), which
+ returns the list of interval variables that can be ranked first or
+ last; and RankFirst/RankNotFirst/RankLast/RankNotLast, which can be
+ used to create the search decision.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.SequenceVar_DebugString(self)
+
+ defRankFirst(self,index:"int")->"void":
+ r"""
+ Ranks the index_th interval var first of all unranked interval
+ vars. After that, it will no longer be considered ranked.
+ """
+ return_pywrapcp.SequenceVar_RankFirst(self,index)
+
+ defRankNotFirst(self,index:"int")->"void":
+ r"""
+ Indicates that the index_th interval var will not be ranked first
+ of all currently unranked interval vars.
+ """
+ return_pywrapcp.SequenceVar_RankNotFirst(self,index)
+
+ defRankLast(self,index:"int")->"void":
+ r"""
+ Ranks the index_th interval var first of all unranked interval
+ vars. After that, it will no longer be considered ranked.
+ """
+ return_pywrapcp.SequenceVar_RankLast(self,index)
+
+ defRankNotLast(self,index:"int")->"void":
+ r"""
+ Indicates that the index_th interval var will not be ranked first
+ of all currently unranked interval vars.
+ """
+ return_pywrapcp.SequenceVar_RankNotLast(self,index)
+
+ defInterval(self,index:"int")->"operations_research::IntervalVar *":
+ r""" Returns the index_th interval of the sequence."""
+ return_pywrapcp.SequenceVar_Interval(self,index)
+
+ defNext(self,index:"int")->"operations_research::IntVar *":
+ r""" Returns the next of the index_th interval of the sequence."""
+ return_pywrapcp.SequenceVar_Next(self,index)
+
+ defSize(self)->"int64_t":
+ r""" Returns the number of interval vars in the sequence."""
+ return_pywrapcp.SequenceVar_Size(self)
+
+ def__repr__(self)->"std::string":
+ return_pywrapcp.SequenceVar___repr__(self)
+
+ def__str__(self)->"std::string":
+ return_pywrapcp.SequenceVar___str__(self)
+
+
+
+
+
A sequence variable is a variable whose domain is a set of possible
+orderings of the interval variables. It allows ordering of tasks. It
+has two sets of methods: ComputePossibleFirstsAndLasts(), which
+returns the list of interval variables that can be ranked first or
+last; and RankFirst/RankNotFirst/RankLast/RankNotLast, which can be
+used to create the search decision.
defRankFirst(self,index:"int")->"void":
+ r"""
+ Ranks the index_th interval var first of all unranked interval
+ vars. After that, it will no longer be considered ranked.
+ """
+ return_pywrapcp.SequenceVar_RankFirst(self,index)
+
+
+
+
+
Ranks the index_th interval var first of all unranked interval
+vars. After that, it will no longer be considered ranked.
defRankNotFirst(self,index:"int")->"void":
+ r"""
+ Indicates that the index_th interval var will not be ranked first
+ of all currently unranked interval vars.
+ """
+ return_pywrapcp.SequenceVar_RankNotFirst(self,index)
+
+
+
+
+
Indicates that the index_th interval var will not be ranked first
+of all currently unranked interval vars.
defRankLast(self,index:"int")->"void":
+ r"""
+ Ranks the index_th interval var first of all unranked interval
+ vars. After that, it will no longer be considered ranked.
+ """
+ return_pywrapcp.SequenceVar_RankLast(self,index)
+
+
+
+
+
Ranks the index_th interval var first of all unranked interval
+vars. After that, it will no longer be considered ranked.
defRankNotLast(self,index:"int")->"void":
+ r"""
+ Indicates that the index_th interval var will not be ranked first
+ of all currently unranked interval vars.
+ """
+ return_pywrapcp.SequenceVar_RankNotLast(self,index)
+
+
+
+
+
Indicates that the index_th interval var will not be ranked first
+of all currently unranked interval vars.
defInterval(self,index:"int")->"operations_research::IntervalVar *":
+ r""" Returns the index_th interval of the sequence."""
+ return_pywrapcp.SequenceVar_Interval(self,index)
+
defNext(self,index:"int")->"operations_research::IntVar *":
+ r""" Returns the next of the index_th interval of the sequence."""
+ return_pywrapcp.SequenceVar_Next(self,index)
+
+
+
+
+
Returns the next of the index_th interval of the sequence.
classSequenceVarElement(AssignmentElement):
+ r"""
+ The SequenceVarElement stores a partial representation of ranked
+ interval variables in the underlying sequence variable.
+ This representation consists of three vectors:
+ - the forward sequence. That is the list of interval variables
+ ranked first in the sequence. The first element of the backward
+ sequence is the first interval in the sequence variable.
+ - the backward sequence. That is the list of interval variables
+ ranked last in the sequence. The first element of the backward
+ sequence is the last interval in the sequence variable.
+ - The list of unperformed interval variables.
+ Furthermore, if all performed variables are ranked, then by
+ convention, the forward_sequence will contain all such variables
+ and the backward_sequence will be empty.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defVar(self)->"operations_research::SequenceVar *":
+ return_pywrapcp.SequenceVarElement_Var(self)
+
+ defForwardSequence(self)->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarElement_ForwardSequence(self)
+
+ defBackwardSequence(self)->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarElement_BackwardSequence(self)
+
+ defUnperformed(self)->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarElement_Unperformed(self)
+
+ defSetSequence(self,forward_sequence:"std::vector< int > const &",backward_sequence:"std::vector< int > const &",unperformed:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetSequence(self,forward_sequence,backward_sequence,unperformed)
+
+ defSetForwardSequence(self,forward_sequence:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetForwardSequence(self,forward_sequence)
+
+ defSetBackwardSequence(self,backward_sequence:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetBackwardSequence(self,backward_sequence)
+
+ defSetUnperformed(self,unperformed:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarElement_SetUnperformed(self,unperformed)
+
+ def__eq__(self,element:"SequenceVarElement")->"bool":
+ return_pywrapcp.SequenceVarElement___eq__(self,element)
+
+ def__ne__(self,element:"SequenceVarElement")->"bool":
+ return_pywrapcp.SequenceVarElement___ne__(self,element)
+ __swig_destroy__=_pywrapcp.delete_SequenceVarElement
+
+
+
+
+
The SequenceVarElement stores a partial representation of ranked
+interval variables in the underlying sequence variable.
+
+
This representation consists of three vectors
+
+
+
+
the forward sequence. That is the list of interval variables
+ ranked first in the sequence. The first element of the backward
+ sequence is the first interval in the sequence variable.
+
the backward sequence. That is the list of interval variables
+ ranked last in the sequence. The first element of the backward
+ sequence is the last interval in the sequence variable.
+
The list of unperformed interval variables.
+ Furthermore, if all performed variables are ranked, then by
+ convention, the forward_sequence will contain all such variables
+ and the backward_sequence will be empty.
classPack(Constraint):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defAddWeightedSumLessOrEqualConstantDimension(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Dimensions are additional constraints than can restrict what is
+ possible with the pack constraint. It can be used to set capacity
+ limits, to count objects per bin, to compute unassigned
+ penalties...
+ This dimension imposes that for all bins b, the weighted sum
+ (weights[i]) of all objects i assigned to 'b' is less or equal
+ 'bounds[b]'.
+
+ |
+
+ *Overload 2:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i)) of all objects i assigned to 'b' is less or
+ equal to 'bounds[b]'. Ownership of the callback is transferred to
+ the pack constraint.
+
+ |
+
+ *Overload 3:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i, b) of all objects i assigned to 'b' is less or
+ equal to 'bounds[b]'. Ownership of the callback is transferred to
+ the pack constraint.
+ """
+ return_pywrapcp.Pack_AddWeightedSumLessOrEqualConstantDimension(self,*args)
+
+ defAddWeightedSumEqualVarDimension(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights[i]) of all objects i assigned to 'b' is equal to loads[b].
+
+ |
+
+ *Overload 2:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i, b)) of all objects i assigned to 'b' is equal to
+ loads[b].
+ """
+ return_pywrapcp.Pack_AddWeightedSumEqualVarDimension(self,*args)
+
+ defAddSumVariableWeightsLessOrEqualConstantDimension(self,usage:"std::vector< operations_research::IntVar * > const &",capacity:"std::vector< int64_t > const &")->"void":
+ r"""
+ This dimension imposes:
+ forall b in bins,
+ sum (i in items: usage[i] * is_assigned(i, b)) <= capacity[b]
+ where is_assigned(i, b) is true if and only if item i is assigned
+ to the bin b.
+
+ This can be used to model shapes of items by linking variables of
+ the same item on parallel dimensions with an allowed assignment
+ constraint.
+ """
+ return_pywrapcp.Pack_AddSumVariableWeightsLessOrEqualConstantDimension(self,usage,capacity)
+
+ defAddWeightedSumOfAssignedDimension(self,weights:"std::vector< int64_t > const &",cost_var:"IntVar")->"void":
+ r"""
+ This dimension enforces that cost_var == sum of weights[i] for
+ all objects 'i' assigned to a bin.
+ """
+ return_pywrapcp.Pack_AddWeightedSumOfAssignedDimension(self,weights,cost_var)
+
+ defAddCountUsedBinDimension(self,count_var:"IntVar")->"void":
+ r"""
+ This dimension links 'count_var' to the actual number of bins used in the
+ pack.
+ """
+ return_pywrapcp.Pack_AddCountUsedBinDimension(self,count_var)
+
+ defAddCountAssignedItemsDimension(self,count_var:"IntVar")->"void":
+ r"""
+ This dimension links 'count_var' to the actual number of items
+ assigned to a bin in the pack.
+ """
+ return_pywrapcp.Pack_AddCountAssignedItemsDimension(self,count_var)
+
+ defPost(self)->"void":
+ return_pywrapcp.Pack_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ return_pywrapcp.Pack_InitialPropagateWrapper(self)
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.Pack_DebugString(self)
+
+
+
+
+
A constraint is the main modeling object. It provides two methods:
+
+
+
Post() is responsible for creating the demons and attaching them to
+immediate demons().
+
InitialPropagate() is called once just after Post and performs
+the initial propagation. The subsequent propagations will be performed
+by the demons Posted during the post() method.
defAddWeightedSumLessOrEqualConstantDimension(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ Dimensions are additional constraints than can restrict what is
+ possible with the pack constraint. It can be used to set capacity
+ limits, to count objects per bin, to compute unassigned
+ penalties...
+ This dimension imposes that for all bins b, the weighted sum
+ (weights[i]) of all objects i assigned to 'b' is less or equal
+ 'bounds[b]'.
+
+ |
+
+ *Overload 2:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i)) of all objects i assigned to 'b' is less or
+ equal to 'bounds[b]'. Ownership of the callback is transferred to
+ the pack constraint.
+
+ |
+
+ *Overload 3:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i, b) of all objects i assigned to 'b' is less or
+ equal to 'bounds[b]'. Ownership of the callback is transferred to
+ the pack constraint.
+ """
+ return_pywrapcp.Pack_AddWeightedSumLessOrEqualConstantDimension(self,*args)
+
+
+
+
+
Overload 1:
+Dimensions are additional constraints than can restrict what is
+possible with the pack constraint. It can be used to set capacity
+limits, to count objects per bin, to compute unassigned
+penalties...
+This dimension imposes that for all bins b, the weighted sum
+(weights[i]) of all objects i assigned to 'b' is less or equal
+'bounds[b]'.
+
+
|
+
+
Overload 2:
+This dimension imposes that for all bins b, the weighted sum
+(weights->Run(i)) of all objects i assigned to 'b' is less or
+equal to 'bounds[b]'. Ownership of the callback is transferred to
+the pack constraint.
+
+
|
+
+
Overload 3:
+This dimension imposes that for all bins b, the weighted sum
+(weights->Run(i, b) of all objects i assigned to 'b' is less or
+equal to 'bounds[b]'. Ownership of the callback is transferred to
+the pack constraint.
defAddWeightedSumEqualVarDimension(self,*args)->"void":
+ r"""
+ *Overload 1:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights[i]) of all objects i assigned to 'b' is equal to loads[b].
+
+ |
+
+ *Overload 2:*
+ This dimension imposes that for all bins b, the weighted sum
+ (weights->Run(i, b)) of all objects i assigned to 'b' is equal to
+ loads[b].
+ """
+ return_pywrapcp.Pack_AddWeightedSumEqualVarDimension(self,*args)
+
+
+
+
+
Overload 1:
+This dimension imposes that for all bins b, the weighted sum
+(weights[i]) of all objects i assigned to 'b' is equal to loads[b].
+
+
|
+
+
Overload 2:
+This dimension imposes that for all bins b, the weighted sum
+(weights->Run(i, b)) of all objects i assigned to 'b' is equal to
+loads[b].
defAddSumVariableWeightsLessOrEqualConstantDimension(self,usage:"std::vector< operations_research::IntVar * > const &",capacity:"std::vector< int64_t > const &")->"void":
+ r"""
+ This dimension imposes:
+ forall b in bins,
+ sum (i in items: usage[i] * is_assigned(i, b)) <= capacity[b]
+ where is_assigned(i, b) is true if and only if item i is assigned
+ to the bin b.
+
+ This can be used to model shapes of items by linking variables of
+ the same item on parallel dimensions with an allowed assignment
+ constraint.
+ """
+ return_pywrapcp.Pack_AddSumVariableWeightsLessOrEqualConstantDimension(self,usage,capacity)
+
+
+
+
+
This dimension imposes:
+forall b in bins,
+ sum (i in items: usage[i] * is_assigned(i, b)) <= capacity[b]
+where is_assigned(i, b) is true if and only if item i is assigned
+to the bin b.
+
+
This can be used to model shapes of items by linking variables of
+the same item on parallel dimensions with an allowed assignment
+constraint.
defAddWeightedSumOfAssignedDimension(self,weights:"std::vector< int64_t > const &",cost_var:"IntVar")->"void":
+ r"""
+ This dimension enforces that cost_var == sum of weights[i] for
+ all objects 'i' assigned to a bin.
+ """
+ return_pywrapcp.Pack_AddWeightedSumOfAssignedDimension(self,weights,cost_var)
+
+
+
+
+
This dimension enforces that cost_var == sum of weights[i] for
+all objects 'i' assigned to a bin.
defAddCountUsedBinDimension(self,count_var:"IntVar")->"void":
+ r"""
+ This dimension links 'count_var' to the actual number of bins used in the
+ pack.
+ """
+ return_pywrapcp.Pack_AddCountUsedBinDimension(self,count_var)
+
+
+
+
+
This dimension links 'count_var' to the actual number of bins used in the
+pack.
defAddCountAssignedItemsDimension(self,count_var:"IntVar")->"void":
+ r"""
+ This dimension links 'count_var' to the actual number of items
+ assigned to a bin in the pack.
+ """
+ return_pywrapcp.Pack_AddCountAssignedItemsDimension(self,count_var)
+
+
+
+
+
This dimension links 'count_var' to the actual number of items
+assigned to a bin in the pack.
classDisjunctiveConstraint(Constraint):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defSequenceVar(self)->"operations_research::SequenceVar *":
+ r""" Creates a sequence variable from the constraint."""
+ return_pywrapcp.DisjunctiveConstraint_SequenceVar(self)
+
+ defSetTransitionTime(self,transition_time:"operations_research::Solver::IndexEvaluator2")->"void":
+ r"""
+ Add a transition time between intervals. It forces the distance between
+ the end of interval a and start of interval b that follows it to be at
+ least transition_time(a, b). This function must always return
+ a positive or null value.
+ """
+ return_pywrapcp.DisjunctiveConstraint_SetTransitionTime(self,transition_time)
+
+ defTransitionTime(self,before_index:"int",after_index:"int")->"int64_t":
+ return_pywrapcp.DisjunctiveConstraint_TransitionTime(self,before_index,after_index)
+
+
+
+
+
A constraint is the main modeling object. It provides two methods:
+
+
+
Post() is responsible for creating the demons and attaching them to
+immediate demons().
+
InitialPropagate() is called once just after Post and performs
+the initial propagation. The subsequent propagations will be performed
+by the demons Posted during the post() method.
defSequenceVar(self)->"operations_research::SequenceVar *":
+ r""" Creates a sequence variable from the constraint."""
+ return_pywrapcp.DisjunctiveConstraint_SequenceVar(self)
+
defSetTransitionTime(self,transition_time:"operations_research::Solver::IndexEvaluator2")->"void":
+ r"""
+ Add a transition time between intervals. It forces the distance between
+ the end of interval a and start of interval b that follows it to be at
+ least transition_time(a, b). This function must always return
+ a positive or null value.
+ """
+ return_pywrapcp.DisjunctiveConstraint_SetTransitionTime(self,transition_time)
+
+
+
+
+
Add a transition time between intervals. It forces the distance between
+the end of interval a and start of interval b that follows it to be at
+least transition_time(a, b). This function must always return
+a positive or null value.
classRevInteger(object):
+ r"""
+ This class adds reversibility to a POD type.
+ It contains the stamp optimization. i.e. the SaveValue call is done
+ only once per node of the search tree. Please note that actual
+ stamps always starts at 1, thus an initial value of 0 will always
+ trigger the first SaveValue.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,val:"long const &"):
+ _pywrapcp.RevInteger_swiginit(self,_pywrapcp.new_RevInteger(val))
+
+ defValue(self)->"long const &":
+ return_pywrapcp.RevInteger_Value(self)
+
+ defSetValue(self,s:"Solver",val:"long const &")->"void":
+ return_pywrapcp.RevInteger_SetValue(self,s,val)
+ __swig_destroy__=_pywrapcp.delete_RevInteger
+
+
+
+
+
This class adds reversibility to a POD type.
+It contains the stamp optimization. i.e. the SaveValue call is done
+only once per node of the search tree. Please note that actual
+stamps always starts at 1, thus an initial value of 0 will always
+trigger the first SaveValue.
classRevBool(object):
+ r"""
+ This class adds reversibility to a POD type.
+ It contains the stamp optimization. i.e. the SaveValue call is done
+ only once per node of the search tree. Please note that actual
+ stamps always starts at 1, thus an initial value of 0 will always
+ trigger the first SaveValue.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,val:"bool const &"):
+ _pywrapcp.RevBool_swiginit(self,_pywrapcp.new_RevBool(val))
+
+ defValue(self)->"bool const &":
+ return_pywrapcp.RevBool_Value(self)
+
+ defSetValue(self,s:"Solver",val:"bool const &")->"void":
+ return_pywrapcp.RevBool_SetValue(self,s,val)
+ __swig_destroy__=_pywrapcp.delete_RevBool
+
+
+
+
+
This class adds reversibility to a POD type.
+It contains the stamp optimization. i.e. the SaveValue call is done
+only once per node of the search tree. Please note that actual
+stamps always starts at 1, thus an initial value of 0 will always
+trigger the first SaveValue.
classLocalSearchOperator(BaseObject):
+ r"""
+ This class represent a reversible FIFO structure.
+ The main difference w.r.t a standard FIFO structure is that a Solver is
+ given as parameter to the modifiers such that the solver can store the
+ backtrack information
+ Iterator's traversing order should not be changed, as some algorithm
+ depend on it to be consistent.
+ It's main use is to store a list of demons in the various classes of
+ variables.
+ The base class for all local search operators.
+
+ A local search operator is an object that defines the neighborhood of a
+ solution. In other words, a neighborhood is the set of solutions which can
+ be reached from a given solution using an operator.
+
+ The behavior of the LocalSearchOperator class is similar to iterators.
+ The operator is synchronized with an assignment (gives the
+ current values of the variables); this is done in the Start() method.
+
+ Then one can iterate over the neighbors using the MakeNextNeighbor method.
+ This method returns an assignment which represents the incremental changes
+ to the current solution. It also returns a second assignment representing
+ the changes to the last solution defined by the neighborhood operator; this
+ assignment is empty if the neighborhood operator cannot track this
+ information.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defNextNeighbor(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+ return_pywrapcp.LocalSearchOperator_NextNeighbor(self,delta,deltadelta)
+
+ defStart(self,assignment:"Assignment")->"void":
+ return_pywrapcp.LocalSearchOperator_Start(self,assignment)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_LocalSearchOperator(self)
+ returnweakref.proxy(self)
+
+
+
+
+
This class represent a reversible FIFO structure.
+The main difference w.r.t a standard FIFO structure is that a Solver is
+given as parameter to the modifiers such that the solver can store the
+backtrack information
+Iterator's traversing order should not be changed, as some algorithm
+depend on it to be consistent.
+It's main use is to store a list of demons in the various classes of
+variables.
+The base class for all local search operators.
+
+
A local search operator is an object that defines the neighborhood of a
+solution. In other words, a neighborhood is the set of solutions which can
+be reached from a given solution using an operator.
+
+
The behavior of the LocalSearchOperator class is similar to iterators.
+The operator is synchronized with an assignment (gives the
+current values of the variables); this is done in the Start() method.
+
+
Then one can iterate over the neighbors using the MakeNextNeighbor method.
+This method returns an assignment which represents the incremental changes
+to the current solution. It also returns a second assignment representing
+the changes to the last solution defined by the neighborhood operator; this
+assignment is empty if the neighborhood operator cannot track this
+information.
classIntVarLocalSearchOperatorTemplate(LocalSearchOperator):
+ r""" Base operator class for operators manipulating variables."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defStart(self,assignment:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnStart() instead which is
+ called before exiting this method.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Start(self,assignment)
+
+ defIsIncremental(self)->"bool":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_IsIncremental(self)
+
+ defSize(self)->"int":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Size(self)
+
+ defValue(self,index:"int64_t")->"long const &":
+ r"""
+ Returns the value in the current assignment of the variable of given
+ index.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Value(self,index)
+
+ defOldValue(self,index:"int64_t")->"long const &":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_OldValue(self,index)
+
+ defSetValue(self,index:"int64_t",value:"long const &")->"void":
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_SetValue(self,index,value)
+
+ defOnStart(self)->"void":
+ r"""
+ Called by Start() after synchronizing the operator with the current
+ assignment. Should be overridden instead of Start() to avoid calling
+ VarLocalSearchOperator::Start explicitly.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_OnStart(self)
+
+
+
+
+
Base operator class for operators manipulating variables.
defStart(self,assignment:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnStart() instead which is
+ called before exiting this method.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Start(self,assignment)
+
+
+
+
+
This method should not be overridden. Override OnStart() instead which is
+called before exiting this method.
defValue(self,index:"int64_t")->"long const &":
+ r"""
+ Returns the value in the current assignment of the variable of given
+ index.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_Value(self,index)
+
+
+
+
+
Returns the value in the current assignment of the variable of given
+index.
defOnStart(self)->"void":
+ r"""
+ Called by Start() after synchronizing the operator with the current
+ assignment. Should be overridden instead of Start() to avoid calling
+ VarLocalSearchOperator::Start explicitly.
+ """
+ return_pywrapcp.IntVarLocalSearchOperatorTemplate_OnStart(self)
+
+
+
+
+
Called by Start() after synchronizing the operator with the current
+assignment. Should be overridden instead of Start() to avoid calling
+VarLocalSearchOperator::Start explicitly.
classIntVarLocalSearchOperator(IntVarLocalSearchOperatorTemplate):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,*args):
+ ifself.__class__==IntVarLocalSearchOperator:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.IntVarLocalSearchOperator_swiginit(self,_pywrapcp.new_IntVarLocalSearchOperator(_self,*args))
+ __swig_destroy__=_pywrapcp.delete_IntVarLocalSearchOperator
+
+ defNextNeighbor(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+ r"""
+ Redefines MakeNextNeighbor to export a simpler interface. The calls to
+ ApplyChanges() and RevertChanges() are factored in this method, hiding
+ both delta and deltadelta from subclasses which only need to override
+ MakeOneNeighbor().
+ Therefore this method should not be overridden. Override MakeOneNeighbor()
+ instead.
+ """
+ return_pywrapcp.IntVarLocalSearchOperator_NextNeighbor(self,delta,deltadelta)
+
+ defOneNeighbor(self)->"bool":
+ r"""
+ Creates a new neighbor. It returns false when the neighborhood is
+ completely explored.
+ MakeNextNeighbor() in a subclass of IntVarLocalSearchOperator.
+ """
+ return_pywrapcp.IntVarLocalSearchOperator_OneNeighbor(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_IntVarLocalSearchOperator(self)
+ returnweakref.proxy(self)
+
+
+
+
+
Base operator class for operators manipulating variables.
defNextNeighbor(self,delta:"Assignment",deltadelta:"Assignment")->"bool":
+ r"""
+ Redefines MakeNextNeighbor to export a simpler interface. The calls to
+ ApplyChanges() and RevertChanges() are factored in this method, hiding
+ both delta and deltadelta from subclasses which only need to override
+ MakeOneNeighbor().
+ Therefore this method should not be overridden. Override MakeOneNeighbor()
+ instead.
+ """
+ return_pywrapcp.IntVarLocalSearchOperator_NextNeighbor(self,delta,deltadelta)
+
+
+
+
+
Redefines MakeNextNeighbor to export a simpler interface. The calls to
+ApplyChanges() and RevertChanges() are factored in this method, hiding
+both delta and deltadelta from subclasses which only need to override
+MakeOneNeighbor().
+Therefore this method should not be overridden. Override MakeOneNeighbor()
+instead.
defOneNeighbor(self)->"bool":
+ r"""
+ Creates a new neighbor. It returns false when the neighborhood is
+ completely explored.
+ MakeNextNeighbor() in a subclass of IntVarLocalSearchOperator.
+ """
+ return_pywrapcp.IntVarLocalSearchOperator_OneNeighbor(self)
+
+
+
+
+
Creates a new neighbor. It returns false when the neighborhood is
+completely explored.
+MakeNextNeighbor() in a subclass of IntVarLocalSearchOperator.
classSequenceVarLocalSearchOperatorTemplate(LocalSearchOperator):
+ r""" Base operator class for operators manipulating variables."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defStart(self,assignment:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnStart() instead which is
+ called before exiting this method.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Start(self,assignment)
+
+ defIsIncremental(self)->"bool":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_IsIncremental(self)
+
+ defSize(self)->"int":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Size(self)
+
+ defValue(self,index:"int64_t")->"std::vector< int > const &":
+ r"""
+ Returns the value in the current assignment of the variable of given
+ index.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Value(self,index)
+
+ defOldValue(self,index:"int64_t")->"std::vector< int > const &":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_OldValue(self,index)
+
+ defSetValue(self,index:"int64_t",value:"std::vector< int > const &")->"void":
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_SetValue(self,index,value)
+
+ defOnStart(self)->"void":
+ r"""
+ Called by Start() after synchronizing the operator with the current
+ assignment. Should be overridden instead of Start() to avoid calling
+ VarLocalSearchOperator::Start explicitly.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_OnStart(self)
+
+
+
+
+
Base operator class for operators manipulating variables.
defStart(self,assignment:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnStart() instead which is
+ called before exiting this method.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Start(self,assignment)
+
+
+
+
+
This method should not be overridden. Override OnStart() instead which is
+called before exiting this method.
defValue(self,index:"int64_t")->"std::vector< int > const &":
+ r"""
+ Returns the value in the current assignment of the variable of given
+ index.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_Value(self,index)
+
+
+
+
+
Returns the value in the current assignment of the variable of given
+index.
defOnStart(self)->"void":
+ r"""
+ Called by Start() after synchronizing the operator with the current
+ assignment. Should be overridden instead of Start() to avoid calling
+ VarLocalSearchOperator::Start explicitly.
+ """
+ return_pywrapcp.SequenceVarLocalSearchOperatorTemplate_OnStart(self)
+
+
+
+
+
Called by Start() after synchronizing the operator with the current
+assignment. Should be overridden instead of Start() to avoid calling
+VarLocalSearchOperator::Start explicitly.
classBaseLns(IntVarLocalSearchOperator):
+ r"""
+ This is the base class for building an Lns operator. An Lns fragment is a
+ collection of variables which will be relaxed. Fragments are built with
+ NextFragment(), which returns false if there are no more fragments to build.
+ Optionally one can override InitFragments, which is called from
+ LocalSearchOperator::Start to initialize fragment data.
+
+ Here's a sample relaxing one variable at a time:
+
+ class OneVarLns : public BaseLns {
+ public:
+ OneVarLns(const std::vector<IntVar*>& vars) : BaseLns(vars), index_(0) {}
+ virtual ~OneVarLns() {}
+ virtual void InitFragments() { index_ = 0; }
+ virtual bool NextFragment() {
+ const int size = Size();
+ if (index_ < size) {
+ AppendToFragment(index_);
+ ++index_;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ int index_;
+ };
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,vars:"std::vector< operations_research::IntVar * > const &"):
+ ifself.__class__==BaseLns:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.BaseLns_swiginit(self,_pywrapcp.new_BaseLns(_self,vars))
+ __swig_destroy__=_pywrapcp.delete_BaseLns
+
+ defInitFragments(self)->"void":
+ return_pywrapcp.BaseLns_InitFragments(self)
+
+ defNextFragment(self)->"bool":
+ return_pywrapcp.BaseLns_NextFragment(self)
+
+ defAppendToFragment(self,index:"int")->"void":
+ return_pywrapcp.BaseLns_AppendToFragment(self,index)
+
+ defFragmentSize(self)->"int":
+ return_pywrapcp.BaseLns_FragmentSize(self)
+
+ def__getitem__(self,index:"int")->"int64_t":
+ return_pywrapcp.BaseLns___getitem__(self,index)
+
+ def__len__(self)->"int":
+ return_pywrapcp.BaseLns___len__(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_BaseLns(self)
+ returnweakref.proxy(self)
+
+
+
+
+
This is the base class for building an Lns operator. An Lns fragment is a
+collection of variables which will be relaxed. Fragments are built with
+NextFragment(), which returns false if there are no more fragments to build.
+Optionally one can override InitFragments, which is called from
+LocalSearchOperator::Start to initialize fragment data.
classChangeValue(IntVarLocalSearchOperator):
+ r"""
+ Defines operators which change the value of variables;
+ each neighbor corresponds to *one* modified variable.
+ Sub-classes have to define ModifyValue which determines what the new
+ variable value is going to be (given the current value and the variable).
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,vars:"std::vector< operations_research::IntVar * > const &"):
+ ifself.__class__==ChangeValue:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.ChangeValue_swiginit(self,_pywrapcp.new_ChangeValue(_self,vars))
+ __swig_destroy__=_pywrapcp.delete_ChangeValue
+
+ defModifyValue(self,index:"int64_t",value:"int64_t")->"int64_t":
+ return_pywrapcp.ChangeValue_ModifyValue(self,index,value)
+
+ defOneNeighbor(self)->"bool":
+ r""" This method should not be overridden. Override ModifyValue() instead."""
+ return_pywrapcp.ChangeValue_OneNeighbor(self)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_ChangeValue(self)
+ returnweakref.proxy(self)
+
+
+
+
+
Defines operators which change the value of variables;
+each neighbor corresponds to one modified variable.
+Sub-classes have to define ModifyValue which determines what the new
+variable value is going to be (given the current value and the variable).
defOneNeighbor(self)->"bool":
+ r""" This method should not be overridden. Override ModifyValue() instead."""
+ return_pywrapcp.ChangeValue_OneNeighbor(self)
+
+
+
+
+
This method should not be overridden. Override ModifyValue() instead.
classPathOperator(IntVarLocalSearchOperator):
+ r"""
+ Base class of the local search operators dedicated to path modifications
+ (a path is a set of nodes linked together by arcs).
+ This family of neighborhoods supposes they are handling next variables
+ representing the arcs (var[i] represents the node immediately after i on
+ a path).
+ Several services are provided:
+ - arc manipulators (SetNext(), ReverseChain(), MoveChain())
+ - path inspectors (Next(), Prev(), IsPathEnd())
+ - path iterators: operators need a given number of nodes to define a
+ neighbor; this class provides the iteration on a given number of (base)
+ nodes which can be used to define a neighbor (through the BaseNode method)
+ Subclasses only need to override MakeNeighbor to create neighbors using
+ the services above (no direct manipulation of assignments).
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defNeighbor(self)->"bool":
+ return_pywrapcp.PathOperator_Neighbor(self)
+
+
+
+
+
Base class of the local search operators dedicated to path modifications
+(a path is a set of nodes linked together by arcs).
+This family of neighborhoods supposes they are handling next variables
+representing the arcs (var[i] represents the node immediately after i on
+a path).
+Several services are provided:
path iterators: operators need a given number of nodes to define a
+neighbor; this class provides the iteration on a given number of (base)
+nodes which can be used to define a neighbor (through the BaseNode method)
+Subclasses only need to override MakeNeighbor to create neighbors using
+the services above (no direct manipulation of assignments).
classLocalSearchFilter(BaseObject):
+ r"""
+ Classes to which this template function can be applied to as of 04/2014.
+ Usage: LocalSearchOperator* op = MakeLocalSearchOperator<Relocate>(...);
+ class TwoOpt;
+ class Relocate;
+ class Exchange;
+ class Cross;
+ class MakeActiveOperator;
+ class MakeInactiveOperator;
+ class MakeChainInactiveOperator;
+ class SwapActiveOperator;
+ class ExtendedSwapActiveOperator;
+ class MakeActiveAndRelocate;
+ class RelocateAndMakeActiveOperator;
+ class RelocateAndMakeInactiveOperator;
+ Local Search Filters are used for fast neighbor pruning.
+ Filtering a move is done in several phases:
+ - in the Relax phase, filters determine which parts of their internals
+ will be changed by the candidate, and modify intermediary State
+ - in the Accept phase, filters check that the candidate is feasible,
+ - if the Accept phase succeeds, the solver may decide to trigger a
+ Synchronize phase that makes filters change their internal representation
+ to the last candidate,
+ - otherwise (Accept fails or the solver does not want to synchronize),
+ a Revert phase makes filters erase any intermediary State generated by the
+ Relax and Accept phases.
+ A given filter has phases called with the following pattern:
+ (Relax.Accept.Synchronize | Relax.Accept.Revert | Relax.Revert)*.
+ Filters's Revert() is always called in the reverse order their Accept() was
+ called, to allow late filters to use state done/undone by early filters'
+ Accept()/Revert().
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined - class is abstract")
+ __repr__=_swig_repr
+
+ defAccept(self,delta:"Assignment",deltadelta:"Assignment",objective_min:"int64_t",objective_max:"int64_t")->"bool":
+ r"""
+ Accepts a "delta" given the assignment with which the filter has been
+ synchronized; the delta holds the variables which have been modified and
+ their new value.
+ If the filter represents a part of the global objective, its contribution
+ must be between objective_min and objective_max.
+ Sample: supposing one wants to maintain a[0,1] + b[0,1] <= 1,
+ for the assignment (a,1), (b,0), the delta (b,1) will be rejected
+ but the delta (a,0) will be accepted.
+ TODO(user): Remove arguments when there are no more need for those.
+ """
+ return_pywrapcp.LocalSearchFilter_Accept(self,delta,deltadelta,objective_min,objective_max)
+
+ defIsIncremental(self)->"bool":
+ return_pywrapcp.LocalSearchFilter_IsIncremental(self)
+
+ defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r"""
+ Synchronizes the filter with the current solution, delta being the
+ difference with the solution passed to the previous call to Synchronize()
+ or IncrementalSynchronize(). 'delta' can be used to incrementally
+ synchronizing the filter with the new solution by only considering the
+ changes in delta.
+ """
+ return_pywrapcp.LocalSearchFilter_Synchronize(self,assignment,delta)
+ __swig_destroy__=_pywrapcp.delete_LocalSearchFilter
+
+
+
+
+
Classes to which this template function can be applied to as of 04/2014.
+Usage: LocalSearchOperator* op = MakeLocalSearchOperator(...);
+class TwoOpt;
+class Relocate;
+class Exchange;
+class Cross;
+class MakeActiveOperator;
+class MakeInactiveOperator;
+class MakeChainInactiveOperator;
+class SwapActiveOperator;
+class ExtendedSwapActiveOperator;
+class MakeActiveAndRelocate;
+class RelocateAndMakeActiveOperator;
+class RelocateAndMakeInactiveOperator;
+Local Search Filters are used for fast neighbor pruning.
+Filtering a move is done in several phases:
+
+
+
in the Relax phase, filters determine which parts of their internals
+will be changed by the candidate, and modify intermediary State
+
in the Accept phase, filters check that the candidate is feasible,
+
if the Accept phase succeeds, the solver may decide to trigger a
+Synchronize phase that makes filters change their internal representation
+to the last candidate,
+
otherwise (Accept fails or the solver does not want to synchronize),
+a Revert phase makes filters erase any intermediary State generated by the
+Relax and Accept phases.
+A given filter has phases called with the following pattern:
+(Relax.Accept.Synchronize | Relax.Accept.Revert | Relax.Revert)*.
+Filters's Revert() is always called in the reverse order their Accept() was
+called, to allow late filters to use state done/undone by early filters'
+Accept()/Revert().
defAccept(self,delta:"Assignment",deltadelta:"Assignment",objective_min:"int64_t",objective_max:"int64_t")->"bool":
+ r"""
+ Accepts a "delta" given the assignment with which the filter has been
+ synchronized; the delta holds the variables which have been modified and
+ their new value.
+ If the filter represents a part of the global objective, its contribution
+ must be between objective_min and objective_max.
+ Sample: supposing one wants to maintain a[0,1] + b[0,1] <= 1,
+ for the assignment (a,1), (b,0), the delta (b,1) will be rejected
+ but the delta (a,0) will be accepted.
+ TODO(user): Remove arguments when there are no more need for those.
+ """
+ return_pywrapcp.LocalSearchFilter_Accept(self,delta,deltadelta,objective_min,objective_max)
+
+
+
+
+
Accepts a "delta" given the assignment with which the filter has been
+synchronized; the delta holds the variables which have been modified and
+their new value.
+If the filter represents a part of the global objective, its contribution
+must be between objective_min and objective_max.
+Sample: supposing one wants to maintain a[0,1] + b[0,1] <= 1,
+for the assignment (a,1), (b,0), the delta (b,1) will be rejected
+but the delta (a,0) will be accepted.
+TODO(user): Remove arguments when there are no more need for those.
defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r"""
+ Synchronizes the filter with the current solution, delta being the
+ difference with the solution passed to the previous call to Synchronize()
+ or IncrementalSynchronize(). 'delta' can be used to incrementally
+ synchronizing the filter with the new solution by only considering the
+ changes in delta.
+ """
+ return_pywrapcp.LocalSearchFilter_Synchronize(self,assignment,delta)
+
+
+
+
+
Synchronizes the filter with the current solution, delta being the
+difference with the solution passed to the previous call to Synchronize()
+or IncrementalSynchronize(). 'delta' can be used to incrementally
+synchronizing the filter with the new solution by only considering the
+changes in delta.
classLocalSearchFilterManager(BaseObject):
+ r"""
+ Filter manager: when a move is made, filters are executed to decide whether
+ the solution is feasible and compute parts of the new cost. This class
+ schedules filter execution and composes costs as a sum.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.LocalSearchFilterManager_DebugString(self)
+
+ def__init__(self,*args):
+ _pywrapcp.LocalSearchFilterManager_swiginit(self,_pywrapcp.new_LocalSearchFilterManager(*args))
+
+ defAccept(self,monitor:"operations_research::LocalSearchMonitor *const",delta:"Assignment",deltadelta:"Assignment",objective_min:"int64_t",objective_max:"int64_t")->"bool":
+ r"""
+ Returns true iff all filters return true, and the sum of their accepted
+ objectives is between objective_min and objective_max.
+ The monitor has its Begin/EndFiltering events triggered.
+ """
+ return_pywrapcp.LocalSearchFilterManager_Accept(self,monitor,delta,deltadelta,objective_min,objective_max)
+
+ defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r""" Synchronizes all filters to assignment."""
+ return_pywrapcp.LocalSearchFilterManager_Synchronize(self,assignment,delta)
+ __swig_destroy__=_pywrapcp.delete_LocalSearchFilterManager
+
+
+
+
+
Filter manager: when a move is made, filters are executed to decide whether
+the solution is feasible and compute parts of the new cost. This class
+schedules filter execution and composes costs as a sum.
defAccept(self,monitor:"operations_research::LocalSearchMonitor *const",delta:"Assignment",deltadelta:"Assignment",objective_min:"int64_t",objective_max:"int64_t")->"bool":
+ r"""
+ Returns true iff all filters return true, and the sum of their accepted
+ objectives is between objective_min and objective_max.
+ The monitor has its Begin/EndFiltering events triggered.
+ """
+ return_pywrapcp.LocalSearchFilterManager_Accept(self,monitor,delta,deltadelta,objective_min,objective_max)
+
+
+
+
+
Returns true iff all filters return true, and the sum of their accepted
+objectives is between objective_min and objective_max.
+The monitor has its Begin/EndFiltering events triggered.
classIntVarLocalSearchFilter(LocalSearchFilter):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,vars:"std::vector< operations_research::IntVar * > const &"):
+ ifself.__class__==IntVarLocalSearchFilter:
+ _self=None
+ else:
+ _self=self
+ _pywrapcp.IntVarLocalSearchFilter_swiginit(self,_pywrapcp.new_IntVarLocalSearchFilter(_self,vars))
+ __swig_destroy__=_pywrapcp.delete_IntVarLocalSearchFilter
+
+ defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnSynchronize() instead
+ which is called before exiting this method.
+ """
+ return_pywrapcp.IntVarLocalSearchFilter_Synchronize(self,assignment,delta)
+
+ defSize(self)->"int":
+ return_pywrapcp.IntVarLocalSearchFilter_Size(self)
+
+ defValue(self,index:"int")->"int64_t":
+ return_pywrapcp.IntVarLocalSearchFilter_Value(self,index)
+
+ defIndexFromVar(self,var:"IntVar")->"int64_t":
+ return_pywrapcp.IntVarLocalSearchFilter_IndexFromVar(self,var)
+ def__disown__(self):
+ self.this.disown()
+ _pywrapcp.disown_IntVarLocalSearchFilter(self)
+ returnweakref.proxy(self)
+
+
+
+
+
Classes to which this template function can be applied to as of 04/2014.
+Usage: LocalSearchOperator* op = MakeLocalSearchOperator(...);
+class TwoOpt;
+class Relocate;
+class Exchange;
+class Cross;
+class MakeActiveOperator;
+class MakeInactiveOperator;
+class MakeChainInactiveOperator;
+class SwapActiveOperator;
+class ExtendedSwapActiveOperator;
+class MakeActiveAndRelocate;
+class RelocateAndMakeActiveOperator;
+class RelocateAndMakeInactiveOperator;
+Local Search Filters are used for fast neighbor pruning.
+Filtering a move is done in several phases:
+
+
+
in the Relax phase, filters determine which parts of their internals
+will be changed by the candidate, and modify intermediary State
+
in the Accept phase, filters check that the candidate is feasible,
+
if the Accept phase succeeds, the solver may decide to trigger a
+Synchronize phase that makes filters change their internal representation
+to the last candidate,
+
otherwise (Accept fails or the solver does not want to synchronize),
+a Revert phase makes filters erase any intermediary State generated by the
+Relax and Accept phases.
+A given filter has phases called with the following pattern:
+(Relax.Accept.Synchronize | Relax.Accept.Revert | Relax.Revert)*.
+Filters's Revert() is always called in the reverse order their Accept() was
+called, to allow late filters to use state done/undone by early filters'
+Accept()/Revert().
defSynchronize(self,assignment:"Assignment",delta:"Assignment")->"void":
+ r"""
+ This method should not be overridden. Override OnSynchronize() instead
+ which is called before exiting this method.
+ """
+ return_pywrapcp.IntVarLocalSearchFilter_Synchronize(self,assignment,delta)
+
+
+
+
+
This method should not be overridden. Override OnSynchronize() instead
+which is called before exiting this method.
The class IntVar is a subset of IntExpr. In addition to the
+IntExpr protocol, it offers persistence, removing values from the domains,
+and a finer model for events.
Creates a hole iterator. When 'reversible' is false, the returned
+object is created on the normal C++ heap and the solver does NOT
+take ownership of the object.
Creates a domain iterator. When 'reversible' is false, the
+returned object is created on the normal C++ heap and the solver
+does NOT take ownership of the object.
This is the main method of the decision builder class. It must
+return a decision (an instance of the class Decision). If it
+returns nullptr, this means that the decision builder has finished
+its work.
A Demon is the base element of a propagation queue. It is the main
+ object responsible for implementing the actual propagation
+ of the constraint and pruning the inconsistent values in the domains
+ of the variables. The main concept is that demons are listeners that are
+ attached to the variables and listen to their modifications.
+
+
There are two methods
+
+
+
+
Run() is the actual method called when the demon is processed.
+
priority() returns its priority. Standard priorities are slow, normal
+ or fast. "immediate" is reserved for variables and is treated separately.
A Demon is the base element of a propagation queue. It is the main
+ object responsible for implementing the actual propagation
+ of the constraint and pruning the inconsistent values in the domains
+ of the variables. The main concept is that demons are listeners that are
+ attached to the variables and listen to their modifications.
+
+
There are two methods
+
+
+
+
Run() is the actual method called when the demon is processed.
+
priority() returns its priority. Standard priorities are slow, normal
+ or fast. "immediate" is reserved for variables and is treated separately.
This method returns the priority of the demon. Usually a demon is
+fast, slow or normal. Immediate demons are reserved for internal
+use to maintain variables.
A constraint is the main modeling object. It provides two methods:
+
+
+
Post() is responsible for creating the demons and attaching them to
+immediate demons().
+
InitialPropagate() is called once just after Post and performs
+the initial propagation. The subsequent propagations will be performed
+by the demons Posted during the post() method.
classRoutingIndexManager(object):
+ r"""
+ Manager for any NodeIndex <-> variable index conversion. The routing solver
+ uses variable indices internally and through its API. These variable indices
+ are tricky to manage directly because one Node can correspond to a multitude
+ of variables, depending on the number of times they appear in the model, and
+ if they're used as start and/or end points. This class aims to simplify
+ variable index usage, allowing users to use NodeIndex instead.
+
+ Usage:
+
+ .. code-block:: c++
+
+ auto starts_ends = ...; /// These are NodeIndex.
+ RoutingIndexManager manager(10, 4, starts_ends); // 10 nodes, 4 vehicles.
+ RoutingModel model(manager);
+
+ Then, use 'manager.NodeToIndex(node)' whenever model requires a variable
+ index.
+
+ Note: the mapping between node indices and variables indices is subject to
+ change so no assumption should be made on it. The only guarantee is that
+ indices range between 0 and n-1, where n = number of vehicles * 2 (for start
+ and end nodes) + number of non-start or end nodes.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,*args):
+ _pywrapcp.RoutingIndexManager_swiginit(self,_pywrapcp.new_RoutingIndexManager(*args))
+ __swig_destroy__=_pywrapcp.delete_RoutingIndexManager
+
+ defGetNumberOfNodes(self)->"int":
+ return_pywrapcp.RoutingIndexManager_GetNumberOfNodes(self)
+
+ defGetNumberOfVehicles(self)->"int":
+ return_pywrapcp.RoutingIndexManager_GetNumberOfVehicles(self)
+
+ defGetNumberOfIndices(self)->"int":
+ return_pywrapcp.RoutingIndexManager_GetNumberOfIndices(self)
+
+ defGetStartIndex(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingIndexManager_GetStartIndex(self,vehicle)
+
+ defGetEndIndex(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingIndexManager_GetEndIndex(self,vehicle)
+
+ defNodeToIndex(self,node:"operations_research::RoutingIndexManager::NodeIndex")->"int64_t":
+ return_pywrapcp.RoutingIndexManager_NodeToIndex(self,node)
+
+ defIndexToNode(self,index:"int64_t")->"operations_research::RoutingIndexManager::NodeIndex":
+ return_pywrapcp.RoutingIndexManager_IndexToNode(self,index)
+
+
+
+
+
Manager for any NodeIndex <-> variable index conversion. The routing solver
+uses variable indices internally and through its API. These variable indices
+are tricky to manage directly because one Node can correspond to a multitude
+of variables, depending on the number of times they appear in the model, and
+if they're used as start and/or end points. This class aims to simplify
+variable index usage, allowing users to use NodeIndex instead.
+
+
Usage
+
+
+
.. code-block:: c++
+
+
auto starts_ends = ...; /// These are NodeIndex.
+RoutingIndexManager manager(10, 4, starts_ends); // 10 nodes, 4 vehicles.
+RoutingModel model(manager);
+
+
+
+
Then, use 'manager.NodeToIndex(node)' whenever model requires a variable
+index.
+
+
Note: the mapping between node indices and variables indices is subject to
+change so no assumption should be made on it. The only guarantee is that
+indices range between 0 and n-1, where n = number of vehicles * 2 (for start
+and end nodes) + number of non-start or end nodes.
defFindErrorInRoutingSearchParameters(search_parameters:"operations_research::RoutingSearchParameters const &")->"std::string":
+ r"""
+ Returns an empty std::string if the routing search parameters are valid, and
+ a non-empty, human readable error description if they're not.
+ """
+ return_pywrapcp.FindErrorInRoutingSearchParameters(search_parameters)
+
+
+
+
+
Returns an empty std::string if the routing search parameters are valid, and
+a non-empty, human readable error description if they're not.
classRoutingModel(object):
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ ROUTING_NOT_SOLVED=_pywrapcp.RoutingModel_ROUTING_NOT_SOLVED
+ r""" Problem not solved yet (before calling RoutingModel::Solve())."""
+ ROUTING_SUCCESS=_pywrapcp.RoutingModel_ROUTING_SUCCESS
+ r""" Problem solved successfully after calling RoutingModel::Solve()."""
+ ROUTING_FAIL=_pywrapcp.RoutingModel_ROUTING_FAIL
+ r""" No solution found to the problem after calling RoutingModel::Solve()."""
+ ROUTING_FAIL_TIMEOUT=_pywrapcp.RoutingModel_ROUTING_FAIL_TIMEOUT
+ r""" Time limit reached before finding a solution with RoutingModel::Solve()."""
+ ROUTING_INVALID=_pywrapcp.RoutingModel_ROUTING_INVALID
+ r""" Model, model parameters or flags are not valid."""
+ ROUTING_INFEASIBLE=_pywrapcp.RoutingModel_ROUTING_INFEASIBLE
+ r""" Problem proven to be infeasible."""
+ PICKUP_AND_DELIVERY_NO_ORDER=_pywrapcp.RoutingModel_PICKUP_AND_DELIVERY_NO_ORDER
+ r""" Any precedence is accepted."""
+ PICKUP_AND_DELIVERY_LIFO=_pywrapcp.RoutingModel_PICKUP_AND_DELIVERY_LIFO
+ r""" Deliveries must be performed in reverse order of pickups."""
+ PICKUP_AND_DELIVERY_FIFO=_pywrapcp.RoutingModel_PICKUP_AND_DELIVERY_FIFO
+ r""" Deliveries must be performed in the same order as pickups."""
+
+ def__init__(self,*args):
+ _pywrapcp.RoutingModel_swiginit(self,_pywrapcp.new_RoutingModel(*args))
+ __swig_destroy__=_pywrapcp.delete_RoutingModel
+
+ defRegisterUnaryTransitVector(self,values:"std::vector< int64_t >")->"int":
+ r""" Registers 'callback' and returns its index."""
+ return_pywrapcp.RoutingModel_RegisterUnaryTransitVector(self,values)
+
+ defRegisterUnaryTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback1")->"int":
+ return_pywrapcp.RoutingModel_RegisterUnaryTransitCallback(self,callback)
+
+ defRegisterPositiveUnaryTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback1")->"int":
+ return_pywrapcp.RoutingModel_RegisterPositiveUnaryTransitCallback(self,callback)
+
+ defRegisterTransitMatrix(self,values:"std::vector< std::vector< int64_t > >")->"int":
+ return_pywrapcp.RoutingModel_RegisterTransitMatrix(self,values)
+
+ defRegisterTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback2")->"int":
+ return_pywrapcp.RoutingModel_RegisterTransitCallback(self,callback)
+
+ defRegisterPositiveTransitCallback(self,callback:"operations_research::RoutingModel::TransitCallback2")->"int":
+ return_pywrapcp.RoutingModel_RegisterPositiveTransitCallback(self,callback)
+
+ defTransitCallback(self,callback_index:"int")->"operations_research::RoutingModel::TransitCallback2 const &":
+ return_pywrapcp.RoutingModel_TransitCallback(self,callback_index)
+
+ defUnaryTransitCallbackOrNull(self,callback_index:"int")->"operations_research::RoutingModel::TransitCallback1 const &":
+ return_pywrapcp.RoutingModel_UnaryTransitCallbackOrNull(self,callback_index)
+
+ defAddDimension(self,evaluator_index:"int",slack_max:"int64_t",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ r"""
+ Model creation
+ Methods to add dimensions to routes; dimensions represent quantities
+ accumulated at nodes along the routes. They represent quantities such as
+ weights or volumes carried along the route, or distance or times.
+ Quantities at a node are represented by "cumul" variables and the increase
+ or decrease of quantities between nodes are represented by "transit"
+ variables. These variables are linked as follows:
+ if j == next(i), cumul(j) = cumul(i) + transit(i) + slack(i)
+ where slack is a positive slack variable (can represent waiting times for
+ a time dimension).
+ Setting the value of fix_start_cumul_to_zero to true will force the
+ "cumul" variable of the start node of all vehicles to be equal to 0.
+ Creates a dimension where the transit variable is constrained to be
+ equal to evaluator(i, next(i)); 'slack_max' is the upper bound of the
+ slack variable and 'capacity' is the upper bound of the cumul variables.
+ 'name' is the name used to reference the dimension; this name is used to
+ get cumul and transit variables from the routing model.
+ Returns false if a dimension with the same name has already been created
+ (and doesn't create the new dimension).
+ Takes ownership of the callback 'evaluator'.
+ """
+ return_pywrapcp.RoutingModel_AddDimension(self,evaluator_index,slack_max,capacity,fix_start_cumul_to_zero,name)
+
+ defAddDimensionWithVehicleTransits(self,evaluator_indices:"std::vector< int > const &",slack_max:"int64_t",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ return_pywrapcp.RoutingModel_AddDimensionWithVehicleTransits(self,evaluator_indices,slack_max,capacity,fix_start_cumul_to_zero,name)
+
+ defAddDimensionWithVehicleCapacity(self,evaluator_index:"int",slack_max:"int64_t",vehicle_capacities:"std::vector< int64_t >",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ return_pywrapcp.RoutingModel_AddDimensionWithVehicleCapacity(self,evaluator_index,slack_max,vehicle_capacities,fix_start_cumul_to_zero,name)
+
+ defAddDimensionWithVehicleTransitAndCapacity(self,evaluator_indices:"std::vector< int > const &",slack_max:"int64_t",vehicle_capacities:"std::vector< int64_t >",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ return_pywrapcp.RoutingModel_AddDimensionWithVehicleTransitAndCapacity(self,evaluator_indices,slack_max,vehicle_capacities,fix_start_cumul_to_zero,name)
+
+ defAddConstantDimensionWithSlack(self,value:"int64_t",capacity:"int64_t",slack_max:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'value'; 'capacity' is the upper bound of the cumul variables.
+ 'name' is the name used to reference the dimension; this name is used to
+ get cumul and transit variables from the routing model.
+ Returns a pair consisting of an index to the registered unary transit
+ callback and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddConstantDimensionWithSlack(self,value,capacity,slack_max,fix_start_cumul_to_zero,name)
+
+ defAddConstantDimension(self,value:"int64_t",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ return_pywrapcp.RoutingModel_AddConstantDimension(self,value,capacity,fix_start_cumul_to_zero,name)
+
+ defAddVectorDimension(self,values:"std::vector< int64_t >",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'values[i]' for node i; 'capacity' is the upper bound of
+ the cumul variables. 'name' is the name used to reference the dimension;
+ this name is used to get cumul and transit variables from the routing
+ model.
+ Returns a pair consisting of an index to the registered unary transit
+ callback and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddVectorDimension(self,values,capacity,fix_start_cumul_to_zero,name)
+
+ defAddMatrixDimension(self,values:"std::vector< std::vector< int64_t > >",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'values[i][next(i)]' for node i; 'capacity' is the upper bound of
+ the cumul variables. 'name' is the name used to reference the dimension;
+ this name is used to get cumul and transit variables from the routing
+ model.
+ Returns a pair consisting of an index to the registered transit callback
+ and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddMatrixDimension(self,values,capacity,fix_start_cumul_to_zero,name)
+
+ defMakePathSpansAndTotalSlacks(self,dimension:"RoutingDimension",spans:"std::vector< operations_research::IntVar * >",total_slacks:"std::vector< operations_research::IntVar * >")->"operations_research::Constraint *":
+ r"""
+ For every vehicle of the routing model:
+ - if total_slacks[vehicle] is not nullptr, constrains it to be the sum of
+ slacks on that vehicle, that is,
+ dimension->CumulVar(end) - dimension->CumulVar(start) -
+ sum_{node in path of vehicle} dimension->FixedTransitVar(node).
+ - if spans[vehicle] is not nullptr, constrains it to be
+ dimension->CumulVar(end) - dimension->CumulVar(start)
+ This does stronger propagation than a decomposition, and takes breaks into
+ account.
+ """
+ return_pywrapcp.RoutingModel_MakePathSpansAndTotalSlacks(self,dimension,spans,total_slacks)
+
+ defGetAllDimensionNames(self)->"std::vector< std::string >":
+ r""" Outputs the names of all dimensions added to the routing engine."""
+ return_pywrapcp.RoutingModel_GetAllDimensionNames(self)
+
+ defGetDimensions(self)->"std::vector< operations_research::RoutingDimension * > const &":
+ r""" Returns all dimensions of the model."""
+ return_pywrapcp.RoutingModel_GetDimensions(self)
+
+ defGetDimensionsWithSoftOrSpanCosts(self)->"std::vector< operations_research::RoutingDimension * >":
+ r""" Returns dimensions with soft or vehicle span costs."""
+ return_pywrapcp.RoutingModel_GetDimensionsWithSoftOrSpanCosts(self)
+
+ defGetGlobalDimensionCumulOptimizers(self)->"std::vector< std::unique_ptr< operations_research::GlobalDimensionCumulOptimizer > > const &":
+ r"""
+ Returns [global|local]_dimension_optimizers_, which are empty if the model
+ has not been closed.
+ """
+ return_pywrapcp.RoutingModel_GetGlobalDimensionCumulOptimizers(self)
+
+ defGetGlobalDimensionCumulMPOptimizers(self)->"std::vector< std::unique_ptr< operations_research::GlobalDimensionCumulOptimizer > > const &":
+ return_pywrapcp.RoutingModel_GetGlobalDimensionCumulMPOptimizers(self)
+
+ defGetLocalDimensionCumulOptimizers(self)->"std::vector< std::unique_ptr< operations_research::LocalDimensionCumulOptimizer > > const &":
+ return_pywrapcp.RoutingModel_GetLocalDimensionCumulOptimizers(self)
+
+ defGetLocalDimensionCumulMPOptimizers(self)->"std::vector< std::unique_ptr< operations_research::LocalDimensionCumulOptimizer > > const &":
+ return_pywrapcp.RoutingModel_GetLocalDimensionCumulMPOptimizers(self)
+
+ defGetMutableGlobalCumulOptimizer(self,dimension:"RoutingDimension")->"operations_research::GlobalDimensionCumulOptimizer *":
+ r"""
+ Returns the global/local dimension cumul optimizer for a given dimension,
+ or nullptr if there is none.
+ """
+ return_pywrapcp.RoutingModel_GetMutableGlobalCumulOptimizer(self,dimension)
+
+ defGetMutableGlobalCumulMPOptimizer(self,dimension:"RoutingDimension")->"operations_research::GlobalDimensionCumulOptimizer *":
+ return_pywrapcp.RoutingModel_GetMutableGlobalCumulMPOptimizer(self,dimension)
+
+ defGetMutableLocalCumulOptimizer(self,dimension:"RoutingDimension")->"operations_research::LocalDimensionCumulOptimizer *":
+ return_pywrapcp.RoutingModel_GetMutableLocalCumulOptimizer(self,dimension)
+
+ defGetMutableLocalCumulMPOptimizer(self,dimension:"RoutingDimension")->"operations_research::LocalDimensionCumulOptimizer *":
+ return_pywrapcp.RoutingModel_GetMutableLocalCumulMPOptimizer(self,dimension)
+
+ defHasDimension(self,dimension_name:"std::string const &")->"bool":
+ r""" Returns true if a dimension exists for a given dimension name."""
+ return_pywrapcp.RoutingModel_HasDimension(self,dimension_name)
+
+ defGetDimensionOrDie(self,dimension_name:"std::string const &")->"operations_research::RoutingDimension const &":
+ r""" Returns a dimension from its name. Dies if the dimension does not exist."""
+ return_pywrapcp.RoutingModel_GetDimensionOrDie(self,dimension_name)
+
+ defGetMutableDimension(self,dimension_name:"std::string const &")->"operations_research::RoutingDimension *":
+ r"""
+ Returns a dimension from its name. Returns nullptr if the dimension does
+ not exist.
+ """
+ return_pywrapcp.RoutingModel_GetMutableDimension(self,dimension_name)
+
+ defSetPrimaryConstrainedDimension(self,dimension_name:"std::string const &")->"void":
+ r"""
+ Set the given dimension as "primary constrained". As of August 2013, this
+ is only used by ArcIsMoreConstrainedThanArc().
+ "dimension" must be the name of an existing dimension, or be empty, in
+ which case there will not be a primary dimension after this call.
+ """
+ return_pywrapcp.RoutingModel_SetPrimaryConstrainedDimension(self,dimension_name)
+
+ defGetPrimaryConstrainedDimension(self)->"std::string const &":
+ r""" Get the primary constrained dimension, or an empty string if it is unset."""
+ return_pywrapcp.RoutingModel_GetPrimaryConstrainedDimension(self)
+
+ defAddResourceGroup(self)->"int":
+ r"""
+ Adds a resource group to the routing model. Returns its index in
+ resource_groups_.
+ """
+ return_pywrapcp.RoutingModel_AddResourceGroup(self)
+
+ defGetDimensionResourceGroupIndices(self,dimension:"RoutingDimension")->"std::vector< int > const &":
+ r"""
+ Returns the indices of resource groups for this dimension. This method can
+ only be called after the model has been closed.
+ """
+ return_pywrapcp.RoutingModel_GetDimensionResourceGroupIndices(self,dimension)
+
+ defGetDimensionResourceGroupIndex(self,dimension:"RoutingDimension")->"int":
+ r"""
+ Returns the index of the resource group attached to the dimension.
+ DCHECKS that there's exactly one resource group for this dimension.
+ """
+ return_pywrapcp.RoutingModel_GetDimensionResourceGroupIndex(self,dimension)
+
+ defAddDisjunction(self,*args)->"operations_research::RoutingModel::DisjunctionIndex":
+ r"""
+ Adds a disjunction constraint on the indices: exactly 'max_cardinality' of
+ the indices are active. Start and end indices of any vehicle cannot be
+ part of a disjunction.
+
+ If a penalty is given, at most 'max_cardinality' of the indices can be
+ active, and if less are active, 'penalty' is payed per inactive index.
+ This is equivalent to adding the constraint:
+ p + Sum(i)active[i] == max_cardinality
+ where p is an integer variable, and the following cost to the cost
+ function:
+ p * penalty.
+ 'penalty' must be positive to make the disjunction optional; a negative
+ penalty will force 'max_cardinality' indices of the disjunction to be
+ performed, and therefore p == 0.
+ Note: passing a vector with a single index will model an optional index
+ with a penalty cost if it is not visited.
+ """
+ return_pywrapcp.RoutingModel_AddDisjunction(self,*args)
+
+ defGetDisjunctionIndices(self,index:"int64_t")->"std::vector< operations_research::RoutingModel::DisjunctionIndex > const &":
+ r""" Returns the indices of the disjunctions to which an index belongs."""
+ return_pywrapcp.RoutingModel_GetDisjunctionIndices(self,index)
+
+ defGetDisjunctionPenalty(self,index:"operations_research::RoutingModel::DisjunctionIndex")->"int64_t":
+ r""" Returns the penalty of the node disjunction of index 'index'."""
+ return_pywrapcp.RoutingModel_GetDisjunctionPenalty(self,index)
+
+ defGetDisjunctionMaxCardinality(self,index:"operations_research::RoutingModel::DisjunctionIndex")->"int64_t":
+ r"""
+ Returns the maximum number of possible active nodes of the node
+ disjunction of index 'index'.
+ """
+ return_pywrapcp.RoutingModel_GetDisjunctionMaxCardinality(self,index)
+
+ defGetNumberOfDisjunctions(self)->"int":
+ r""" Returns the number of node disjunctions in the model."""
+ return_pywrapcp.RoutingModel_GetNumberOfDisjunctions(self)
+
+ defHasMandatoryDisjunctions(self)->"bool":
+ r"""
+ Returns true if the model contains mandatory disjunctions (ones with
+ kNoPenalty as penalty).
+ """
+ return_pywrapcp.RoutingModel_HasMandatoryDisjunctions(self)
+
+ defHasMaxCardinalityConstrainedDisjunctions(self)->"bool":
+ r"""
+ Returns true if the model contains at least one disjunction which is
+ constrained by its max_cardinality.
+ """
+ return_pywrapcp.RoutingModel_HasMaxCardinalityConstrainedDisjunctions(self)
+
+ defGetPerfectBinaryDisjunctions(self)->"std::vector< std::pair< int64_t,int64_t > >":
+ r"""
+ Returns the list of all perfect binary disjunctions, as pairs of variable
+ indices: a disjunction is "perfect" when its variables do not appear in
+ any other disjunction. Each pair is sorted (lowest variable index first),
+ and the output vector is also sorted (lowest pairs first).
+ """
+ return_pywrapcp.RoutingModel_GetPerfectBinaryDisjunctions(self)
+
+ defIgnoreDisjunctionsAlreadyForcedToZero(self)->"void":
+ r"""
+ SPECIAL: Makes the solver ignore all the disjunctions whose active
+ variables are all trivially zero (i.e. Max() == 0), by setting their
+ max_cardinality to 0.
+ This can be useful when using the BaseBinaryDisjunctionNeighborhood
+ operators, in the context of arc-based routing.
+ """
+ return_pywrapcp.RoutingModel_IgnoreDisjunctionsAlreadyForcedToZero(self)
+
+ defAddSoftSameVehicleConstraint(self,indices:"std::vector< int64_t > const &",cost:"int64_t")->"void":
+ r"""
+ Adds a soft constraint to force a set of variable indices to be on the
+ same vehicle. If all nodes are not on the same vehicle, each extra vehicle
+ used adds 'cost' to the cost function.
+ """
+ return_pywrapcp.RoutingModel_AddSoftSameVehicleConstraint(self,indices,cost)
+
+ defSetAllowedVehiclesForIndex(self,vehicles:"std::vector< int > const &",index:"int64_t")->"void":
+ r"""
+ Sets the vehicles which can visit a given node. If the node is in a
+ disjunction, this will not prevent it from being unperformed.
+ Specifying an empty vector of vehicles has no effect (all vehicles
+ will be allowed to visit the node).
+ """
+ return_pywrapcp.RoutingModel_SetAllowedVehiclesForIndex(self,vehicles,index)
+
+ defIsVehicleAllowedForIndex(self,vehicle:"int",index:"int64_t")->"bool":
+ r""" Returns true if a vehicle is allowed to visit a given node."""
+ return_pywrapcp.RoutingModel_IsVehicleAllowedForIndex(self,vehicle,index)
+
+ defAddPickupAndDelivery(self,pickup:"int64_t",delivery:"int64_t")->"void":
+ r"""
+ Notifies that index1 and index2 form a pair of nodes which should belong
+ to the same route. This methods helps the search find better solutions,
+ especially in the local search phase.
+ It should be called each time you have an equality constraint linking
+ the vehicle variables of two node (including for instance pickup and
+ delivery problems):
+ Solver* const solver = routing.solver();
+ int64_t index1 = manager.NodeToIndex(node1);
+ int64_t index2 = manager.NodeToIndex(node2);
+ solver->AddConstraint(solver->MakeEquality(
+ routing.VehicleVar(index1),
+ routing.VehicleVar(index2)));
+ routing.AddPickupAndDelivery(index1, index2);
+ """
+ return_pywrapcp.RoutingModel_AddPickupAndDelivery(self,pickup,delivery)
+
+ defAddPickupAndDeliverySets(self,pickup_disjunction:"operations_research::RoutingModel::DisjunctionIndex",delivery_disjunction:"operations_research::RoutingModel::DisjunctionIndex")->"void":
+ r"""
+ Same as AddPickupAndDelivery but notifying that the performed node from
+ the disjunction of index 'pickup_disjunction' is on the same route as the
+ performed node from the disjunction of index 'delivery_disjunction'.
+ """
+ return_pywrapcp.RoutingModel_AddPickupAndDeliverySets(self,pickup_disjunction,delivery_disjunction)
+
+ defGetPickupIndexPairs(self,node_index:"int64_t")->"std::vector< std::pair< int,int > > const &":
+ r"""
+ Returns pairs for which the node is a pickup; the first element of each
+ pair is the index in the pickup and delivery pairs list in which the
+ pickup appears, the second element is its index in the pickups list.
+ """
+ return_pywrapcp.RoutingModel_GetPickupIndexPairs(self,node_index)
+
+ defGetDeliveryIndexPairs(self,node_index:"int64_t")->"std::vector< std::pair< int,int > > const &":
+ r""" Same as above for deliveries."""
+ return_pywrapcp.RoutingModel_GetDeliveryIndexPairs(self,node_index)
+
+ defSetPickupAndDeliveryPolicyOfAllVehicles(self,policy:"operations_research::RoutingModel::PickupAndDeliveryPolicy")->"void":
+ r"""
+ Sets the Pickup and delivery policy of all vehicles. It is equivalent to
+ calling SetPickupAndDeliveryPolicyOfVehicle on all vehicles.
+ """
+ return_pywrapcp.RoutingModel_SetPickupAndDeliveryPolicyOfAllVehicles(self,policy)
+
+ defSetPickupAndDeliveryPolicyOfVehicle(self,policy:"operations_research::RoutingModel::PickupAndDeliveryPolicy",vehicle:"int")->"void":
+ return_pywrapcp.RoutingModel_SetPickupAndDeliveryPolicyOfVehicle(self,policy,vehicle)
+
+ defGetPickupAndDeliveryPolicyOfVehicle(self,vehicle:"int")->"operations_research::RoutingModel::PickupAndDeliveryPolicy":
+ return_pywrapcp.RoutingModel_GetPickupAndDeliveryPolicyOfVehicle(self,vehicle)
+
+ defGetNumOfSingletonNodes(self)->"int":
+ r"""
+ Returns the number of non-start/end nodes which do not appear in a
+ pickup/delivery pair.
+ """
+ return_pywrapcp.RoutingModel_GetNumOfSingletonNodes(self)
+ TYPE_ADDED_TO_VEHICLE=_pywrapcp.RoutingModel_TYPE_ADDED_TO_VEHICLE
+ r""" When visited, the number of types 'T' on the vehicle increases by one."""
+ ADDED_TYPE_REMOVED_FROM_VEHICLE=_pywrapcp.RoutingModel_ADDED_TYPE_REMOVED_FROM_VEHICLE
+ r"""
+ When visited, one instance of type 'T' previously added to the route
+ (TYPE_ADDED_TO_VEHICLE), if any, is removed from the vehicle.
+ If the type was not previously added to the route or all added instances
+ have already been removed, this visit has no effect on the types.
+ """
+ TYPE_ON_VEHICLE_UP_TO_VISIT=_pywrapcp.RoutingModel_TYPE_ON_VEHICLE_UP_TO_VISIT
+ r"""
+ With the following policy, the visit enforces that type 'T' is
+ considered on the route from its start until this node is visited.
+ """
+ TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED=_pywrapcp.RoutingModel_TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED
+ r"""
+ The visit doesn't have an impact on the number of types 'T' on the
+ route, as it's (virtually) added and removed directly.
+ This policy can be used for visits which are part of an incompatibility
+ or requirement set without affecting the type count on the route.
+ """
+
+ defSetVisitType(self,index:"int64_t",type:"int",type_policy:"operations_research::RoutingModel::VisitTypePolicy")->"void":
+ return_pywrapcp.RoutingModel_SetVisitType(self,index,type,type_policy)
+
+ defGetVisitType(self,index:"int64_t")->"int":
+ return_pywrapcp.RoutingModel_GetVisitType(self,index)
+
+ defGetSingleNodesOfType(self,type:"int")->"std::vector< int > const &":
+ return_pywrapcp.RoutingModel_GetSingleNodesOfType(self,type)
+
+ defGetPairIndicesOfType(self,type:"int")->"std::vector< int > const &":
+ return_pywrapcp.RoutingModel_GetPairIndicesOfType(self,type)
+
+ defGetVisitTypePolicy(self,index:"int64_t")->"operations_research::RoutingModel::VisitTypePolicy":
+ return_pywrapcp.RoutingModel_GetVisitTypePolicy(self,index)
+
+ defCloseVisitTypes(self)->"void":
+ r"""
+ This function should be called once all node visit types have been set and
+ prior to adding any incompatibilities/requirements.
+ "close" types.
+ """
+ return_pywrapcp.RoutingModel_CloseVisitTypes(self)
+
+ defGetNumberOfVisitTypes(self)->"int":
+ return_pywrapcp.RoutingModel_GetNumberOfVisitTypes(self)
+
+ defAddHardTypeIncompatibility(self,type1:"int",type2:"int")->"void":
+ r"""
+ Incompatibilities:
+ Two nodes with "hard" incompatible types cannot share the same route at
+ all, while with a "temporal" incompatibility they can't be on the same
+ route at the same time.
+ """
+ return_pywrapcp.RoutingModel_AddHardTypeIncompatibility(self,type1,type2)
+
+ defAddTemporalTypeIncompatibility(self,type1:"int",type2:"int")->"void":
+ return_pywrapcp.RoutingModel_AddTemporalTypeIncompatibility(self,type1,type2)
+
+ defGetHardTypeIncompatibilitiesOfType(self,type:"int")->"absl::flat_hash_set< int > const &":
+ r""" Returns visit types incompatible with a given type."""
+ return_pywrapcp.RoutingModel_GetHardTypeIncompatibilitiesOfType(self,type)
+
+ defGetTemporalTypeIncompatibilitiesOfType(self,type:"int")->"absl::flat_hash_set< int > const &":
+ return_pywrapcp.RoutingModel_GetTemporalTypeIncompatibilitiesOfType(self,type)
+
+ defHasHardTypeIncompatibilities(self)->"bool":
+ r"""
+ Returns true iff any hard (resp. temporal) type incompatibilities have
+ been added to the model.
+ """
+ return_pywrapcp.RoutingModel_HasHardTypeIncompatibilities(self)
+
+ defHasTemporalTypeIncompatibilities(self)->"bool":
+ return_pywrapcp.RoutingModel_HasTemporalTypeIncompatibilities(self)
+
+ defAddSameVehicleRequiredTypeAlternatives(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ Requirements:
+ NOTE: As of 2019-04, cycles in the requirement graph are not supported,
+ and lead to the dependent nodes being skipped if possible (otherwise
+ the model is considered infeasible).
+ The following functions specify that "dependent_type" requires at least
+ one of the types in "required_type_alternatives".
+
+ For same-vehicle requirements, a node of dependent type type_D requires at
+ least one node of type type_R among the required alternatives on the same
+ route.
+ """
+ return_pywrapcp.RoutingModel_AddSameVehicleRequiredTypeAlternatives(self,dependent_type,required_type_alternatives)
+
+ defAddRequiredTypeAlternativesWhenAddingType(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ If type_D depends on type_R when adding type_D, any node_D of type_D and
+ VisitTypePolicy TYPE_ADDED_TO_VEHICLE or
+ TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED requires at least one type_R on its
+ vehicle at the time node_D is visited.
+ """
+ return_pywrapcp.RoutingModel_AddRequiredTypeAlternativesWhenAddingType(self,dependent_type,required_type_alternatives)
+
+ defAddRequiredTypeAlternativesWhenRemovingType(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ The following requirements apply when visiting dependent nodes that remove
+ their type from the route, i.e. type_R must be on the vehicle when type_D
+ of VisitTypePolicy ADDED_TYPE_REMOVED_FROM_VEHICLE,
+ TYPE_ON_VEHICLE_UP_TO_VISIT or TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED is
+ visited.
+ """
+ return_pywrapcp.RoutingModel_AddRequiredTypeAlternativesWhenRemovingType(self,dependent_type,required_type_alternatives)
+
+ defGetSameVehicleRequiredTypeAlternativesOfType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r"""
+ Returns the set of same-vehicle requirement alternatives for the given
+ type.
+ """
+ return_pywrapcp.RoutingModel_GetSameVehicleRequiredTypeAlternativesOfType(self,type)
+
+ defGetRequiredTypeAlternativesWhenAddingType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r""" Returns the set of requirement alternatives when adding the given type."""
+ return_pywrapcp.RoutingModel_GetRequiredTypeAlternativesWhenAddingType(self,type)
+
+ defGetRequiredTypeAlternativesWhenRemovingType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r""" Returns the set of requirement alternatives when removing the given type."""
+ return_pywrapcp.RoutingModel_GetRequiredTypeAlternativesWhenRemovingType(self,type)
+
+ defHasSameVehicleTypeRequirements(self)->"bool":
+ r"""
+ Returns true iff any same-route (resp. temporal) type requirements have
+ been added to the model.
+ """
+ return_pywrapcp.RoutingModel_HasSameVehicleTypeRequirements(self)
+
+ defHasTemporalTypeRequirements(self)->"bool":
+ return_pywrapcp.RoutingModel_HasTemporalTypeRequirements(self)
+
+ defHasTypeRegulations(self)->"bool":
+ r"""
+ Returns true iff the model has any incompatibilities or requirements set
+ on node types.
+ """
+ return_pywrapcp.RoutingModel_HasTypeRegulations(self)
+
+ defUnperformedPenalty(self,var_index:"int64_t")->"int64_t":
+ r"""
+ Get the "unperformed" penalty of a node. This is only well defined if the
+ node is only part of a single Disjunction, and that disjunction has a
+ penalty. For forced active nodes returns max int64_t. In all other cases,
+ this returns 0.
+ """
+ return_pywrapcp.RoutingModel_UnperformedPenalty(self,var_index)
+
+ defUnperformedPenaltyOrValue(self,default_value:"int64_t",var_index:"int64_t")->"int64_t":
+ r"""
+ Same as above except that it returns default_value instead of 0 when
+ penalty is not well defined (default value is passed as first argument to
+ simplify the usage of the method in a callback).
+ """
+ return_pywrapcp.RoutingModel_UnperformedPenaltyOrValue(self,default_value,var_index)
+
+ defGetDepot(self)->"int64_t":
+ r"""
+ Returns the variable index of the first starting or ending node of all
+ routes. If all routes start and end at the same node (single depot), this
+ is the node returned.
+ """
+ return_pywrapcp.RoutingModel_GetDepot(self)
+
+ defSetMaximumNumberOfActiveVehicles(self,max_active_vehicles:"int")->"void":
+ r"""
+ Constrains the maximum number of active vehicles, aka the number of
+ vehicles which do not have an empty route. For instance, this can be used
+ to limit the number of routes in the case where there are fewer drivers
+ than vehicles and that the fleet of vehicle is heterogeneous.
+ """
+ return_pywrapcp.RoutingModel_SetMaximumNumberOfActiveVehicles(self,max_active_vehicles)
+
+ defGetMaximumNumberOfActiveVehicles(self)->"int":
+ r""" Returns the maximum number of active vehicles."""
+ return_pywrapcp.RoutingModel_GetMaximumNumberOfActiveVehicles(self)
+
+ defSetArcCostEvaluatorOfAllVehicles(self,evaluator_index:"int")->"void":
+ r"""
+ Sets the cost function of the model such that the cost of a segment of a
+ route between node 'from' and 'to' is evaluator(from, to), whatever the
+ route or vehicle performing the route.
+ """
+ return_pywrapcp.RoutingModel_SetArcCostEvaluatorOfAllVehicles(self,evaluator_index)
+
+ defSetArcCostEvaluatorOfVehicle(self,evaluator_index:"int",vehicle:"int")->"void":
+ r""" Sets the cost function for a given vehicle route."""
+ return_pywrapcp.RoutingModel_SetArcCostEvaluatorOfVehicle(self,evaluator_index,vehicle)
+
+ defSetFixedCostOfAllVehicles(self,cost:"int64_t")->"void":
+ r"""
+ Sets the fixed cost of all vehicle routes. It is equivalent to calling
+ SetFixedCostOfVehicle on all vehicle routes.
+ """
+ return_pywrapcp.RoutingModel_SetFixedCostOfAllVehicles(self,cost)
+
+ defSetFixedCostOfVehicle(self,cost:"int64_t",vehicle:"int")->"void":
+ r""" Sets the fixed cost of one vehicle route."""
+ return_pywrapcp.RoutingModel_SetFixedCostOfVehicle(self,cost,vehicle)
+
+ defGetFixedCostOfVehicle(self,vehicle:"int")->"int64_t":
+ r"""
+ Returns the route fixed cost taken into account if the route of the
+ vehicle is not empty, aka there's at least one node on the route other
+ than the first and last nodes.
+ """
+ return_pywrapcp.RoutingModel_GetFixedCostOfVehicle(self,vehicle)
+
+ defSetAmortizedCostFactorsOfAllVehicles(self,linear_cost_factor:"int64_t",quadratic_cost_factor:"int64_t")->"void":
+ r"""
+ The following methods set the linear and quadratic cost factors of
+ vehicles (must be positive values). The default value of these parameters
+ is zero for all vehicles.
+
+ When set, the cost_ of the model will contain terms aiming at reducing the
+ number of vehicles used in the model, by adding the following to the
+ objective for every vehicle v:
+ INDICATOR(v used in the model) *
+ [linear_cost_factor_of_vehicle_[v]
+ - quadratic_cost_factor_of_vehicle_[v]*(square of length of route v)]
+ i.e. for every used vehicle, we add the linear factor as fixed cost, and
+ subtract the square of the route length multiplied by the quadratic
+ factor. This second term aims at making the routes as dense as possible.
+
+ Sets the linear and quadratic cost factor of all vehicles.
+ """
+ return_pywrapcp.RoutingModel_SetAmortizedCostFactorsOfAllVehicles(self,linear_cost_factor,quadratic_cost_factor)
+
+ defSetAmortizedCostFactorsOfVehicle(self,linear_cost_factor:"int64_t",quadratic_cost_factor:"int64_t",vehicle:"int")->"void":
+ r""" Sets the linear and quadratic cost factor of the given vehicle."""
+ return_pywrapcp.RoutingModel_SetAmortizedCostFactorsOfVehicle(self,linear_cost_factor,quadratic_cost_factor,vehicle)
+
+ defGetAmortizedLinearCostFactorOfVehicles(self)->"std::vector< int64_t > const &":
+ return_pywrapcp.RoutingModel_GetAmortizedLinearCostFactorOfVehicles(self)
+
+ defGetAmortizedQuadraticCostFactorOfVehicles(self)->"std::vector< int64_t > const &":
+ return_pywrapcp.RoutingModel_GetAmortizedQuadraticCostFactorOfVehicles(self)
+
+ defSetVehicleUsedWhenEmpty(self,is_used:"bool",vehicle:"int")->"void":
+ return_pywrapcp.RoutingModel_SetVehicleUsedWhenEmpty(self,is_used,vehicle)
+
+ defIsVehicleUsedWhenEmpty(self,vehicle:"int")->"bool":
+ return_pywrapcp.RoutingModel_IsVehicleUsedWhenEmpty(self,vehicle)
+
+ defSetFirstSolutionEvaluator(self,evaluator:"operations_research::Solver::IndexEvaluator2")->"void":
+ r"""
+ Gets/sets the evaluator used during the search. Only relevant when
+ RoutingSearchParameters.first_solution_strategy = EVALUATOR_STRATEGY.
+ Takes ownership of evaluator.
+ """
+ return_pywrapcp.RoutingModel_SetFirstSolutionEvaluator(self,evaluator)
+
+ defAddLocalSearchOperator(self,ls_operator:"LocalSearchOperator")->"void":
+ r"""
+ Adds a local search operator to the set of operators used to solve the
+ vehicle routing problem.
+ """
+ return_pywrapcp.RoutingModel_AddLocalSearchOperator(self,ls_operator)
+
+ defAddSearchMonitor(self,monitor:"SearchMonitor")->"void":
+ r""" Adds a search monitor to the search used to solve the routing model."""
+ return_pywrapcp.RoutingModel_AddSearchMonitor(self,monitor)
+
+ defAddAtSolutionCallback(self,callback:"std::function< void () >")->"void":
+ r"""
+ Adds a callback called each time a solution is found during the search.
+ This is a shortcut to creating a monitor to call the callback on
+ AtSolution() and adding it with AddSearchMonitor.
+ """
+ return_pywrapcp.RoutingModel_AddAtSolutionCallback(self,callback)
+
+ defAddVariableMinimizedByFinalizer(self,var:"IntVar")->"void":
+ r"""
+ Adds a variable to minimize in the solution finalizer. The solution
+ finalizer is called each time a solution is found during the search and
+ allows to instantiate secondary variables (such as dimension cumul
+ variables).
+ """
+ return_pywrapcp.RoutingModel_AddVariableMinimizedByFinalizer(self,var)
+
+ defAddVariableMaximizedByFinalizer(self,var:"IntVar")->"void":
+ r"""
+ Adds a variable to maximize in the solution finalizer (see above for
+ information on the solution finalizer).
+ """
+ return_pywrapcp.RoutingModel_AddVariableMaximizedByFinalizer(self,var)
+
+ defAddWeightedVariableMinimizedByFinalizer(self,var:"IntVar",cost:"int64_t")->"void":
+ r"""
+ Adds a variable to minimize in the solution finalizer, with a weighted
+ priority: the higher the more priority it has.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableMinimizedByFinalizer(self,var,cost)
+
+ defAddWeightedVariableMaximizedByFinalizer(self,var:"IntVar",cost:"int64_t")->"void":
+ r"""
+ Adds a variable to maximize in the solution finalizer, with a weighted
+ priority: the higher the more priority it has.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableMaximizedByFinalizer(self,var,cost)
+
+ defAddVariableTargetToFinalizer(self,var:"IntVar",target:"int64_t")->"void":
+ r"""
+ Add a variable to set the closest possible to the target value in the
+ solution finalizer.
+ """
+ return_pywrapcp.RoutingModel_AddVariableTargetToFinalizer(self,var,target)
+
+ defAddWeightedVariableTargetToFinalizer(self,var:"IntVar",target:"int64_t",cost:"int64_t")->"void":
+ r"""
+ Same as above with a weighted priority: the higher the cost, the more
+ priority it has to be set close to the target value.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableTargetToFinalizer(self,var,target,cost)
+
+ defCloseModel(self)->"void":
+ r"""
+ Closes the current routing model; after this method is called, no
+ modification to the model can be done, but RoutesToAssignment becomes
+ available. Note that CloseModel() is automatically called by Solve() and
+ other methods that produce solution.
+ This is equivalent to calling
+ CloseModelWithParameters(DefaultRoutingSearchParameters()).
+ """
+ return_pywrapcp.RoutingModel_CloseModel(self)
+
+ defCloseModelWithParameters(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"void":
+ r"""
+ Same as above taking search parameters (as of 10/2015 some the parameters
+ have to be set when closing the model).
+ """
+ return_pywrapcp.RoutingModel_CloseModelWithParameters(self,search_parameters)
+
+ defSolve(self,assignment:"Assignment"=None)->"operations_research::Assignment const *":
+ r"""
+ Solves the current routing model; closes the current model.
+ This is equivalent to calling
+ SolveWithParameters(DefaultRoutingSearchParameters())
+ or
+ SolveFromAssignmentWithParameters(assignment,
+ DefaultRoutingSearchParameters()).
+ """
+ return_pywrapcp.RoutingModel_Solve(self,assignment)
+
+ defSolveWithParameters(self,search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Solves the current routing model with the given parameters. If 'solutions'
+ is specified, it will contain the k best solutions found during the search
+ (from worst to best, including the one returned by this method), where k
+ corresponds to the 'number_of_solutions_to_collect' in
+ 'search_parameters'. Note that the Assignment returned by the method and
+ the ones in solutions are owned by the underlying solver and should not be
+ deleted.
+ """
+ return_pywrapcp.RoutingModel_SolveWithParameters(self,search_parameters,solutions)
+
+ defSolveFromAssignmentWithParameters(self,assignment:"Assignment",search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Same as above, except that if assignment is not null, it will be used as
+ the initial solution.
+ """
+ return_pywrapcp.RoutingModel_SolveFromAssignmentWithParameters(self,assignment,search_parameters,solutions)
+
+ defSolveFromAssignmentsWithParameters(self,assignments:"std::vector< operations_research::Assignment const * > const &",search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Same as above but will try all assignments in order as first solutions
+ until one succeeds.
+ """
+ return_pywrapcp.RoutingModel_SolveFromAssignmentsWithParameters(self,assignments,search_parameters,solutions)
+
+ defSetAssignmentFromOtherModelAssignment(self,target_assignment:"Assignment",source_model:"RoutingModel",source_assignment:"Assignment")->"void":
+ r"""
+ Given a "source_model" and its "source_assignment", resets
+ "target_assignment" with the IntVar variables (nexts_, and vehicle_vars_
+ if costs aren't homogeneous across vehicles) of "this" model, with the
+ values set according to those in "other_assignment".
+ The objective_element of target_assignment is set to this->cost_.
+ """
+ return_pywrapcp.RoutingModel_SetAssignmentFromOtherModelAssignment(self,target_assignment,source_model,source_assignment)
+
+ defComputeLowerBound(self)->"int64_t":
+ r"""
+ Computes a lower bound to the routing problem solving a linear assignment
+ problem. The routing model must be closed before calling this method.
+ Note that problems with node disjunction constraints (including optional
+ nodes) and non-homogenous costs are not supported (the method returns 0 in
+ these cases).
+ """
+ return_pywrapcp.RoutingModel_ComputeLowerBound(self)
+
+ defstatus(self)->"operations_research::RoutingModel::Status":
+ r""" Returns the current status of the routing model."""
+ return_pywrapcp.RoutingModel_status(self)
+
+ defApplyLocks(self,locks:"std::vector< int64_t > const &")->"operations_research::IntVar *":
+ r"""
+ Applies a lock chain to the next search. 'locks' represents an ordered
+ vector of nodes representing a partial route which will be fixed during
+ the next search; it will constrain next variables such that:
+ next[locks[i]] == locks[i+1].
+
+ Returns the next variable at the end of the locked chain; this variable is
+ not locked. An assignment containing the locks can be obtained by calling
+ PreAssignment().
+ """
+ return_pywrapcp.RoutingModel_ApplyLocks(self,locks)
+
+ defApplyLocksToAllVehicles(self,locks:"std::vector< std::vector< int64_t > > const &",close_routes:"bool")->"bool":
+ r"""
+ Applies lock chains to all vehicles to the next search, such that locks[p]
+ is the lock chain for route p. Returns false if the locks do not contain
+ valid routes; expects that the routes do not contain the depots,
+ i.e. there are empty vectors in place of empty routes.
+ If close_routes is set to true, adds the end nodes to the route of each
+ vehicle and deactivates other nodes.
+ An assignment containing the locks can be obtained by calling
+ PreAssignment().
+ """
+ return_pywrapcp.RoutingModel_ApplyLocksToAllVehicles(self,locks,close_routes)
+
+ defPreAssignment(self)->"operations_research::Assignment const *const":
+ r"""
+ Returns an assignment used to fix some of the variables of the problem.
+ In practice, this assignment locks partial routes of the problem. This
+ can be used in the context of locking the parts of the routes which have
+ already been driven in online routing problems.
+ """
+ return_pywrapcp.RoutingModel_PreAssignment(self)
+
+ defMutablePreAssignment(self)->"operations_research::Assignment *":
+ return_pywrapcp.RoutingModel_MutablePreAssignment(self)
+
+ defWriteAssignment(self,file_name:"std::string const &")->"bool":
+ r"""
+ Writes the current solution to a file containing an AssignmentProto.
+ Returns false if the file cannot be opened or if there is no current
+ solution.
+ """
+ return_pywrapcp.RoutingModel_WriteAssignment(self,file_name)
+
+ defReadAssignment(self,file_name:"std::string const &")->"operations_research::Assignment *":
+ r"""
+ Reads an assignment from a file and returns the current solution.
+ Returns nullptr if the file cannot be opened or if the assignment is not
+ valid.
+ """
+ return_pywrapcp.RoutingModel_ReadAssignment(self,file_name)
+
+ defRestoreAssignment(self,solution:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Restores an assignment as a solution in the routing model and returns the
+ new solution. Returns nullptr if the assignment is not valid.
+ """
+ return_pywrapcp.RoutingModel_RestoreAssignment(self,solution)
+
+ defReadAssignmentFromRoutes(self,routes:"std::vector< std::vector< int64_t > > const &",ignore_inactive_indices:"bool")->"operations_research::Assignment *":
+ r"""
+ Restores the routes as the current solution. Returns nullptr if the
+ solution cannot be restored (routes do not contain a valid solution). Note
+ that calling this method will run the solver to assign values to the
+ dimension variables; this may take considerable amount of time, especially
+ when using dimensions with slack.
+ """
+ return_pywrapcp.RoutingModel_ReadAssignmentFromRoutes(self,routes,ignore_inactive_indices)
+
+ defRoutesToAssignment(self,routes:"std::vector< std::vector< int64_t > > const &",ignore_inactive_indices:"bool",close_routes:"bool",assignment:"Assignment")->"bool":
+ r"""
+ Fills an assignment from a specification of the routes of the
+ vehicles. The routes are specified as lists of variable indices that
+ appear on the routes of the vehicles. The indices of the outer vector in
+ 'routes' correspond to vehicles IDs, the inner vector contains the
+ variable indices on the routes for the given vehicle. The inner vectors
+ must not contain the start and end indices, as these are determined by the
+ routing model. Sets the value of NextVars in the assignment, adding the
+ variables to the assignment if necessary. The method does not touch other
+ variables in the assignment. The method can only be called after the model
+ is closed. With ignore_inactive_indices set to false, this method will
+ fail (return nullptr) in case some of the route contain indices that are
+ deactivated in the model; when set to true, these indices will be
+ skipped. Returns true if routes were successfully
+ loaded. However, such assignment still might not be a valid
+ solution to the routing problem due to more complex constraints;
+ it is advisible to call solver()->CheckSolution() afterwards.
+ """
+ return_pywrapcp.RoutingModel_RoutesToAssignment(self,routes,ignore_inactive_indices,close_routes,assignment)
+
+ defAssignmentToRoutes(self,assignment:"Assignment",routes:"std::vector< std::vector< int64_t > > *const")->"void":
+ r"""
+ Converts the solution in the given assignment to routes for all vehicles.
+ Expects that assignment contains a valid solution (i.e. routes for all
+ vehicles end with an end index for that vehicle).
+ """
+ return_pywrapcp.RoutingModel_AssignmentToRoutes(self,assignment,routes)
+
+ defCompactAssignment(self,assignment:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Converts the solution in the given assignment to routes for all vehicles.
+ If the returned vector is route_indices, route_indices[i][j] is the index
+ for jth location visited on route i. Note that contrary to
+ AssignmentToRoutes, the vectors do include start and end locations.
+ Returns a compacted version of the given assignment, in which all vehicles
+ with id lower or equal to some N have non-empty routes, and all vehicles
+ with id greater than N have empty routes. Does not take ownership of the
+ returned object.
+ If found, the cost of the compact assignment is the same as in the
+ original assignment and it preserves the values of 'active' variables.
+ Returns nullptr if a compact assignment was not found.
+ This method only works in homogenous mode, and it only swaps equivalent
+ vehicles (vehicles with the same start and end nodes). When creating the
+ compact assignment, the empty plan is replaced by the route assigned to
+ the compatible vehicle with the highest id. Note that with more complex
+ constraints on vehicle variables, this method might fail even if a compact
+ solution exists.
+ This method changes the vehicle and dimension variables as necessary.
+ While compacting the solution, only basic checks on vehicle variables are
+ performed; if one of these checks fails no attempts to repair it are made
+ (instead, the method returns nullptr).
+ """
+ return_pywrapcp.RoutingModel_CompactAssignment(self,assignment)
+
+ defCompactAndCheckAssignment(self,assignment:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Same as CompactAssignment() but also checks the validity of the final
+ compact solution; if it is not valid, no attempts to repair it are made
+ (instead, the method returns nullptr).
+ """
+ return_pywrapcp.RoutingModel_CompactAndCheckAssignment(self,assignment)
+
+ defAddToAssignment(self,var:"IntVar")->"void":
+ r""" Adds an extra variable to the vehicle routing assignment."""
+ return_pywrapcp.RoutingModel_AddToAssignment(self,var)
+
+ defAddIntervalToAssignment(self,interval:"IntervalVar")->"void":
+ return_pywrapcp.RoutingModel_AddIntervalToAssignment(self,interval)
+
+ defPackCumulsOfOptimizerDimensionsFromAssignment(self,original_assignment:"Assignment",duration_limit:"absl::Duration")->"operations_research::Assignment const *":
+ r"""
+ For every dimension in the model with an optimizer in
+ local/global_dimension_optimizers_, this method tries to pack the cumul
+ values of the dimension, such that:
+ - The cumul costs (span costs, soft lower and upper bound costs, etc) are
+ minimized.
+ - The cumuls of the ends of the routes are minimized for this given
+ minimal cumul cost.
+ - Given these minimal end cumuls, the route start cumuls are maximized.
+ Returns the assignment resulting from allocating these packed cumuls with
+ the solver, and nullptr if these cumuls could not be set by the solver.
+ """
+ return_pywrapcp.RoutingModel_PackCumulsOfOptimizerDimensionsFromAssignment(self,original_assignment,duration_limit)
+
+ defAddLocalSearchFilter(self,filter:"LocalSearchFilter")->"void":
+ r"""
+ Adds a custom local search filter to the list of filters used to speed up
+ local search by pruning unfeasible variable assignments.
+ Calling this method after the routing model has been closed (CloseModel()
+ or Solve() has been called) has no effect.
+ The routing model does not take ownership of the filter.
+ """
+ return_pywrapcp.RoutingModel_AddLocalSearchFilter(self,filter)
+
+ defStart(self,vehicle:"int")->"int64_t":
+ r"""
+ Model inspection.
+ Returns the variable index of the starting node of a vehicle route.
+ """
+ return_pywrapcp.RoutingModel_Start(self,vehicle)
+
+ defEnd(self,vehicle:"int")->"int64_t":
+ r""" Returns the variable index of the ending node of a vehicle route."""
+ return_pywrapcp.RoutingModel_End(self,vehicle)
+
+ defIsStart(self,index:"int64_t")->"bool":
+ r""" Returns true if 'index' represents the first node of a route."""
+ return_pywrapcp.RoutingModel_IsStart(self,index)
+
+ defIsEnd(self,index:"int64_t")->"bool":
+ r""" Returns true if 'index' represents the last node of a route."""
+ return_pywrapcp.RoutingModel_IsEnd(self,index)
+
+ defVehicleIndex(self,index:"int64_t")->"int":
+ r"""
+ Returns the vehicle of the given start/end index, and -1 if the given
+ index is not a vehicle start/end.
+ """
+ return_pywrapcp.RoutingModel_VehicleIndex(self,index)
+
+ defNext(self,assignment:"Assignment",index:"int64_t")->"int64_t":
+ r"""
+ Assignment inspection
+ Returns the variable index of the node directly after the node
+ corresponding to 'index' in 'assignment'.
+ """
+ return_pywrapcp.RoutingModel_Next(self,assignment,index)
+
+ defIsVehicleUsed(self,assignment:"Assignment",vehicle:"int")->"bool":
+ r""" Returns true if the route of 'vehicle' is non empty in 'assignment'."""
+ return_pywrapcp.RoutingModel_IsVehicleUsed(self,assignment,vehicle)
+
+ defNextVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Returns the next variable of the node corresponding to index. Note that
+ NextVar(index) == index is equivalent to ActiveVar(index) == 0.
+ """
+ return_pywrapcp.RoutingModel_NextVar(self,index)
+
+ defActiveVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r""" Returns the active variable of the node corresponding to index."""
+ return_pywrapcp.RoutingModel_ActiveVar(self,index)
+
+ defActiveVehicleVar(self,vehicle:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the active variable of the vehicle. It will be equal to 1 iff the
+ route of the vehicle is not empty, 0 otherwise.
+ """
+ return_pywrapcp.RoutingModel_ActiveVehicleVar(self,vehicle)
+
+ defVehicleRouteConsideredVar(self,vehicle:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the variable specifying whether or not the given vehicle route is
+ considered for costs and constraints. It will be equal to 1 iff the route
+ of the vehicle is not empty OR vehicle_used_when_empty_[vehicle] is true.
+ """
+ return_pywrapcp.RoutingModel_VehicleRouteConsideredVar(self,vehicle)
+
+ defVehicleVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Returns the vehicle variable of the node corresponding to index. Note that
+ VehicleVar(index) == -1 is equivalent to ActiveVar(index) == 0.
+ """
+ return_pywrapcp.RoutingModel_VehicleVar(self,index)
+
+ defResourceVar(self,vehicle:"int",resource_group:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the resource variable for the given vehicle index in the given
+ resource group. If a vehicle doesn't require a resource from the
+ corresponding resource group, then ResourceVar(v, r_g) == -1.
+ """
+ return_pywrapcp.RoutingModel_ResourceVar(self,vehicle,resource_group)
+
+ defCostVar(self)->"operations_research::IntVar *":
+ r""" Returns the global cost variable which is being minimized."""
+ return_pywrapcp.RoutingModel_CostVar(self)
+
+ defGetArcCostForVehicle(self,from_index:"int64_t",to_index:"int64_t",vehicle:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the transit arc between two nodes for a given vehicle.
+ Input are variable indices of node. This returns 0 if vehicle < 0.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForVehicle(self,from_index,to_index,vehicle)
+
+ defCostsAreHomogeneousAcrossVehicles(self)->"bool":
+ r""" Whether costs are homogeneous across all vehicles."""
+ return_pywrapcp.RoutingModel_CostsAreHomogeneousAcrossVehicles(self)
+
+ defGetHomogeneousCost(self,from_index:"int64_t",to_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the segment between two nodes supposing all vehicle
+ costs are the same (returns the cost for the first vehicle otherwise).
+ """
+ return_pywrapcp.RoutingModel_GetHomogeneousCost(self,from_index,to_index)
+
+ defGetArcCostForFirstSolution(self,from_index:"int64_t",to_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the arc in the context of the first solution strategy.
+ This is typically a simplification of the actual cost; see the .cc.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForFirstSolution(self,from_index,to_index)
+
+ defGetArcCostForClass(self,from_index:"int64_t",to_index:"int64_t",cost_class_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the segment between two nodes for a given cost
+ class. Input are variable indices of nodes and the cost class.
+ Unlike GetArcCostForVehicle(), if cost_class is kNoCost, then the
+ returned cost won't necessarily be zero: only some of the components
+ of the cost that depend on the cost class will be omited. See the code
+ for details.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForClass(self,from_index,to_index,cost_class_index)
+
+ defGetCostClassIndexOfVehicle(self,vehicle:"int64_t")->"operations_research::RoutingModel::CostClassIndex":
+ r""" Get the cost class index of the given vehicle."""
+ return_pywrapcp.RoutingModel_GetCostClassIndexOfVehicle(self,vehicle)
+
+ defHasVehicleWithCostClassIndex(self,cost_class_index:"operations_research::RoutingModel::CostClassIndex")->"bool":
+ r"""
+ Returns true iff the model contains a vehicle with the given
+ cost_class_index.
+ """
+ return_pywrapcp.RoutingModel_HasVehicleWithCostClassIndex(self,cost_class_index)
+
+ defGetCostClassesCount(self)->"int":
+ r""" Returns the number of different cost classes in the model."""
+ return_pywrapcp.RoutingModel_GetCostClassesCount(self)
+
+ defGetNonZeroCostClassesCount(self)->"int":
+ r""" Ditto, minus the 'always zero', built-in cost class."""
+ return_pywrapcp.RoutingModel_GetNonZeroCostClassesCount(self)
+
+ defGetVehicleClassIndexOfVehicle(self,vehicle:"int64_t")->"operations_research::RoutingModel::VehicleClassIndex":
+ return_pywrapcp.RoutingModel_GetVehicleClassIndexOfVehicle(self,vehicle)
+
+ defGetVehicleOfClass(self,vehicle_class:"operations_research::RoutingModel::VehicleClassIndex")->"int":
+ r"""
+ Returns a vehicle of the given vehicle class, and -1 if there are no
+ vehicles for this class.
+ """
+ return_pywrapcp.RoutingModel_GetVehicleOfClass(self,vehicle_class)
+
+ defGetVehicleClassesCount(self)->"int":
+ r""" Returns the number of different vehicle classes in the model."""
+ return_pywrapcp.RoutingModel_GetVehicleClassesCount(self)
+
+ defGetSameVehicleIndicesOfIndex(self,node:"int")->"std::vector< int > const &":
+ r""" Returns variable indices of nodes constrained to be on the same route."""
+ return_pywrapcp.RoutingModel_GetSameVehicleIndicesOfIndex(self,node)
+
+ defGetVehicleTypeContainer(self)->"operations_research::RoutingModel::VehicleTypeContainer const &":
+ return_pywrapcp.RoutingModel_GetVehicleTypeContainer(self)
+
+ defArcIsMoreConstrainedThanArc(self,_from:"int64_t",to1:"int64_t",to2:"int64_t")->"bool":
+ r"""
+ Returns whether the arc from->to1 is more constrained than from->to2,
+ taking into account, in order:
+ - whether the destination node isn't an end node
+ - whether the destination node is mandatory
+ - whether the destination node is bound to the same vehicle as the source
+ - the "primary constrained" dimension (see SetPrimaryConstrainedDimension)
+ It then breaks ties using, in order:
+ - the arc cost (taking unperformed penalties into account)
+ - the size of the vehicle vars of "to1" and "to2" (lowest size wins)
+ - the value: the lowest value of the indices to1 and to2 wins.
+ See the .cc for details.
+ The more constrained arc is typically preferable when building a
+ first solution. This method is intended to be used as a callback for the
+ BestValueByComparisonSelector value selector.
+ Args:
+ from: the variable index of the source node
+ to1: the variable index of the first candidate destination node.
+ to2: the variable index of the second candidate destination node.
+ """
+ return_pywrapcp.RoutingModel_ArcIsMoreConstrainedThanArc(self,_from,to1,to2)
+
+ defDebugOutputAssignment(self,solution_assignment:"Assignment",dimension_to_print:"std::string const &")->"std::string":
+ r"""
+ Print some debugging information about an assignment, including the
+ feasible intervals of the CumulVar for dimension "dimension_to_print"
+ at each step of the routes.
+ If "dimension_to_print" is omitted, all dimensions will be printed.
+ """
+ return_pywrapcp.RoutingModel_DebugOutputAssignment(self,solution_assignment,dimension_to_print)
+
+ defsolver(self)->"operations_research::Solver *":
+ r"""
+ Returns a vector cumul_bounds, for which cumul_bounds[i][j] is a pair
+ containing the minimum and maximum of the CumulVar of the jth node on
+ route i.
+ - cumul_bounds[i][j].first is the minimum.
+ - cumul_bounds[i][j].second is the maximum.
+ Returns the underlying constraint solver. Can be used to add extra
+ constraints and/or modify search algorithms.
+ """
+ return_pywrapcp.RoutingModel_solver(self)
+
+ defCheckLimit(self)->"bool":
+ r""" Returns true if the search limit has been crossed."""
+ return_pywrapcp.RoutingModel_CheckLimit(self)
+
+ defRemainingTime(self)->"absl::Duration":
+ r""" Returns the time left in the search limit."""
+ return_pywrapcp.RoutingModel_RemainingTime(self)
+
+ defnodes(self)->"int":
+ r"""
+ Sizes and indices
+ Returns the number of nodes in the model.
+ """
+ return_pywrapcp.RoutingModel_nodes(self)
+
+ defvehicles(self)->"int":
+ r""" Returns the number of vehicle routes in the model."""
+ return_pywrapcp.RoutingModel_vehicles(self)
+
+ defSize(self)->"int64_t":
+ r""" Returns the number of next variables in the model."""
+ return_pywrapcp.RoutingModel_Size(self)
+
+ defGetNumberOfDecisionsInFirstSolution(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"int64_t":
+ r"""
+ Returns statistics on first solution search, number of decisions sent to
+ filters, number of decisions rejected by filters.
+ """
+ return_pywrapcp.RoutingModel_GetNumberOfDecisionsInFirstSolution(self,search_parameters)
+
+ defGetNumberOfRejectsInFirstSolution(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"int64_t":
+ return_pywrapcp.RoutingModel_GetNumberOfRejectsInFirstSolution(self,search_parameters)
+
+ defGetAutomaticFirstSolutionStrategy(self)->"operations_research::FirstSolutionStrategy::Value":
+ r""" Returns the automatic first solution strategy selected."""
+ return_pywrapcp.RoutingModel_GetAutomaticFirstSolutionStrategy(self)
+
+ defIsMatchingModel(self)->"bool":
+ r""" Returns true if a vehicle/node matching problem is detected."""
+ return_pywrapcp.RoutingModel_IsMatchingModel(self)
+
+ defMakeGuidedSlackFinalizer(self,dimension:"RoutingDimension",initializer:"std::function< int64_t (int64_t) >")->"operations_research::DecisionBuilder *":
+ r"""
+ The next few members are in the public section only for testing purposes.
+
+ MakeGuidedSlackFinalizer creates a DecisionBuilder for the slacks of a
+ dimension using a callback to choose which values to start with.
+ The finalizer works only when all next variables in the model have
+ been fixed. It has the following two characteristics:
+ 1. It follows the routes defined by the nexts variables when choosing a
+ variable to make a decision on.
+ 2. When it comes to choose a value for the slack of node i, the decision
+ builder first calls the callback with argument i, and supposingly the
+ returned value is x it creates decisions slack[i] = x, slack[i] = x +
+ 1, slack[i] = x - 1, slack[i] = x + 2, etc.
+ """
+ return_pywrapcp.RoutingModel_MakeGuidedSlackFinalizer(self,dimension,initializer)
+
+ defMakeSelfDependentDimensionFinalizer(self,dimension:"RoutingDimension")->"operations_research::DecisionBuilder *":
+ r"""
+ MakeSelfDependentDimensionFinalizer is a finalizer for the slacks of a
+ self-dependent dimension. It makes an extensive use of the caches of the
+ state dependent transits.
+ In detail, MakeSelfDependentDimensionFinalizer returns a composition of a
+ local search decision builder with a greedy descent operator for the cumul
+ of the start of each route and a guided slack finalizer. Provided there
+ are no time windows and the maximum slacks are large enough, once the
+ cumul of the start of route is fixed, the guided finalizer can find
+ optimal values of the slacks for the rest of the route in time
+ proportional to the length of the route. Therefore the composed finalizer
+ generally works in time O(log(t)*n*m), where t is the latest possible
+ departute time, n is the number of nodes in the network and m is the
+ number of vehicles.
+ """
+ return_pywrapcp.RoutingModel_MakeSelfDependentDimensionFinalizer(self,dimension)
+
defAddDimension(self,evaluator_index:"int",slack_max:"int64_t",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"bool":
+ r"""
+ Model creation
+ Methods to add dimensions to routes; dimensions represent quantities
+ accumulated at nodes along the routes. They represent quantities such as
+ weights or volumes carried along the route, or distance or times.
+ Quantities at a node are represented by "cumul" variables and the increase
+ or decrease of quantities between nodes are represented by "transit"
+ variables. These variables are linked as follows:
+ if j == next(i), cumul(j) = cumul(i) + transit(i) + slack(i)
+ where slack is a positive slack variable (can represent waiting times for
+ a time dimension).
+ Setting the value of fix_start_cumul_to_zero to true will force the
+ "cumul" variable of the start node of all vehicles to be equal to 0.
+ Creates a dimension where the transit variable is constrained to be
+ equal to evaluator(i, next(i)); 'slack_max' is the upper bound of the
+ slack variable and 'capacity' is the upper bound of the cumul variables.
+ 'name' is the name used to reference the dimension; this name is used to
+ get cumul and transit variables from the routing model.
+ Returns false if a dimension with the same name has already been created
+ (and doesn't create the new dimension).
+ Takes ownership of the callback 'evaluator'.
+ """
+ return_pywrapcp.RoutingModel_AddDimension(self,evaluator_index,slack_max,capacity,fix_start_cumul_to_zero,name)
+
+
+
+
+
Model creation
+Methods to add dimensions to routes; dimensions represent quantities
+accumulated at nodes along the routes. They represent quantities such as
+weights or volumes carried along the route, or distance or times.
+Quantities at a node are represented by "cumul" variables and the increase
+or decrease of quantities between nodes are represented by "transit"
+variables. These variables are linked as follows:
+if j == next(i), cumul(j) = cumul(i) + transit(i) + slack(i)
+where slack is a positive slack variable (can represent waiting times for
+a time dimension).
+Setting the value of fix_start_cumul_to_zero to true will force the
+"cumul" variable of the start node of all vehicles to be equal to 0.
+Creates a dimension where the transit variable is constrained to be
+equal to evaluator(i, next(i)); 'slack_max' is the upper bound of the
+slack variable and 'capacity' is the upper bound of the cumul variables.
+'name' is the name used to reference the dimension; this name is used to
+get cumul and transit variables from the routing model.
+Returns false if a dimension with the same name has already been created
+(and doesn't create the new dimension).
+Takes ownership of the callback 'evaluator'.
defAddConstantDimensionWithSlack(self,value:"int64_t",capacity:"int64_t",slack_max:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'value'; 'capacity' is the upper bound of the cumul variables.
+ 'name' is the name used to reference the dimension; this name is used to
+ get cumul and transit variables from the routing model.
+ Returns a pair consisting of an index to the registered unary transit
+ callback and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddConstantDimensionWithSlack(self,value,capacity,slack_max,fix_start_cumul_to_zero,name)
+
+
+
+
+
Creates a dimension where the transit variable is constrained to be
+equal to 'value'; 'capacity' is the upper bound of the cumul variables.
+'name' is the name used to reference the dimension; this name is used to
+get cumul and transit variables from the routing model.
+Returns a pair consisting of an index to the registered unary transit
+callback and a bool denoting whether the dimension has been created.
+It is false if a dimension with the same name has already been created
+(and doesn't create the new dimension but still register a new callback).
defAddVectorDimension(self,values:"std::vector< int64_t >",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'values[i]' for node i; 'capacity' is the upper bound of
+ the cumul variables. 'name' is the name used to reference the dimension;
+ this name is used to get cumul and transit variables from the routing
+ model.
+ Returns a pair consisting of an index to the registered unary transit
+ callback and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddVectorDimension(self,values,capacity,fix_start_cumul_to_zero,name)
+
+
+
+
+
Creates a dimension where the transit variable is constrained to be
+equal to 'values[i]' for node i; 'capacity' is the upper bound of
+the cumul variables. 'name' is the name used to reference the dimension;
+this name is used to get cumul and transit variables from the routing
+model.
+Returns a pair consisting of an index to the registered unary transit
+callback and a bool denoting whether the dimension has been created.
+It is false if a dimension with the same name has already been created
+(and doesn't create the new dimension but still register a new callback).
defAddMatrixDimension(self,values:"std::vector< std::vector< int64_t > >",capacity:"int64_t",fix_start_cumul_to_zero:"bool",name:"std::string const &")->"std::pair< int,bool >":
+ r"""
+ Creates a dimension where the transit variable is constrained to be
+ equal to 'values[i][next(i)]' for node i; 'capacity' is the upper bound of
+ the cumul variables. 'name' is the name used to reference the dimension;
+ this name is used to get cumul and transit variables from the routing
+ model.
+ Returns a pair consisting of an index to the registered transit callback
+ and a bool denoting whether the dimension has been created.
+ It is false if a dimension with the same name has already been created
+ (and doesn't create the new dimension but still register a new callback).
+ """
+ return_pywrapcp.RoutingModel_AddMatrixDimension(self,values,capacity,fix_start_cumul_to_zero,name)
+
+
+
+
+
Creates a dimension where the transit variable is constrained to be
+equal to 'values[i][next(i)]' for node i; 'capacity' is the upper bound of
+the cumul variables. 'name' is the name used to reference the dimension;
+this name is used to get cumul and transit variables from the routing
+model.
+Returns a pair consisting of an index to the registered transit callback
+and a bool denoting whether the dimension has been created.
+It is false if a dimension with the same name has already been created
+(and doesn't create the new dimension but still register a new callback).
defMakePathSpansAndTotalSlacks(self,dimension:"RoutingDimension",spans:"std::vector< operations_research::IntVar * >",total_slacks:"std::vector< operations_research::IntVar * >")->"operations_research::Constraint *":
+ r"""
+ For every vehicle of the routing model:
+ - if total_slacks[vehicle] is not nullptr, constrains it to be the sum of
+ slacks on that vehicle, that is,
+ dimension->CumulVar(end) - dimension->CumulVar(start) -
+ sum_{node in path of vehicle} dimension->FixedTransitVar(node).
+ - if spans[vehicle] is not nullptr, constrains it to be
+ dimension->CumulVar(end) - dimension->CumulVar(start)
+ This does stronger propagation than a decomposition, and takes breaks into
+ account.
+ """
+ return_pywrapcp.RoutingModel_MakePathSpansAndTotalSlacks(self,dimension,spans,total_slacks)
+
+
+
+
+
For every vehicle of the routing model:
+
+
+
if total_slacks[vehicle] is not nullptr, constrains it to be the sum of
+slacks on that vehicle, that is,
+dimension->CumulVar(end) - dimension->CumulVar(start) -
+sum_{node in path of vehicle} dimension->FixedTransitVar(node).
+
if spans[vehicle] is not nullptr, constrains it to be
+dimension->CumulVar(end) - dimension->CumulVar(start)
+This does stronger propagation than a decomposition, and takes breaks into
+account.
defGetAllDimensionNames(self)->"std::vector< std::string >":
+ r""" Outputs the names of all dimensions added to the routing engine."""
+ return_pywrapcp.RoutingModel_GetAllDimensionNames(self)
+
+
+
+
+
Outputs the names of all dimensions added to the routing engine.
defGetGlobalDimensionCumulOptimizers(self)->"std::vector< std::unique_ptr< operations_research::GlobalDimensionCumulOptimizer > > const &":
+ r"""
+ Returns [global|local]_dimension_optimizers_, which are empty if the model
+ has not been closed.
+ """
+ return_pywrapcp.RoutingModel_GetGlobalDimensionCumulOptimizers(self)
+
+
+
+
+
Returns [global|local]_dimension_optimizers_, which are empty if the model
+has not been closed.
defGetMutableGlobalCumulOptimizer(self,dimension:"RoutingDimension")->"operations_research::GlobalDimensionCumulOptimizer *":
+ r"""
+ Returns the global/local dimension cumul optimizer for a given dimension,
+ or nullptr if there is none.
+ """
+ return_pywrapcp.RoutingModel_GetMutableGlobalCumulOptimizer(self,dimension)
+
+
+
+
+
Returns the global/local dimension cumul optimizer for a given dimension,
+or nullptr if there is none.
defHasDimension(self,dimension_name:"std::string const &")->"bool":
+ r""" Returns true if a dimension exists for a given dimension name."""
+ return_pywrapcp.RoutingModel_HasDimension(self,dimension_name)
+
+
+
+
+
Returns true if a dimension exists for a given dimension name.
defGetDimensionOrDie(self,dimension_name:"std::string const &")->"operations_research::RoutingDimension const &":
+ r""" Returns a dimension from its name. Dies if the dimension does not exist."""
+ return_pywrapcp.RoutingModel_GetDimensionOrDie(self,dimension_name)
+
+
+
+
+
Returns a dimension from its name. Dies if the dimension does not exist.
defGetMutableDimension(self,dimension_name:"std::string const &")->"operations_research::RoutingDimension *":
+ r"""
+ Returns a dimension from its name. Returns nullptr if the dimension does
+ not exist.
+ """
+ return_pywrapcp.RoutingModel_GetMutableDimension(self,dimension_name)
+
+
+
+
+
Returns a dimension from its name. Returns nullptr if the dimension does
+not exist.
defSetPrimaryConstrainedDimension(self,dimension_name:"std::string const &")->"void":
+ r"""
+ Set the given dimension as "primary constrained". As of August 2013, this
+ is only used by ArcIsMoreConstrainedThanArc().
+ "dimension" must be the name of an existing dimension, or be empty, in
+ which case there will not be a primary dimension after this call.
+ """
+ return_pywrapcp.RoutingModel_SetPrimaryConstrainedDimension(self,dimension_name)
+
+
+
+
+
Set the given dimension as "primary constrained". As of August 2013, this
+is only used by ArcIsMoreConstrainedThanArc().
+"dimension" must be the name of an existing dimension, or be empty, in
+which case there will not be a primary dimension after this call.
defGetPrimaryConstrainedDimension(self)->"std::string const &":
+ r""" Get the primary constrained dimension, or an empty string if it is unset."""
+ return_pywrapcp.RoutingModel_GetPrimaryConstrainedDimension(self)
+
+
+
+
+
Get the primary constrained dimension, or an empty string if it is unset.
defAddResourceGroup(self)->"int":
+ r"""
+ Adds a resource group to the routing model. Returns its index in
+ resource_groups_.
+ """
+ return_pywrapcp.RoutingModel_AddResourceGroup(self)
+
+
+
+
+
Adds a resource group to the routing model. Returns its index in
+resource_groups_.
defGetDimensionResourceGroupIndices(self,dimension:"RoutingDimension")->"std::vector< int > const &":
+ r"""
+ Returns the indices of resource groups for this dimension. This method can
+ only be called after the model has been closed.
+ """
+ return_pywrapcp.RoutingModel_GetDimensionResourceGroupIndices(self,dimension)
+
+
+
+
+
Returns the indices of resource groups for this dimension. This method can
+only be called after the model has been closed.
defGetDimensionResourceGroupIndex(self,dimension:"RoutingDimension")->"int":
+ r"""
+ Returns the index of the resource group attached to the dimension.
+ DCHECKS that there's exactly one resource group for this dimension.
+ """
+ return_pywrapcp.RoutingModel_GetDimensionResourceGroupIndex(self,dimension)
+
+
+
+
+
Returns the index of the resource group attached to the dimension.
+DCHECKS that there's exactly one resource group for this dimension.
defAddDisjunction(self,*args)->"operations_research::RoutingModel::DisjunctionIndex":
+ r"""
+ Adds a disjunction constraint on the indices: exactly 'max_cardinality' of
+ the indices are active. Start and end indices of any vehicle cannot be
+ part of a disjunction.
+
+ If a penalty is given, at most 'max_cardinality' of the indices can be
+ active, and if less are active, 'penalty' is payed per inactive index.
+ This is equivalent to adding the constraint:
+ p + Sum(i)active[i] == max_cardinality
+ where p is an integer variable, and the following cost to the cost
+ function:
+ p * penalty.
+ 'penalty' must be positive to make the disjunction optional; a negative
+ penalty will force 'max_cardinality' indices of the disjunction to be
+ performed, and therefore p == 0.
+ Note: passing a vector with a single index will model an optional index
+ with a penalty cost if it is not visited.
+ """
+ return_pywrapcp.RoutingModel_AddDisjunction(self,*args)
+
+
+
+
+
Adds a disjunction constraint on the indices: exactly 'max_cardinality' of
+the indices are active. Start and end indices of any vehicle cannot be
+part of a disjunction.
+
+
If a penalty is given, at most 'max_cardinality' of the indices can be
+active, and if less are active, 'penalty' is payed per inactive index.
+
+
This is equivalent to adding the constraint
+
+
+
p + Sum(i)active[i] == max_cardinality
+
+
+
where p is an integer variable, and the following cost to the cost
+function:
+ p * penalty.
+'penalty' must be positive to make the disjunction optional; a negative
+penalty will force 'max_cardinality' indices of the disjunction to be
+performed, and therefore p == 0.
+Note: passing a vector with a single index will model an optional index
+with a penalty cost if it is not visited.
defGetDisjunctionIndices(self,index:"int64_t")->"std::vector< operations_research::RoutingModel::DisjunctionIndex > const &":
+ r""" Returns the indices of the disjunctions to which an index belongs."""
+ return_pywrapcp.RoutingModel_GetDisjunctionIndices(self,index)
+
+
+
+
+
Returns the indices of the disjunctions to which an index belongs.
defGetDisjunctionPenalty(self,index:"operations_research::RoutingModel::DisjunctionIndex")->"int64_t":
+ r""" Returns the penalty of the node disjunction of index 'index'."""
+ return_pywrapcp.RoutingModel_GetDisjunctionPenalty(self,index)
+
+
+
+
+
Returns the penalty of the node disjunction of index 'index'.
defGetDisjunctionMaxCardinality(self,index:"operations_research::RoutingModel::DisjunctionIndex")->"int64_t":
+ r"""
+ Returns the maximum number of possible active nodes of the node
+ disjunction of index 'index'.
+ """
+ return_pywrapcp.RoutingModel_GetDisjunctionMaxCardinality(self,index)
+
+
+
+
+
Returns the maximum number of possible active nodes of the node
+disjunction of index 'index'.
defGetNumberOfDisjunctions(self)->"int":
+ r""" Returns the number of node disjunctions in the model."""
+ return_pywrapcp.RoutingModel_GetNumberOfDisjunctions(self)
+
+
+
+
+
Returns the number of node disjunctions in the model.
defHasMandatoryDisjunctions(self)->"bool":
+ r"""
+ Returns true if the model contains mandatory disjunctions (ones with
+ kNoPenalty as penalty).
+ """
+ return_pywrapcp.RoutingModel_HasMandatoryDisjunctions(self)
+
+
+
+
+
Returns true if the model contains mandatory disjunctions (ones with
+kNoPenalty as penalty).
defHasMaxCardinalityConstrainedDisjunctions(self)->"bool":
+ r"""
+ Returns true if the model contains at least one disjunction which is
+ constrained by its max_cardinality.
+ """
+ return_pywrapcp.RoutingModel_HasMaxCardinalityConstrainedDisjunctions(self)
+
+
+
+
+
Returns true if the model contains at least one disjunction which is
+constrained by its max_cardinality.
defGetPerfectBinaryDisjunctions(self)->"std::vector< std::pair< int64_t,int64_t > >":
+ r"""
+ Returns the list of all perfect binary disjunctions, as pairs of variable
+ indices: a disjunction is "perfect" when its variables do not appear in
+ any other disjunction. Each pair is sorted (lowest variable index first),
+ and the output vector is also sorted (lowest pairs first).
+ """
+ return_pywrapcp.RoutingModel_GetPerfectBinaryDisjunctions(self)
+
+
+
+
+
Returns the list of all perfect binary disjunctions, as pairs of variable
+indices: a disjunction is "perfect" when its variables do not appear in
+any other disjunction. Each pair is sorted (lowest variable index first),
+and the output vector is also sorted (lowest pairs first).
defIgnoreDisjunctionsAlreadyForcedToZero(self)->"void":
+ r"""
+ SPECIAL: Makes the solver ignore all the disjunctions whose active
+ variables are all trivially zero (i.e. Max() == 0), by setting their
+ max_cardinality to 0.
+ This can be useful when using the BaseBinaryDisjunctionNeighborhood
+ operators, in the context of arc-based routing.
+ """
+ return_pywrapcp.RoutingModel_IgnoreDisjunctionsAlreadyForcedToZero(self)
+
+
+
+
+
SPECIAL: Makes the solver ignore all the disjunctions whose active
+variables are all trivially zero (i.e. Max() == 0), by setting their
+max_cardinality to 0.
+This can be useful when using the BaseBinaryDisjunctionNeighborhood
+operators, in the context of arc-based routing.
defAddSoftSameVehicleConstraint(self,indices:"std::vector< int64_t > const &",cost:"int64_t")->"void":
+ r"""
+ Adds a soft constraint to force a set of variable indices to be on the
+ same vehicle. If all nodes are not on the same vehicle, each extra vehicle
+ used adds 'cost' to the cost function.
+ """
+ return_pywrapcp.RoutingModel_AddSoftSameVehicleConstraint(self,indices,cost)
+
+
+
+
+
Adds a soft constraint to force a set of variable indices to be on the
+same vehicle. If all nodes are not on the same vehicle, each extra vehicle
+used adds 'cost' to the cost function.
defSetAllowedVehiclesForIndex(self,vehicles:"std::vector< int > const &",index:"int64_t")->"void":
+ r"""
+ Sets the vehicles which can visit a given node. If the node is in a
+ disjunction, this will not prevent it from being unperformed.
+ Specifying an empty vector of vehicles has no effect (all vehicles
+ will be allowed to visit the node).
+ """
+ return_pywrapcp.RoutingModel_SetAllowedVehiclesForIndex(self,vehicles,index)
+
+
+
+
+
Sets the vehicles which can visit a given node. If the node is in a
+disjunction, this will not prevent it from being unperformed.
+Specifying an empty vector of vehicles has no effect (all vehicles
+will be allowed to visit the node).
defIsVehicleAllowedForIndex(self,vehicle:"int",index:"int64_t")->"bool":
+ r""" Returns true if a vehicle is allowed to visit a given node."""
+ return_pywrapcp.RoutingModel_IsVehicleAllowedForIndex(self,vehicle,index)
+
+
+
+
+
Returns true if a vehicle is allowed to visit a given node.
defAddPickupAndDelivery(self,pickup:"int64_t",delivery:"int64_t")->"void":
+ r"""
+ Notifies that index1 and index2 form a pair of nodes which should belong
+ to the same route. This methods helps the search find better solutions,
+ especially in the local search phase.
+ It should be called each time you have an equality constraint linking
+ the vehicle variables of two node (including for instance pickup and
+ delivery problems):
+ Solver* const solver = routing.solver();
+ int64_t index1 = manager.NodeToIndex(node1);
+ int64_t index2 = manager.NodeToIndex(node2);
+ solver->AddConstraint(solver->MakeEquality(
+ routing.VehicleVar(index1),
+ routing.VehicleVar(index2)));
+ routing.AddPickupAndDelivery(index1, index2);
+ """
+ return_pywrapcp.RoutingModel_AddPickupAndDelivery(self,pickup,delivery)
+
+
+
+
+
Notifies that index1 and index2 form a pair of nodes which should belong
+to the same route. This methods helps the search find better solutions,
+especially in the local search phase.
+It should be called each time you have an equality constraint linking
+the vehicle variables of two node (including for instance pickup and
+delivery problems):
+ Solver* const solver = routing.solver();
+ int64_t index1 = manager.NodeToIndex(node1);
+ int64_t index2 = manager.NodeToIndex(node2);
+ solver->AddConstraint(solver->MakeEquality(
+ routing.VehicleVar(index1),
+ routing.VehicleVar(index2)));
+ routing.AddPickupAndDelivery(index1, index2);
defAddPickupAndDeliverySets(self,pickup_disjunction:"operations_research::RoutingModel::DisjunctionIndex",delivery_disjunction:"operations_research::RoutingModel::DisjunctionIndex")->"void":
+ r"""
+ Same as AddPickupAndDelivery but notifying that the performed node from
+ the disjunction of index 'pickup_disjunction' is on the same route as the
+ performed node from the disjunction of index 'delivery_disjunction'.
+ """
+ return_pywrapcp.RoutingModel_AddPickupAndDeliverySets(self,pickup_disjunction,delivery_disjunction)
+
+
+
+
+
Same as AddPickupAndDelivery but notifying that the performed node from
+the disjunction of index 'pickup_disjunction' is on the same route as the
+performed node from the disjunction of index 'delivery_disjunction'.
defGetPickupIndexPairs(self,node_index:"int64_t")->"std::vector< std::pair< int,int > > const &":
+ r"""
+ Returns pairs for which the node is a pickup; the first element of each
+ pair is the index in the pickup and delivery pairs list in which the
+ pickup appears, the second element is its index in the pickups list.
+ """
+ return_pywrapcp.RoutingModel_GetPickupIndexPairs(self,node_index)
+
+
+
+
+
Returns pairs for which the node is a pickup; the first element of each
+pair is the index in the pickup and delivery pairs list in which the
+pickup appears, the second element is its index in the pickups list.
defSetPickupAndDeliveryPolicyOfAllVehicles(self,policy:"operations_research::RoutingModel::PickupAndDeliveryPolicy")->"void":
+ r"""
+ Sets the Pickup and delivery policy of all vehicles. It is equivalent to
+ calling SetPickupAndDeliveryPolicyOfVehicle on all vehicles.
+ """
+ return_pywrapcp.RoutingModel_SetPickupAndDeliveryPolicyOfAllVehicles(self,policy)
+
+
+
+
+
Sets the Pickup and delivery policy of all vehicles. It is equivalent to
+calling SetPickupAndDeliveryPolicyOfVehicle on all vehicles.
defGetNumOfSingletonNodes(self)->"int":
+ r"""
+ Returns the number of non-start/end nodes which do not appear in a
+ pickup/delivery pair.
+ """
+ return_pywrapcp.RoutingModel_GetNumOfSingletonNodes(self)
+
+
+
+
+
Returns the number of non-start/end nodes which do not appear in a
+pickup/delivery pair.
When visited, one instance of type 'T' previously added to the route
+(TYPE_ADDED_TO_VEHICLE), if any, is removed from the vehicle.
+If the type was not previously added to the route or all added instances
+have already been removed, this visit has no effect on the types.
The visit doesn't have an impact on the number of types 'T' on the
+route, as it's (virtually) added and removed directly.
+This policy can be used for visits which are part of an incompatibility
+or requirement set without affecting the type count on the route.
defCloseVisitTypes(self)->"void":
+ r"""
+ This function should be called once all node visit types have been set and
+ prior to adding any incompatibilities/requirements.
+ "close" types.
+ """
+ return_pywrapcp.RoutingModel_CloseVisitTypes(self)
+
+
+
+
+
This function should be called once all node visit types have been set and
+prior to adding any incompatibilities/requirements.
+"close" types.
defAddHardTypeIncompatibility(self,type1:"int",type2:"int")->"void":
+ r"""
+ Incompatibilities:
+ Two nodes with "hard" incompatible types cannot share the same route at
+ all, while with a "temporal" incompatibility they can't be on the same
+ route at the same time.
+ """
+ return_pywrapcp.RoutingModel_AddHardTypeIncompatibility(self,type1,type2)
+
+
+
+
+
Incompatibilities:
+Two nodes with "hard" incompatible types cannot share the same route at
+all, while with a "temporal" incompatibility they can't be on the same
+route at the same time.
defGetHardTypeIncompatibilitiesOfType(self,type:"int")->"absl::flat_hash_set< int > const &":
+ r""" Returns visit types incompatible with a given type."""
+ return_pywrapcp.RoutingModel_GetHardTypeIncompatibilitiesOfType(self,type)
+
+
+
+
+
Returns visit types incompatible with a given type.
defHasHardTypeIncompatibilities(self)->"bool":
+ r"""
+ Returns true iff any hard (resp. temporal) type incompatibilities have
+ been added to the model.
+ """
+ return_pywrapcp.RoutingModel_HasHardTypeIncompatibilities(self)
+
+
+
+
+
Returns true iff any hard (resp. temporal) type incompatibilities have
+been added to the model.
defAddSameVehicleRequiredTypeAlternatives(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ Requirements:
+ NOTE: As of 2019-04, cycles in the requirement graph are not supported,
+ and lead to the dependent nodes being skipped if possible (otherwise
+ the model is considered infeasible).
+ The following functions specify that "dependent_type" requires at least
+ one of the types in "required_type_alternatives".
+
+ For same-vehicle requirements, a node of dependent type type_D requires at
+ least one node of type type_R among the required alternatives on the same
+ route.
+ """
+ return_pywrapcp.RoutingModel_AddSameVehicleRequiredTypeAlternatives(self,dependent_type,required_type_alternatives)
+
+
+
+
+
Requirements:
+NOTE: As of 2019-04, cycles in the requirement graph are not supported,
+and lead to the dependent nodes being skipped if possible (otherwise
+the model is considered infeasible).
+The following functions specify that "dependent_type" requires at least
+one of the types in "required_type_alternatives".
+
+
For same-vehicle requirements, a node of dependent type type_D requires at
+least one node of type type_R among the required alternatives on the same
+route.
defAddRequiredTypeAlternativesWhenAddingType(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ If type_D depends on type_R when adding type_D, any node_D of type_D and
+ VisitTypePolicy TYPE_ADDED_TO_VEHICLE or
+ TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED requires at least one type_R on its
+ vehicle at the time node_D is visited.
+ """
+ return_pywrapcp.RoutingModel_AddRequiredTypeAlternativesWhenAddingType(self,dependent_type,required_type_alternatives)
+
+
+
+
+
If type_D depends on type_R when adding type_D, any node_D of type_D and
+VisitTypePolicy TYPE_ADDED_TO_VEHICLE or
+TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED requires at least one type_R on its
+vehicle at the time node_D is visited.
defAddRequiredTypeAlternativesWhenRemovingType(self,dependent_type:"int",required_type_alternatives:"absl::flat_hash_set< int >")->"void":
+ r"""
+ The following requirements apply when visiting dependent nodes that remove
+ their type from the route, i.e. type_R must be on the vehicle when type_D
+ of VisitTypePolicy ADDED_TYPE_REMOVED_FROM_VEHICLE,
+ TYPE_ON_VEHICLE_UP_TO_VISIT or TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED is
+ visited.
+ """
+ return_pywrapcp.RoutingModel_AddRequiredTypeAlternativesWhenRemovingType(self,dependent_type,required_type_alternatives)
+
+
+
+
+
The following requirements apply when visiting dependent nodes that remove
+their type from the route, i.e. type_R must be on the vehicle when type_D
+of VisitTypePolicy ADDED_TYPE_REMOVED_FROM_VEHICLE,
+TYPE_ON_VEHICLE_UP_TO_VISIT or TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED is
+visited.
defGetSameVehicleRequiredTypeAlternativesOfType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r"""
+ Returns the set of same-vehicle requirement alternatives for the given
+ type.
+ """
+ return_pywrapcp.RoutingModel_GetSameVehicleRequiredTypeAlternativesOfType(self,type)
+
+
+
+
+
Returns the set of same-vehicle requirement alternatives for the given
+type.
defGetRequiredTypeAlternativesWhenAddingType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r""" Returns the set of requirement alternatives when adding the given type."""
+ return_pywrapcp.RoutingModel_GetRequiredTypeAlternativesWhenAddingType(self,type)
+
+
+
+
+
Returns the set of requirement alternatives when adding the given type.
defGetRequiredTypeAlternativesWhenRemovingType(self,type:"int")->"std::vector< absl::flat_hash_set< int > > const &":
+ r""" Returns the set of requirement alternatives when removing the given type."""
+ return_pywrapcp.RoutingModel_GetRequiredTypeAlternativesWhenRemovingType(self,type)
+
+
+
+
+
Returns the set of requirement alternatives when removing the given type.
defHasSameVehicleTypeRequirements(self)->"bool":
+ r"""
+ Returns true iff any same-route (resp. temporal) type requirements have
+ been added to the model.
+ """
+ return_pywrapcp.RoutingModel_HasSameVehicleTypeRequirements(self)
+
+
+
+
+
Returns true iff any same-route (resp. temporal) type requirements have
+been added to the model.
defHasTypeRegulations(self)->"bool":
+ r"""
+ Returns true iff the model has any incompatibilities or requirements set
+ on node types.
+ """
+ return_pywrapcp.RoutingModel_HasTypeRegulations(self)
+
+
+
+
+
Returns true iff the model has any incompatibilities or requirements set
+on node types.
defUnperformedPenalty(self,var_index:"int64_t")->"int64_t":
+ r"""
+ Get the "unperformed" penalty of a node. This is only well defined if the
+ node is only part of a single Disjunction, and that disjunction has a
+ penalty. For forced active nodes returns max int64_t. In all other cases,
+ this returns 0.
+ """
+ return_pywrapcp.RoutingModel_UnperformedPenalty(self,var_index)
+
+
+
+
+
Get the "unperformed" penalty of a node. This is only well defined if the
+node is only part of a single Disjunction, and that disjunction has a
+penalty. For forced active nodes returns max int64_t. In all other cases,
+this returns 0.
defUnperformedPenaltyOrValue(self,default_value:"int64_t",var_index:"int64_t")->"int64_t":
+ r"""
+ Same as above except that it returns default_value instead of 0 when
+ penalty is not well defined (default value is passed as first argument to
+ simplify the usage of the method in a callback).
+ """
+ return_pywrapcp.RoutingModel_UnperformedPenaltyOrValue(self,default_value,var_index)
+
+
+
+
+
Same as above except that it returns default_value instead of 0 when
+penalty is not well defined (default value is passed as first argument to
+simplify the usage of the method in a callback).
defGetDepot(self)->"int64_t":
+ r"""
+ Returns the variable index of the first starting or ending node of all
+ routes. If all routes start and end at the same node (single depot), this
+ is the node returned.
+ """
+ return_pywrapcp.RoutingModel_GetDepot(self)
+
+
+
+
+
Returns the variable index of the first starting or ending node of all
+routes. If all routes start and end at the same node (single depot), this
+is the node returned.
defSetMaximumNumberOfActiveVehicles(self,max_active_vehicles:"int")->"void":
+ r"""
+ Constrains the maximum number of active vehicles, aka the number of
+ vehicles which do not have an empty route. For instance, this can be used
+ to limit the number of routes in the case where there are fewer drivers
+ than vehicles and that the fleet of vehicle is heterogeneous.
+ """
+ return_pywrapcp.RoutingModel_SetMaximumNumberOfActiveVehicles(self,max_active_vehicles)
+
+
+
+
+
Constrains the maximum number of active vehicles, aka the number of
+vehicles which do not have an empty route. For instance, this can be used
+to limit the number of routes in the case where there are fewer drivers
+than vehicles and that the fleet of vehicle is heterogeneous.
defGetMaximumNumberOfActiveVehicles(self)->"int":
+ r""" Returns the maximum number of active vehicles."""
+ return_pywrapcp.RoutingModel_GetMaximumNumberOfActiveVehicles(self)
+
defSetArcCostEvaluatorOfAllVehicles(self,evaluator_index:"int")->"void":
+ r"""
+ Sets the cost function of the model such that the cost of a segment of a
+ route between node 'from' and 'to' is evaluator(from, to), whatever the
+ route or vehicle performing the route.
+ """
+ return_pywrapcp.RoutingModel_SetArcCostEvaluatorOfAllVehicles(self,evaluator_index)
+
+
+
+
+
Sets the cost function of the model such that the cost of a segment of a
+route between node 'from' and 'to' is evaluator(from, to), whatever the
+route or vehicle performing the route.
defSetArcCostEvaluatorOfVehicle(self,evaluator_index:"int",vehicle:"int")->"void":
+ r""" Sets the cost function for a given vehicle route."""
+ return_pywrapcp.RoutingModel_SetArcCostEvaluatorOfVehicle(self,evaluator_index,vehicle)
+
defSetFixedCostOfAllVehicles(self,cost:"int64_t")->"void":
+ r"""
+ Sets the fixed cost of all vehicle routes. It is equivalent to calling
+ SetFixedCostOfVehicle on all vehicle routes.
+ """
+ return_pywrapcp.RoutingModel_SetFixedCostOfAllVehicles(self,cost)
+
+
+
+
+
Sets the fixed cost of all vehicle routes. It is equivalent to calling
+SetFixedCostOfVehicle on all vehicle routes.
defSetFixedCostOfVehicle(self,cost:"int64_t",vehicle:"int")->"void":
+ r""" Sets the fixed cost of one vehicle route."""
+ return_pywrapcp.RoutingModel_SetFixedCostOfVehicle(self,cost,vehicle)
+
defGetFixedCostOfVehicle(self,vehicle:"int")->"int64_t":
+ r"""
+ Returns the route fixed cost taken into account if the route of the
+ vehicle is not empty, aka there's at least one node on the route other
+ than the first and last nodes.
+ """
+ return_pywrapcp.RoutingModel_GetFixedCostOfVehicle(self,vehicle)
+
+
+
+
+
Returns the route fixed cost taken into account if the route of the
+vehicle is not empty, aka there's at least one node on the route other
+than the first and last nodes.
defSetAmortizedCostFactorsOfAllVehicles(self,linear_cost_factor:"int64_t",quadratic_cost_factor:"int64_t")->"void":
+ r"""
+ The following methods set the linear and quadratic cost factors of
+ vehicles (must be positive values). The default value of these parameters
+ is zero for all vehicles.
+
+ When set, the cost_ of the model will contain terms aiming at reducing the
+ number of vehicles used in the model, by adding the following to the
+ objective for every vehicle v:
+ INDICATOR(v used in the model) *
+ [linear_cost_factor_of_vehicle_[v]
+ - quadratic_cost_factor_of_vehicle_[v]*(square of length of route v)]
+ i.e. for every used vehicle, we add the linear factor as fixed cost, and
+ subtract the square of the route length multiplied by the quadratic
+ factor. This second term aims at making the routes as dense as possible.
+
+ Sets the linear and quadratic cost factor of all vehicles.
+ """
+ return_pywrapcp.RoutingModel_SetAmortizedCostFactorsOfAllVehicles(self,linear_cost_factor,quadratic_cost_factor)
+
+
+
+
+
The following methods set the linear and quadratic cost factors of
+vehicles (must be positive values). The default value of these parameters
+is zero for all vehicles.
+
+
When set, the cost_ of the model will contain terms aiming at reducing the
+number of vehicles used in the model, by adding the following to the
+objective for every vehicle v:
+INDICATOR(v used in the model) *
+ [linear_cost_factor_of_vehicle_[v]
+
+
+
quadratic_cost_factor_of_vehicle_[v]*(square of length of route v)]
+i.e. for every used vehicle, we add the linear factor as fixed cost, and
+subtract the square of the route length multiplied by the quadratic
+factor. This second term aims at making the routes as dense as possible.
+
+
+
Sets the linear and quadratic cost factor of all vehicles.
defSetAmortizedCostFactorsOfVehicle(self,linear_cost_factor:"int64_t",quadratic_cost_factor:"int64_t",vehicle:"int")->"void":
+ r""" Sets the linear and quadratic cost factor of the given vehicle."""
+ return_pywrapcp.RoutingModel_SetAmortizedCostFactorsOfVehicle(self,linear_cost_factor,quadratic_cost_factor,vehicle)
+
+
+
+
+
Sets the linear and quadratic cost factor of the given vehicle.
defSetFirstSolutionEvaluator(self,evaluator:"operations_research::Solver::IndexEvaluator2")->"void":
+ r"""
+ Gets/sets the evaluator used during the search. Only relevant when
+ RoutingSearchParameters.first_solution_strategy = EVALUATOR_STRATEGY.
+ Takes ownership of evaluator.
+ """
+ return_pywrapcp.RoutingModel_SetFirstSolutionEvaluator(self,evaluator)
+
+
+
+
+
Gets/sets the evaluator used during the search. Only relevant when
+RoutingSearchParameters.first_solution_strategy = EVALUATOR_STRATEGY.
+Takes ownership of evaluator.
defAddLocalSearchOperator(self,ls_operator:"LocalSearchOperator")->"void":
+ r"""
+ Adds a local search operator to the set of operators used to solve the
+ vehicle routing problem.
+ """
+ return_pywrapcp.RoutingModel_AddLocalSearchOperator(self,ls_operator)
+
+
+
+
+
Adds a local search operator to the set of operators used to solve the
+vehicle routing problem.
defAddSearchMonitor(self,monitor:"SearchMonitor")->"void":
+ r""" Adds a search monitor to the search used to solve the routing model."""
+ return_pywrapcp.RoutingModel_AddSearchMonitor(self,monitor)
+
+
+
+
+
Adds a search monitor to the search used to solve the routing model.
defAddAtSolutionCallback(self,callback:"std::function< void () >")->"void":
+ r"""
+ Adds a callback called each time a solution is found during the search.
+ This is a shortcut to creating a monitor to call the callback on
+ AtSolution() and adding it with AddSearchMonitor.
+ """
+ return_pywrapcp.RoutingModel_AddAtSolutionCallback(self,callback)
+
+
+
+
+
Adds a callback called each time a solution is found during the search.
+This is a shortcut to creating a monitor to call the callback on
+AtSolution() and adding it with AddSearchMonitor.
defAddVariableMinimizedByFinalizer(self,var:"IntVar")->"void":
+ r"""
+ Adds a variable to minimize in the solution finalizer. The solution
+ finalizer is called each time a solution is found during the search and
+ allows to instantiate secondary variables (such as dimension cumul
+ variables).
+ """
+ return_pywrapcp.RoutingModel_AddVariableMinimizedByFinalizer(self,var)
+
+
+
+
+
Adds a variable to minimize in the solution finalizer. The solution
+finalizer is called each time a solution is found during the search and
+allows to instantiate secondary variables (such as dimension cumul
+variables).
defAddVariableMaximizedByFinalizer(self,var:"IntVar")->"void":
+ r"""
+ Adds a variable to maximize in the solution finalizer (see above for
+ information on the solution finalizer).
+ """
+ return_pywrapcp.RoutingModel_AddVariableMaximizedByFinalizer(self,var)
+
+
+
+
+
Adds a variable to maximize in the solution finalizer (see above for
+information on the solution finalizer).
defAddWeightedVariableMinimizedByFinalizer(self,var:"IntVar",cost:"int64_t")->"void":
+ r"""
+ Adds a variable to minimize in the solution finalizer, with a weighted
+ priority: the higher the more priority it has.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableMinimizedByFinalizer(self,var,cost)
+
+
+
+
+
Adds a variable to minimize in the solution finalizer, with a weighted
+priority: the higher the more priority it has.
defAddWeightedVariableMaximizedByFinalizer(self,var:"IntVar",cost:"int64_t")->"void":
+ r"""
+ Adds a variable to maximize in the solution finalizer, with a weighted
+ priority: the higher the more priority it has.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableMaximizedByFinalizer(self,var,cost)
+
+
+
+
+
Adds a variable to maximize in the solution finalizer, with a weighted
+priority: the higher the more priority it has.
defAddVariableTargetToFinalizer(self,var:"IntVar",target:"int64_t")->"void":
+ r"""
+ Add a variable to set the closest possible to the target value in the
+ solution finalizer.
+ """
+ return_pywrapcp.RoutingModel_AddVariableTargetToFinalizer(self,var,target)
+
+
+
+
+
Add a variable to set the closest possible to the target value in the
+solution finalizer.
defAddWeightedVariableTargetToFinalizer(self,var:"IntVar",target:"int64_t",cost:"int64_t")->"void":
+ r"""
+ Same as above with a weighted priority: the higher the cost, the more
+ priority it has to be set close to the target value.
+ """
+ return_pywrapcp.RoutingModel_AddWeightedVariableTargetToFinalizer(self,var,target,cost)
+
+
+
+
+
Same as above with a weighted priority: the higher the cost, the more
+priority it has to be set close to the target value.
defCloseModel(self)->"void":
+ r"""
+ Closes the current routing model; after this method is called, no
+ modification to the model can be done, but RoutesToAssignment becomes
+ available. Note that CloseModel() is automatically called by Solve() and
+ other methods that produce solution.
+ This is equivalent to calling
+ CloseModelWithParameters(DefaultRoutingSearchParameters()).
+ """
+ return_pywrapcp.RoutingModel_CloseModel(self)
+
+
+
+
+
Closes the current routing model; after this method is called, no
+modification to the model can be done, but RoutesToAssignment becomes
+available. Note that CloseModel() is automatically called by Solve() and
+other methods that produce solution.
+This is equivalent to calling
+CloseModelWithParameters(DefaultRoutingSearchParameters()).
defCloseModelWithParameters(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"void":
+ r"""
+ Same as above taking search parameters (as of 10/2015 some the parameters
+ have to be set when closing the model).
+ """
+ return_pywrapcp.RoutingModel_CloseModelWithParameters(self,search_parameters)
+
+
+
+
+
Same as above taking search parameters (as of 10/2015 some the parameters
+have to be set when closing the model).
defSolve(self,assignment:"Assignment"=None)->"operations_research::Assignment const *":
+ r"""
+ Solves the current routing model; closes the current model.
+ This is equivalent to calling
+ SolveWithParameters(DefaultRoutingSearchParameters())
+ or
+ SolveFromAssignmentWithParameters(assignment,
+ DefaultRoutingSearchParameters()).
+ """
+ return_pywrapcp.RoutingModel_Solve(self,assignment)
+
+
+
+
+
Solves the current routing model; closes the current model.
+This is equivalent to calling
+SolveWithParameters(DefaultRoutingSearchParameters())
+or
+SolveFromAssignmentWithParameters(assignment,
+ DefaultRoutingSearchParameters()).
defSolveWithParameters(self,search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Solves the current routing model with the given parameters. If 'solutions'
+ is specified, it will contain the k best solutions found during the search
+ (from worst to best, including the one returned by this method), where k
+ corresponds to the 'number_of_solutions_to_collect' in
+ 'search_parameters'. Note that the Assignment returned by the method and
+ the ones in solutions are owned by the underlying solver and should not be
+ deleted.
+ """
+ return_pywrapcp.RoutingModel_SolveWithParameters(self,search_parameters,solutions)
+
+
+
+
+
Solves the current routing model with the given parameters. If 'solutions'
+is specified, it will contain the k best solutions found during the search
+(from worst to best, including the one returned by this method), where k
+corresponds to the 'number_of_solutions_to_collect' in
+'search_parameters'. Note that the Assignment returned by the method and
+the ones in solutions are owned by the underlying solver and should not be
+deleted.
defSolveFromAssignmentWithParameters(self,assignment:"Assignment",search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Same as above, except that if assignment is not null, it will be used as
+ the initial solution.
+ """
+ return_pywrapcp.RoutingModel_SolveFromAssignmentWithParameters(self,assignment,search_parameters,solutions)
+
+
+
+
+
Same as above, except that if assignment is not null, it will be used as
+the initial solution.
defSolveFromAssignmentsWithParameters(self,assignments:"std::vector< operations_research::Assignment const * > const &",search_parameters:"operations_research::RoutingSearchParameters const &",solutions:"std::vector< operations_research::Assignment const * > *"=None)->"operations_research::Assignment const *":
+ r"""
+ Same as above but will try all assignments in order as first solutions
+ until one succeeds.
+ """
+ return_pywrapcp.RoutingModel_SolveFromAssignmentsWithParameters(self,assignments,search_parameters,solutions)
+
+
+
+
+
Same as above but will try all assignments in order as first solutions
+until one succeeds.
defSetAssignmentFromOtherModelAssignment(self,target_assignment:"Assignment",source_model:"RoutingModel",source_assignment:"Assignment")->"void":
+ r"""
+ Given a "source_model" and its "source_assignment", resets
+ "target_assignment" with the IntVar variables (nexts_, and vehicle_vars_
+ if costs aren't homogeneous across vehicles) of "this" model, with the
+ values set according to those in "other_assignment".
+ The objective_element of target_assignment is set to this->cost_.
+ """
+ return_pywrapcp.RoutingModel_SetAssignmentFromOtherModelAssignment(self,target_assignment,source_model,source_assignment)
+
+
+
+
+
Given a "source_model" and its "source_assignment", resets
+"target_assignment" with the IntVar variables (nexts_, and vehicle_vars_
+if costs aren't homogeneous across vehicles) of "this" model, with the
+values set according to those in "other_assignment".
+The objective_element of target_assignment is set to this->cost_.
defComputeLowerBound(self)->"int64_t":
+ r"""
+ Computes a lower bound to the routing problem solving a linear assignment
+ problem. The routing model must be closed before calling this method.
+ Note that problems with node disjunction constraints (including optional
+ nodes) and non-homogenous costs are not supported (the method returns 0 in
+ these cases).
+ """
+ return_pywrapcp.RoutingModel_ComputeLowerBound(self)
+
+
+
+
+
Computes a lower bound to the routing problem solving a linear assignment
+problem. The routing model must be closed before calling this method.
+Note that problems with node disjunction constraints (including optional
+nodes) and non-homogenous costs are not supported (the method returns 0 in
+these cases).
defstatus(self)->"operations_research::RoutingModel::Status":
+ r""" Returns the current status of the routing model."""
+ return_pywrapcp.RoutingModel_status(self)
+
defApplyLocks(self,locks:"std::vector< int64_t > const &")->"operations_research::IntVar *":
+ r"""
+ Applies a lock chain to the next search. 'locks' represents an ordered
+ vector of nodes representing a partial route which will be fixed during
+ the next search; it will constrain next variables such that:
+ next[locks[i]] == locks[i+1].
+
+ Returns the next variable at the end of the locked chain; this variable is
+ not locked. An assignment containing the locks can be obtained by calling
+ PreAssignment().
+ """
+ return_pywrapcp.RoutingModel_ApplyLocks(self,locks)
+
+
+
+
+
Applies a lock chain to the next search. 'locks' represents an ordered
+vector of nodes representing a partial route which will be fixed during
+the next search; it will constrain next variables such that:
+next[locks[i]] == locks[i+1].
+
+
Returns the next variable at the end of the locked chain; this variable is
+not locked. An assignment containing the locks can be obtained by calling
+PreAssignment().
defApplyLocksToAllVehicles(self,locks:"std::vector< std::vector< int64_t > > const &",close_routes:"bool")->"bool":
+ r"""
+ Applies lock chains to all vehicles to the next search, such that locks[p]
+ is the lock chain for route p. Returns false if the locks do not contain
+ valid routes; expects that the routes do not contain the depots,
+ i.e. there are empty vectors in place of empty routes.
+ If close_routes is set to true, adds the end nodes to the route of each
+ vehicle and deactivates other nodes.
+ An assignment containing the locks can be obtained by calling
+ PreAssignment().
+ """
+ return_pywrapcp.RoutingModel_ApplyLocksToAllVehicles(self,locks,close_routes)
+
+
+
+
+
Applies lock chains to all vehicles to the next search, such that locks[p]
+is the lock chain for route p. Returns false if the locks do not contain
+valid routes; expects that the routes do not contain the depots,
+i.e. there are empty vectors in place of empty routes.
+If close_routes is set to true, adds the end nodes to the route of each
+vehicle and deactivates other nodes.
+An assignment containing the locks can be obtained by calling
+PreAssignment().
defPreAssignment(self)->"operations_research::Assignment const *const":
+ r"""
+ Returns an assignment used to fix some of the variables of the problem.
+ In practice, this assignment locks partial routes of the problem. This
+ can be used in the context of locking the parts of the routes which have
+ already been driven in online routing problems.
+ """
+ return_pywrapcp.RoutingModel_PreAssignment(self)
+
+
+
+
+
Returns an assignment used to fix some of the variables of the problem.
+In practice, this assignment locks partial routes of the problem. This
+can be used in the context of locking the parts of the routes which have
+already been driven in online routing problems.
defWriteAssignment(self,file_name:"std::string const &")->"bool":
+ r"""
+ Writes the current solution to a file containing an AssignmentProto.
+ Returns false if the file cannot be opened or if there is no current
+ solution.
+ """
+ return_pywrapcp.RoutingModel_WriteAssignment(self,file_name)
+
+
+
+
+
Writes the current solution to a file containing an AssignmentProto.
+Returns false if the file cannot be opened or if there is no current
+solution.
defReadAssignment(self,file_name:"std::string const &")->"operations_research::Assignment *":
+ r"""
+ Reads an assignment from a file and returns the current solution.
+ Returns nullptr if the file cannot be opened or if the assignment is not
+ valid.
+ """
+ return_pywrapcp.RoutingModel_ReadAssignment(self,file_name)
+
+
+
+
+
Reads an assignment from a file and returns the current solution.
+Returns nullptr if the file cannot be opened or if the assignment is not
+valid.
defRestoreAssignment(self,solution:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Restores an assignment as a solution in the routing model and returns the
+ new solution. Returns nullptr if the assignment is not valid.
+ """
+ return_pywrapcp.RoutingModel_RestoreAssignment(self,solution)
+
+
+
+
+
Restores an assignment as a solution in the routing model and returns the
+new solution. Returns nullptr if the assignment is not valid.
defReadAssignmentFromRoutes(self,routes:"std::vector< std::vector< int64_t > > const &",ignore_inactive_indices:"bool")->"operations_research::Assignment *":
+ r"""
+ Restores the routes as the current solution. Returns nullptr if the
+ solution cannot be restored (routes do not contain a valid solution). Note
+ that calling this method will run the solver to assign values to the
+ dimension variables; this may take considerable amount of time, especially
+ when using dimensions with slack.
+ """
+ return_pywrapcp.RoutingModel_ReadAssignmentFromRoutes(self,routes,ignore_inactive_indices)
+
+
+
+
+
Restores the routes as the current solution. Returns nullptr if the
+solution cannot be restored (routes do not contain a valid solution). Note
+that calling this method will run the solver to assign values to the
+dimension variables; this may take considerable amount of time, especially
+when using dimensions with slack.
defRoutesToAssignment(self,routes:"std::vector< std::vector< int64_t > > const &",ignore_inactive_indices:"bool",close_routes:"bool",assignment:"Assignment")->"bool":
+ r"""
+ Fills an assignment from a specification of the routes of the
+ vehicles. The routes are specified as lists of variable indices that
+ appear on the routes of the vehicles. The indices of the outer vector in
+ 'routes' correspond to vehicles IDs, the inner vector contains the
+ variable indices on the routes for the given vehicle. The inner vectors
+ must not contain the start and end indices, as these are determined by the
+ routing model. Sets the value of NextVars in the assignment, adding the
+ variables to the assignment if necessary. The method does not touch other
+ variables in the assignment. The method can only be called after the model
+ is closed. With ignore_inactive_indices set to false, this method will
+ fail (return nullptr) in case some of the route contain indices that are
+ deactivated in the model; when set to true, these indices will be
+ skipped. Returns true if routes were successfully
+ loaded. However, such assignment still might not be a valid
+ solution to the routing problem due to more complex constraints;
+ it is advisible to call solver()->CheckSolution() afterwards.
+ """
+ return_pywrapcp.RoutingModel_RoutesToAssignment(self,routes,ignore_inactive_indices,close_routes,assignment)
+
+
+
+
+
Fills an assignment from a specification of the routes of the
+vehicles. The routes are specified as lists of variable indices that
+appear on the routes of the vehicles. The indices of the outer vector in
+'routes' correspond to vehicles IDs, the inner vector contains the
+variable indices on the routes for the given vehicle. The inner vectors
+must not contain the start and end indices, as these are determined by the
+routing model. Sets the value of NextVars in the assignment, adding the
+variables to the assignment if necessary. The method does not touch other
+variables in the assignment. The method can only be called after the model
+is closed. With ignore_inactive_indices set to false, this method will
+fail (return nullptr) in case some of the route contain indices that are
+deactivated in the model; when set to true, these indices will be
+skipped. Returns true if routes were successfully
+loaded. However, such assignment still might not be a valid
+solution to the routing problem due to more complex constraints;
+it is advisible to call solver()->CheckSolution() afterwards.
defAssignmentToRoutes(self,assignment:"Assignment",routes:"std::vector< std::vector< int64_t > > *const")->"void":
+ r"""
+ Converts the solution in the given assignment to routes for all vehicles.
+ Expects that assignment contains a valid solution (i.e. routes for all
+ vehicles end with an end index for that vehicle).
+ """
+ return_pywrapcp.RoutingModel_AssignmentToRoutes(self,assignment,routes)
+
+
+
+
+
Converts the solution in the given assignment to routes for all vehicles.
+Expects that assignment contains a valid solution (i.e. routes for all
+vehicles end with an end index for that vehicle).
defCompactAssignment(self,assignment:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Converts the solution in the given assignment to routes for all vehicles.
+ If the returned vector is route_indices, route_indices[i][j] is the index
+ for jth location visited on route i. Note that contrary to
+ AssignmentToRoutes, the vectors do include start and end locations.
+ Returns a compacted version of the given assignment, in which all vehicles
+ with id lower or equal to some N have non-empty routes, and all vehicles
+ with id greater than N have empty routes. Does not take ownership of the
+ returned object.
+ If found, the cost of the compact assignment is the same as in the
+ original assignment and it preserves the values of 'active' variables.
+ Returns nullptr if a compact assignment was not found.
+ This method only works in homogenous mode, and it only swaps equivalent
+ vehicles (vehicles with the same start and end nodes). When creating the
+ compact assignment, the empty plan is replaced by the route assigned to
+ the compatible vehicle with the highest id. Note that with more complex
+ constraints on vehicle variables, this method might fail even if a compact
+ solution exists.
+ This method changes the vehicle and dimension variables as necessary.
+ While compacting the solution, only basic checks on vehicle variables are
+ performed; if one of these checks fails no attempts to repair it are made
+ (instead, the method returns nullptr).
+ """
+ return_pywrapcp.RoutingModel_CompactAssignment(self,assignment)
+
+
+
+
+
Converts the solution in the given assignment to routes for all vehicles.
+If the returned vector is route_indices, route_indices[i][j] is the index
+for jth location visited on route i. Note that contrary to
+AssignmentToRoutes, the vectors do include start and end locations.
+Returns a compacted version of the given assignment, in which all vehicles
+with id lower or equal to some N have non-empty routes, and all vehicles
+with id greater than N have empty routes. Does not take ownership of the
+returned object.
+If found, the cost of the compact assignment is the same as in the
+original assignment and it preserves the values of 'active' variables.
+Returns nullptr if a compact assignment was not found.
+This method only works in homogenous mode, and it only swaps equivalent
+vehicles (vehicles with the same start and end nodes). When creating the
+compact assignment, the empty plan is replaced by the route assigned to
+the compatible vehicle with the highest id. Note that with more complex
+constraints on vehicle variables, this method might fail even if a compact
+solution exists.
+This method changes the vehicle and dimension variables as necessary.
+While compacting the solution, only basic checks on vehicle variables are
+performed; if one of these checks fails no attempts to repair it are made
+(instead, the method returns nullptr).
defCompactAndCheckAssignment(self,assignment:"Assignment")->"operations_research::Assignment *":
+ r"""
+ Same as CompactAssignment() but also checks the validity of the final
+ compact solution; if it is not valid, no attempts to repair it are made
+ (instead, the method returns nullptr).
+ """
+ return_pywrapcp.RoutingModel_CompactAndCheckAssignment(self,assignment)
+
+
+
+
+
Same as CompactAssignment() but also checks the validity of the final
+compact solution; if it is not valid, no attempts to repair it are made
+(instead, the method returns nullptr).
defAddToAssignment(self,var:"IntVar")->"void":
+ r""" Adds an extra variable to the vehicle routing assignment."""
+ return_pywrapcp.RoutingModel_AddToAssignment(self,var)
+
+
+
+
+
Adds an extra variable to the vehicle routing assignment.
defPackCumulsOfOptimizerDimensionsFromAssignment(self,original_assignment:"Assignment",duration_limit:"absl::Duration")->"operations_research::Assignment const *":
+ r"""
+ For every dimension in the model with an optimizer in
+ local/global_dimension_optimizers_, this method tries to pack the cumul
+ values of the dimension, such that:
+ - The cumul costs (span costs, soft lower and upper bound costs, etc) are
+ minimized.
+ - The cumuls of the ends of the routes are minimized for this given
+ minimal cumul cost.
+ - Given these minimal end cumuls, the route start cumuls are maximized.
+ Returns the assignment resulting from allocating these packed cumuls with
+ the solver, and nullptr if these cumuls could not be set by the solver.
+ """
+ return_pywrapcp.RoutingModel_PackCumulsOfOptimizerDimensionsFromAssignment(self,original_assignment,duration_limit)
+
+
+
+
+
For every dimension in the model with an optimizer in
+local/global_dimension_optimizers_, this method tries to pack the cumul
+values of the dimension, such that:
+
+
+
The cumul costs (span costs, soft lower and upper bound costs, etc) are
+minimized.
+
The cumuls of the ends of the routes are minimized for this given
+minimal cumul cost.
+
Given these minimal end cumuls, the route start cumuls are maximized.
+Returns the assignment resulting from allocating these packed cumuls with
+the solver, and nullptr if these cumuls could not be set by the solver.
defAddLocalSearchFilter(self,filter:"LocalSearchFilter")->"void":
+ r"""
+ Adds a custom local search filter to the list of filters used to speed up
+ local search by pruning unfeasible variable assignments.
+ Calling this method after the routing model has been closed (CloseModel()
+ or Solve() has been called) has no effect.
+ The routing model does not take ownership of the filter.
+ """
+ return_pywrapcp.RoutingModel_AddLocalSearchFilter(self,filter)
+
+
+
+
+
Adds a custom local search filter to the list of filters used to speed up
+local search by pruning unfeasible variable assignments.
+Calling this method after the routing model has been closed (CloseModel()
+or Solve() has been called) has no effect.
+The routing model does not take ownership of the filter.
defStart(self,vehicle:"int")->"int64_t":
+ r"""
+ Model inspection.
+ Returns the variable index of the starting node of a vehicle route.
+ """
+ return_pywrapcp.RoutingModel_Start(self,vehicle)
+
+
+
+
+
Model inspection.
+Returns the variable index of the starting node of a vehicle route.
defEnd(self,vehicle:"int")->"int64_t":
+ r""" Returns the variable index of the ending node of a vehicle route."""
+ return_pywrapcp.RoutingModel_End(self,vehicle)
+
+
+
+
+
Returns the variable index of the ending node of a vehicle route.
defIsStart(self,index:"int64_t")->"bool":
+ r""" Returns true if 'index' represents the first node of a route."""
+ return_pywrapcp.RoutingModel_IsStart(self,index)
+
+
+
+
+
Returns true if 'index' represents the first node of a route.
defIsEnd(self,index:"int64_t")->"bool":
+ r""" Returns true if 'index' represents the last node of a route."""
+ return_pywrapcp.RoutingModel_IsEnd(self,index)
+
+
+
+
+
Returns true if 'index' represents the last node of a route.
defVehicleIndex(self,index:"int64_t")->"int":
+ r"""
+ Returns the vehicle of the given start/end index, and -1 if the given
+ index is not a vehicle start/end.
+ """
+ return_pywrapcp.RoutingModel_VehicleIndex(self,index)
+
+
+
+
+
Returns the vehicle of the given start/end index, and -1 if the given
+index is not a vehicle start/end.
defNext(self,assignment:"Assignment",index:"int64_t")->"int64_t":
+ r"""
+ Assignment inspection
+ Returns the variable index of the node directly after the node
+ corresponding to 'index' in 'assignment'.
+ """
+ return_pywrapcp.RoutingModel_Next(self,assignment,index)
+
+
+
+
+
Assignment inspection
+Returns the variable index of the node directly after the node
+corresponding to 'index' in 'assignment'.
defIsVehicleUsed(self,assignment:"Assignment",vehicle:"int")->"bool":
+ r""" Returns true if the route of 'vehicle' is non empty in 'assignment'."""
+ return_pywrapcp.RoutingModel_IsVehicleUsed(self,assignment,vehicle)
+
+
+
+
+
Returns true if the route of 'vehicle' is non empty in 'assignment'.
defNextVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Returns the next variable of the node corresponding to index. Note that
+ NextVar(index) == index is equivalent to ActiveVar(index) == 0.
+ """
+ return_pywrapcp.RoutingModel_NextVar(self,index)
+
+
+
+
+
Returns the next variable of the node corresponding to index. Note that
+NextVar(index) == index is equivalent to ActiveVar(index) == 0.
defActiveVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r""" Returns the active variable of the node corresponding to index."""
+ return_pywrapcp.RoutingModel_ActiveVar(self,index)
+
+
+
+
+
Returns the active variable of the node corresponding to index.
defActiveVehicleVar(self,vehicle:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the active variable of the vehicle. It will be equal to 1 iff the
+ route of the vehicle is not empty, 0 otherwise.
+ """
+ return_pywrapcp.RoutingModel_ActiveVehicleVar(self,vehicle)
+
+
+
+
+
Returns the active variable of the vehicle. It will be equal to 1 iff the
+route of the vehicle is not empty, 0 otherwise.
defVehicleRouteConsideredVar(self,vehicle:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the variable specifying whether or not the given vehicle route is
+ considered for costs and constraints. It will be equal to 1 iff the route
+ of the vehicle is not empty OR vehicle_used_when_empty_[vehicle] is true.
+ """
+ return_pywrapcp.RoutingModel_VehicleRouteConsideredVar(self,vehicle)
+
+
+
+
+
Returns the variable specifying whether or not the given vehicle route is
+considered for costs and constraints. It will be equal to 1 iff the route
+of the vehicle is not empty OR vehicle_used_when_empty_[vehicle] is true.
defVehicleVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Returns the vehicle variable of the node corresponding to index. Note that
+ VehicleVar(index) == -1 is equivalent to ActiveVar(index) == 0.
+ """
+ return_pywrapcp.RoutingModel_VehicleVar(self,index)
+
+
+
+
+
Returns the vehicle variable of the node corresponding to index. Note that
+VehicleVar(index) == -1 is equivalent to ActiveVar(index) == 0.
defResourceVar(self,vehicle:"int",resource_group:"int")->"operations_research::IntVar *":
+ r"""
+ Returns the resource variable for the given vehicle index in the given
+ resource group. If a vehicle doesn't require a resource from the
+ corresponding resource group, then ResourceVar(v, r_g) == -1.
+ """
+ return_pywrapcp.RoutingModel_ResourceVar(self,vehicle,resource_group)
+
+
+
+
+
Returns the resource variable for the given vehicle index in the given
+resource group. If a vehicle doesn't require a resource from the
+corresponding resource group, then ResourceVar(v, r_g) == -1.
defCostVar(self)->"operations_research::IntVar *":
+ r""" Returns the global cost variable which is being minimized."""
+ return_pywrapcp.RoutingModel_CostVar(self)
+
+
+
+
+
Returns the global cost variable which is being minimized.
defGetArcCostForVehicle(self,from_index:"int64_t",to_index:"int64_t",vehicle:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the transit arc between two nodes for a given vehicle.
+ Input are variable indices of node. This returns 0 if vehicle < 0.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForVehicle(self,from_index,to_index,vehicle)
+
+
+
+
+
Returns the cost of the transit arc between two nodes for a given vehicle.
+Input are variable indices of node. This returns 0 if vehicle < 0.
defCostsAreHomogeneousAcrossVehicles(self)->"bool":
+ r""" Whether costs are homogeneous across all vehicles."""
+ return_pywrapcp.RoutingModel_CostsAreHomogeneousAcrossVehicles(self)
+
+
+
+
+
Whether costs are homogeneous across all vehicles.
defGetHomogeneousCost(self,from_index:"int64_t",to_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the segment between two nodes supposing all vehicle
+ costs are the same (returns the cost for the first vehicle otherwise).
+ """
+ return_pywrapcp.RoutingModel_GetHomogeneousCost(self,from_index,to_index)
+
+
+
+
+
Returns the cost of the segment between two nodes supposing all vehicle
+costs are the same (returns the cost for the first vehicle otherwise).
defGetArcCostForFirstSolution(self,from_index:"int64_t",to_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the arc in the context of the first solution strategy.
+ This is typically a simplification of the actual cost; see the .cc.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForFirstSolution(self,from_index,to_index)
+
+
+
+
+
Returns the cost of the arc in the context of the first solution strategy.
+This is typically a simplification of the actual cost; see the .cc.
defGetArcCostForClass(self,from_index:"int64_t",to_index:"int64_t",cost_class_index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost of the segment between two nodes for a given cost
+ class. Input are variable indices of nodes and the cost class.
+ Unlike GetArcCostForVehicle(), if cost_class is kNoCost, then the
+ returned cost won't necessarily be zero: only some of the components
+ of the cost that depend on the cost class will be omited. See the code
+ for details.
+ """
+ return_pywrapcp.RoutingModel_GetArcCostForClass(self,from_index,to_index,cost_class_index)
+
+
+
+
+
Returns the cost of the segment between two nodes for a given cost
+class. Input are variable indices of nodes and the cost class.
+Unlike GetArcCostForVehicle(), if cost_class is kNoCost, then the
+returned cost won't necessarily be zero: only some of the components
+of the cost that depend on the cost class will be omited. See the code
+for details.
defGetCostClassIndexOfVehicle(self,vehicle:"int64_t")->"operations_research::RoutingModel::CostClassIndex":
+ r""" Get the cost class index of the given vehicle."""
+ return_pywrapcp.RoutingModel_GetCostClassIndexOfVehicle(self,vehicle)
+
defHasVehicleWithCostClassIndex(self,cost_class_index:"operations_research::RoutingModel::CostClassIndex")->"bool":
+ r"""
+ Returns true iff the model contains a vehicle with the given
+ cost_class_index.
+ """
+ return_pywrapcp.RoutingModel_HasVehicleWithCostClassIndex(self,cost_class_index)
+
+
+
+
+
Returns true iff the model contains a vehicle with the given
+cost_class_index.
defGetCostClassesCount(self)->"int":
+ r""" Returns the number of different cost classes in the model."""
+ return_pywrapcp.RoutingModel_GetCostClassesCount(self)
+
+
+
+
+
Returns the number of different cost classes in the model.
defGetVehicleOfClass(self,vehicle_class:"operations_research::RoutingModel::VehicleClassIndex")->"int":
+ r"""
+ Returns a vehicle of the given vehicle class, and -1 if there are no
+ vehicles for this class.
+ """
+ return_pywrapcp.RoutingModel_GetVehicleOfClass(self,vehicle_class)
+
+
+
+
+
Returns a vehicle of the given vehicle class, and -1 if there are no
+vehicles for this class.
defGetVehicleClassesCount(self)->"int":
+ r""" Returns the number of different vehicle classes in the model."""
+ return_pywrapcp.RoutingModel_GetVehicleClassesCount(self)
+
+
+
+
+
Returns the number of different vehicle classes in the model.
defGetSameVehicleIndicesOfIndex(self,node:"int")->"std::vector< int > const &":
+ r""" Returns variable indices of nodes constrained to be on the same route."""
+ return_pywrapcp.RoutingModel_GetSameVehicleIndicesOfIndex(self,node)
+
+
+
+
+
Returns variable indices of nodes constrained to be on the same route.
defArcIsMoreConstrainedThanArc(self,_from:"int64_t",to1:"int64_t",to2:"int64_t")->"bool":
+ r"""
+ Returns whether the arc from->to1 is more constrained than from->to2,
+ taking into account, in order:
+ - whether the destination node isn't an end node
+ - whether the destination node is mandatory
+ - whether the destination node is bound to the same vehicle as the source
+ - the "primary constrained" dimension (see SetPrimaryConstrainedDimension)
+ It then breaks ties using, in order:
+ - the arc cost (taking unperformed penalties into account)
+ - the size of the vehicle vars of "to1" and "to2" (lowest size wins)
+ - the value: the lowest value of the indices to1 and to2 wins.
+ See the .cc for details.
+ The more constrained arc is typically preferable when building a
+ first solution. This method is intended to be used as a callback for the
+ BestValueByComparisonSelector value selector.
+ Args:
+ from: the variable index of the source node
+ to1: the variable index of the first candidate destination node.
+ to2: the variable index of the second candidate destination node.
+ """
+ return_pywrapcp.RoutingModel_ArcIsMoreConstrainedThanArc(self,_from,to1,to2)
+
+
+
+
+
Returns whether the arc from->to1 is more constrained than from->to2,
+taking into account, in order:
+
+
+
whether the destination node isn't an end node
+
whether the destination node is mandatory
+
whether the destination node is bound to the same vehicle as the source
+
the "primary constrained" dimension (see SetPrimaryConstrainedDimension)
+It then breaks ties using, in order:
+
the arc cost (taking unperformed penalties into account)
+
the size of the vehicle vars of "to1" and "to2" (lowest size wins)
+
the value: the lowest value of the indices to1 and to2 wins.
+See the .cc for details.
+The more constrained arc is typically preferable when building a
+first solution. This method is intended to be used as a callback for the
+BestValueByComparisonSelector value selector.
+
+
+
Args
+
+
+
from: the variable index of the source node
+
to1: the variable index of the first candidate destination node.
+
to2: the variable index of the second candidate destination node.
defDebugOutputAssignment(self,solution_assignment:"Assignment",dimension_to_print:"std::string const &")->"std::string":
+ r"""
+ Print some debugging information about an assignment, including the
+ feasible intervals of the CumulVar for dimension "dimension_to_print"
+ at each step of the routes.
+ If "dimension_to_print" is omitted, all dimensions will be printed.
+ """
+ return_pywrapcp.RoutingModel_DebugOutputAssignment(self,solution_assignment,dimension_to_print)
+
+
+
+
+
Print some debugging information about an assignment, including the
+feasible intervals of the CumulVar for dimension "dimension_to_print"
+at each step of the routes.
+If "dimension_to_print" is omitted, all dimensions will be printed.
defsolver(self)->"operations_research::Solver *":
+ r"""
+ Returns a vector cumul_bounds, for which cumul_bounds[i][j] is a pair
+ containing the minimum and maximum of the CumulVar of the jth node on
+ route i.
+ - cumul_bounds[i][j].first is the minimum.
+ - cumul_bounds[i][j].second is the maximum.
+ Returns the underlying constraint solver. Can be used to add extra
+ constraints and/or modify search algorithms.
+ """
+ return_pywrapcp.RoutingModel_solver(self)
+
+
+
+
+
Returns a vector cumul_bounds, for which cumul_bounds[i][j] is a pair
+containing the minimum and maximum of the CumulVar of the jth node on
+route i.
+
+
+
cumul_bounds[i][j].first is the minimum.
+
cumul_bounds[i][j].second is the maximum.
+Returns the underlying constraint solver. Can be used to add extra
+constraints and/or modify search algorithms.
defGetNumberOfDecisionsInFirstSolution(self,search_parameters:"operations_research::RoutingSearchParameters const &")->"int64_t":
+ r"""
+ Returns statistics on first solution search, number of decisions sent to
+ filters, number of decisions rejected by filters.
+ """
+ return_pywrapcp.RoutingModel_GetNumberOfDecisionsInFirstSolution(self,search_parameters)
+
+
+
+
+
Returns statistics on first solution search, number of decisions sent to
+filters, number of decisions rejected by filters.
defIsMatchingModel(self)->"bool":
+ r""" Returns true if a vehicle/node matching problem is detected."""
+ return_pywrapcp.RoutingModel_IsMatchingModel(self)
+
+
+
+
+
Returns true if a vehicle/node matching problem is detected.
defMakeGuidedSlackFinalizer(self,dimension:"RoutingDimension",initializer:"std::function< int64_t (int64_t) >")->"operations_research::DecisionBuilder *":
+ r"""
+ The next few members are in the public section only for testing purposes.
+
+ MakeGuidedSlackFinalizer creates a DecisionBuilder for the slacks of a
+ dimension using a callback to choose which values to start with.
+ The finalizer works only when all next variables in the model have
+ been fixed. It has the following two characteristics:
+ 1. It follows the routes defined by the nexts variables when choosing a
+ variable to make a decision on.
+ 2. When it comes to choose a value for the slack of node i, the decision
+ builder first calls the callback with argument i, and supposingly the
+ returned value is x it creates decisions slack[i] = x, slack[i] = x +
+ 1, slack[i] = x - 1, slack[i] = x + 2, etc.
+ """
+ return_pywrapcp.RoutingModel_MakeGuidedSlackFinalizer(self,dimension,initializer)
+
+
+
+
+
The next few members are in the public section only for testing purposes.
+
+
MakeGuidedSlackFinalizer creates a DecisionBuilder for the slacks of a
+dimension using a callback to choose which values to start with.
+The finalizer works only when all next variables in the model have
+been fixed. It has the following two characteristics:
+
+
+
It follows the routes defined by the nexts variables when choosing a
+variable to make a decision on.
+
When it comes to choose a value for the slack of node i, the decision
+builder first calls the callback with argument i, and supposingly the
+returned value is x it creates decisions slack[i] = x, slack[i] = x +
+1, slack[i] = x - 1, slack[i] = x + 2, etc.
defMakeSelfDependentDimensionFinalizer(self,dimension:"RoutingDimension")->"operations_research::DecisionBuilder *":
+ r"""
+ MakeSelfDependentDimensionFinalizer is a finalizer for the slacks of a
+ self-dependent dimension. It makes an extensive use of the caches of the
+ state dependent transits.
+ In detail, MakeSelfDependentDimensionFinalizer returns a composition of a
+ local search decision builder with a greedy descent operator for the cumul
+ of the start of each route and a guided slack finalizer. Provided there
+ are no time windows and the maximum slacks are large enough, once the
+ cumul of the start of route is fixed, the guided finalizer can find
+ optimal values of the slacks for the rest of the route in time
+ proportional to the length of the route. Therefore the composed finalizer
+ generally works in time O(log(t)*n*m), where t is the latest possible
+ departute time, n is the number of nodes in the network and m is the
+ number of vehicles.
+ """
+ return_pywrapcp.RoutingModel_MakeSelfDependentDimensionFinalizer(self,dimension)
+
+
+
+
+
MakeSelfDependentDimensionFinalizer is a finalizer for the slacks of a
+self-dependent dimension. It makes an extensive use of the caches of the
+state dependent transits.
+In detail, MakeSelfDependentDimensionFinalizer returns a composition of a
+local search decision builder with a greedy descent operator for the cumul
+of the start of each route and a guided slack finalizer. Provided there
+are no time windows and the maximum slacks are large enough, once the
+cumul of the start of route is fixed, the guided finalizer can find
+optimal values of the slacks for the rest of the route in time
+proportional to the length of the route. Therefore the composed finalizer
+generally works in time O(log(t)nm), where t is the latest possible
+departute time, n is the number of nodes in the network and m is the
+number of vehicles.
+ #  
+
+
+ class
+ GlobalVehicleBreaksConstraint(Constraint):
+
+
+
+ View Source
+
classGlobalVehicleBreaksConstraint(Constraint):
+ r"""
+ GlobalVehicleBreaksConstraint ensures breaks constraints are enforced on
+ all vehicles in the dimension passed to its constructor.
+ It is intended to be used for dimensions representing time.
+ A break constraint ensures break intervals fit on the route of a vehicle.
+ For a given vehicle, it forces break intervals to be disjoint from visit
+ intervals, where visit intervals start at CumulVar(node) and last for
+ node_visit_transit[node]. Moreover, it ensures that there is enough time
+ between two consecutive nodes of a route to do transit and vehicle breaks,
+ i.e. if Next(nodeA) = nodeB, CumulVar(nodeA) = tA and CumulVar(nodeB) = tB,
+ then SlackVar(nodeA) >= sum_{breaks [tA, tB)} duration(break).
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,dimension:"RoutingDimension"):
+ _pywrapcp.GlobalVehicleBreaksConstraint_swiginit(self,_pywrapcp.new_GlobalVehicleBreaksConstraint(dimension))
+
+ defDebugString(self)->"std::string":
+ return_pywrapcp.GlobalVehicleBreaksConstraint_DebugString(self)
+
+ defPost(self)->"void":
+ return_pywrapcp.GlobalVehicleBreaksConstraint_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ return_pywrapcp.GlobalVehicleBreaksConstraint_InitialPropagateWrapper(self)
+ __swig_destroy__=_pywrapcp.delete_GlobalVehicleBreaksConstraint
+
+
+
+
+
GlobalVehicleBreaksConstraint ensures breaks constraints are enforced on
+all vehicles in the dimension passed to its constructor.
+It is intended to be used for dimensions representing time.
+A break constraint ensures break intervals fit on the route of a vehicle.
+For a given vehicle, it forces break intervals to be disjoint from visit
+intervals, where visit intervals start at CumulVar(node) and last for
+node_visit_transit[node]. Moreover, it ensures that there is enough time
+between two consecutive nodes of a route to do transit and vehicle breaks,
+i.e. if Next(nodeA) = nodeB, CumulVar(nodeA) = tA and CumulVar(nodeB) = tB,
+then SlackVar(nodeA) >= sum_{breaks [tA, tB)} duration(break).
classTypeRegulationsConstraint(Constraint):
+ r"""
+ The following constraint ensures that incompatibilities and requirements
+ between types are respected.
+
+ It verifies both "hard" and "temporal" incompatibilities.
+ Two nodes with hard incompatible types cannot be served by the same vehicle
+ at all, while with a temporal incompatibility they can't be on the same
+ route at the same time.
+ The VisitTypePolicy of a node determines how visiting it impacts the type
+ count on the route.
+
+ For example, for
+ - three temporally incompatible types T1 T2 and T3
+ - 2 pairs of nodes a1/r1 and a2/r2 of type T1 and T2 respectively, with
+ - a1 and a2 of VisitTypePolicy TYPE_ADDED_TO_VEHICLE
+ - r1 and r2 of policy ADDED_TYPE_REMOVED_FROM_VEHICLE
+ - 3 nodes A, UV and AR of type T3, respectively with type policies
+ TYPE_ADDED_TO_VEHICLE, TYPE_ON_VEHICLE_UP_TO_VISIT and
+ TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED
+ the configurations
+ UV --> a1 --> r1 --> a2 --> r2, a1 --> r1 --> a2 --> r2 --> A and
+ a1 --> r1 --> AR --> a2 --> r2 are acceptable, whereas the configurations
+ a1 --> a2 --> r1 --> ..., or A --> a1 --> r1 --> ..., or
+ a1 --> r1 --> UV --> ... are not feasible.
+
+ It also verifies same-vehicle and temporal type requirements.
+ A node of type T_d with a same-vehicle requirement for type T_r needs to be
+ served by the same vehicle as a node of type T_r.
+ Temporal requirements, on the other hand, can take effect either when the
+ dependent type is being added to the route or when it's removed from it,
+ which is determined by the dependent node's VisitTypePolicy.
+ In the above example:
+ - If T3 is required on the same vehicle as T1, A, AR or UV must be on the
+ same vehicle as a1.
+ - If T2 is required when adding T1, a2 must be visited *before* a1, and if
+ r2 is also visited on the route, it must be *after* a1, i.e. T2 must be on
+ the vehicle when a1 is visited:
+ ... --> a2 --> ... --> a1 --> ... --> r2 --> ...
+ - If T3 is required when removing T1, T3 needs to be on the vehicle when
+ r1 is visited:
+ ... --> A --> ... --> r1 --> ... OR ... --> r1 --> ... --> UV --> ...
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self,model:"RoutingModel"):
+ _pywrapcp.TypeRegulationsConstraint_swiginit(self,_pywrapcp.new_TypeRegulationsConstraint(model))
+
+ defPost(self)->"void":
+ return_pywrapcp.TypeRegulationsConstraint_Post(self)
+
+ defInitialPropagateWrapper(self)->"void":
+ return_pywrapcp.TypeRegulationsConstraint_InitialPropagateWrapper(self)
+ __swig_destroy__=_pywrapcp.delete_TypeRegulationsConstraint
+
+
+
+
+
The following constraint ensures that incompatibilities and requirements
+between types are respected.
+
+
It verifies both "hard" and "temporal" incompatibilities.
+Two nodes with hard incompatible types cannot be served by the same vehicle
+at all, while with a temporal incompatibility they can't be on the same
+route at the same time.
+The VisitTypePolicy of a node determines how visiting it impacts the type
+count on the route.
+
+
For example, for
+
+
+
three temporally incompatible types T1 T2 and T3
+
2 pairs of nodes a1/r1 and a2/r2 of type T1 and T2 respectively, with
+
+
a1 and a2 of VisitTypePolicy TYPE_ADDED_TO_VEHICLE
+
r1 and r2 of policy ADDED_TYPE_REMOVED_FROM_VEHICLE
+
+
3 nodes A, UV and AR of type T3, respectively with type policies
+TYPE_ADDED_TO_VEHICLE, TYPE_ON_VEHICLE_UP_TO_VISIT and
+TYPE_SIMULTANEOUSLY_ADDED_AND_REMOVED
+the configurations
+UV --> a1 --> r1 --> a2 --> r2, a1 --> r1 --> a2 --> r2 --> A and
+a1 --> r1 --> AR --> a2 --> r2 are acceptable, whereas the configurations
+a1 --> a2 --> r1 --> ..., or A --> a1 --> r1 --> ..., or
+a1 --> r1 --> UV --> ... are not feasible.
+
+
+
It also verifies same-vehicle and temporal type requirements.
+A node of type T_d with a same-vehicle requirement for type T_r needs to be
+served by the same vehicle as a node of type T_r.
+Temporal requirements, on the other hand, can take effect either when the
+dependent type is being added to the route or when it's removed from it,
+which is determined by the dependent node's VisitTypePolicy.
+In the above example:
+
+
+
If T3 is required on the same vehicle as T1, A, AR or UV must be on the
+same vehicle as a1.
+
If T2 is required when adding T1, a2 must be visited before a1, and if
+r2 is also visited on the route, it must be after a1, i.e. T2 must be on
+the vehicle when a1 is visited:
+... --> a2 --> ... --> a1 --> ... --> r2 --> ...
+
If T3 is required when removing T1, T3 needs to be on the vehicle when
+r1 is visited:
+... --> A --> ... --> r1 --> ... OR ... --> r1 --> ... --> UV --> ...
classRoutingDimension(object):
+ r"""
+ Dimensions represent quantities accumulated at nodes along the routes. They
+ represent quantities such as weights or volumes carried along the route, or
+ distance or times.
+
+ Quantities at a node are represented by "cumul" variables and the increase
+ or decrease of quantities between nodes are represented by "transit"
+ variables. These variables are linked as follows:
+
+ if j == next(i),
+ cumuls(j) = cumuls(i) + transits(i) + slacks(i) +
+ state_dependent_transits(i)
+
+ where slack is a positive slack variable (can represent waiting times for
+ a time dimension), and state_dependent_transits is a non-purely functional
+ version of transits_. Favour transits over state_dependent_transits when
+ possible, because purely functional callbacks allow more optimisations and
+ make the model faster and easier to solve.
+ for a given vehicle, it is passed as an external vector, it would be better
+ to have this information here.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+ __swig_destroy__=_pywrapcp.delete_RoutingDimension
+
+ defmodel(self)->"operations_research::RoutingModel *":
+ r""" Returns the model on which the dimension was created."""
+ return_pywrapcp.RoutingDimension_model(self)
+
+ defGetTransitValue(self,from_index:"int64_t",to_index:"int64_t",vehicle:"int64_t")->"int64_t":
+ r"""
+ Returns the transition value for a given pair of nodes (as var index);
+ this value is the one taken by the corresponding transit variable when
+ the 'next' variable for 'from_index' is bound to 'to_index'.
+ """
+ return_pywrapcp.RoutingDimension_GetTransitValue(self,from_index,to_index,vehicle)
+
+ defGetTransitValueFromClass(self,from_index:"int64_t",to_index:"int64_t",vehicle_class:"int64_t")->"int64_t":
+ r"""
+ Same as above but taking a vehicle class of the dimension instead of a
+ vehicle (the class of a vehicle can be obtained with vehicle_to_class()).
+ """
+ return_pywrapcp.RoutingDimension_GetTransitValueFromClass(self,from_index,to_index,vehicle_class)
+
+ defCumulVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Get the cumul, transit and slack variables for the given node (given as
+ int64_t var index).
+ """
+ return_pywrapcp.RoutingDimension_CumulVar(self,index)
+
+ defTransitVar(self,index:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.RoutingDimension_TransitVar(self,index)
+
+ defFixedTransitVar(self,index:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.RoutingDimension_FixedTransitVar(self,index)
+
+ defSlackVar(self,index:"int64_t")->"operations_research::IntVar *":
+ return_pywrapcp.RoutingDimension_SlackVar(self,index)
+
+ defSetSpanUpperBoundForVehicle(self,upper_bound:"int64_t",vehicle:"int")->"void":
+ r"""
+ Sets an upper bound on the dimension span on a given vehicle. This is the
+ preferred way to limit the "length" of the route of a vehicle according to
+ a dimension.
+ """
+ return_pywrapcp.RoutingDimension_SetSpanUpperBoundForVehicle(self,upper_bound,vehicle)
+
+ defSetSpanCostCoefficientForVehicle(self,coefficient:"int64_t",vehicle:"int")->"void":
+ r"""
+ Sets a cost proportional to the dimension span on a given vehicle,
+ or on all vehicles at once. "coefficient" must be nonnegative.
+ This is handy to model costs proportional to idle time when the dimension
+ represents time.
+ The cost for a vehicle is
+ span_cost = coefficient * (dimension end value - dimension start value).
+ """
+ return_pywrapcp.RoutingDimension_SetSpanCostCoefficientForVehicle(self,coefficient,vehicle)
+
+ defSetSpanCostCoefficientForAllVehicles(self,coefficient:"int64_t")->"void":
+ return_pywrapcp.RoutingDimension_SetSpanCostCoefficientForAllVehicles(self,coefficient)
+
+ defSetGlobalSpanCostCoefficient(self,coefficient:"int64_t")->"void":
+ r"""
+ Sets a cost proportional to the *global* dimension span, that is the
+ difference between the largest value of route end cumul variables and
+ the smallest value of route start cumul variables.
+ In other words:
+ global_span_cost =
+ coefficient * (Max(dimension end value) - Min(dimension start value)).
+ """
+ return_pywrapcp.RoutingDimension_SetGlobalSpanCostCoefficient(self,coefficient)
+
+ defSetCumulVarSoftUpperBound(self,index:"int64_t",upper_bound:"int64_t",coefficient:"int64_t")->"void":
+ r"""
+ Sets a soft upper bound to the cumul variable of a given variable index.
+ If the value of the cumul variable is greater than the bound, a cost
+ proportional to the difference between this value and the bound is added
+ to the cost function of the model:
+ cumulVar <= upper_bound -> cost = 0
+ cumulVar > upper_bound -> cost = coefficient * (cumulVar - upper_bound)
+ This is also handy to model tardiness costs when the dimension represents
+ time.
+ """
+ return_pywrapcp.RoutingDimension_SetCumulVarSoftUpperBound(self,index,upper_bound,coefficient)
+
+ defHasCumulVarSoftUpperBound(self,index:"int64_t")->"bool":
+ r"""
+ Returns true if a soft upper bound has been set for a given variable
+ index.
+ """
+ return_pywrapcp.RoutingDimension_HasCumulVarSoftUpperBound(self,index)
+
+ defGetCumulVarSoftUpperBound(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the soft upper bound of a cumul variable for a given variable
+ index. The "hard" upper bound of the variable is returned if no soft upper
+ bound has been set.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftUpperBound(self,index)
+
+ defGetCumulVarSoftUpperBoundCoefficient(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost coefficient of the soft upper bound of a cumul variable
+ for a given variable index. If no soft upper bound has been set, 0 is
+ returned.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftUpperBoundCoefficient(self,index)
+
+ defSetCumulVarSoftLowerBound(self,index:"int64_t",lower_bound:"int64_t",coefficient:"int64_t")->"void":
+ r"""
+ Sets a soft lower bound to the cumul variable of a given variable index.
+ If the value of the cumul variable is less than the bound, a cost
+ proportional to the difference between this value and the bound is added
+ to the cost function of the model:
+ cumulVar > lower_bound -> cost = 0
+ cumulVar <= lower_bound -> cost = coefficient * (lower_bound -
+ cumulVar).
+ This is also handy to model earliness costs when the dimension represents
+ time.
+ """
+ return_pywrapcp.RoutingDimension_SetCumulVarSoftLowerBound(self,index,lower_bound,coefficient)
+
+ defHasCumulVarSoftLowerBound(self,index:"int64_t")->"bool":
+ r"""
+ Returns true if a soft lower bound has been set for a given variable
+ index.
+ """
+ return_pywrapcp.RoutingDimension_HasCumulVarSoftLowerBound(self,index)
+
+ defGetCumulVarSoftLowerBound(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the soft lower bound of a cumul variable for a given variable
+ index. The "hard" lower bound of the variable is returned if no soft lower
+ bound has been set.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftLowerBound(self,index)
+
+ defGetCumulVarSoftLowerBoundCoefficient(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost coefficient of the soft lower bound of a cumul variable
+ for a given variable index. If no soft lower bound has been set, 0 is
+ returned.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftLowerBoundCoefficient(self,index)
+
+ defSetBreakIntervalsOfVehicle(self,breaks:"std::vector< operations_research::IntervalVar * >",vehicle:"int",node_visit_transits:"std::vector< int64_t >")->"void":
+ r"""
+ Sets the breaks for a given vehicle. Breaks are represented by
+ IntervalVars. They may interrupt transits between nodes and increase
+ the value of corresponding slack variables.
+ A break may take place before the start of a vehicle, after the end of
+ a vehicle, or during a travel i -> j.
+
+ In that case, the interval [break.Start(), break.End()) must be a subset
+ of [CumulVar(i) + pre_travel(i, j), CumulVar(j) - post_travel(i, j)). In
+ other words, a break may not overlap any node n's visit, given by
+ [CumulVar(n) - post_travel(_, n), CumulVar(n) + pre_travel(n, _)).
+ This formula considers post_travel(_, start) and pre_travel(end, _) to be
+ 0; pre_travel will never be called on any (_, start) and post_travel will
+ never we called on any (end, _). If pre_travel_evaluator or
+ post_travel_evaluator is -1, it will be taken as a function that always
+ returns 0.
+ Deprecated, sets pre_travel(i, j) = node_visit_transit[i].
+ """
+ return_pywrapcp.RoutingDimension_SetBreakIntervalsOfVehicle(self,breaks,vehicle,node_visit_transits)
+
+ defSetBreakDistanceDurationOfVehicle(self,distance:"int64_t",duration:"int64_t",vehicle:"int")->"void":
+ r"""
+ With breaks supposed to be consecutive, this forces the distance between
+ breaks of size at least minimum_break_duration to be at most distance.
+ This supposes that the time until route start and after route end are
+ infinite breaks.
+ """
+ return_pywrapcp.RoutingDimension_SetBreakDistanceDurationOfVehicle(self,distance,duration,vehicle)
+
+ defInitializeBreaks(self)->"void":
+ r"""
+ Sets up vehicle_break_intervals_, vehicle_break_distance_duration_,
+ pre_travel_evaluators and post_travel_evaluators.
+ """
+ return_pywrapcp.RoutingDimension_InitializeBreaks(self)
+
+ defHasBreakConstraints(self)->"bool":
+ r""" Returns true if any break interval or break distance was defined."""
+ return_pywrapcp.RoutingDimension_HasBreakConstraints(self)
+
+ defGetPreTravelEvaluatorOfVehicle(self,vehicle:"int")->"int":
+ return_pywrapcp.RoutingDimension_GetPreTravelEvaluatorOfVehicle(self,vehicle)
+
+ defGetPostTravelEvaluatorOfVehicle(self,vehicle:"int")->"int":
+ return_pywrapcp.RoutingDimension_GetPostTravelEvaluatorOfVehicle(self,vehicle)
+
+ defbase_dimension(self)->"operations_research::RoutingDimension const *":
+ r""" Returns the parent in the dependency tree if any or nullptr otherwise."""
+ return_pywrapcp.RoutingDimension_base_dimension(self)
+
+ defShortestTransitionSlack(self,node:"int64_t")->"int64_t":
+ r"""
+ It makes sense to use the function only for self-dependent dimension.
+ For such dimensions the value of the slack of a node determines the
+ transition cost of the next transit. Provided that
+ 1. cumul[node] is fixed,
+ 2. next[node] and next[next[node]] (if exists) are fixed,
+ the value of slack[node] for which cumul[next[node]] + transit[next[node]]
+ is minimized can be found in O(1) using this function.
+ """
+ return_pywrapcp.RoutingDimension_ShortestTransitionSlack(self,node)
+
+ defname(self)->"std::string const &":
+ r""" Returns the name of the dimension."""
+ return_pywrapcp.RoutingDimension_name(self)
+
+ defSetPickupToDeliveryLimitFunctionForPair(self,limit_function:"operations_research::RoutingDimension::PickupToDeliveryLimitFunction",pair_index:"int")->"void":
+ return_pywrapcp.RoutingDimension_SetPickupToDeliveryLimitFunctionForPair(self,limit_function,pair_index)
+
+ defHasPickupToDeliveryLimits(self)->"bool":
+ return_pywrapcp.RoutingDimension_HasPickupToDeliveryLimits(self)
+
+ defAddNodePrecedence(self,first_node:"int64_t",second_node:"int64_t",offset:"int64_t")->"void":
+ return_pywrapcp.RoutingDimension_AddNodePrecedence(self,first_node,second_node,offset)
+
+ defGetSpanUpperBoundForVehicle(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingDimension_GetSpanUpperBoundForVehicle(self,vehicle)
+
+ defGetSpanCostCoefficientForVehicle(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingDimension_GetSpanCostCoefficientForVehicle(self,vehicle)
+
+ defglobal_span_cost_coefficient(self)->"int64_t":
+ return_pywrapcp.RoutingDimension_global_span_cost_coefficient(self)
+
+ defGetGlobalOptimizerOffset(self)->"int64_t":
+ return_pywrapcp.RoutingDimension_GetGlobalOptimizerOffset(self)
+
+ defGetLocalOptimizerOffsetForVehicle(self,vehicle:"int")->"int64_t":
+ return_pywrapcp.RoutingDimension_GetLocalOptimizerOffsetForVehicle(self,vehicle)
+
+
+
+
+
Dimensions represent quantities accumulated at nodes along the routes. They
+represent quantities such as weights or volumes carried along the route, or
+distance or times.
+
+
Quantities at a node are represented by "cumul" variables and the increase
+or decrease of quantities between nodes are represented by "transit"
+variables. These variables are linked as follows:
where slack is a positive slack variable (can represent waiting times for
+a time dimension), and state_dependent_transits is a non-purely functional
+version of transits_. Favour transits over state_dependent_transits when
+possible, because purely functional callbacks allow more optimisations and
+make the model faster and easier to solve.
+for a given vehicle, it is passed as an external vector, it would be better
+to have this information here.
defmodel(self)->"operations_research::RoutingModel *":
+ r""" Returns the model on which the dimension was created."""
+ return_pywrapcp.RoutingDimension_model(self)
+
+
+
+
+
Returns the model on which the dimension was created.
defGetTransitValue(self,from_index:"int64_t",to_index:"int64_t",vehicle:"int64_t")->"int64_t":
+ r"""
+ Returns the transition value for a given pair of nodes (as var index);
+ this value is the one taken by the corresponding transit variable when
+ the 'next' variable for 'from_index' is bound to 'to_index'.
+ """
+ return_pywrapcp.RoutingDimension_GetTransitValue(self,from_index,to_index,vehicle)
+
+
+
+
+
Returns the transition value for a given pair of nodes (as var index);
+this value is the one taken by the corresponding transit variable when
+the 'next' variable for 'from_index' is bound to 'to_index'.
defGetTransitValueFromClass(self,from_index:"int64_t",to_index:"int64_t",vehicle_class:"int64_t")->"int64_t":
+ r"""
+ Same as above but taking a vehicle class of the dimension instead of a
+ vehicle (the class of a vehicle can be obtained with vehicle_to_class()).
+ """
+ return_pywrapcp.RoutingDimension_GetTransitValueFromClass(self,from_index,to_index,vehicle_class)
+
+
+
+
+
Same as above but taking a vehicle class of the dimension instead of a
+vehicle (the class of a vehicle can be obtained with vehicle_to_class()).
defCumulVar(self,index:"int64_t")->"operations_research::IntVar *":
+ r"""
+ Get the cumul, transit and slack variables for the given node (given as
+ int64_t var index).
+ """
+ return_pywrapcp.RoutingDimension_CumulVar(self,index)
+
+
+
+
+
Get the cumul, transit and slack variables for the given node (given as
+int64_t var index).
defSetSpanUpperBoundForVehicle(self,upper_bound:"int64_t",vehicle:"int")->"void":
+ r"""
+ Sets an upper bound on the dimension span on a given vehicle. This is the
+ preferred way to limit the "length" of the route of a vehicle according to
+ a dimension.
+ """
+ return_pywrapcp.RoutingDimension_SetSpanUpperBoundForVehicle(self,upper_bound,vehicle)
+
+
+
+
+
Sets an upper bound on the dimension span on a given vehicle. This is the
+preferred way to limit the "length" of the route of a vehicle according to
+a dimension.
defSetSpanCostCoefficientForVehicle(self,coefficient:"int64_t",vehicle:"int")->"void":
+ r"""
+ Sets a cost proportional to the dimension span on a given vehicle,
+ or on all vehicles at once. "coefficient" must be nonnegative.
+ This is handy to model costs proportional to idle time when the dimension
+ represents time.
+ The cost for a vehicle is
+ span_cost = coefficient * (dimension end value - dimension start value).
+ """
+ return_pywrapcp.RoutingDimension_SetSpanCostCoefficientForVehicle(self,coefficient,vehicle)
+
+
+
+
+
Sets a cost proportional to the dimension span on a given vehicle,
+or on all vehicles at once. "coefficient" must be nonnegative.
+This is handy to model costs proportional to idle time when the dimension
+represents time.
+The cost for a vehicle is
+ span_cost = coefficient * (dimension end value - dimension start value).
defSetGlobalSpanCostCoefficient(self,coefficient:"int64_t")->"void":
+ r"""
+ Sets a cost proportional to the *global* dimension span, that is the
+ difference between the largest value of route end cumul variables and
+ the smallest value of route start cumul variables.
+ In other words:
+ global_span_cost =
+ coefficient * (Max(dimension end value) - Min(dimension start value)).
+ """
+ return_pywrapcp.RoutingDimension_SetGlobalSpanCostCoefficient(self,coefficient)
+
+
+
+
+
Sets a cost proportional to the global dimension span, that is the
+difference between the largest value of route end cumul variables and
+the smallest value of route start cumul variables.
+In other words:
+global_span_cost =
+ coefficient * (Max(dimension end value) - Min(dimension start value)).
defSetCumulVarSoftUpperBound(self,index:"int64_t",upper_bound:"int64_t",coefficient:"int64_t")->"void":
+ r"""
+ Sets a soft upper bound to the cumul variable of a given variable index.
+ If the value of the cumul variable is greater than the bound, a cost
+ proportional to the difference between this value and the bound is added
+ to the cost function of the model:
+ cumulVar <= upper_bound -> cost = 0
+ cumulVar > upper_bound -> cost = coefficient * (cumulVar - upper_bound)
+ This is also handy to model tardiness costs when the dimension represents
+ time.
+ """
+ return_pywrapcp.RoutingDimension_SetCumulVarSoftUpperBound(self,index,upper_bound,coefficient)
+
+
+
+
+
Sets a soft upper bound to the cumul variable of a given variable index.
+If the value of the cumul variable is greater than the bound, a cost
+proportional to the difference between this value and the bound is added
+to the cost function of the model:
+ cumulVar <= upper_bound -> cost = 0
+ cumulVar > upper_bound -> cost = coefficient * (cumulVar - upper_bound)
+This is also handy to model tardiness costs when the dimension represents
+time.
defHasCumulVarSoftUpperBound(self,index:"int64_t")->"bool":
+ r"""
+ Returns true if a soft upper bound has been set for a given variable
+ index.
+ """
+ return_pywrapcp.RoutingDimension_HasCumulVarSoftUpperBound(self,index)
+
+
+
+
+
Returns true if a soft upper bound has been set for a given variable
+index.
defGetCumulVarSoftUpperBound(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the soft upper bound of a cumul variable for a given variable
+ index. The "hard" upper bound of the variable is returned if no soft upper
+ bound has been set.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftUpperBound(self,index)
+
+
+
+
+
Returns the soft upper bound of a cumul variable for a given variable
+index. The "hard" upper bound of the variable is returned if no soft upper
+bound has been set.
defGetCumulVarSoftUpperBoundCoefficient(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost coefficient of the soft upper bound of a cumul variable
+ for a given variable index. If no soft upper bound has been set, 0 is
+ returned.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftUpperBoundCoefficient(self,index)
+
+
+
+
+
Returns the cost coefficient of the soft upper bound of a cumul variable
+for a given variable index. If no soft upper bound has been set, 0 is
+returned.
defSetCumulVarSoftLowerBound(self,index:"int64_t",lower_bound:"int64_t",coefficient:"int64_t")->"void":
+ r"""
+ Sets a soft lower bound to the cumul variable of a given variable index.
+ If the value of the cumul variable is less than the bound, a cost
+ proportional to the difference between this value and the bound is added
+ to the cost function of the model:
+ cumulVar > lower_bound -> cost = 0
+ cumulVar <= lower_bound -> cost = coefficient * (lower_bound -
+ cumulVar).
+ This is also handy to model earliness costs when the dimension represents
+ time.
+ """
+ return_pywrapcp.RoutingDimension_SetCumulVarSoftLowerBound(self,index,lower_bound,coefficient)
+
+
+
+
+
Sets a soft lower bound to the cumul variable of a given variable index.
+If the value of the cumul variable is less than the bound, a cost
+proportional to the difference between this value and the bound is added
+to the cost function of the model:
+ cumulVar > lower_bound -> cost = 0
+ cumulVar <= lower_bound -> cost = coefficient * (lower_bound -
+ cumulVar).
+This is also handy to model earliness costs when the dimension represents
+time.
defHasCumulVarSoftLowerBound(self,index:"int64_t")->"bool":
+ r"""
+ Returns true if a soft lower bound has been set for a given variable
+ index.
+ """
+ return_pywrapcp.RoutingDimension_HasCumulVarSoftLowerBound(self,index)
+
+
+
+
+
Returns true if a soft lower bound has been set for a given variable
+index.
defGetCumulVarSoftLowerBound(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the soft lower bound of a cumul variable for a given variable
+ index. The "hard" lower bound of the variable is returned if no soft lower
+ bound has been set.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftLowerBound(self,index)
+
+
+
+
+
Returns the soft lower bound of a cumul variable for a given variable
+index. The "hard" lower bound of the variable is returned if no soft lower
+bound has been set.
defGetCumulVarSoftLowerBoundCoefficient(self,index:"int64_t")->"int64_t":
+ r"""
+ Returns the cost coefficient of the soft lower bound of a cumul variable
+ for a given variable index. If no soft lower bound has been set, 0 is
+ returned.
+ """
+ return_pywrapcp.RoutingDimension_GetCumulVarSoftLowerBoundCoefficient(self,index)
+
+
+
+
+
Returns the cost coefficient of the soft lower bound of a cumul variable
+for a given variable index. If no soft lower bound has been set, 0 is
+returned.
defSetBreakIntervalsOfVehicle(self,breaks:"std::vector< operations_research::IntervalVar * >",vehicle:"int",node_visit_transits:"std::vector< int64_t >")->"void":
+ r"""
+ Sets the breaks for a given vehicle. Breaks are represented by
+ IntervalVars. They may interrupt transits between nodes and increase
+ the value of corresponding slack variables.
+ A break may take place before the start of a vehicle, after the end of
+ a vehicle, or during a travel i -> j.
+
+ In that case, the interval [break.Start(), break.End()) must be a subset
+ of [CumulVar(i) + pre_travel(i, j), CumulVar(j) - post_travel(i, j)). In
+ other words, a break may not overlap any node n's visit, given by
+ [CumulVar(n) - post_travel(_, n), CumulVar(n) + pre_travel(n, _)).
+ This formula considers post_travel(_, start) and pre_travel(end, _) to be
+ 0; pre_travel will never be called on any (_, start) and post_travel will
+ never we called on any (end, _). If pre_travel_evaluator or
+ post_travel_evaluator is -1, it will be taken as a function that always
+ returns 0.
+ Deprecated, sets pre_travel(i, j) = node_visit_transit[i].
+ """
+ return_pywrapcp.RoutingDimension_SetBreakIntervalsOfVehicle(self,breaks,vehicle,node_visit_transits)
+
+
+
+
+
Sets the breaks for a given vehicle. Breaks are represented by
+IntervalVars. They may interrupt transits between nodes and increase
+the value of corresponding slack variables.
+A break may take place before the start of a vehicle, after the end of
+a vehicle, or during a travel i -> j.
+
+
In that case, the interval [break.Start(), break.End()) must be a subset
+of [CumulVar(i) + pre_travel(i, j), CumulVar(j) - post_travel(i, j)). In
+other words, a break may not overlap any node n's visit, given by
+[CumulVar(n) - post_travel(_, n), CumulVar(n) + pre_travel(n, _)).
+This formula considers post_travel(_, start) and pre_travel(end, _) to be
+0; pre_travel will never be called on any (_, start) and post_travel will
+never we called on any (end, _). If pre_travel_evaluator or
+post_travel_evaluator is -1, it will be taken as a function that always
+returns 0.
+Deprecated, sets pre_travel(i, j) = node_visit_transit[i].
defSetBreakDistanceDurationOfVehicle(self,distance:"int64_t",duration:"int64_t",vehicle:"int")->"void":
+ r"""
+ With breaks supposed to be consecutive, this forces the distance between
+ breaks of size at least minimum_break_duration to be at most distance.
+ This supposes that the time until route start and after route end are
+ infinite breaks.
+ """
+ return_pywrapcp.RoutingDimension_SetBreakDistanceDurationOfVehicle(self,distance,duration,vehicle)
+
+
+
+
+
With breaks supposed to be consecutive, this forces the distance between
+breaks of size at least minimum_break_duration to be at most distance.
+This supposes that the time until route start and after route end are
+infinite breaks.
defHasBreakConstraints(self)->"bool":
+ r""" Returns true if any break interval or break distance was defined."""
+ return_pywrapcp.RoutingDimension_HasBreakConstraints(self)
+
+
+
+
+
Returns true if any break interval or break distance was defined.
defbase_dimension(self)->"operations_research::RoutingDimension const *":
+ r""" Returns the parent in the dependency tree if any or nullptr otherwise."""
+ return_pywrapcp.RoutingDimension_base_dimension(self)
+
+
+
+
+
Returns the parent in the dependency tree if any or nullptr otherwise.
defShortestTransitionSlack(self,node:"int64_t")->"int64_t":
+ r"""
+ It makes sense to use the function only for self-dependent dimension.
+ For such dimensions the value of the slack of a node determines the
+ transition cost of the next transit. Provided that
+ 1. cumul[node] is fixed,
+ 2. next[node] and next[next[node]] (if exists) are fixed,
+ the value of slack[node] for which cumul[next[node]] + transit[next[node]]
+ is minimized can be found in O(1) using this function.
+ """
+ return_pywrapcp.RoutingDimension_ShortestTransitionSlack(self,node)
+
+
+
+
+
It makes sense to use the function only for self-dependent dimension.
+For such dimensions the value of the slack of a node determines the
+transition cost of the next transit. Provided that
+
+
+
cumul[node] is fixed,
+
next[node] and next[next[node]] (if exists) are fixed,
+the value of slack[node] for which cumul[next[node]] + transit[next[node]]
+is minimized can be found in O(1) using this function.
defMakeSetValuesFromTargets(solver:"Solver",variables:"std::vector< operations_research::IntVar * >",targets:"std::vector< int64_t >")->"operations_research::DecisionBuilder *":
+ r"""
+ A decision builder which tries to assign values to variables as close as
+ possible to target values first.
+ """
+ return_pywrapcp.MakeSetValuesFromTargets(solver,variables,targets)
+
+
+
+
+
A decision builder which tries to assign values to variables as close as
+possible to target values first.
defSolveModelWithSat(model:"RoutingModel",search_parameters:"operations_research::RoutingSearchParameters const &",initial_solution:"Assignment",solution:"Assignment")->"bool":
+ r"""
+ Attempts to solve the model using the cp-sat solver. As of 5/2019, will
+ solve the TSP corresponding to the model if it has a single vehicle.
+ Therefore the resulting solution might not actually be feasible. Will return
+ false if a solution could not be found.
+ """
+ return_pywrapcp.SolveModelWithSat(model,search_parameters,initial_solution,solution)
+
+
+
+
+
Attempts to solve the model using the cp-sat solver. As of 5/2019, will
+solve the TSP corresponding to the model if it has a single vehicle.
+Therefore the resulting solution might not actually be feasible. Will return
+false if a solution could not be found.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/python/ortools/graph/index.html b/docs/python/ortools/graph/index.html
index b0b64f18c3..271e6e1c78 100644
--- a/docs/python/ortools/graph/index.html
+++ b/docs/python/ortools/graph/index.html
@@ -1,58 +1,7 @@
-
+
-
-
- Module List – pdoc 8.0.0
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/docs/python/ortools/graph/ortools/graph/pywrapgraph.html b/docs/python/ortools/graph/ortools/graph/pywrapgraph.html
new file mode 100644
index 0000000000..b98bdcdacc
--- /dev/null
+++ b/docs/python/ortools/graph/ortools/graph/pywrapgraph.html
@@ -0,0 +1,1832 @@
+
+
+
+
+
+
+ ortools.graph.pywrapgraph API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/python/ortools/linear_solver/index.html b/docs/python/ortools/linear_solver/index.html
index d9f2a731dc..9eb7e9fc1e 100644
--- a/docs/python/ortools/linear_solver/index.html
+++ b/docs/python/ortools/linear_solver/index.html
@@ -1,58 +1,7 @@
-
+
-
-
- Module List – pdoc 8.0.0
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/docs/python/ortools/linear_solver/ortools/linear_solver/pywraplp.html b/docs/python/ortools/linear_solver/ortools/linear_solver/pywraplp.html
new file mode 100644
index 0000000000..5c0ef11848
--- /dev/null
+++ b/docs/python/ortools/linear_solver/ortools/linear_solver/pywraplp.html
@@ -0,0 +1,6407 @@
+
+
+
+
+
+
+ ortools.linear_solver.pywraplp API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+ortools.linear_solver.pywraplp
+
+
+
+ View Source
+
# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 4.0.2
+#
+# Do not make changes to this file unless you know what you are doing--modify
+# the SWIG interface file instead.
+
+fromsysimportversion_infoas_swig_python_version_info
+if_swig_python_version_info<(2,7,0):
+ raiseRuntimeError("Python 2.7 or later required")
+
+# Import the low-level C/C++ module
+if__package__or"."in__name__:
+ from.import_pywraplp
+else:
+ import_pywraplp
+
+try:
+ importbuiltinsas__builtin__
+exceptImportError:
+ import__builtin__
+
+def_swig_repr(self):
+ try:
+ strthis="proxy of "+self.this.__repr__()
+ except__builtin__.Exception:
+ strthis=""
+ return"<%s.%s; %s >"%(self.__class__.__module__,self.__class__.__name__,strthis,)
+
+
+def_swig_setattr_nondynamic_instance_variable(set):
+ defset_instance_attr(self,name,value):
+ ifname=="thisown":
+ self.this.own(value)
+ elifname=="this":
+ set(self,name,value)
+ elifhasattr(self,name)andisinstance(getattr(type(self),name),property):
+ set(self,name,value)
+ else:
+ raiseAttributeError("You cannot add instance attributes to %s"%self)
+ returnset_instance_attr
+
+
+def_swig_setattr_nondynamic_class_variable(set):
+ defset_class_attr(cls,name,value):
+ ifhasattr(cls,name)andnotisinstance(getattr(cls,name),property):
+ set(cls,name,value)
+ else:
+ raiseAttributeError("You cannot add class attributes to %s"%cls)
+ returnset_class_attr
+
+
+def_swig_add_metaclass(metaclass):
+ """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
+ defwrapper(cls):
+ returnmetaclass(cls.__name__,cls.__bases__,cls.__dict__.copy())
+ returnwrapper
+
+
+class_SwigNonDynamicMeta(type):
+ """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
+ __setattr__=_swig_setattr_nondynamic_class_variable(type.__setattr__)
+
+
+
+importnumbers
+fromortools.linear_solver.linear_solver_natural_apiimportOFFSET_KEY
+fromortools.linear_solver.linear_solver_natural_apiimportinf
+fromortools.linear_solver.linear_solver_natural_apiimportLinearExpr
+fromortools.linear_solver.linear_solver_natural_apiimportProductCst
+fromortools.linear_solver.linear_solver_natural_apiimportSum
+fromortools.linear_solver.linear_solver_natural_apiimportSumArray
+fromortools.linear_solver.linear_solver_natural_apiimportSumCst
+fromortools.linear_solver.linear_solver_natural_apiimportLinearConstraint
+fromortools.linear_solver.linear_solver_natural_apiimportVariableExpr
+
+classSolver(object):
+ r"""
+ This mathematical programming (MP) solver class is the main class
+ though which users build and solve problems.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ CLP_LINEAR_PROGRAMMING=_pywraplp.Solver_CLP_LINEAR_PROGRAMMING
+ GLPK_LINEAR_PROGRAMMING=_pywraplp.Solver_GLPK_LINEAR_PROGRAMMING
+ GLOP_LINEAR_PROGRAMMING=_pywraplp.Solver_GLOP_LINEAR_PROGRAMMING
+ PDLP_LINEAR_PROGRAMMING=_pywraplp.Solver_PDLP_LINEAR_PROGRAMMING
+ SCIP_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_SCIP_MIXED_INTEGER_PROGRAMMING
+ GLPK_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_GLPK_MIXED_INTEGER_PROGRAMMING
+ CBC_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_CBC_MIXED_INTEGER_PROGRAMMING
+ GUROBI_LINEAR_PROGRAMMING=_pywraplp.Solver_GUROBI_LINEAR_PROGRAMMING
+ GUROBI_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_GUROBI_MIXED_INTEGER_PROGRAMMING
+ CPLEX_LINEAR_PROGRAMMING=_pywraplp.Solver_CPLEX_LINEAR_PROGRAMMING
+ CPLEX_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_CPLEX_MIXED_INTEGER_PROGRAMMING
+ XPRESS_LINEAR_PROGRAMMING=_pywraplp.Solver_XPRESS_LINEAR_PROGRAMMING
+ XPRESS_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_XPRESS_MIXED_INTEGER_PROGRAMMING
+ BOP_INTEGER_PROGRAMMING=_pywraplp.Solver_BOP_INTEGER_PROGRAMMING
+ SAT_INTEGER_PROGRAMMING=_pywraplp.Solver_SAT_INTEGER_PROGRAMMING
+
+ def__init__(self,name:"std::string const &",problem_type:"operations_research::MPSolver::OptimizationProblemType"):
+ r""" Create a solver with the given name and underlying solver backend."""
+ _pywraplp.Solver_swiginit(self,_pywraplp.new_Solver(name,problem_type))
+ __swig_destroy__=_pywraplp.delete_Solver
+
+ @staticmethod
+ defCreateSolver(solver_id:"std::string const &")->"operations_research::MPSolver *":
+ r"""
+ Recommended factory method to create a MPSolver instance, especially in
+ non C++ languages.
+
+ It returns a newly created solver instance if successful, or a nullptr
+ otherwise. This can occur if the relevant interface is not linked in, or if
+ a needed license is not accessible for commercial solvers.
+
+ Ownership of the solver is passed on to the caller of this method.
+ It will accept both string names of the OptimizationProblemType enum, as
+ well as a short version (i.e. "SCIP_MIXED_INTEGER_PROGRAMMING" or "SCIP").
+
+ solver_id is case insensitive, and the following names are supported:
+ - CLP_LINEAR_PROGRAMMING or CLP
+ - CBC_MIXED_INTEGER_PROGRAMMING or CBC
+ - GLOP_LINEAR_PROGRAMMING or GLOP
+ - BOP_INTEGER_PROGRAMMING or BOP
+ - SAT_INTEGER_PROGRAMMING or SAT or CP_SAT
+ - SCIP_MIXED_INTEGER_PROGRAMMING or SCIP
+ - GUROBI_LINEAR_PROGRAMMING or GUROBI_LP
+ - GUROBI_MIXED_INTEGER_PROGRAMMING or GUROBI or GUROBI_MIP
+ - CPLEX_LINEAR_PROGRAMMING or CPLEX_LP
+ - CPLEX_MIXED_INTEGER_PROGRAMMING or CPLEX or CPLEX_MIP
+ - XPRESS_LINEAR_PROGRAMMING or XPRESS_LP
+ - XPRESS_MIXED_INTEGER_PROGRAMMING or XPRESS or XPRESS_MIP
+ - GLPK_LINEAR_PROGRAMMING or GLPK_LP
+ - GLPK_MIXED_INTEGER_PROGRAMMING or GLPK or GLPK_MIP
+ """
+ return_pywraplp.Solver_CreateSolver(solver_id)
+
+ @staticmethod
+ defSupportsProblemType(problem_type:"operations_research::MPSolver::OptimizationProblemType")->"bool":
+ r"""
+ Whether the given problem type is supported (this will depend on the
+ targets that you linked).
+ """
+ return_pywraplp.Solver_SupportsProblemType(problem_type)
+
+ defClear(self)->"void":
+ r"""
+ Clears the objective (including the optimization direction), all variables
+ and constraints. All the other properties of the MPSolver (like the time
+ limit) are kept untouched.
+ """
+ return_pywraplp.Solver_Clear(self)
+
+ defNumVariables(self)->"int":
+ r""" Returns the number of variables."""
+ return_pywraplp.Solver_NumVariables(self)
+
+ defvariables(self)->"std::vector< operations_research::MPVariable * > const &":
+ r"""
+ Returns the array of variables handled by the MPSolver. (They are listed in
+ the order in which they were created.)
+ """
+ return_pywraplp.Solver_variables(self)
+
+ defvariable(self,index:"int")->"operations_research::MPVariable *":
+ r"""Returns the variable at position index."""
+ return_pywraplp.Solver_variable(self,index)
+
+ defLookupVariable(self,var_name:"std::string const &")->"operations_research::MPVariable *":
+ r"""
+ Looks up a variable by name, and returns nullptr if it does not exist. The
+ first call has a O(n) complexity, as the variable name index is lazily
+ created upon first use. Will crash if variable names are not unique.
+ """
+ return_pywraplp.Solver_LookupVariable(self,var_name)
+
+ defVar(self,lb:"double",ub:"double",integer:"bool",name:"std::string const &")->"operations_research::MPVariable *":
+ r"""
+ Creates a variable with the given bounds, integrality requirement and
+ name. Bounds can be finite or +/- MPSolver::infinity(). The MPSolver owns
+ the variable (i.e. the returned pointer is borrowed). Variable names are
+ optional. If you give an empty name, name() will auto-generate one for you
+ upon request.
+ """
+ return_pywraplp.Solver_Var(self,lb,ub,integer,name)
+
+ defNumVar(self,lb:"double",ub:"double",name:"std::string const &")->"operations_research::MPVariable *":
+ r""" Creates a continuous variable."""
+ return_pywraplp.Solver_NumVar(self,lb,ub,name)
+
+ defIntVar(self,lb:"double",ub:"double",name:"std::string const &")->"operations_research::MPVariable *":
+ r""" Creates an integer variable."""
+ return_pywraplp.Solver_IntVar(self,lb,ub,name)
+
+ defBoolVar(self,name:"std::string const &")->"operations_research::MPVariable *":
+ r""" Creates a boolean variable."""
+ return_pywraplp.Solver_BoolVar(self,name)
+
+ defNumConstraints(self)->"int":
+ r""" Returns the number of constraints."""
+ return_pywraplp.Solver_NumConstraints(self)
+
+ defconstraints(self)->"std::vector< operations_research::MPConstraint * > const &":
+ r"""
+ Returns the array of constraints handled by the MPSolver.
+
+ They are listed in the order in which they were created.
+ """
+ return_pywraplp.Solver_constraints(self)
+
+ defconstraint(self,index:"int")->"operations_research::MPConstraint *":
+ r""" Returns the constraint at the given index."""
+ return_pywraplp.Solver_constraint(self,index)
+
+ defLookupConstraint(self,constraint_name:"std::string const &")->"operations_research::MPConstraint *":
+ r"""
+ Looks up a constraint by name, and returns nullptr if it does not exist.
+
+ The first call has a O(n) complexity, as the constraint name index is
+ lazily created upon first use. Will crash if constraint names are not
+ unique.
+ """
+ return_pywraplp.Solver_LookupConstraint(self,constraint_name)
+
+ defConstraint(self,*args)->"operations_research::MPConstraint *":
+ r"""
+ *Overload 1:*
+
+ Creates a linear constraint with given bounds.
+
+ Bounds can be finite or +/- MPSolver::infinity(). The MPSolver class
+ assumes ownership of the constraint.
+
+ :rtype: :py:class:`MPConstraint`
+ :return: a pointer to the newly created constraint.
+
+ |
+
+ *Overload 2:*
+ Creates a constraint with -infinity and +infinity bounds.
+
+ |
+
+ *Overload 3:*
+ Creates a named constraint with given bounds.
+
+ |
+
+ *Overload 4:*
+ Creates a named constraint with -infinity and +infinity bounds.
+ """
+ return_pywraplp.Solver_Constraint(self,*args)
+
+ defObjective(self)->"operations_research::MPObjective *":
+ r""" Returns the mutable objective object."""
+ return_pywraplp.Solver_Objective(self)
+ OPTIMAL=_pywraplp.Solver_OPTIMAL
+ r""" optimal."""
+ FEASIBLE=_pywraplp.Solver_FEASIBLE
+ r""" feasible, or stopped by limit."""
+ INFEASIBLE=_pywraplp.Solver_INFEASIBLE
+ r""" proven infeasible."""
+ UNBOUNDED=_pywraplp.Solver_UNBOUNDED
+ r""" proven unbounded."""
+ ABNORMAL=_pywraplp.Solver_ABNORMAL
+ r""" abnormal, i.e., error of some kind."""
+ NOT_SOLVED=_pywraplp.Solver_NOT_SOLVED
+ r""" not been solved yet."""
+
+ defSolve(self,*args)->"operations_research::MPSolver::ResultStatus":
+ r"""
+ *Overload 1:*
+ Solves the problem using the default parameter values.
+
+ |
+
+ *Overload 2:*
+ Solves the problem using the specified parameter values.
+ """
+ return_pywraplp.Solver_Solve(self,*args)
+
+ defComputeConstraintActivities(self)->"std::vector< double >":
+ r"""
+ Advanced usage: compute the "activities" of all constraints, which are the
+ sums of their linear terms. The activities are returned in the same order
+ as constraints(), which is the order in which constraints were added; but
+ you can also use MPConstraint::index() to get a constraint's index.
+ """
+ return_pywraplp.Solver_ComputeConstraintActivities(self)
+
+ defVerifySolution(self,tolerance:"double",log_errors:"bool")->"bool":
+ r"""
+ Advanced usage: Verifies the *correctness* of the solution.
+
+ It verifies that all variables must be within their domains, all
+ constraints must be satisfied, and the reported objective value must be
+ accurate.
+
+ Usage:
+ - This can only be called after Solve() was called.
+ - "tolerance" is interpreted as an absolute error threshold.
+ - For the objective value only, if the absolute error is too large,
+ the tolerance is interpreted as a relative error threshold instead.
+ - If "log_errors" is true, every single violation will be logged.
+ - If "tolerance" is negative, it will be set to infinity().
+
+ Most users should just set the --verify_solution flag and not bother using
+ this method directly.
+ """
+ return_pywraplp.Solver_VerifySolution(self,tolerance,log_errors)
+
+ defInterruptSolve(self)->"bool":
+ r"""
+ Interrupts the Solve() execution to terminate processing if possible.
+
+ If the underlying interface supports interruption; it does that and returns
+ true regardless of whether there's an ongoing Solve() or not. The Solve()
+ call may still linger for a while depending on the conditions. If
+ interruption is not supported; returns false and does nothing.
+ MPSolver::SolverTypeSupportsInterruption can be used to check if
+ interruption is supported for a given solver type.
+ """
+ return_pywraplp.Solver_InterruptSolve(self)
+
+ defFillSolutionResponseProto(self,response:"operations_research::MPSolutionResponse *")->"void":
+ r""" Encodes the current solution in a solution response protocol buffer."""
+ return_pywraplp.Solver_FillSolutionResponseProto(self,response)
+
+ @staticmethod
+ defSolveWithProto(model_request:"operations_research::MPModelRequest const &",response:"operations_research::MPSolutionResponse *",interrupt:"std::atomic< bool > *"=None)->"operations_research::MPSolutionResponse *":
+ r"""
+ Solves the model encoded by a MPModelRequest protocol buffer and fills the
+ solution encoded as a MPSolutionResponse. The solve is stopped prematurely
+ if interrupt is non-null at set to true during (or before) solving.
+ Interruption is only supported if SolverTypeSupportsInterruption() returns
+ true for the requested solver. Passing a non-null interruption with any
+ other solver type immediately returns an MPSOLVER_INCOMPATIBLE_OPTIONS
+ error.
+
+ Note(user): This attempts to first use `DirectlySolveProto()` (if
+ implemented). Consequently, this most likely does *not* override any of
+ the default parameters of the underlying solver. This behavior *differs*
+ from `MPSolver::Solve()` which by default sets the feasibility tolerance
+ and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
+ """
+ return_pywraplp.Solver_SolveWithProto(model_request,response,interrupt)
+
+ defExportModelToProto(self,output_model:"operations_research::MPModelProto *")->"void":
+ r""" Exports model to protocol buffer."""
+ return_pywraplp.Solver_ExportModelToProto(self,output_model)
+
+ defSetSolverSpecificParametersAsString(self,parameters:"std::string const &")->"bool":
+ r"""
+ Advanced usage: pass solver specific parameters in text format.
+
+ The format is solver-specific and is the same as the corresponding solver
+ configuration file format. Returns true if the operation was successful.
+ """
+ return_pywraplp.Solver_SetSolverSpecificParametersAsString(self,parameters)
+ FREE=_pywraplp.Solver_FREE
+ AT_LOWER_BOUND=_pywraplp.Solver_AT_LOWER_BOUND
+ AT_UPPER_BOUND=_pywraplp.Solver_AT_UPPER_BOUND
+ FIXED_VALUE=_pywraplp.Solver_FIXED_VALUE
+ BASIC=_pywraplp.Solver_BASIC
+
+ @staticmethod
+ definfinity()->"double":
+ r"""
+ Infinity.
+
+ You can use -MPSolver::infinity() for negative infinity.
+ """
+ return_pywraplp.Solver_infinity()
+
+ defEnableOutput(self)->"void":
+ r""" Enables solver logging."""
+ return_pywraplp.Solver_EnableOutput(self)
+
+ defSuppressOutput(self)->"void":
+ r""" Suppresses solver logging."""
+ return_pywraplp.Solver_SuppressOutput(self)
+
+ defiterations(self)->"int64_t":
+ r""" Returns the number of simplex iterations."""
+ return_pywraplp.Solver_iterations(self)
+
+ defnodes(self)->"int64_t":
+ r"""
+ Returns the number of branch-and-bound nodes evaluated during the solve.
+
+ Only available for discrete problems.
+ """
+ return_pywraplp.Solver_nodes(self)
+
+ defComputeExactConditionNumber(self)->"double":
+ r"""
+ Advanced usage: computes the exact condition number of the current scaled
+ basis: L1norm(B) * L1norm(inverse(B)), where B is the scaled basis.
+
+ This method requires that a basis exists: it should be called after Solve.
+ It is only available for continuous problems. It is implemented for GLPK
+ but not CLP because CLP does not provide the API for doing it.
+
+ The condition number measures how well the constraint matrix is conditioned
+ and can be used to predict whether numerical issues will arise during the
+ solve: the model is declared infeasible whereas it is feasible (or
+ vice-versa), the solution obtained is not optimal or violates some
+ constraints, the resolution is slow because of repeated singularities.
+
+ The rule of thumb to interpret the condition number kappa is:
+ - o kappa <= 1e7: virtually no chance of numerical issues
+ - o 1e7 < kappa <= 1e10: small chance of numerical issues
+ - o 1e10 < kappa <= 1e13: medium chance of numerical issues
+ - o kappa > 1e13: high chance of numerical issues
+
+ The computation of the condition number depends on the quality of the LU
+ decomposition, so it is not very accurate when the matrix is ill
+ conditioned.
+ """
+ return_pywraplp.Solver_ComputeExactConditionNumber(self)
+
+ defNextSolution(self)->"bool":
+ r"""
+ Some solvers (MIP only, not LP) can produce multiple solutions to the
+ problem. Returns true when another solution is available, and updates the
+ MPVariable* objects to make the new solution queryable. Call only after
+ calling solve.
+
+ The optimality properties of the additional solutions found, and whether or
+ not the solver computes them ahead of time or when NextSolution() is called
+ is solver specific.
+
+ As of 2020-02-10, only Gurobi and SCIP support NextSolution(), see
+ linear_solver_interfaces_test for an example of how to configure these
+ solvers for multiple solutions. Other solvers return false unconditionally.
+ """
+ return_pywraplp.Solver_NextSolution(self)
+
+ defset_time_limit(self,time_limit_milliseconds:"int64_t")->"void":
+ return_pywraplp.Solver_set_time_limit(self,time_limit_milliseconds)
+
+ defwall_time(self)->"int64_t":
+ return_pywraplp.Solver_wall_time(self)
+
+ defLoadModelFromProto(self,input_model:"operations_research::MPModelProto const &")->"std::string":
+ return_pywraplp.Solver_LoadModelFromProto(self,input_model)
+
+ defLoadModelFromProtoWithUniqueNamesOrDie(self,input_model:"operations_research::MPModelProto const &")->"std::string":
+ return_pywraplp.Solver_LoadModelFromProtoWithUniqueNamesOrDie(self,input_model)
+
+ defLoadSolutionFromProto(self,*args)->"bool":
+ return_pywraplp.Solver_LoadSolutionFromProto(self,*args)
+
+ defExportModelAsLpFormat(self,obfuscated:"bool")->"std::string":
+ return_pywraplp.Solver_ExportModelAsLpFormat(self,obfuscated)
+
+ defExportModelAsMpsFormat(self,fixed_format:"bool",obfuscated:"bool")->"std::string":
+ return_pywraplp.Solver_ExportModelAsMpsFormat(self,fixed_format,obfuscated)
+
+ defSetHint(self,variables:"std::vector< operations_research::MPVariable * > const &",values:"std::vector< double > const &")->"void":
+ r"""
+ Set a hint for solution.
+
+ If a feasible or almost-feasible solution to the problem is already known,
+ it may be helpful to pass it to the solver so that it can be used. A
+ solver that supports this feature will try to use this information to
+ create its initial feasible solution.
+
+ Note that it may not always be faster to give a hint like this to the
+ solver. There is also no guarantee that the solver will use this hint or
+ try to return a solution "close" to this assignment in case of multiple
+ optimal solutions.
+ """
+ return_pywraplp.Solver_SetHint(self,variables,values)
+
+ defSetNumThreads(self,num_theads:"int")->"bool":
+ r""" Sets the number of threads to be used by the solver."""
+ return_pywraplp.Solver_SetNumThreads(self,num_theads)
+
+ defAdd(self,constraint,name=''):
+ ifisinstance(constraint,bool):
+ ifconstraint:
+ returnself.RowConstraint(0,0,name)
+ else:
+ returnself.RowConstraint(1,1,name)
+ else:
+ returnconstraint.Extract(self,name)
+
+ defSum(self,expr_array):
+ result=SumArray(expr_array)
+ returnresult
+
+ defRowConstraint(self,*args):
+ returnself.Constraint(*args)
+
+ defMinimize(self,expr):
+ objective=self.Objective()
+ objective.Clear()
+ objective.SetMinimization()
+ ifisinstance(expr,numbers.Number):
+ objective.SetOffset(expr)
+ else:
+ coeffs=expr.GetCoeffs()
+ objective.SetOffset(coeffs.pop(OFFSET_KEY,0.0))
+ forv,c,inlist(coeffs.items()):
+ objective.SetCoefficient(v,float(c))
+
+ defMaximize(self,expr):
+ objective=self.Objective()
+ objective.Clear()
+ objective.SetMaximization()
+ ifisinstance(expr,numbers.Number):
+ objective.SetOffset(expr)
+ else:
+ coeffs=expr.GetCoeffs()
+ objective.SetOffset(coeffs.pop(OFFSET_KEY,0.0))
+ forv,c,inlist(coeffs.items()):
+ objective.SetCoefficient(v,float(c))
+
+
+ @staticmethod
+ defInfinity()->"double":
+ return_pywraplp.Solver_Infinity()
+
+ defSetTimeLimit(self,x:"int64_t")->"void":
+ return_pywraplp.Solver_SetTimeLimit(self,x)
+
+ defWallTime(self)->"int64_t":
+ return_pywraplp.Solver_WallTime(self)
+
+ defIterations(self)->"int64_t":
+ return_pywraplp.Solver_Iterations(self)
+
+# Register Solver in _pywraplp:
+_pywraplp.Solver_swigregister(Solver)
+
+defSolver_CreateSolver(solver_id:"std::string const &")->"operations_research::MPSolver *":
+ r"""
+ Recommended factory method to create a MPSolver instance, especially in
+ non C++ languages.
+
+ It returns a newly created solver instance if successful, or a nullptr
+ otherwise. This can occur if the relevant interface is not linked in, or if
+ a needed license is not accessible for commercial solvers.
+
+ Ownership of the solver is passed on to the caller of this method.
+ It will accept both string names of the OptimizationProblemType enum, as
+ well as a short version (i.e. "SCIP_MIXED_INTEGER_PROGRAMMING" or "SCIP").
+
+ solver_id is case insensitive, and the following names are supported:
+ - CLP_LINEAR_PROGRAMMING or CLP
+ - CBC_MIXED_INTEGER_PROGRAMMING or CBC
+ - GLOP_LINEAR_PROGRAMMING or GLOP
+ - BOP_INTEGER_PROGRAMMING or BOP
+ - SAT_INTEGER_PROGRAMMING or SAT or CP_SAT
+ - SCIP_MIXED_INTEGER_PROGRAMMING or SCIP
+ - GUROBI_LINEAR_PROGRAMMING or GUROBI_LP
+ - GUROBI_MIXED_INTEGER_PROGRAMMING or GUROBI or GUROBI_MIP
+ - CPLEX_LINEAR_PROGRAMMING or CPLEX_LP
+ - CPLEX_MIXED_INTEGER_PROGRAMMING or CPLEX or CPLEX_MIP
+ - XPRESS_LINEAR_PROGRAMMING or XPRESS_LP
+ - XPRESS_MIXED_INTEGER_PROGRAMMING or XPRESS or XPRESS_MIP
+ - GLPK_LINEAR_PROGRAMMING or GLPK_LP
+ - GLPK_MIXED_INTEGER_PROGRAMMING or GLPK or GLPK_MIP
+ """
+ return_pywraplp.Solver_CreateSolver(solver_id)
+
+defSolver_SupportsProblemType(problem_type:"operations_research::MPSolver::OptimizationProblemType")->"bool":
+ r"""
+ Whether the given problem type is supported (this will depend on the
+ targets that you linked).
+ """
+ return_pywraplp.Solver_SupportsProblemType(problem_type)
+
+defSolver_SolveWithProto(model_request:"operations_research::MPModelRequest const &",response:"operations_research::MPSolutionResponse *",interrupt:"std::atomic< bool > *"=None)->"operations_research::MPSolutionResponse *":
+ r"""
+ Solves the model encoded by a MPModelRequest protocol buffer and fills the
+ solution encoded as a MPSolutionResponse. The solve is stopped prematurely
+ if interrupt is non-null at set to true during (or before) solving.
+ Interruption is only supported if SolverTypeSupportsInterruption() returns
+ true for the requested solver. Passing a non-null interruption with any
+ other solver type immediately returns an MPSOLVER_INCOMPATIBLE_OPTIONS
+ error.
+
+ Note(user): This attempts to first use `DirectlySolveProto()` (if
+ implemented). Consequently, this most likely does *not* override any of
+ the default parameters of the underlying solver. This behavior *differs*
+ from `MPSolver::Solve()` which by default sets the feasibility tolerance
+ and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
+ """
+ return_pywraplp.Solver_SolveWithProto(model_request,response,interrupt)
+
+defSolver_infinity()->"double":
+ r"""
+ Infinity.
+
+ You can use -MPSolver::infinity() for negative infinity.
+ """
+ return_pywraplp.Solver_infinity()
+
+defSolver_Infinity()->"double":
+ return_pywraplp.Solver_Infinity()
+
+
+def__lshift__(*args)->"std::ostream &":
+ return_pywraplp.__lshift__(*args)
+classObjective(object):
+ r""" A class to express a linear objective."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defClear(self)->"void":
+ r"""
+ Clears the offset, all variables and coefficients, and the optimization
+ direction.
+ """
+ return_pywraplp.Objective_Clear(self)
+
+ defSetCoefficient(self,var:"Variable",coeff:"double")->"void":
+ r"""
+ Sets the coefficient of the variable in the objective.
+
+ If the variable does not belong to the solver, the function just returns,
+ or crashes in non-opt mode.
+ """
+ return_pywraplp.Objective_SetCoefficient(self,var,coeff)
+
+ defGetCoefficient(self,var:"Variable")->"double":
+ r"""
+ Gets the coefficient of a given variable in the objective
+
+ It returns 0 if the variable does not appear in the objective).
+ """
+ return_pywraplp.Objective_GetCoefficient(self,var)
+
+ defSetOffset(self,value:"double")->"void":
+ r""" Sets the constant term in the objective."""
+ return_pywraplp.Objective_SetOffset(self,value)
+
+ defoffset(self)->"double":
+ r""" Gets the constant term in the objective."""
+ return_pywraplp.Objective_offset(self)
+
+ defSetOptimizationDirection(self,maximize:"bool")->"void":
+ r""" Sets the optimization direction (maximize: true or minimize: false)."""
+ return_pywraplp.Objective_SetOptimizationDirection(self,maximize)
+
+ defSetMinimization(self)->"void":
+ r""" Sets the optimization direction to minimize."""
+ return_pywraplp.Objective_SetMinimization(self)
+
+ defSetMaximization(self)->"void":
+ r""" Sets the optimization direction to maximize."""
+ return_pywraplp.Objective_SetMaximization(self)
+
+ defmaximization(self)->"bool":
+ r""" Is the optimization direction set to maximize?"""
+ return_pywraplp.Objective_maximization(self)
+
+ defminimization(self)->"bool":
+ r""" Is the optimization direction set to minimize?"""
+ return_pywraplp.Objective_minimization(self)
+
+ defValue(self)->"double":
+ r"""
+ Returns the objective value of the best solution found so far.
+
+ It is the optimal objective value if the problem has been solved to
+ optimality.
+
+ Note: the objective value may be slightly different than what you could
+ compute yourself using ``MPVariable::solution_value();`` please use the
+ --verify_solution flag to gain confidence about the numerical stability of
+ your solution.
+ """
+ return_pywraplp.Objective_Value(self)
+
+ defBestBound(self)->"double":
+ r"""
+ Returns the best objective bound.
+
+ In case of minimization, it is a lower bound on the objective value of the
+ optimal integer solution. Only available for discrete problems.
+ """
+ return_pywraplp.Objective_BestBound(self)
+
+ defOffset(self)->"double":
+ return_pywraplp.Objective_Offset(self)
+ __swig_destroy__=_pywraplp.delete_Objective
+
+# Register Objective in _pywraplp:
+_pywraplp.Objective_swigregister(Objective)
+
+classVariable(object):
+ r""" The class for variables of a Mathematical Programming (MP) model."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+
+ defname(self)->"std::string const &":
+ r""" Returns the name of the variable."""
+ return_pywraplp.Variable_name(self)
+
+ defSetInteger(self,integer:"bool")->"void":
+ r""" Sets the integrality requirement of the variable."""
+ return_pywraplp.Variable_SetInteger(self,integer)
+
+ definteger(self)->"bool":
+ r""" Returns the integrality requirement of the variable."""
+ return_pywraplp.Variable_integer(self)
+
+ defsolution_value(self)->"double":
+ r"""
+ Returns the value of the variable in the current solution.
+
+ If the variable is integer, then the value will always be an integer (the
+ underlying solver handles floating-point values only, but this function
+ automatically rounds it to the nearest integer; see: man 3 round).
+ """
+ return_pywraplp.Variable_solution_value(self)
+
+ defindex(self)->"int":
+ r""" Returns the index of the variable in the MPSolver::variables_."""
+ return_pywraplp.Variable_index(self)
+
+ deflb(self)->"double":
+ r""" Returns the lower bound."""
+ return_pywraplp.Variable_lb(self)
+
+ defub(self)->"double":
+ r""" Returns the upper bound."""
+ return_pywraplp.Variable_ub(self)
+
+ defSetBounds(self,lb:"double",ub:"double")->"void":
+ r""" Sets both the lower and upper bounds."""
+ return_pywraplp.Variable_SetBounds(self,lb,ub)
+
+ defreduced_cost(self)->"double":
+ r"""
+ Advanced usage: returns the reduced cost of the variable in the current
+ solution (only available for continuous problems).
+ """
+ return_pywraplp.Variable_reduced_cost(self)
+
+ defbasis_status(self)->"operations_research::MPSolver::BasisStatus":
+ r"""
+ Advanced usage: returns the basis status of the variable in the current
+ solution (only available for continuous problems).
+
+ See also: MPSolver::BasisStatus.
+ """
+ return_pywraplp.Variable_basis_status(self)
+
+ defbranching_priority(self)->"int":
+ r"""
+ Advanced usage: Certain MIP solvers (e.g. Gurobi or SCIP) allow you to set
+ a per-variable priority for determining which variable to branch on.
+
+ A value of 0 is treated as default, and is equivalent to not setting the
+ branching priority. The solver looks first to branch on fractional
+ variables in higher priority levels. As of 2019-05, only Gurobi and SCIP
+ support setting branching priority; all other solvers will simply ignore
+ this annotation.
+ """
+ return_pywraplp.Variable_branching_priority(self)
+
+ defSetBranchingPriority(self,priority:"int")->"void":
+ return_pywraplp.Variable_SetBranchingPriority(self,priority)
+
+ def__str__(self)->"std::string":
+ return_pywraplp.Variable___str__(self)
+
+ def__repr__(self)->"std::string":
+ return_pywraplp.Variable___repr__(self)
+
+ def__getattr__(self,name):
+ returngetattr(VariableExpr(self),name)
+
+
+ defSolutionValue(self)->"double":
+ return_pywraplp.Variable_SolutionValue(self)
+
+ defInteger(self)->"bool":
+ return_pywraplp.Variable_Integer(self)
+
+ defLb(self)->"double":
+ return_pywraplp.Variable_Lb(self)
+
+ defUb(self)->"double":
+ return_pywraplp.Variable_Ub(self)
+
+ defSetLb(self,x:"double")->"void":
+ return_pywraplp.Variable_SetLb(self,x)
+
+ defSetUb(self,x:"double")->"void":
+ return_pywraplp.Variable_SetUb(self,x)
+
+ defReducedCost(self)->"double":
+ return_pywraplp.Variable_ReducedCost(self)
+ __swig_destroy__=_pywraplp.delete_Variable
+
+# Register Variable in _pywraplp:
+_pywraplp.Variable_swigregister(Variable)
+
+classConstraint(object):
+ r"""
+ The class for constraints of a Mathematical Programming (MP) model.
+
+ A constraint is represented as a linear equation or inequality.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defname(self)->"std::string const &":
+ r""" Returns the name of the constraint."""
+ return_pywraplp.Constraint_name(self)
+
+ defClear(self)->"void":
+ r""" Clears all variables and coefficients. Does not clear the bounds."""
+ return_pywraplp.Constraint_Clear(self)
+
+ defSetCoefficient(self,var:"Variable",coeff:"double")->"void":
+ r"""
+ Sets the coefficient of the variable on the constraint.
+
+ If the variable does not belong to the solver, the function just returns,
+ or crashes in non-opt mode.
+ """
+ return_pywraplp.Constraint_SetCoefficient(self,var,coeff)
+
+ defGetCoefficient(self,var:"Variable")->"double":
+ r"""
+ Gets the coefficient of a given variable on the constraint (which is 0 if
+ the variable does not appear in the constraint).
+ """
+ return_pywraplp.Constraint_GetCoefficient(self,var)
+
+ deflb(self)->"double":
+ r""" Returns the lower bound."""
+ return_pywraplp.Constraint_lb(self)
+
+ defub(self)->"double":
+ r""" Returns the upper bound."""
+ return_pywraplp.Constraint_ub(self)
+
+ defSetBounds(self,lb:"double",ub:"double")->"void":
+ r""" Sets both the lower and upper bounds."""
+ return_pywraplp.Constraint_SetBounds(self,lb,ub)
+
+ defset_is_lazy(self,laziness:"bool")->"void":
+ r"""
+ Advanced usage: sets the constraint "laziness".
+
+ **This is only supported for SCIP and has no effect on other
+ solvers.**
+
+ When **laziness** is true, the constraint is only considered by the Linear
+ Programming solver if its current solution violates the constraint. In this
+ case, the constraint is definitively added to the problem. This may be
+ useful in some MIP problems, and may have a dramatic impact on performance.
+
+ For more info see: http://tinyurl.com/lazy-constraints.
+ """
+ return_pywraplp.Constraint_set_is_lazy(self,laziness)
+
+ defindex(self)->"int":
+ r""" Returns the index of the constraint in the MPSolver::constraints_."""
+ return_pywraplp.Constraint_index(self)
+
+ defdual_value(self)->"double":
+ r"""
+ Advanced usage: returns the dual value of the constraint in the current
+ solution (only available for continuous problems).
+ """
+ return_pywraplp.Constraint_dual_value(self)
+
+ defbasis_status(self)->"operations_research::MPSolver::BasisStatus":
+ r"""
+ Advanced usage: returns the basis status of the constraint.
+
+ It is only available for continuous problems).
+
+ Note that if a constraint "linear_expression in [lb, ub]" is transformed
+ into "linear_expression + slack = 0" with slack in [-ub, -lb], then this
+ status is the same as the status of the slack variable with AT_UPPER_BOUND
+ and AT_LOWER_BOUND swapped.
+
+ See also: MPSolver::BasisStatus.
+ """
+ return_pywraplp.Constraint_basis_status(self)
+
+ defLb(self)->"double":
+ return_pywraplp.Constraint_Lb(self)
+
+ defUb(self)->"double":
+ return_pywraplp.Constraint_Ub(self)
+
+ defSetLb(self,x:"double")->"void":
+ return_pywraplp.Constraint_SetLb(self,x)
+
+ defSetUb(self,x:"double")->"void":
+ return_pywraplp.Constraint_SetUb(self,x)
+
+ defDualValue(self)->"double":
+ return_pywraplp.Constraint_DualValue(self)
+ __swig_destroy__=_pywraplp.delete_Constraint
+
+# Register Constraint in _pywraplp:
+_pywraplp.Constraint_swigregister(Constraint)
+
+classMPSolverParameters(object):
+ r"""
+ This class stores parameter settings for LP and MIP solvers. Some parameters
+ are marked as advanced: do not change their values unless you know what you
+ are doing!
+
+ For developers: how to add a new parameter:
+ - Add the new Foo parameter in the DoubleParam or IntegerParam enum.
+ - If it is a categorical param, add a FooValues enum.
+ - Decide if the wrapper should define a default value for it: yes
+ if it controls the properties of the solution (example:
+ tolerances) or if it consistently improves performance, no
+ otherwise. If yes, define kDefaultFoo.
+ - Add a foo_value_ member and, if no default value is defined, a
+ foo_is_default_ member.
+ - Add code to handle Foo in Set...Param, Reset...Param,
+ Get...Param, Reset and the constructor.
+ - In class MPSolverInterface, add a virtual method SetFoo, add it
+ to SetCommonParameters or SetMIPParameters, and implement it for
+ each solver. Sometimes, parameters need to be implemented
+ differently, see for example the INCREMENTALITY implementation.
+ - Add a test in linear_solver_test.cc.
+
+ TODO(user): store the parameter values in a protocol buffer
+ instead. We need to figure out how to deal with the subtleties of
+ the default values.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ RELATIVE_MIP_GAP=_pywraplp.MPSolverParameters_RELATIVE_MIP_GAP
+ r""" Limit for relative MIP gap."""
+ PRIMAL_TOLERANCE=_pywraplp.MPSolverParameters_PRIMAL_TOLERANCE
+ r"""
+ Advanced usage: tolerance for primal feasibility of basic solutions.
+
+ This does not control the integer feasibility tolerance of integer
+ solutions for MIP or the tolerance used during presolve.
+ """
+ DUAL_TOLERANCE=_pywraplp.MPSolverParameters_DUAL_TOLERANCE
+ r""" Advanced usage: tolerance for dual feasibility of basic solutions."""
+ PRESOLVE=_pywraplp.MPSolverParameters_PRESOLVE
+ r""" Advanced usage: presolve mode."""
+ LP_ALGORITHM=_pywraplp.MPSolverParameters_LP_ALGORITHM
+ r""" Algorithm to solve linear programs."""
+ INCREMENTALITY=_pywraplp.MPSolverParameters_INCREMENTALITY
+ r""" Advanced usage: incrementality from one solve to the next."""
+ SCALING=_pywraplp.MPSolverParameters_SCALING
+ r""" Advanced usage: enable or disable matrix scaling."""
+ PRESOLVE_OFF=_pywraplp.MPSolverParameters_PRESOLVE_OFF
+ r""" Presolve is off."""
+ PRESOLVE_ON=_pywraplp.MPSolverParameters_PRESOLVE_ON
+ r""" Presolve is on."""
+ DUAL=_pywraplp.MPSolverParameters_DUAL
+ r""" Dual simplex."""
+ PRIMAL=_pywraplp.MPSolverParameters_PRIMAL
+ r""" Primal simplex."""
+ BARRIER=_pywraplp.MPSolverParameters_BARRIER
+ r""" Barrier algorithm."""
+ INCREMENTALITY_OFF=_pywraplp.MPSolverParameters_INCREMENTALITY_OFF
+ r""" Start solve from scratch."""
+ INCREMENTALITY_ON=_pywraplp.MPSolverParameters_INCREMENTALITY_ON
+ r"""
+ Reuse results from previous solve as much as the underlying solver
+ allows.
+ """
+ SCALING_OFF=_pywraplp.MPSolverParameters_SCALING_OFF
+ r""" Scaling is off."""
+ SCALING_ON=_pywraplp.MPSolverParameters_SCALING_ON
+ r""" Scaling is on."""
+
+ def__init__(self):
+ r""" The constructor sets all parameters to their default value."""
+ _pywraplp.MPSolverParameters_swiginit(self,_pywraplp.new_MPSolverParameters())
+
+ defSetDoubleParam(self,param:"operations_research::MPSolverParameters::DoubleParam",value:"double")->"void":
+ r""" Sets a double parameter to a specific value."""
+ return_pywraplp.MPSolverParameters_SetDoubleParam(self,param,value)
+
+ defSetIntegerParam(self,param:"operations_research::MPSolverParameters::IntegerParam",value:"int")->"void":
+ r""" Sets a integer parameter to a specific value."""
+ return_pywraplp.MPSolverParameters_SetIntegerParam(self,param,value)
+
+ defGetDoubleParam(self,param:"operations_research::MPSolverParameters::DoubleParam")->"double":
+ r""" Returns the value of a double parameter."""
+ return_pywraplp.MPSolverParameters_GetDoubleParam(self,param)
+
+ defGetIntegerParam(self,param:"operations_research::MPSolverParameters::IntegerParam")->"int":
+ r""" Returns the value of an integer parameter."""
+ return_pywraplp.MPSolverParameters_GetIntegerParam(self,param)
+ __swig_destroy__=_pywraplp.delete_MPSolverParameters
+
+# Register MPSolverParameters in _pywraplp:
+_pywraplp.MPSolverParameters_swigregister(MPSolverParameters)
+cvar=_pywraplp.cvar
+MPSolverParameters.kDefaultRelativeMipGap=_pywraplp.cvar.MPSolverParameters_kDefaultRelativeMipGap
+MPSolverParameters.kDefaultPrimalTolerance=_pywraplp.cvar.MPSolverParameters_kDefaultPrimalTolerance
+MPSolverParameters.kDefaultDualTolerance=_pywraplp.cvar.MPSolverParameters_kDefaultDualTolerance
+MPSolverParameters.kDefaultPresolve=_pywraplp.cvar.MPSolverParameters_kDefaultPresolve
+MPSolverParameters.kDefaultIncrementality=_pywraplp.cvar.MPSolverParameters_kDefaultIncrementality
+
+classModelExportOptions(object):
+ r""" Export options."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+
+ def__init__(self):
+ _pywraplp.ModelExportOptions_swiginit(self,_pywraplp.new_ModelExportOptions())
+ __swig_destroy__=_pywraplp.delete_ModelExportOptions
+
+# Register ModelExportOptions in _pywraplp:
+_pywraplp.ModelExportOptions_swigregister(ModelExportOptions)
+
+
+defExportModelAsLpFormat(*args)->"std::string":
+ return_pywraplp.ExportModelAsLpFormat(*args)
+
+defExportModelAsMpsFormat(*args)->"std::string":
+ return_pywraplp.ExportModelAsMpsFormat(*args)
+
+defFindErrorInModelProto(input_model:"operations_research::MPModelProto const &")->"std::string":
+ return_pywraplp.FindErrorInModelProto(input_model)
+
+defsetup_variable_operator(opname):
+ setattr(Variable,opname,
+ lambdaself,*args:getattr(VariableExpr(self),opname)(*args))
+foropnameinLinearExpr.OVERRIDDEN_OPERATOR_METHODS:
+ setup_variable_operator(opname)
+
classSolver(object):
+ r"""
+ This mathematical programming (MP) solver class is the main class
+ though which users build and solve problems.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ CLP_LINEAR_PROGRAMMING=_pywraplp.Solver_CLP_LINEAR_PROGRAMMING
+ GLPK_LINEAR_PROGRAMMING=_pywraplp.Solver_GLPK_LINEAR_PROGRAMMING
+ GLOP_LINEAR_PROGRAMMING=_pywraplp.Solver_GLOP_LINEAR_PROGRAMMING
+ PDLP_LINEAR_PROGRAMMING=_pywraplp.Solver_PDLP_LINEAR_PROGRAMMING
+ SCIP_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_SCIP_MIXED_INTEGER_PROGRAMMING
+ GLPK_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_GLPK_MIXED_INTEGER_PROGRAMMING
+ CBC_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_CBC_MIXED_INTEGER_PROGRAMMING
+ GUROBI_LINEAR_PROGRAMMING=_pywraplp.Solver_GUROBI_LINEAR_PROGRAMMING
+ GUROBI_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_GUROBI_MIXED_INTEGER_PROGRAMMING
+ CPLEX_LINEAR_PROGRAMMING=_pywraplp.Solver_CPLEX_LINEAR_PROGRAMMING
+ CPLEX_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_CPLEX_MIXED_INTEGER_PROGRAMMING
+ XPRESS_LINEAR_PROGRAMMING=_pywraplp.Solver_XPRESS_LINEAR_PROGRAMMING
+ XPRESS_MIXED_INTEGER_PROGRAMMING=_pywraplp.Solver_XPRESS_MIXED_INTEGER_PROGRAMMING
+ BOP_INTEGER_PROGRAMMING=_pywraplp.Solver_BOP_INTEGER_PROGRAMMING
+ SAT_INTEGER_PROGRAMMING=_pywraplp.Solver_SAT_INTEGER_PROGRAMMING
+
+ def__init__(self,name:"std::string const &",problem_type:"operations_research::MPSolver::OptimizationProblemType"):
+ r""" Create a solver with the given name and underlying solver backend."""
+ _pywraplp.Solver_swiginit(self,_pywraplp.new_Solver(name,problem_type))
+ __swig_destroy__=_pywraplp.delete_Solver
+
+ @staticmethod
+ defCreateSolver(solver_id:"std::string const &")->"operations_research::MPSolver *":
+ r"""
+ Recommended factory method to create a MPSolver instance, especially in
+ non C++ languages.
+
+ It returns a newly created solver instance if successful, or a nullptr
+ otherwise. This can occur if the relevant interface is not linked in, or if
+ a needed license is not accessible for commercial solvers.
+
+ Ownership of the solver is passed on to the caller of this method.
+ It will accept both string names of the OptimizationProblemType enum, as
+ well as a short version (i.e. "SCIP_MIXED_INTEGER_PROGRAMMING" or "SCIP").
+
+ solver_id is case insensitive, and the following names are supported:
+ - CLP_LINEAR_PROGRAMMING or CLP
+ - CBC_MIXED_INTEGER_PROGRAMMING or CBC
+ - GLOP_LINEAR_PROGRAMMING or GLOP
+ - BOP_INTEGER_PROGRAMMING or BOP
+ - SAT_INTEGER_PROGRAMMING or SAT or CP_SAT
+ - SCIP_MIXED_INTEGER_PROGRAMMING or SCIP
+ - GUROBI_LINEAR_PROGRAMMING or GUROBI_LP
+ - GUROBI_MIXED_INTEGER_PROGRAMMING or GUROBI or GUROBI_MIP
+ - CPLEX_LINEAR_PROGRAMMING or CPLEX_LP
+ - CPLEX_MIXED_INTEGER_PROGRAMMING or CPLEX or CPLEX_MIP
+ - XPRESS_LINEAR_PROGRAMMING or XPRESS_LP
+ - XPRESS_MIXED_INTEGER_PROGRAMMING or XPRESS or XPRESS_MIP
+ - GLPK_LINEAR_PROGRAMMING or GLPK_LP
+ - GLPK_MIXED_INTEGER_PROGRAMMING or GLPK or GLPK_MIP
+ """
+ return_pywraplp.Solver_CreateSolver(solver_id)
+
+ @staticmethod
+ defSupportsProblemType(problem_type:"operations_research::MPSolver::OptimizationProblemType")->"bool":
+ r"""
+ Whether the given problem type is supported (this will depend on the
+ targets that you linked).
+ """
+ return_pywraplp.Solver_SupportsProblemType(problem_type)
+
+ defClear(self)->"void":
+ r"""
+ Clears the objective (including the optimization direction), all variables
+ and constraints. All the other properties of the MPSolver (like the time
+ limit) are kept untouched.
+ """
+ return_pywraplp.Solver_Clear(self)
+
+ defNumVariables(self)->"int":
+ r""" Returns the number of variables."""
+ return_pywraplp.Solver_NumVariables(self)
+
+ defvariables(self)->"std::vector< operations_research::MPVariable * > const &":
+ r"""
+ Returns the array of variables handled by the MPSolver. (They are listed in
+ the order in which they were created.)
+ """
+ return_pywraplp.Solver_variables(self)
+
+ defvariable(self,index:"int")->"operations_research::MPVariable *":
+ r"""Returns the variable at position index."""
+ return_pywraplp.Solver_variable(self,index)
+
+ defLookupVariable(self,var_name:"std::string const &")->"operations_research::MPVariable *":
+ r"""
+ Looks up a variable by name, and returns nullptr if it does not exist. The
+ first call has a O(n) complexity, as the variable name index is lazily
+ created upon first use. Will crash if variable names are not unique.
+ """
+ return_pywraplp.Solver_LookupVariable(self,var_name)
+
+ defVar(self,lb:"double",ub:"double",integer:"bool",name:"std::string const &")->"operations_research::MPVariable *":
+ r"""
+ Creates a variable with the given bounds, integrality requirement and
+ name. Bounds can be finite or +/- MPSolver::infinity(). The MPSolver owns
+ the variable (i.e. the returned pointer is borrowed). Variable names are
+ optional. If you give an empty name, name() will auto-generate one for you
+ upon request.
+ """
+ return_pywraplp.Solver_Var(self,lb,ub,integer,name)
+
+ defNumVar(self,lb:"double",ub:"double",name:"std::string const &")->"operations_research::MPVariable *":
+ r""" Creates a continuous variable."""
+ return_pywraplp.Solver_NumVar(self,lb,ub,name)
+
+ defIntVar(self,lb:"double",ub:"double",name:"std::string const &")->"operations_research::MPVariable *":
+ r""" Creates an integer variable."""
+ return_pywraplp.Solver_IntVar(self,lb,ub,name)
+
+ defBoolVar(self,name:"std::string const &")->"operations_research::MPVariable *":
+ r""" Creates a boolean variable."""
+ return_pywraplp.Solver_BoolVar(self,name)
+
+ defNumConstraints(self)->"int":
+ r""" Returns the number of constraints."""
+ return_pywraplp.Solver_NumConstraints(self)
+
+ defconstraints(self)->"std::vector< operations_research::MPConstraint * > const &":
+ r"""
+ Returns the array of constraints handled by the MPSolver.
+
+ They are listed in the order in which they were created.
+ """
+ return_pywraplp.Solver_constraints(self)
+
+ defconstraint(self,index:"int")->"operations_research::MPConstraint *":
+ r""" Returns the constraint at the given index."""
+ return_pywraplp.Solver_constraint(self,index)
+
+ defLookupConstraint(self,constraint_name:"std::string const &")->"operations_research::MPConstraint *":
+ r"""
+ Looks up a constraint by name, and returns nullptr if it does not exist.
+
+ The first call has a O(n) complexity, as the constraint name index is
+ lazily created upon first use. Will crash if constraint names are not
+ unique.
+ """
+ return_pywraplp.Solver_LookupConstraint(self,constraint_name)
+
+ defConstraint(self,*args)->"operations_research::MPConstraint *":
+ r"""
+ *Overload 1:*
+
+ Creates a linear constraint with given bounds.
+
+ Bounds can be finite or +/- MPSolver::infinity(). The MPSolver class
+ assumes ownership of the constraint.
+
+ :rtype: :py:class:`MPConstraint`
+ :return: a pointer to the newly created constraint.
+
+ |
+
+ *Overload 2:*
+ Creates a constraint with -infinity and +infinity bounds.
+
+ |
+
+ *Overload 3:*
+ Creates a named constraint with given bounds.
+
+ |
+
+ *Overload 4:*
+ Creates a named constraint with -infinity and +infinity bounds.
+ """
+ return_pywraplp.Solver_Constraint(self,*args)
+
+ defObjective(self)->"operations_research::MPObjective *":
+ r""" Returns the mutable objective object."""
+ return_pywraplp.Solver_Objective(self)
+ OPTIMAL=_pywraplp.Solver_OPTIMAL
+ r""" optimal."""
+ FEASIBLE=_pywraplp.Solver_FEASIBLE
+ r""" feasible, or stopped by limit."""
+ INFEASIBLE=_pywraplp.Solver_INFEASIBLE
+ r""" proven infeasible."""
+ UNBOUNDED=_pywraplp.Solver_UNBOUNDED
+ r""" proven unbounded."""
+ ABNORMAL=_pywraplp.Solver_ABNORMAL
+ r""" abnormal, i.e., error of some kind."""
+ NOT_SOLVED=_pywraplp.Solver_NOT_SOLVED
+ r""" not been solved yet."""
+
+ defSolve(self,*args)->"operations_research::MPSolver::ResultStatus":
+ r"""
+ *Overload 1:*
+ Solves the problem using the default parameter values.
+
+ |
+
+ *Overload 2:*
+ Solves the problem using the specified parameter values.
+ """
+ return_pywraplp.Solver_Solve(self,*args)
+
+ defComputeConstraintActivities(self)->"std::vector< double >":
+ r"""
+ Advanced usage: compute the "activities" of all constraints, which are the
+ sums of their linear terms. The activities are returned in the same order
+ as constraints(), which is the order in which constraints were added; but
+ you can also use MPConstraint::index() to get a constraint's index.
+ """
+ return_pywraplp.Solver_ComputeConstraintActivities(self)
+
+ defVerifySolution(self,tolerance:"double",log_errors:"bool")->"bool":
+ r"""
+ Advanced usage: Verifies the *correctness* of the solution.
+
+ It verifies that all variables must be within their domains, all
+ constraints must be satisfied, and the reported objective value must be
+ accurate.
+
+ Usage:
+ - This can only be called after Solve() was called.
+ - "tolerance" is interpreted as an absolute error threshold.
+ - For the objective value only, if the absolute error is too large,
+ the tolerance is interpreted as a relative error threshold instead.
+ - If "log_errors" is true, every single violation will be logged.
+ - If "tolerance" is negative, it will be set to infinity().
+
+ Most users should just set the --verify_solution flag and not bother using
+ this method directly.
+ """
+ return_pywraplp.Solver_VerifySolution(self,tolerance,log_errors)
+
+ defInterruptSolve(self)->"bool":
+ r"""
+ Interrupts the Solve() execution to terminate processing if possible.
+
+ If the underlying interface supports interruption; it does that and returns
+ true regardless of whether there's an ongoing Solve() or not. The Solve()
+ call may still linger for a while depending on the conditions. If
+ interruption is not supported; returns false and does nothing.
+ MPSolver::SolverTypeSupportsInterruption can be used to check if
+ interruption is supported for a given solver type.
+ """
+ return_pywraplp.Solver_InterruptSolve(self)
+
+ defFillSolutionResponseProto(self,response:"operations_research::MPSolutionResponse *")->"void":
+ r""" Encodes the current solution in a solution response protocol buffer."""
+ return_pywraplp.Solver_FillSolutionResponseProto(self,response)
+
+ @staticmethod
+ defSolveWithProto(model_request:"operations_research::MPModelRequest const &",response:"operations_research::MPSolutionResponse *",interrupt:"std::atomic< bool > *"=None)->"operations_research::MPSolutionResponse *":
+ r"""
+ Solves the model encoded by a MPModelRequest protocol buffer and fills the
+ solution encoded as a MPSolutionResponse. The solve is stopped prematurely
+ if interrupt is non-null at set to true during (or before) solving.
+ Interruption is only supported if SolverTypeSupportsInterruption() returns
+ true for the requested solver. Passing a non-null interruption with any
+ other solver type immediately returns an MPSOLVER_INCOMPATIBLE_OPTIONS
+ error.
+
+ Note(user): This attempts to first use `DirectlySolveProto()` (if
+ implemented). Consequently, this most likely does *not* override any of
+ the default parameters of the underlying solver. This behavior *differs*
+ from `MPSolver::Solve()` which by default sets the feasibility tolerance
+ and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
+ """
+ return_pywraplp.Solver_SolveWithProto(model_request,response,interrupt)
+
+ defExportModelToProto(self,output_model:"operations_research::MPModelProto *")->"void":
+ r""" Exports model to protocol buffer."""
+ return_pywraplp.Solver_ExportModelToProto(self,output_model)
+
+ defSetSolverSpecificParametersAsString(self,parameters:"std::string const &")->"bool":
+ r"""
+ Advanced usage: pass solver specific parameters in text format.
+
+ The format is solver-specific and is the same as the corresponding solver
+ configuration file format. Returns true if the operation was successful.
+ """
+ return_pywraplp.Solver_SetSolverSpecificParametersAsString(self,parameters)
+ FREE=_pywraplp.Solver_FREE
+ AT_LOWER_BOUND=_pywraplp.Solver_AT_LOWER_BOUND
+ AT_UPPER_BOUND=_pywraplp.Solver_AT_UPPER_BOUND
+ FIXED_VALUE=_pywraplp.Solver_FIXED_VALUE
+ BASIC=_pywraplp.Solver_BASIC
+
+ @staticmethod
+ definfinity()->"double":
+ r"""
+ Infinity.
+
+ You can use -MPSolver::infinity() for negative infinity.
+ """
+ return_pywraplp.Solver_infinity()
+
+ defEnableOutput(self)->"void":
+ r""" Enables solver logging."""
+ return_pywraplp.Solver_EnableOutput(self)
+
+ defSuppressOutput(self)->"void":
+ r""" Suppresses solver logging."""
+ return_pywraplp.Solver_SuppressOutput(self)
+
+ defiterations(self)->"int64_t":
+ r""" Returns the number of simplex iterations."""
+ return_pywraplp.Solver_iterations(self)
+
+ defnodes(self)->"int64_t":
+ r"""
+ Returns the number of branch-and-bound nodes evaluated during the solve.
+
+ Only available for discrete problems.
+ """
+ return_pywraplp.Solver_nodes(self)
+
+ defComputeExactConditionNumber(self)->"double":
+ r"""
+ Advanced usage: computes the exact condition number of the current scaled
+ basis: L1norm(B) * L1norm(inverse(B)), where B is the scaled basis.
+
+ This method requires that a basis exists: it should be called after Solve.
+ It is only available for continuous problems. It is implemented for GLPK
+ but not CLP because CLP does not provide the API for doing it.
+
+ The condition number measures how well the constraint matrix is conditioned
+ and can be used to predict whether numerical issues will arise during the
+ solve: the model is declared infeasible whereas it is feasible (or
+ vice-versa), the solution obtained is not optimal or violates some
+ constraints, the resolution is slow because of repeated singularities.
+
+ The rule of thumb to interpret the condition number kappa is:
+ - o kappa <= 1e7: virtually no chance of numerical issues
+ - o 1e7 < kappa <= 1e10: small chance of numerical issues
+ - o 1e10 < kappa <= 1e13: medium chance of numerical issues
+ - o kappa > 1e13: high chance of numerical issues
+
+ The computation of the condition number depends on the quality of the LU
+ decomposition, so it is not very accurate when the matrix is ill
+ conditioned.
+ """
+ return_pywraplp.Solver_ComputeExactConditionNumber(self)
+
+ defNextSolution(self)->"bool":
+ r"""
+ Some solvers (MIP only, not LP) can produce multiple solutions to the
+ problem. Returns true when another solution is available, and updates the
+ MPVariable* objects to make the new solution queryable. Call only after
+ calling solve.
+
+ The optimality properties of the additional solutions found, and whether or
+ not the solver computes them ahead of time or when NextSolution() is called
+ is solver specific.
+
+ As of 2020-02-10, only Gurobi and SCIP support NextSolution(), see
+ linear_solver_interfaces_test for an example of how to configure these
+ solvers for multiple solutions. Other solvers return false unconditionally.
+ """
+ return_pywraplp.Solver_NextSolution(self)
+
+ defset_time_limit(self,time_limit_milliseconds:"int64_t")->"void":
+ return_pywraplp.Solver_set_time_limit(self,time_limit_milliseconds)
+
+ defwall_time(self)->"int64_t":
+ return_pywraplp.Solver_wall_time(self)
+
+ defLoadModelFromProto(self,input_model:"operations_research::MPModelProto const &")->"std::string":
+ return_pywraplp.Solver_LoadModelFromProto(self,input_model)
+
+ defLoadModelFromProtoWithUniqueNamesOrDie(self,input_model:"operations_research::MPModelProto const &")->"std::string":
+ return_pywraplp.Solver_LoadModelFromProtoWithUniqueNamesOrDie(self,input_model)
+
+ defLoadSolutionFromProto(self,*args)->"bool":
+ return_pywraplp.Solver_LoadSolutionFromProto(self,*args)
+
+ defExportModelAsLpFormat(self,obfuscated:"bool")->"std::string":
+ return_pywraplp.Solver_ExportModelAsLpFormat(self,obfuscated)
+
+ defExportModelAsMpsFormat(self,fixed_format:"bool",obfuscated:"bool")->"std::string":
+ return_pywraplp.Solver_ExportModelAsMpsFormat(self,fixed_format,obfuscated)
+
+ defSetHint(self,variables:"std::vector< operations_research::MPVariable * > const &",values:"std::vector< double > const &")->"void":
+ r"""
+ Set a hint for solution.
+
+ If a feasible or almost-feasible solution to the problem is already known,
+ it may be helpful to pass it to the solver so that it can be used. A
+ solver that supports this feature will try to use this information to
+ create its initial feasible solution.
+
+ Note that it may not always be faster to give a hint like this to the
+ solver. There is also no guarantee that the solver will use this hint or
+ try to return a solution "close" to this assignment in case of multiple
+ optimal solutions.
+ """
+ return_pywraplp.Solver_SetHint(self,variables,values)
+
+ defSetNumThreads(self,num_theads:"int")->"bool":
+ r""" Sets the number of threads to be used by the solver."""
+ return_pywraplp.Solver_SetNumThreads(self,num_theads)
+
+ defAdd(self,constraint,name=''):
+ ifisinstance(constraint,bool):
+ ifconstraint:
+ returnself.RowConstraint(0,0,name)
+ else:
+ returnself.RowConstraint(1,1,name)
+ else:
+ returnconstraint.Extract(self,name)
+
+ defSum(self,expr_array):
+ result=SumArray(expr_array)
+ returnresult
+
+ defRowConstraint(self,*args):
+ returnself.Constraint(*args)
+
+ defMinimize(self,expr):
+ objective=self.Objective()
+ objective.Clear()
+ objective.SetMinimization()
+ ifisinstance(expr,numbers.Number):
+ objective.SetOffset(expr)
+ else:
+ coeffs=expr.GetCoeffs()
+ objective.SetOffset(coeffs.pop(OFFSET_KEY,0.0))
+ forv,c,inlist(coeffs.items()):
+ objective.SetCoefficient(v,float(c))
+
+ defMaximize(self,expr):
+ objective=self.Objective()
+ objective.Clear()
+ objective.SetMaximization()
+ ifisinstance(expr,numbers.Number):
+ objective.SetOffset(expr)
+ else:
+ coeffs=expr.GetCoeffs()
+ objective.SetOffset(coeffs.pop(OFFSET_KEY,0.0))
+ forv,c,inlist(coeffs.items()):
+ objective.SetCoefficient(v,float(c))
+
+
+ @staticmethod
+ defInfinity()->"double":
+ return_pywraplp.Solver_Infinity()
+
+ defSetTimeLimit(self,x:"int64_t")->"void":
+ return_pywraplp.Solver_SetTimeLimit(self,x)
+
+ defWallTime(self)->"int64_t":
+ return_pywraplp.Solver_WallTime(self)
+
+ defIterations(self)->"int64_t":
+ return_pywraplp.Solver_Iterations(self)
+
+
+
+
+
This mathematical programming (MP) solver class is the main class
+though which users build and solve problems.
def__init__(self,name:"std::string const &",problem_type:"operations_research::MPSolver::OptimizationProblemType"):
+ r""" Create a solver with the given name and underlying solver backend."""
+ _pywraplp.Solver_swiginit(self,_pywraplp.new_Solver(name,problem_type))
+
+
+
+
+
Create a solver with the given name and underlying solver backend.
@staticmethod
+ defCreateSolver(solver_id:"std::string const &")->"operations_research::MPSolver *":
+ r"""
+ Recommended factory method to create a MPSolver instance, especially in
+ non C++ languages.
+
+ It returns a newly created solver instance if successful, or a nullptr
+ otherwise. This can occur if the relevant interface is not linked in, or if
+ a needed license is not accessible for commercial solvers.
+
+ Ownership of the solver is passed on to the caller of this method.
+ It will accept both string names of the OptimizationProblemType enum, as
+ well as a short version (i.e. "SCIP_MIXED_INTEGER_PROGRAMMING" or "SCIP").
+
+ solver_id is case insensitive, and the following names are supported:
+ - CLP_LINEAR_PROGRAMMING or CLP
+ - CBC_MIXED_INTEGER_PROGRAMMING or CBC
+ - GLOP_LINEAR_PROGRAMMING or GLOP
+ - BOP_INTEGER_PROGRAMMING or BOP
+ - SAT_INTEGER_PROGRAMMING or SAT or CP_SAT
+ - SCIP_MIXED_INTEGER_PROGRAMMING or SCIP
+ - GUROBI_LINEAR_PROGRAMMING or GUROBI_LP
+ - GUROBI_MIXED_INTEGER_PROGRAMMING or GUROBI or GUROBI_MIP
+ - CPLEX_LINEAR_PROGRAMMING or CPLEX_LP
+ - CPLEX_MIXED_INTEGER_PROGRAMMING or CPLEX or CPLEX_MIP
+ - XPRESS_LINEAR_PROGRAMMING or XPRESS_LP
+ - XPRESS_MIXED_INTEGER_PROGRAMMING or XPRESS or XPRESS_MIP
+ - GLPK_LINEAR_PROGRAMMING or GLPK_LP
+ - GLPK_MIXED_INTEGER_PROGRAMMING or GLPK or GLPK_MIP
+ """
+ return_pywraplp.Solver_CreateSolver(solver_id)
+
+
+
+
+
Recommended factory method to create a MPSolver instance, especially in
+non C++ languages.
+
+
It returns a newly created solver instance if successful, or a nullptr
+otherwise. This can occur if the relevant interface is not linked in, or if
+a needed license is not accessible for commercial solvers.
+
+
Ownership of the solver is passed on to the caller of this method.
+It will accept both string names of the OptimizationProblemType enum, as
+well as a short version (i.e. "SCIP_MIXED_INTEGER_PROGRAMMING" or "SCIP").
+
+
solver_id is case insensitive, and the following names are supported:
+
+
+
CLP_LINEAR_PROGRAMMING or CLP
+
CBC_MIXED_INTEGER_PROGRAMMING or CBC
+
GLOP_LINEAR_PROGRAMMING or GLOP
+
BOP_INTEGER_PROGRAMMING or BOP
+
SAT_INTEGER_PROGRAMMING or SAT or CP_SAT
+
SCIP_MIXED_INTEGER_PROGRAMMING or SCIP
+
GUROBI_LINEAR_PROGRAMMING or GUROBI_LP
+
GUROBI_MIXED_INTEGER_PROGRAMMING or GUROBI or GUROBI_MIP
+
CPLEX_LINEAR_PROGRAMMING or CPLEX_LP
+
CPLEX_MIXED_INTEGER_PROGRAMMING or CPLEX or CPLEX_MIP
+
XPRESS_LINEAR_PROGRAMMING or XPRESS_LP
+
XPRESS_MIXED_INTEGER_PROGRAMMING or XPRESS or XPRESS_MIP
+
GLPK_LINEAR_PROGRAMMING or GLPK_LP
+
GLPK_MIXED_INTEGER_PROGRAMMING or GLPK or GLPK_MIP
@staticmethod
+ defSupportsProblemType(problem_type:"operations_research::MPSolver::OptimizationProblemType")->"bool":
+ r"""
+ Whether the given problem type is supported (this will depend on the
+ targets that you linked).
+ """
+ return_pywraplp.Solver_SupportsProblemType(problem_type)
+
+
+
+
+
Whether the given problem type is supported (this will depend on the
+targets that you linked).
defClear(self)->"void":
+ r"""
+ Clears the objective (including the optimization direction), all variables
+ and constraints. All the other properties of the MPSolver (like the time
+ limit) are kept untouched.
+ """
+ return_pywraplp.Solver_Clear(self)
+
+
+
+
+
Clears the objective (including the optimization direction), all variables
+and constraints. All the other properties of the MPSolver (like the time
+limit) are kept untouched.
defvariables(self)->"std::vector< operations_research::MPVariable * > const &":
+ r"""
+ Returns the array of variables handled by the MPSolver. (They are listed in
+ the order in which they were created.)
+ """
+ return_pywraplp.Solver_variables(self)
+
+
+
+
+
Returns the array of variables handled by the MPSolver. (They are listed in
+the order in which they were created.)
defvariable(self,index:"int")->"operations_research::MPVariable *":
+ r"""Returns the variable at position index."""
+ return_pywraplp.Solver_variable(self,index)
+
defLookupVariable(self,var_name:"std::string const &")->"operations_research::MPVariable *":
+ r"""
+ Looks up a variable by name, and returns nullptr if it does not exist. The
+ first call has a O(n) complexity, as the variable name index is lazily
+ created upon first use. Will crash if variable names are not unique.
+ """
+ return_pywraplp.Solver_LookupVariable(self,var_name)
+
+
+
+
+
Looks up a variable by name, and returns nullptr if it does not exist. The
+first call has a O(n) complexity, as the variable name index is lazily
+created upon first use. Will crash if variable names are not unique.
defVar(self,lb:"double",ub:"double",integer:"bool",name:"std::string const &")->"operations_research::MPVariable *":
+ r"""
+ Creates a variable with the given bounds, integrality requirement and
+ name. Bounds can be finite or +/- MPSolver::infinity(). The MPSolver owns
+ the variable (i.e. the returned pointer is borrowed). Variable names are
+ optional. If you give an empty name, name() will auto-generate one for you
+ upon request.
+ """
+ return_pywraplp.Solver_Var(self,lb,ub,integer,name)
+
+
+
+
+
Creates a variable with the given bounds, integrality requirement and
+name. Bounds can be finite or +/- MPSolver::infinity(). The MPSolver owns
+the variable (i.e. the returned pointer is borrowed). Variable names are
+optional. If you give an empty name, name() will auto-generate one for you
+upon request.
defconstraints(self)->"std::vector< operations_research::MPConstraint * > const &":
+ r"""
+ Returns the array of constraints handled by the MPSolver.
+
+ They are listed in the order in which they were created.
+ """
+ return_pywraplp.Solver_constraints(self)
+
+
+
+
+
Returns the array of constraints handled by the MPSolver.
+
+
They are listed in the order in which they were created.
defconstraint(self,index:"int")->"operations_research::MPConstraint *":
+ r""" Returns the constraint at the given index."""
+ return_pywraplp.Solver_constraint(self,index)
+
defLookupConstraint(self,constraint_name:"std::string const &")->"operations_research::MPConstraint *":
+ r"""
+ Looks up a constraint by name, and returns nullptr if it does not exist.
+
+ The first call has a O(n) complexity, as the constraint name index is
+ lazily created upon first use. Will crash if constraint names are not
+ unique.
+ """
+ return_pywraplp.Solver_LookupConstraint(self,constraint_name)
+
+
+
+
+
Looks up a constraint by name, and returns nullptr if it does not exist.
+
+
The first call has a O(n) complexity, as the constraint name index is
+lazily created upon first use. Will crash if constraint names are not
+unique.
defConstraint(self,*args)->"operations_research::MPConstraint *":
+ r"""
+ *Overload 1:*
+
+ Creates a linear constraint with given bounds.
+
+ Bounds can be finite or +/- MPSolver::infinity(). The MPSolver class
+ assumes ownership of the constraint.
+
+ :rtype: :py:class:`MPConstraint`
+ :return: a pointer to the newly created constraint.
+
+ |
+
+ *Overload 2:*
+ Creates a constraint with -infinity and +infinity bounds.
+
+ |
+
+ *Overload 3:*
+ Creates a named constraint with given bounds.
+
+ |
+
+ *Overload 4:*
+ Creates a named constraint with -infinity and +infinity bounds.
+ """
+ return_pywraplp.Solver_Constraint(self,*args)
+
+
+
+
+
Overload 1:
+
+
Creates a linear constraint with given bounds.
+
+
Bounds can be finite or +/- MPSolver::infinity(). The MPSolver class
+assumes ownership of the constraint.
+
+
:rtype: MPConstraint
+:return: a pointer to the newly created constraint.
+
+
|
+
+
Overload 2:
+ Creates a constraint with -infinity and +infinity bounds.
+
+
|
+
+
Overload 3:
+ Creates a named constraint with given bounds.
+
+
|
+
+
Overload 4:
+ Creates a named constraint with -infinity and +infinity bounds.
defSolve(self,*args)->"operations_research::MPSolver::ResultStatus":
+ r"""
+ *Overload 1:*
+ Solves the problem using the default parameter values.
+
+ |
+
+ *Overload 2:*
+ Solves the problem using the specified parameter values.
+ """
+ return_pywraplp.Solver_Solve(self,*args)
+
+
+
+
+
Overload 1:
+Solves the problem using the default parameter values.
+
+
|
+
+
Overload 2:
+Solves the problem using the specified parameter values.
defComputeConstraintActivities(self)->"std::vector< double >":
+ r"""
+ Advanced usage: compute the "activities" of all constraints, which are the
+ sums of their linear terms. The activities are returned in the same order
+ as constraints(), which is the order in which constraints were added; but
+ you can also use MPConstraint::index() to get a constraint's index.
+ """
+ return_pywraplp.Solver_ComputeConstraintActivities(self)
+
+
+
+
+
Advanced usage: compute the "activities" of all constraints, which are the
+sums of their linear terms. The activities are returned in the same order
+as constraints(), which is the order in which constraints were added; but
+you can also use MPConstraint::index() to get a constraint's index.
defVerifySolution(self,tolerance:"double",log_errors:"bool")->"bool":
+ r"""
+ Advanced usage: Verifies the *correctness* of the solution.
+
+ It verifies that all variables must be within their domains, all
+ constraints must be satisfied, and the reported objective value must be
+ accurate.
+
+ Usage:
+ - This can only be called after Solve() was called.
+ - "tolerance" is interpreted as an absolute error threshold.
+ - For the objective value only, if the absolute error is too large,
+ the tolerance is interpreted as a relative error threshold instead.
+ - If "log_errors" is true, every single violation will be logged.
+ - If "tolerance" is negative, it will be set to infinity().
+
+ Most users should just set the --verify_solution flag and not bother using
+ this method directly.
+ """
+ return_pywraplp.Solver_VerifySolution(self,tolerance,log_errors)
+
+
+
+
+
Advanced usage: Verifies the correctness of the solution.
+
+
It verifies that all variables must be within their domains, all
+constraints must be satisfied, and the reported objective value must be
+accurate.
+
+
Usage:
+
+
+
This can only be called after Solve() was called.
+
"tolerance" is interpreted as an absolute error threshold.
+
For the objective value only, if the absolute error is too large,
+the tolerance is interpreted as a relative error threshold instead.
+
If "log_errors" is true, every single violation will be logged.
+
If "tolerance" is negative, it will be set to infinity().
+
+
+
Most users should just set the --verify_solution flag and not bother using
+this method directly.
defInterruptSolve(self)->"bool":
+ r"""
+ Interrupts the Solve() execution to terminate processing if possible.
+
+ If the underlying interface supports interruption; it does that and returns
+ true regardless of whether there's an ongoing Solve() or not. The Solve()
+ call may still linger for a while depending on the conditions. If
+ interruption is not supported; returns false and does nothing.
+ MPSolver::SolverTypeSupportsInterruption can be used to check if
+ interruption is supported for a given solver type.
+ """
+ return_pywraplp.Solver_InterruptSolve(self)
+
+
+
+
+
Interrupts the Solve() execution to terminate processing if possible.
+
+
If the underlying interface supports interruption; it does that and returns
+true regardless of whether there's an ongoing Solve() or not. The Solve()
+call may still linger for a while depending on the conditions. If
+interruption is not supported; returns false and does nothing.
+MPSolver::SolverTypeSupportsInterruption can be used to check if
+interruption is supported for a given solver type.
defFillSolutionResponseProto(self,response:"operations_research::MPSolutionResponse *")->"void":
+ r""" Encodes the current solution in a solution response protocol buffer."""
+ return_pywraplp.Solver_FillSolutionResponseProto(self,response)
+
+
+
+
+
Encodes the current solution in a solution response protocol buffer.
@staticmethod
+ defSolveWithProto(model_request:"operations_research::MPModelRequest const &",response:"operations_research::MPSolutionResponse *",interrupt:"std::atomic< bool > *"=None)->"operations_research::MPSolutionResponse *":
+ r"""
+ Solves the model encoded by a MPModelRequest protocol buffer and fills the
+ solution encoded as a MPSolutionResponse. The solve is stopped prematurely
+ if interrupt is non-null at set to true during (or before) solving.
+ Interruption is only supported if SolverTypeSupportsInterruption() returns
+ true for the requested solver. Passing a non-null interruption with any
+ other solver type immediately returns an MPSOLVER_INCOMPATIBLE_OPTIONS
+ error.
+
+ Note(user): This attempts to first use `DirectlySolveProto()` (if
+ implemented). Consequently, this most likely does *not* override any of
+ the default parameters of the underlying solver. This behavior *differs*
+ from `MPSolver::Solve()` which by default sets the feasibility tolerance
+ and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
+ """
+ return_pywraplp.Solver_SolveWithProto(model_request,response,interrupt)
+
+
+
+
+
Solves the model encoded by a MPModelRequest protocol buffer and fills the
+solution encoded as a MPSolutionResponse. The solve is stopped prematurely
+if interrupt is non-null at set to true during (or before) solving.
+Interruption is only supported if SolverTypeSupportsInterruption() returns
+true for the requested solver. Passing a non-null interruption with any
+other solver type immediately returns an MPSOLVER_INCOMPATIBLE_OPTIONS
+error.
+
+
Note(user): This attempts to first use DirectlySolveProto() (if
+implemented). Consequently, this most likely does not override any of
+the default parameters of the underlying solver. This behavior differs
+from MPSolver::Solve() which by default sets the feasibility tolerance
+and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
defSetSolverSpecificParametersAsString(self,parameters:"std::string const &")->"bool":
+ r"""
+ Advanced usage: pass solver specific parameters in text format.
+
+ The format is solver-specific and is the same as the corresponding solver
+ configuration file format. Returns true if the operation was successful.
+ """
+ return_pywraplp.Solver_SetSolverSpecificParametersAsString(self,parameters)
+
+
+
+
+
Advanced usage: pass solver specific parameters in text format.
+
+
The format is solver-specific and is the same as the corresponding solver
+configuration file format. Returns true if the operation was successful.
defnodes(self)->"int64_t":
+ r"""
+ Returns the number of branch-and-bound nodes evaluated during the solve.
+
+ Only available for discrete problems.
+ """
+ return_pywraplp.Solver_nodes(self)
+
+
+
+
+
Returns the number of branch-and-bound nodes evaluated during the solve.
defComputeExactConditionNumber(self)->"double":
+ r"""
+ Advanced usage: computes the exact condition number of the current scaled
+ basis: L1norm(B) * L1norm(inverse(B)), where B is the scaled basis.
+
+ This method requires that a basis exists: it should be called after Solve.
+ It is only available for continuous problems. It is implemented for GLPK
+ but not CLP because CLP does not provide the API for doing it.
+
+ The condition number measures how well the constraint matrix is conditioned
+ and can be used to predict whether numerical issues will arise during the
+ solve: the model is declared infeasible whereas it is feasible (or
+ vice-versa), the solution obtained is not optimal or violates some
+ constraints, the resolution is slow because of repeated singularities.
+
+ The rule of thumb to interpret the condition number kappa is:
+ - o kappa <= 1e7: virtually no chance of numerical issues
+ - o 1e7 < kappa <= 1e10: small chance of numerical issues
+ - o 1e10 < kappa <= 1e13: medium chance of numerical issues
+ - o kappa > 1e13: high chance of numerical issues
+
+ The computation of the condition number depends on the quality of the LU
+ decomposition, so it is not very accurate when the matrix is ill
+ conditioned.
+ """
+ return_pywraplp.Solver_ComputeExactConditionNumber(self)
+
+
+
+
+
Advanced usage: computes the exact condition number of the current scaled
+basis: L1norm(B) * L1norm(inverse(B)), where B is the scaled basis.
+
+
This method requires that a basis exists: it should be called after Solve.
+It is only available for continuous problems. It is implemented for GLPK
+but not CLP because CLP does not provide the API for doing it.
+
+
The condition number measures how well the constraint matrix is conditioned
+and can be used to predict whether numerical issues will arise during the
+solve: the model is declared infeasible whereas it is feasible (or
+vice-versa), the solution obtained is not optimal or violates some
+constraints, the resolution is slow because of repeated singularities.
+
+
The rule of thumb to interpret the condition number kappa is
+
+
+
+
o kappa <= 1e7: virtually no chance of numerical issues
+
o 1e7 < kappa <= 1e10: small chance of numerical issues
+
o 1e10 < kappa <= 1e13: medium chance of numerical issues
+
o kappa > 1e13: high chance of numerical issues
+
+
+
+
The computation of the condition number depends on the quality of the LU
+decomposition, so it is not very accurate when the matrix is ill
+conditioned.
defNextSolution(self)->"bool":
+ r"""
+ Some solvers (MIP only, not LP) can produce multiple solutions to the
+ problem. Returns true when another solution is available, and updates the
+ MPVariable* objects to make the new solution queryable. Call only after
+ calling solve.
+
+ The optimality properties of the additional solutions found, and whether or
+ not the solver computes them ahead of time or when NextSolution() is called
+ is solver specific.
+
+ As of 2020-02-10, only Gurobi and SCIP support NextSolution(), see
+ linear_solver_interfaces_test for an example of how to configure these
+ solvers for multiple solutions. Other solvers return false unconditionally.
+ """
+ return_pywraplp.Solver_NextSolution(self)
+
+
+
+
+
Some solvers (MIP only, not LP) can produce multiple solutions to the
+problem. Returns true when another solution is available, and updates the
+MPVariable* objects to make the new solution queryable. Call only after
+calling solve.
+
+
The optimality properties of the additional solutions found, and whether or
+not the solver computes them ahead of time or when NextSolution() is called
+is solver specific.
+
+
As of 2020-02-10, only Gurobi and SCIP support NextSolution(), see
+linear_solver_interfaces_test for an example of how to configure these
+solvers for multiple solutions. Other solvers return false unconditionally.
defSetHint(self,variables:"std::vector< operations_research::MPVariable * > const &",values:"std::vector< double > const &")->"void":
+ r"""
+ Set a hint for solution.
+
+ If a feasible or almost-feasible solution to the problem is already known,
+ it may be helpful to pass it to the solver so that it can be used. A
+ solver that supports this feature will try to use this information to
+ create its initial feasible solution.
+
+ Note that it may not always be faster to give a hint like this to the
+ solver. There is also no guarantee that the solver will use this hint or
+ try to return a solution "close" to this assignment in case of multiple
+ optimal solutions.
+ """
+ return_pywraplp.Solver_SetHint(self,variables,values)
+
+
+
+
+
Set a hint for solution.
+
+
If a feasible or almost-feasible solution to the problem is already known,
+it may be helpful to pass it to the solver so that it can be used. A
+solver that supports this feature will try to use this information to
+create its initial feasible solution.
+
+
Note that it may not always be faster to give a hint like this to the
+solver. There is also no guarantee that the solver will use this hint or
+try to return a solution "close" to this assignment in case of multiple
+optimal solutions.
defSetNumThreads(self,num_theads:"int")->"bool":
+ r""" Sets the number of threads to be used by the solver."""
+ return_pywraplp.Solver_SetNumThreads(self,num_theads)
+
+
+
+
+
Sets the number of threads to be used by the solver.
defSolver_CreateSolver(solver_id:"std::string const &")->"operations_research::MPSolver *":
+ r"""
+ Recommended factory method to create a MPSolver instance, especially in
+ non C++ languages.
+
+ It returns a newly created solver instance if successful, or a nullptr
+ otherwise. This can occur if the relevant interface is not linked in, or if
+ a needed license is not accessible for commercial solvers.
+
+ Ownership of the solver is passed on to the caller of this method.
+ It will accept both string names of the OptimizationProblemType enum, as
+ well as a short version (i.e. "SCIP_MIXED_INTEGER_PROGRAMMING" or "SCIP").
+
+ solver_id is case insensitive, and the following names are supported:
+ - CLP_LINEAR_PROGRAMMING or CLP
+ - CBC_MIXED_INTEGER_PROGRAMMING or CBC
+ - GLOP_LINEAR_PROGRAMMING or GLOP
+ - BOP_INTEGER_PROGRAMMING or BOP
+ - SAT_INTEGER_PROGRAMMING or SAT or CP_SAT
+ - SCIP_MIXED_INTEGER_PROGRAMMING or SCIP
+ - GUROBI_LINEAR_PROGRAMMING or GUROBI_LP
+ - GUROBI_MIXED_INTEGER_PROGRAMMING or GUROBI or GUROBI_MIP
+ - CPLEX_LINEAR_PROGRAMMING or CPLEX_LP
+ - CPLEX_MIXED_INTEGER_PROGRAMMING or CPLEX or CPLEX_MIP
+ - XPRESS_LINEAR_PROGRAMMING or XPRESS_LP
+ - XPRESS_MIXED_INTEGER_PROGRAMMING or XPRESS or XPRESS_MIP
+ - GLPK_LINEAR_PROGRAMMING or GLPK_LP
+ - GLPK_MIXED_INTEGER_PROGRAMMING or GLPK or GLPK_MIP
+ """
+ return_pywraplp.Solver_CreateSolver(solver_id)
+
+
+
+
+
Recommended factory method to create a MPSolver instance, especially in
+non C++ languages.
+
+
It returns a newly created solver instance if successful, or a nullptr
+otherwise. This can occur if the relevant interface is not linked in, or if
+a needed license is not accessible for commercial solvers.
+
+
Ownership of the solver is passed on to the caller of this method.
+It will accept both string names of the OptimizationProblemType enum, as
+well as a short version (i.e. "SCIP_MIXED_INTEGER_PROGRAMMING" or "SCIP").
+
+
solver_id is case insensitive, and the following names are supported:
+
+
+
CLP_LINEAR_PROGRAMMING or CLP
+
CBC_MIXED_INTEGER_PROGRAMMING or CBC
+
GLOP_LINEAR_PROGRAMMING or GLOP
+
BOP_INTEGER_PROGRAMMING or BOP
+
SAT_INTEGER_PROGRAMMING or SAT or CP_SAT
+
SCIP_MIXED_INTEGER_PROGRAMMING or SCIP
+
GUROBI_LINEAR_PROGRAMMING or GUROBI_LP
+
GUROBI_MIXED_INTEGER_PROGRAMMING or GUROBI or GUROBI_MIP
+
CPLEX_LINEAR_PROGRAMMING or CPLEX_LP
+
CPLEX_MIXED_INTEGER_PROGRAMMING or CPLEX or CPLEX_MIP
+
XPRESS_LINEAR_PROGRAMMING or XPRESS_LP
+
XPRESS_MIXED_INTEGER_PROGRAMMING or XPRESS or XPRESS_MIP
+
GLPK_LINEAR_PROGRAMMING or GLPK_LP
+
GLPK_MIXED_INTEGER_PROGRAMMING or GLPK or GLPK_MIP
defSolver_SupportsProblemType(problem_type:"operations_research::MPSolver::OptimizationProblemType")->"bool":
+ r"""
+ Whether the given problem type is supported (this will depend on the
+ targets that you linked).
+ """
+ return_pywraplp.Solver_SupportsProblemType(problem_type)
+
+
+
+
+
Whether the given problem type is supported (this will depend on the
+targets that you linked).
defSolver_SolveWithProto(model_request:"operations_research::MPModelRequest const &",response:"operations_research::MPSolutionResponse *",interrupt:"std::atomic< bool > *"=None)->"operations_research::MPSolutionResponse *":
+ r"""
+ Solves the model encoded by a MPModelRequest protocol buffer and fills the
+ solution encoded as a MPSolutionResponse. The solve is stopped prematurely
+ if interrupt is non-null at set to true during (or before) solving.
+ Interruption is only supported if SolverTypeSupportsInterruption() returns
+ true for the requested solver. Passing a non-null interruption with any
+ other solver type immediately returns an MPSOLVER_INCOMPATIBLE_OPTIONS
+ error.
+
+ Note(user): This attempts to first use `DirectlySolveProto()` (if
+ implemented). Consequently, this most likely does *not* override any of
+ the default parameters of the underlying solver. This behavior *differs*
+ from `MPSolver::Solve()` which by default sets the feasibility tolerance
+ and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
+ """
+ return_pywraplp.Solver_SolveWithProto(model_request,response,interrupt)
+
+
+
+
+
Solves the model encoded by a MPModelRequest protocol buffer and fills the
+solution encoded as a MPSolutionResponse. The solve is stopped prematurely
+if interrupt is non-null at set to true during (or before) solving.
+Interruption is only supported if SolverTypeSupportsInterruption() returns
+true for the requested solver. Passing a non-null interruption with any
+other solver type immediately returns an MPSOLVER_INCOMPATIBLE_OPTIONS
+error.
+
+
Note(user): This attempts to first use DirectlySolveProto() (if
+implemented). Consequently, this most likely does not override any of
+the default parameters of the underlying solver. This behavior differs
+from MPSolver::Solve() which by default sets the feasibility tolerance
+and the gap limit (as of 2020/02/11, to 1e-7 and 0.0001, respectively).
defSolver_infinity()->"double":
+ r"""
+ Infinity.
+
+ You can use -MPSolver::infinity() for negative infinity.
+ """
+ return_pywraplp.Solver_infinity()
+
+
+
+
+
Infinity.
+
+
You can use -MPSolver::infinity() for negative infinity.
classObjective(object):
+ r""" A class to express a linear objective."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defClear(self)->"void":
+ r"""
+ Clears the offset, all variables and coefficients, and the optimization
+ direction.
+ """
+ return_pywraplp.Objective_Clear(self)
+
+ defSetCoefficient(self,var:"Variable",coeff:"double")->"void":
+ r"""
+ Sets the coefficient of the variable in the objective.
+
+ If the variable does not belong to the solver, the function just returns,
+ or crashes in non-opt mode.
+ """
+ return_pywraplp.Objective_SetCoefficient(self,var,coeff)
+
+ defGetCoefficient(self,var:"Variable")->"double":
+ r"""
+ Gets the coefficient of a given variable in the objective
+
+ It returns 0 if the variable does not appear in the objective).
+ """
+ return_pywraplp.Objective_GetCoefficient(self,var)
+
+ defSetOffset(self,value:"double")->"void":
+ r""" Sets the constant term in the objective."""
+ return_pywraplp.Objective_SetOffset(self,value)
+
+ defoffset(self)->"double":
+ r""" Gets the constant term in the objective."""
+ return_pywraplp.Objective_offset(self)
+
+ defSetOptimizationDirection(self,maximize:"bool")->"void":
+ r""" Sets the optimization direction (maximize: true or minimize: false)."""
+ return_pywraplp.Objective_SetOptimizationDirection(self,maximize)
+
+ defSetMinimization(self)->"void":
+ r""" Sets the optimization direction to minimize."""
+ return_pywraplp.Objective_SetMinimization(self)
+
+ defSetMaximization(self)->"void":
+ r""" Sets the optimization direction to maximize."""
+ return_pywraplp.Objective_SetMaximization(self)
+
+ defmaximization(self)->"bool":
+ r""" Is the optimization direction set to maximize?"""
+ return_pywraplp.Objective_maximization(self)
+
+ defminimization(self)->"bool":
+ r""" Is the optimization direction set to minimize?"""
+ return_pywraplp.Objective_minimization(self)
+
+ defValue(self)->"double":
+ r"""
+ Returns the objective value of the best solution found so far.
+
+ It is the optimal objective value if the problem has been solved to
+ optimality.
+
+ Note: the objective value may be slightly different than what you could
+ compute yourself using ``MPVariable::solution_value();`` please use the
+ --verify_solution flag to gain confidence about the numerical stability of
+ your solution.
+ """
+ return_pywraplp.Objective_Value(self)
+
+ defBestBound(self)->"double":
+ r"""
+ Returns the best objective bound.
+
+ In case of minimization, it is a lower bound on the objective value of the
+ optimal integer solution. Only available for discrete problems.
+ """
+ return_pywraplp.Objective_BestBound(self)
+
+ defOffset(self)->"double":
+ return_pywraplp.Objective_Offset(self)
+ __swig_destroy__=_pywraplp.delete_Objective
+
defClear(self)->"void":
+ r"""
+ Clears the offset, all variables and coefficients, and the optimization
+ direction.
+ """
+ return_pywraplp.Objective_Clear(self)
+
+
+
+
+
Clears the offset, all variables and coefficients, and the optimization
+direction.
defSetCoefficient(self,var:"Variable",coeff:"double")->"void":
+ r"""
+ Sets the coefficient of the variable in the objective.
+
+ If the variable does not belong to the solver, the function just returns,
+ or crashes in non-opt mode.
+ """
+ return_pywraplp.Objective_SetCoefficient(self,var,coeff)
+
+
+
+
+
Sets the coefficient of the variable in the objective.
+
+
If the variable does not belong to the solver, the function just returns,
+or crashes in non-opt mode.
defGetCoefficient(self,var:"Variable")->"double":
+ r"""
+ Gets the coefficient of a given variable in the objective
+
+ It returns 0 if the variable does not appear in the objective).
+ """
+ return_pywraplp.Objective_GetCoefficient(self,var)
+
+
+
+
+
Gets the coefficient of a given variable in the objective
+
+
It returns 0 if the variable does not appear in the objective).
defSetOptimizationDirection(self,maximize:"bool")->"void":
+ r""" Sets the optimization direction (maximize: true or minimize: false)."""
+ return_pywraplp.Objective_SetOptimizationDirection(self,maximize)
+
+
+
+
+
Sets the optimization direction (maximize: true or minimize: false).
defValue(self)->"double":
+ r"""
+ Returns the objective value of the best solution found so far.
+
+ It is the optimal objective value if the problem has been solved to
+ optimality.
+
+ Note: the objective value may be slightly different than what you could
+ compute yourself using ``MPVariable::solution_value();`` please use the
+ --verify_solution flag to gain confidence about the numerical stability of
+ your solution.
+ """
+ return_pywraplp.Objective_Value(self)
+
+
+
+
+
Returns the objective value of the best solution found so far.
+
+
It is the optimal objective value if the problem has been solved to
+optimality.
+
+
Note: the objective value may be slightly different than what you could
+compute yourself using MPVariable::solution_value(); please use the
+--verify_solution flag to gain confidence about the numerical stability of
+your solution.
defBestBound(self)->"double":
+ r"""
+ Returns the best objective bound.
+
+ In case of minimization, it is a lower bound on the objective value of the
+ optimal integer solution. Only available for discrete problems.
+ """
+ return_pywraplp.Objective_BestBound(self)
+
+
+
+
+
Returns the best objective bound.
+
+
In case of minimization, it is a lower bound on the objective value of the
+optimal integer solution. Only available for discrete problems.
classVariable(object):
+ r""" The class for variables of a Mathematical Programming (MP) model."""
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+
+ defname(self)->"std::string const &":
+ r""" Returns the name of the variable."""
+ return_pywraplp.Variable_name(self)
+
+ defSetInteger(self,integer:"bool")->"void":
+ r""" Sets the integrality requirement of the variable."""
+ return_pywraplp.Variable_SetInteger(self,integer)
+
+ definteger(self)->"bool":
+ r""" Returns the integrality requirement of the variable."""
+ return_pywraplp.Variable_integer(self)
+
+ defsolution_value(self)->"double":
+ r"""
+ Returns the value of the variable in the current solution.
+
+ If the variable is integer, then the value will always be an integer (the
+ underlying solver handles floating-point values only, but this function
+ automatically rounds it to the nearest integer; see: man 3 round).
+ """
+ return_pywraplp.Variable_solution_value(self)
+
+ defindex(self)->"int":
+ r""" Returns the index of the variable in the MPSolver::variables_."""
+ return_pywraplp.Variable_index(self)
+
+ deflb(self)->"double":
+ r""" Returns the lower bound."""
+ return_pywraplp.Variable_lb(self)
+
+ defub(self)->"double":
+ r""" Returns the upper bound."""
+ return_pywraplp.Variable_ub(self)
+
+ defSetBounds(self,lb:"double",ub:"double")->"void":
+ r""" Sets both the lower and upper bounds."""
+ return_pywraplp.Variable_SetBounds(self,lb,ub)
+
+ defreduced_cost(self)->"double":
+ r"""
+ Advanced usage: returns the reduced cost of the variable in the current
+ solution (only available for continuous problems).
+ """
+ return_pywraplp.Variable_reduced_cost(self)
+
+ defbasis_status(self)->"operations_research::MPSolver::BasisStatus":
+ r"""
+ Advanced usage: returns the basis status of the variable in the current
+ solution (only available for continuous problems).
+
+ See also: MPSolver::BasisStatus.
+ """
+ return_pywraplp.Variable_basis_status(self)
+
+ defbranching_priority(self)->"int":
+ r"""
+ Advanced usage: Certain MIP solvers (e.g. Gurobi or SCIP) allow you to set
+ a per-variable priority for determining which variable to branch on.
+
+ A value of 0 is treated as default, and is equivalent to not setting the
+ branching priority. The solver looks first to branch on fractional
+ variables in higher priority levels. As of 2019-05, only Gurobi and SCIP
+ support setting branching priority; all other solvers will simply ignore
+ this annotation.
+ """
+ return_pywraplp.Variable_branching_priority(self)
+
+ defSetBranchingPriority(self,priority:"int")->"void":
+ return_pywraplp.Variable_SetBranchingPriority(self,priority)
+
+ def__str__(self)->"std::string":
+ return_pywraplp.Variable___str__(self)
+
+ def__repr__(self)->"std::string":
+ return_pywraplp.Variable___repr__(self)
+
+ def__getattr__(self,name):
+ returngetattr(VariableExpr(self),name)
+
+
+ defSolutionValue(self)->"double":
+ return_pywraplp.Variable_SolutionValue(self)
+
+ defInteger(self)->"bool":
+ return_pywraplp.Variable_Integer(self)
+
+ defLb(self)->"double":
+ return_pywraplp.Variable_Lb(self)
+
+ defUb(self)->"double":
+ return_pywraplp.Variable_Ub(self)
+
+ defSetLb(self,x:"double")->"void":
+ return_pywraplp.Variable_SetLb(self,x)
+
+ defSetUb(self,x:"double")->"void":
+ return_pywraplp.Variable_SetUb(self,x)
+
+ defReducedCost(self)->"double":
+ return_pywraplp.Variable_ReducedCost(self)
+ __swig_destroy__=_pywraplp.delete_Variable
+
+
+
+
+
The class for variables of a Mathematical Programming (MP) model.
defSetInteger(self,integer:"bool")->"void":
+ r""" Sets the integrality requirement of the variable."""
+ return_pywraplp.Variable_SetInteger(self,integer)
+
defsolution_value(self)->"double":
+ r"""
+ Returns the value of the variable in the current solution.
+
+ If the variable is integer, then the value will always be an integer (the
+ underlying solver handles floating-point values only, but this function
+ automatically rounds it to the nearest integer; see: man 3 round).
+ """
+ return_pywraplp.Variable_solution_value(self)
+
+
+
+
+
Returns the value of the variable in the current solution.
+
+
If the variable is integer, then the value will always be an integer (the
+underlying solver handles floating-point values only, but this function
+automatically rounds it to the nearest integer; see: man 3 round).
defreduced_cost(self)->"double":
+ r"""
+ Advanced usage: returns the reduced cost of the variable in the current
+ solution (only available for continuous problems).
+ """
+ return_pywraplp.Variable_reduced_cost(self)
+
+
+
+
+
Advanced usage: returns the reduced cost of the variable in the current
+solution (only available for continuous problems).
defbasis_status(self)->"operations_research::MPSolver::BasisStatus":
+ r"""
+ Advanced usage: returns the basis status of the variable in the current
+ solution (only available for continuous problems).
+
+ See also: MPSolver::BasisStatus.
+ """
+ return_pywraplp.Variable_basis_status(self)
+
+
+
+
+
Advanced usage: returns the basis status of the variable in the current
+solution (only available for continuous problems).
defbranching_priority(self)->"int":
+ r"""
+ Advanced usage: Certain MIP solvers (e.g. Gurobi or SCIP) allow you to set
+ a per-variable priority for determining which variable to branch on.
+
+ A value of 0 is treated as default, and is equivalent to not setting the
+ branching priority. The solver looks first to branch on fractional
+ variables in higher priority levels. As of 2019-05, only Gurobi and SCIP
+ support setting branching priority; all other solvers will simply ignore
+ this annotation.
+ """
+ return_pywraplp.Variable_branching_priority(self)
+
+
+
+
+
Advanced usage: Certain MIP solvers (e.g. Gurobi or SCIP) allow you to set
+a per-variable priority for determining which variable to branch on.
+
+
A value of 0 is treated as default, and is equivalent to not setting the
+branching priority. The solver looks first to branch on fractional
+variables in higher priority levels. As of 2019-05, only Gurobi and SCIP
+support setting branching priority; all other solvers will simply ignore
+this annotation.
classConstraint(object):
+ r"""
+ The class for constraints of a Mathematical Programming (MP) model.
+
+ A constraint is represented as a linear equation or inequality.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+
+ def__init__(self,*args,**kwargs):
+ raiseAttributeError("No constructor defined")
+ __repr__=_swig_repr
+
+ defname(self)->"std::string const &":
+ r""" Returns the name of the constraint."""
+ return_pywraplp.Constraint_name(self)
+
+ defClear(self)->"void":
+ r""" Clears all variables and coefficients. Does not clear the bounds."""
+ return_pywraplp.Constraint_Clear(self)
+
+ defSetCoefficient(self,var:"Variable",coeff:"double")->"void":
+ r"""
+ Sets the coefficient of the variable on the constraint.
+
+ If the variable does not belong to the solver, the function just returns,
+ or crashes in non-opt mode.
+ """
+ return_pywraplp.Constraint_SetCoefficient(self,var,coeff)
+
+ defGetCoefficient(self,var:"Variable")->"double":
+ r"""
+ Gets the coefficient of a given variable on the constraint (which is 0 if
+ the variable does not appear in the constraint).
+ """
+ return_pywraplp.Constraint_GetCoefficient(self,var)
+
+ deflb(self)->"double":
+ r""" Returns the lower bound."""
+ return_pywraplp.Constraint_lb(self)
+
+ defub(self)->"double":
+ r""" Returns the upper bound."""
+ return_pywraplp.Constraint_ub(self)
+
+ defSetBounds(self,lb:"double",ub:"double")->"void":
+ r""" Sets both the lower and upper bounds."""
+ return_pywraplp.Constraint_SetBounds(self,lb,ub)
+
+ defset_is_lazy(self,laziness:"bool")->"void":
+ r"""
+ Advanced usage: sets the constraint "laziness".
+
+ **This is only supported for SCIP and has no effect on other
+ solvers.**
+
+ When **laziness** is true, the constraint is only considered by the Linear
+ Programming solver if its current solution violates the constraint. In this
+ case, the constraint is definitively added to the problem. This may be
+ useful in some MIP problems, and may have a dramatic impact on performance.
+
+ For more info see: http://tinyurl.com/lazy-constraints.
+ """
+ return_pywraplp.Constraint_set_is_lazy(self,laziness)
+
+ defindex(self)->"int":
+ r""" Returns the index of the constraint in the MPSolver::constraints_."""
+ return_pywraplp.Constraint_index(self)
+
+ defdual_value(self)->"double":
+ r"""
+ Advanced usage: returns the dual value of the constraint in the current
+ solution (only available for continuous problems).
+ """
+ return_pywraplp.Constraint_dual_value(self)
+
+ defbasis_status(self)->"operations_research::MPSolver::BasisStatus":
+ r"""
+ Advanced usage: returns the basis status of the constraint.
+
+ It is only available for continuous problems).
+
+ Note that if a constraint "linear_expression in [lb, ub]" is transformed
+ into "linear_expression + slack = 0" with slack in [-ub, -lb], then this
+ status is the same as the status of the slack variable with AT_UPPER_BOUND
+ and AT_LOWER_BOUND swapped.
+
+ See also: MPSolver::BasisStatus.
+ """
+ return_pywraplp.Constraint_basis_status(self)
+
+ defLb(self)->"double":
+ return_pywraplp.Constraint_Lb(self)
+
+ defUb(self)->"double":
+ return_pywraplp.Constraint_Ub(self)
+
+ defSetLb(self,x:"double")->"void":
+ return_pywraplp.Constraint_SetLb(self,x)
+
+ defSetUb(self,x:"double")->"void":
+ return_pywraplp.Constraint_SetUb(self,x)
+
+ defDualValue(self)->"double":
+ return_pywraplp.Constraint_DualValue(self)
+ __swig_destroy__=_pywraplp.delete_Constraint
+
+
+
+
+
The class for constraints of a Mathematical Programming (MP) model.
+
+
A constraint is represented as a linear equation or inequality.
defSetCoefficient(self,var:"Variable",coeff:"double")->"void":
+ r"""
+ Sets the coefficient of the variable on the constraint.
+
+ If the variable does not belong to the solver, the function just returns,
+ or crashes in non-opt mode.
+ """
+ return_pywraplp.Constraint_SetCoefficient(self,var,coeff)
+
+
+
+
+
Sets the coefficient of the variable on the constraint.
+
+
If the variable does not belong to the solver, the function just returns,
+or crashes in non-opt mode.
defGetCoefficient(self,var:"Variable")->"double":
+ r"""
+ Gets the coefficient of a given variable on the constraint (which is 0 if
+ the variable does not appear in the constraint).
+ """
+ return_pywraplp.Constraint_GetCoefficient(self,var)
+
+
+
+
+
Gets the coefficient of a given variable on the constraint (which is 0 if
+the variable does not appear in the constraint).
defSetBounds(self,lb:"double",ub:"double")->"void":
+ r""" Sets both the lower and upper bounds."""
+ return_pywraplp.Constraint_SetBounds(self,lb,ub)
+
defset_is_lazy(self,laziness:"bool")->"void":
+ r"""
+ Advanced usage: sets the constraint "laziness".
+
+ **This is only supported for SCIP and has no effect on other
+ solvers.**
+
+ When **laziness** is true, the constraint is only considered by the Linear
+ Programming solver if its current solution violates the constraint. In this
+ case, the constraint is definitively added to the problem. This may be
+ useful in some MIP problems, and may have a dramatic impact on performance.
+
+ For more info see: http://tinyurl.com/lazy-constraints.
+ """
+ return_pywraplp.Constraint_set_is_lazy(self,laziness)
+
+
+
+
+
Advanced usage: sets the constraint "laziness".
+
+
This is only supported for SCIP and has no effect on other
+solvers.
+
+
When laziness is true, the constraint is only considered by the Linear
+Programming solver if its current solution violates the constraint. In this
+case, the constraint is definitively added to the problem. This may be
+useful in some MIP problems, and may have a dramatic impact on performance.
+
+
For more info see: http://tinyurl.com/lazy-constraints.
defdual_value(self)->"double":
+ r"""
+ Advanced usage: returns the dual value of the constraint in the current
+ solution (only available for continuous problems).
+ """
+ return_pywraplp.Constraint_dual_value(self)
+
+
+
+
+
Advanced usage: returns the dual value of the constraint in the current
+solution (only available for continuous problems).
defbasis_status(self)->"operations_research::MPSolver::BasisStatus":
+ r"""
+ Advanced usage: returns the basis status of the constraint.
+
+ It is only available for continuous problems).
+
+ Note that if a constraint "linear_expression in [lb, ub]" is transformed
+ into "linear_expression + slack = 0" with slack in [-ub, -lb], then this
+ status is the same as the status of the slack variable with AT_UPPER_BOUND
+ and AT_LOWER_BOUND swapped.
+
+ See also: MPSolver::BasisStatus.
+ """
+ return_pywraplp.Constraint_basis_status(self)
+
+
+
+
+
Advanced usage: returns the basis status of the constraint.
+
+
It is only available for continuous problems).
+
+
Note that if a constraint "linear_expression in [lb, ub]" is transformed
+into "linear_expression + slack = 0" with slack in [-ub, -lb], then this
+status is the same as the status of the slack variable with AT_UPPER_BOUND
+and AT_LOWER_BOUND swapped.
classMPSolverParameters(object):
+ r"""
+ This class stores parameter settings for LP and MIP solvers. Some parameters
+ are marked as advanced: do not change their values unless you know what you
+ are doing!
+
+ For developers: how to add a new parameter:
+ - Add the new Foo parameter in the DoubleParam or IntegerParam enum.
+ - If it is a categorical param, add a FooValues enum.
+ - Decide if the wrapper should define a default value for it: yes
+ if it controls the properties of the solution (example:
+ tolerances) or if it consistently improves performance, no
+ otherwise. If yes, define kDefaultFoo.
+ - Add a foo_value_ member and, if no default value is defined, a
+ foo_is_default_ member.
+ - Add code to handle Foo in Set...Param, Reset...Param,
+ Get...Param, Reset and the constructor.
+ - In class MPSolverInterface, add a virtual method SetFoo, add it
+ to SetCommonParameters or SetMIPParameters, and implement it for
+ each solver. Sometimes, parameters need to be implemented
+ differently, see for example the INCREMENTALITY implementation.
+ - Add a test in linear_solver_test.cc.
+
+ TODO(user): store the parameter values in a protocol buffer
+ instead. We need to figure out how to deal with the subtleties of
+ the default values.
+ """
+
+ thisown=property(lambdax:x.this.own(),lambdax,v:x.this.own(v),doc="The membership flag")
+ __repr__=_swig_repr
+ RELATIVE_MIP_GAP=_pywraplp.MPSolverParameters_RELATIVE_MIP_GAP
+ r""" Limit for relative MIP gap."""
+ PRIMAL_TOLERANCE=_pywraplp.MPSolverParameters_PRIMAL_TOLERANCE
+ r"""
+ Advanced usage: tolerance for primal feasibility of basic solutions.
+
+ This does not control the integer feasibility tolerance of integer
+ solutions for MIP or the tolerance used during presolve.
+ """
+ DUAL_TOLERANCE=_pywraplp.MPSolverParameters_DUAL_TOLERANCE
+ r""" Advanced usage: tolerance for dual feasibility of basic solutions."""
+ PRESOLVE=_pywraplp.MPSolverParameters_PRESOLVE
+ r""" Advanced usage: presolve mode."""
+ LP_ALGORITHM=_pywraplp.MPSolverParameters_LP_ALGORITHM
+ r""" Algorithm to solve linear programs."""
+ INCREMENTALITY=_pywraplp.MPSolverParameters_INCREMENTALITY
+ r""" Advanced usage: incrementality from one solve to the next."""
+ SCALING=_pywraplp.MPSolverParameters_SCALING
+ r""" Advanced usage: enable or disable matrix scaling."""
+ PRESOLVE_OFF=_pywraplp.MPSolverParameters_PRESOLVE_OFF
+ r""" Presolve is off."""
+ PRESOLVE_ON=_pywraplp.MPSolverParameters_PRESOLVE_ON
+ r""" Presolve is on."""
+ DUAL=_pywraplp.MPSolverParameters_DUAL
+ r""" Dual simplex."""
+ PRIMAL=_pywraplp.MPSolverParameters_PRIMAL
+ r""" Primal simplex."""
+ BARRIER=_pywraplp.MPSolverParameters_BARRIER
+ r""" Barrier algorithm."""
+ INCREMENTALITY_OFF=_pywraplp.MPSolverParameters_INCREMENTALITY_OFF
+ r""" Start solve from scratch."""
+ INCREMENTALITY_ON=_pywraplp.MPSolverParameters_INCREMENTALITY_ON
+ r"""
+ Reuse results from previous solve as much as the underlying solver
+ allows.
+ """
+ SCALING_OFF=_pywraplp.MPSolverParameters_SCALING_OFF
+ r""" Scaling is off."""
+ SCALING_ON=_pywraplp.MPSolverParameters_SCALING_ON
+ r""" Scaling is on."""
+
+ def__init__(self):
+ r""" The constructor sets all parameters to their default value."""
+ _pywraplp.MPSolverParameters_swiginit(self,_pywraplp.new_MPSolverParameters())
+
+ defSetDoubleParam(self,param:"operations_research::MPSolverParameters::DoubleParam",value:"double")->"void":
+ r""" Sets a double parameter to a specific value."""
+ return_pywraplp.MPSolverParameters_SetDoubleParam(self,param,value)
+
+ defSetIntegerParam(self,param:"operations_research::MPSolverParameters::IntegerParam",value:"int")->"void":
+ r""" Sets a integer parameter to a specific value."""
+ return_pywraplp.MPSolverParameters_SetIntegerParam(self,param,value)
+
+ defGetDoubleParam(self,param:"operations_research::MPSolverParameters::DoubleParam")->"double":
+ r""" Returns the value of a double parameter."""
+ return_pywraplp.MPSolverParameters_GetDoubleParam(self,param)
+
+ defGetIntegerParam(self,param:"operations_research::MPSolverParameters::IntegerParam")->"int":
+ r""" Returns the value of an integer parameter."""
+ return_pywraplp.MPSolverParameters_GetIntegerParam(self,param)
+ __swig_destroy__=_pywraplp.delete_MPSolverParameters
+
+
+
+
+
This class stores parameter settings for LP and MIP solvers. Some parameters
+are marked as advanced: do not change their values unless you know what you
+are doing!
+
+
For developers: how to add a new parameter:
+
+
+
Add the new Foo parameter in the DoubleParam or IntegerParam enum.
+
If it is a categorical param, add a FooValues enum.
+
Decide if the wrapper should define a default value for it: yes
+if it controls the properties of the solution (example:
+tolerances) or if it consistently improves performance, no
+otherwise. If yes, define kDefaultFoo.
+
Add a foo_value_ member and, if no default value is defined, a
+foo_is_default_ member.
+
Add code to handle Foo in Set...Param, Reset...Param,
+Get...Param, Reset and the constructor.
+
In class MPSolverInterface, add a virtual method SetFoo, add it
+to SetCommonParameters or SetMIPParameters, and implement it for
+each solver. Sometimes, parameters need to be implemented
+differently, see for example the INCREMENTALITY implementation.
+
Add a test in linear_solver_test.cc.
+
+
+
TODO(user): store the parameter values in a protocol buffer
+instead. We need to figure out how to deal with the subtleties of
+the default values.
def__init__(self):
+ r""" The constructor sets all parameters to their default value."""
+ _pywraplp.MPSolverParameters_swiginit(self,_pywraplp.new_MPSolverParameters())
+
+
+
+
+
The constructor sets all parameters to their default value.
defSetDoubleParam(self,param:"operations_research::MPSolverParameters::DoubleParam",value:"double")->"void":
+ r""" Sets a double parameter to a specific value."""
+ return_pywraplp.MPSolverParameters_SetDoubleParam(self,param,value)
+
defSetIntegerParam(self,param:"operations_research::MPSolverParameters::IntegerParam",value:"int")->"void":
+ r""" Sets a integer parameter to a specific value."""
+ return_pywraplp.MPSolverParameters_SetIntegerParam(self,param,value)
+
defGetDoubleParam(self,param:"operations_research::MPSolverParameters::DoubleParam")->"double":
+ r""" Returns the value of a double parameter."""
+ return_pywraplp.MPSolverParameters_GetDoubleParam(self,param)
+
defGetIntegerParam(self,param:"operations_research::MPSolverParameters::IntegerParam")->"int":
+ r""" Returns the value of an integer parameter."""
+ return_pywraplp.MPSolverParameters_GetIntegerParam(self,param)
+
LinearExpr: Methods for creating constraints
and the objective from large arrays of coefficients.
@@ -530,7 +548,7 @@ rather than for solving specific optimization problems.
View Source
-
# Copyright 2010-2021 Google LLC
+
# Copyright 2010-2021 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
@@ -584,14 +602,14 @@ rather than for solving specific optimization problems.
fromortools.satimportcp_model_pb2fromortools.satimportsat_parameters_pb2fromortools.sat.pythonimportcp_model_helperascmh
-fromortools.satimportpywrapsat
-fromortools.utilimportsorted_interval_list
+fromortools.sat.pythonimportswig_helper
+fromortools.util.pythonimportsorted_interval_listDomain=sorted_interval_list.Domain# The classes below allow linear expressions to be expressed naturally with the
-# usual arithmetic operators +-*/ and with constant numbers, which makes the
-# python API very intuitive. See ../samples/*.py for examples.
+# usual arithmetic operators + - * / and with constant numbers, which makes the
+# python API very intuitive. See../ samples/*.py for examples.INT_MIN=-9223372036854775808# hardcoded to be platform independent.INT_MAX=9223372036854775807
@@ -704,7 +722,7 @@ rather than for solving specific optimization problems.
``` model.Minimize(cp_model.LinearExpr.Sum(expressions))
- model.Add(cp_model.LinearExpr.ScalProd(expressions, coefficients) >= 0)
+ model.Add(cp_model.LinearExpr.WeightedSum(expressions, coefficients) >= 0) ``` """
@@ -716,14 +734,14 @@ rather than for solving specific optimization problems.
return_SumArray(expressions)@classmethod
- defScalProd(cls,expressions,coefficients):
+ defWeightedSum(cls,expressions,coefficients):"""Creates the expression sum(expressions[i] * coefficients[i])."""ifLinearExpr.IsEmptyOrAllNull(coefficients):return0eliflen(expressions)==1:returnexpressions[0]*coefficients[0]else:
- return_ScalProd(expressions,coefficients)
+ return_WeightedSum(expressions,coefficients)@classmethoddefTerm(cls,expression,coefficient):
@@ -761,7 +779,7 @@ rather than for solving specific optimization problems.
ifall_ones:return_SumArray(variables,offset)else:
- return_ScalProd(variables,coeffs,offset)
+ return_WeightedSum(variables,coeffs,offset)defGetIntegerVarValueMap(self):"""Scans the expression, and returns (var_coef_map, constant)."""
@@ -782,7 +800,7 @@ rather than for solving specific optimization problems.
foreinexpr.Expressions():to_process.append((e,coeff))constant+=expr.Constant()*coeff
- elifisinstance(expr,_ScalProd):
+ elifisinstance(expr,_WeightedSum):fore,cinzip(expr.Expressions(),expr.Coefficients()):to_process.append((e,coeff*c))constant+=expr.Constant()*coeff
@@ -817,7 +835,7 @@ rather than for solving specific optimization problems.
foreinexpr.Expressions():to_process.append((e,coeff))constant+=expr.Constant()*coeff
- elifisinstance(expr,_ScalProd):
+ elifisinstance(expr,_WeightedSum):fore,cinzip(expr.Expressions(),expr.Coefficients()):to_process.append((e,coeff*c))constant+=expr.Constant()*coeff
@@ -1079,8 +1097,8 @@ rather than for solving specific optimization problems.
returnself.__constant
-class_ScalProd(LinearExpr):
- """Represents the scalar product of expressions with constants and a constant."""
+class_WeightedSum(LinearExpr):
+ """Represents sum(ai * xi) + b."""def__init__(self,expressions,coefficients,constant=0):self.__expressions=[]
@@ -1088,7 +1106,7 @@ rather than for solving specific optimization problems.
self.__constant=constantiflen(expressions)!=len(coefficients):raiseTypeError(
- 'In the LinearExpr.ScalProd method, the expression array and the '
+ 'In the LinearExpr.WeightedSum method, the expression array and the '' coefficient array must have the same length.')fore,cinzip(expressions,coefficients):c=cmh.assert_is_a_number(c)
@@ -1129,7 +1147,7 @@ rather than for solving specific optimization problems.
returnoutputdef__repr__(self):
- return'ScalProd([{}], [{}], {})'.format(
+ return'WeightedSum([{}], [{}], {})'.format(', '.join(map(repr,self.__expressions)),', '.join(map(repr,self.__coefficients)),self.__constant)
@@ -1328,7 +1346,7 @@ rather than for solving specific optimization problems.
self.__index=len(constraints)self.__constraint=constraints.add()
- defOnlyEnforceIf(self,boolvar):
+ defOnlyEnforceIf(self,*boolvar):"""Adds an enforcement literal to the constraint. This method adds one or more literals (that is, a boolean variable or its
@@ -1340,23 +1358,18 @@ rather than for solving specific optimization problems.
BoolOr, BoolAnd, and linear constraints all support enforcement literals. Args:
- boolvar: A boolean literal or a list of boolean literals.
+ *boolvar: One or more Boolean literals. Returns: self. """
-
- ifcmh.is_integral(boolvar)andint(boolvar)==1:
- # Always true. Do nothing.
- pass
- elifisinstance(boolvar,list):
- forbinboolvar:
- ifcmh.is_integral(b)andint(b)==1:
- pass
- else:
- self.__constraint.enforcement_literal.append(b.Index())
- else:
- self.__constraint.enforcement_literal.append(boolvar.Index())
+ forlitinExpandGeneratorOrTuple(boolvar):
+ if(isinstance(lit,bool)and
+ bool(lit))or(cmh.is_integral(lit)andint(lit)==1):
+ # Always true. Do nothing.
+ pass
+ else:
+ self.__constraint.enforcement_literal.append(lit.Index())returnselfdefIndex(self):
@@ -1592,21 +1605,22 @@ rather than for solving specific optimization problems.
# General Integer Constraints.
- defAddAllDifferent(self,expressions):
+ defAddAllDifferent(self,*expressions):"""Adds AllDifferent(expressions). This constraint forces all expressions to have different values. Args:
- expressions: a list of integer affine expressions.
+ *expressions: simple expressions of the form a * var + constant. Returns: An instance of the `Constraint` class. """ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
+ expanded=ExpandGeneratorOrTuple(expressions)model_ct.all_diff.exprs.extend(
- [self.ParseLinearExpression(x)forxinexpressions])
+ [self.ParseLinearExpression(x)forxinexpanded])returnctdefAddElement(self,index,variables,target):
@@ -1661,6 +1675,44 @@ rather than for solving specific optimization problems.
model_ct.circuit.literals.append(lit)returnct
+ defAddMultipleCircuit(self,arcs):
+ """Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+ The direct graph where arc #i (from tails[i] to head[i]) is present iff
+ literals[i] is true must satisfy this set of properties:
+ - #incoming arcs == 1 except for node 0.
+ - #outgoing arcs == 1 except for node 0.
+ - for node zero, #incoming arcs == #outgoing arcs.
+ - There are no duplicate arcs.
+ - Self-arcs are allowed except for node 0.
+ - There is no cycle in this graph, except through node 0.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError(
+ 'AddMultipleCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.routes.tails.append(tail)
+ model_ct.routes.heads.append(head)
+ model_ct.routes.literals.append(lit)
+ returnct
+
defAddAllowedAssignments(self,variables,tuples_list):"""Adds AllowedAssignments(variables, tuples_list).
@@ -1990,42 +2042,72 @@ rather than for solving specific optimization problems.
model_ct.enforcement_literal.append(self.GetOrMakeBooleanIndex(a))returnct
- defAddBoolOr(self,literals):
- """Adds `Or(literals) == true`."""
+ defAddBoolOr(self,*literals):
+ """Adds `Or(literals) == true`: Sum(literals) >= 1."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.bool_or.literals.extend(
- [self.GetOrMakeBooleanIndex(x)forxinliterals])
+ model_ct.bool_or.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])returnct
- defAddBoolAnd(self,literals):
+ defAddAtLeastOne(self,*literals):
+ """Same as `AddBoolOr`: `Sum(literals) >= 1`."""
+ returnself.AddBoolOr(*literals)
+
+ defAddAtMostOne(self,*literals):
+ """Adds `AtMostOne(literals)`: `Sum(literals) <= 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.at_most_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddExactlyOne(self,*literals):
+ """Adds `ExactlyOne(literals)`: `Sum(literals) == 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.exactly_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddBoolAnd(self,*literals):"""Adds `And(literals) == true`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.bool_and.literals.extend(
- [self.GetOrMakeBooleanIndex(x)forxinliterals])
+ model_ct.bool_and.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])returnct
- defAddBoolXOr(self,literals):
+ defAddBoolXOr(self,*literals):"""Adds `XOr(literals) == true`. In contrast to AddBoolOr and AddBoolAnd, it does not support .OnlyEnforceIf(). Args:
- literals: the list of literals in the constraint.
+ *literals: the list of literals in the constraint. Returns: An `Constraint` object. """ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.bool_xor.literals.extend(
- [self.GetOrMakeBooleanIndex(x)forxinliterals])
+ model_ct.bool_xor.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])returnctdefAddMinEquality(self,target,exprs):
- """Adds `target == Min(variables)`."""
+ """Adds `target == Min(exprs)`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]model_ct.lin_max.exprs.extend(
@@ -2035,7 +2117,7 @@ rather than for solving specific optimization problems.
returnctdefAddMaxEquality(self,target,exprs):
- """Adds `target == Max(variables)`."""
+ """Adds `target == Max(exprs)`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]model_ct.lin_max.exprs.extend(
@@ -2070,12 +2152,14 @@ rather than for solving specific optimization problems.
model_ct.int_mod.target.CopyFrom(self.ParseLinearExpression(target))returnct
- defAddMultiplicationEquality(self,target,expressions):
- """Adds `target == variables[0] * .. * variables[n]`."""
+ defAddMultiplicationEquality(self,target,*expressions):
+ """Adds `target == expressions[0] * .. * expressions[n]`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.int_prod.exprs.extend(
- [self.ParseLinearExpression(expr)forexprinexpressions])
+ model_ct.int_prod.exprs.extend([
+ self.ParseLinearExpression(expr)
+ forexprinExpandGeneratorOrTuple(expressions)
+ ])model_ct.int_prod.target.CopyFrom(self.ParseLinearExpression(target))returnct
@@ -2489,11 +2573,13 @@ rather than for solving specific optimization problems.
defModelStats(self):"""Returns a string containing some model statistics."""
- returnpywrapsat.CpSatHelper.ModelStats(self.__model)
+ returnswig_helper.CpSatHelper.SerializedModelStats(
+ self.__model.SerializeToString())defValidate(self):"""Returns a string indicating that the model is invalid."""
- returnpywrapsat.CpSatHelper.ValidateModel(self.__model)
+ returnswig_helper.CpSatHelper.SerializedValidateModel(
+ self.__model.SerializeToString())defExportToFile(self,file):"""Write the model as a protocol buffer to 'file'.
@@ -2506,7 +2592,8 @@ rather than for solving specific optimization problems.
Returns: True if the model was correctly written. """
- returnpywrapsat.CpSatHelper.WriteModelToFile(self.__model,file)
+ returnswig_helper.CpSatHelper.SerializedWriteModelToFile(
+ self.__model.SerializeToString(),file)defAssertIsBooleanVariable(self,x):ifisinstance(x,IntVar):
@@ -2541,6 +2628,16 @@ rather than for solving specific optimization problems.
self.__model.ClearField('assumptions')
+defExpandGeneratorOrTuple(args):
+ ifhasattr(args,'__len__'):# Tuple
+ iflen(args)!=1:
+ returnargs
+ ifcmh.is_a_number(args[0])orisinstance(args[0],LinearExpr):
+ returnargs
+ # Generator
+ returnargs[0]
+
+
defEvaluateLinearExpr(expression,solution):"""Evaluate a linear expression against a solution."""ifcmh.is_integral(expression):
@@ -2564,7 +2661,7 @@ rather than for solving specific optimization problems.
foreinexpr.Expressions():to_process.append((e,coeff))value+=expr.Constant()*coeff
- elifisinstance(expr,_ScalProd):
+ elifisinstance(expr,_WeightedSum):fore,cinzip(expr.Expressions(),expr.Coefficients()):to_process.append((e,coeff*c))value+=expr.Constant()*coeff
@@ -2609,22 +2706,25 @@ rather than for solving specific optimization problems.
self.__solution:cp_model_pb2.CpSolverResponse=Noneself.parameters=sat_parameters_pb2.SatParameters()self.log_callback=None
- self.__solve_wrapper:pywrapsat.SolveWrapper=None
+ self.__solve_wrapper:swig_helper.SolveWrapper=Noneself.__lock=threading.Lock()defSolve(self,model,solution_callback=None):"""Solves a problem and passes each solution to the callback if not null."""withself.__lock:
- solve_wrapper=pywrapsat.SolveWrapper()
+ solve_wrapper=swig_helper.SolveWrapper()
- solve_wrapper.SetParameters(self.parameters)
+ swig_helper.SolveWrapper.SetSerializedParameters(
+ self.parameters.SerializeToString(),solve_wrapper)ifsolution_callbackisnotNone:solve_wrapper.AddSolutionCallback(solution_callback)ifself.log_callbackisnotNone:solve_wrapper.AddLogCallback(self.log_callback)
- self.__solution=solve_wrapper.Solve(model.Proto())
+ self.__solution=cp_model_pb2.CpSolverResponse.FromString(
+ swig_helper.SolveWrapper.SerializedSolve(
+ model.Proto().SerializeToString(),solve_wrapper))ifsolution_callbackisnotNone:solve_wrapper.ClearSolutionCallback(solution_callback)
@@ -2732,7 +2832,8 @@ rather than for solving specific optimization problems.
defResponseStats(self):"""Returns some statistics on the solution found as a string."""
- returnpywrapsat.CpSatHelper.SolverResponseStats(self.__solution)
+ returnswig_helper.CpSatHelper.SerializedSolverResponseStats(
+ self.__solution.SerializeToString())defResponseProto(self):"""Returns the response object."""
@@ -2751,7 +2852,7 @@ rather than for solving specific optimization problems.
returnself.__solution.solution_info
-classCpSolverSolutionCallback(pywrapsat.SolutionCallback):
+classCpSolverSolutionCallback(swig_helper.SolutionCallback):"""Solution callback. This class implements a callback that will be called at each new solution
@@ -2776,7 +2877,7 @@ rather than for solving specific optimization problems.
"""def__init__(self):
- pywrapsat.SolutionCallback.__init__(self)
+ swig_helper.SolutionCallback.__init__(self)defOnSolutionCallback(self):"""Proxy for the same method in snake case."""
@@ -2836,7 +2937,7 @@ rather than for solving specific optimization problems.
foreinexpr.Expressions():to_process.append((e,coeff))value+=expr.Constant()*coeff
- elifisinstance(expr,_ScalProd):
+ elifisinstance(expr,_WeightedSum):fore,cinzip(expr.Expressions(),expr.Coefficients()):to_process.append((e,coeff*c))value+=expr.Constant()*coeff
@@ -2851,6 +2952,11 @@ rather than for solving specific optimization problems.
returnvalue
+ defResponse(self):
+ """Returns the current solution response."""
+ returncp_model_pb2.CpSolverResponse.FromString(
+ swig_helper.SolutionCallback.SerializedResponse(self))
+
classObjectiveSolutionPrinter(CpSolverSolutionCallback):"""Display the objective value and time of intermediate solutions."""
@@ -2933,9 +3039,9 @@ rather than for solving specific optimization problems.
DisplayBounds(bounds):
-
+ View Source
-
defDisplayBounds(bounds):
+
defDisplayBounds(bounds):"""Displays a flattened list of intervals."""out=''foriinrange(0,len(bounds),2):
@@ -2963,9 +3069,9 @@ rather than for solving specific optimization problems.
ShortName(model, i):
-
+ View Source
-
defShortName(model,i):
+
defShortName(model,i):"""Returns a short name of an integer variable, or its negation."""ifi<0:return'Not(%s)'%ShortName(model,-i-1)
@@ -2993,9 +3099,9 @@ rather than for solving specific optimization problems.
ShortExprName(model, e):
-
+ View Source
-
defShortExprName(model,e):
+
defShortExprName(model,e):"""Pretty-print LinearExpressionProto instances."""ifnote.vars:returnstr(e.offset)
@@ -3034,9 +3140,9 @@ rather than for solving specific optimization problems.
LinearExpr:
-
+ View Source
-
classLinearExpr(object):
+
classLinearExpr(object):"""Holds an integer linear expression. A linear expression is built from integer constants and variables.
@@ -3064,7 +3170,7 @@ rather than for solving specific optimization problems.
``` model.Minimize(cp_model.LinearExpr.Sum(expressions))
- model.Add(cp_model.LinearExpr.ScalProd(expressions, coefficients) >= 0)
+ model.Add(cp_model.LinearExpr.WeightedSum(expressions, coefficients) >= 0) ``` """
@@ -3076,14 +3182,14 @@ rather than for solving specific optimization problems.
return_SumArray(expressions)@classmethod
- defScalProd(cls,expressions,coefficients):
+ defWeightedSum(cls,expressions,coefficients):"""Creates the expression sum(expressions[i] * coefficients[i])."""ifLinearExpr.IsEmptyOrAllNull(coefficients):return0eliflen(expressions)==1:returnexpressions[0]*coefficients[0]else:
- return_ScalProd(expressions,coefficients)
+ return_WeightedSum(expressions,coefficients)@classmethoddefTerm(cls,expression,coefficient):
@@ -3121,7 +3227,7 @@ rather than for solving specific optimization problems.
ifall_ones:return_SumArray(variables,offset)else:
- return_ScalProd(variables,coeffs,offset)
+ return_WeightedSum(variables,coeffs,offset)defGetIntegerVarValueMap(self):"""Scans the expression, and returns (var_coef_map, constant)."""
@@ -3142,7 +3248,7 @@ rather than for solving specific optimization problems.
foreinexpr.Expressions():to_process.append((e,coeff))constant+=expr.Constant()*coeff
- elifisinstance(expr,_ScalProd):
+ elifisinstance(expr,_WeightedSum):fore,cinzip(expr.Expressions(),expr.Coefficients()):to_process.append((e,coeff*c))constant+=expr.Constant()*coeff
@@ -3177,7 +3283,7 @@ rather than for solving specific optimization problems.
foreinexpr.Expressions():to_process.append((e,coeff))constant+=expr.Constant()*coeff
- elifisinstance(expr,_ScalProd):
+ elifisinstance(expr,_WeightedSum):fore,cinzip(expr.Expressions(),expr.Coefficients()):to_process.append((e,coeff*c))constant+=expr.Constant()*coeff
@@ -3384,7 +3490,7 @@ linear expressions or coefficients as follows:
classIntVar(LinearExpr):"""An integer variable. An IntVar is an object that can take on any integer value within defined
@@ -3781,9 +3887,9 @@ model is feasible, or optimal if you provided an objective function.
IntVar(model, domain, name)
-
+ View Source
-
def__init__(self,model,domain,name):
+
def__init__(self,model,domain,name):"""See CpModel.NewIntVar below."""self.__model=modelself.__negation=None
@@ -3819,9 +3925,9 @@ model is feasible, or optimal if you provided an objective function.
Index(self):
-
+ View Source
-
defIndex(self):
+
defIndex(self):"""Returns the index of the variable in the model."""returnself.__index
@@ -3841,9 +3947,9 @@ model is feasible, or optimal if you provided an objective function.
Proto(self):
-
+ View Source
-
defProto(self):
+
defProto(self):"""Returns the variable protobuf."""returnself.__var
@@ -3863,9 +3969,9 @@ model is feasible, or optimal if you provided an objective function.
IsEqualTo(self, other):
-
+ View Source
-
defIsEqualTo(self,other):
+
defIsEqualTo(self,other):"""Returns true if self == other in the python sense."""ifnotisinstance(other,IntVar):returnFalse
@@ -3887,9 +3993,9 @@ model is feasible, or optimal if you provided an objective function.
Name(self):
-
+ View Source
-
defName(self):
+
defName(self):returnself.__var.name
@@ -3906,9 +4012,9 @@ model is feasible, or optimal if you provided an objective function.
Not(self):
-
+ View Source
-
defNot(self):
+
defNot(self):"""Returns the negation of a Boolean variable. This method implements the logical negation of a Boolean variable.
@@ -3943,7 +4049,7 @@ It is only valid if the variable has a Boolean domain (0 or 1).
@@ -3963,9 +4069,9 @@ It is only valid if the variable has a Boolean domain (0 or 1).
BoundedLinearExpression:
-
+ View Source
-
classBoundedLinearExpression(object):
+
classBoundedLinearExpression(object):"""Represents a linear constraint: `lb <= linear expression <= ub`. The only use of this class is to be added to the CpModel through
@@ -4048,9 +4154,9 @@ It is only valid if the variable has a Boolean domain (0 or 1).
BoundedLinearExpression(expr, bounds)
@@ -4068,9 +4174,9 @@ It is only valid if the variable has a Boolean domain (0 or 1).
Expression(self):
-
+ View Source
-
defExpression(self):
+
defExpression(self):returnself.__expr
@@ -4087,9 +4193,9 @@ It is only valid if the variable has a Boolean domain (0 or 1).
Bounds(self):
-
+ View Source
-
defBounds(self):
+
defBounds(self):returnself.__bounds
@@ -4108,9 +4214,9 @@ It is only valid if the variable has a Boolean domain (0 or 1).
Constraint:
-
+ View Source
-
classConstraint(object):
+
classConstraint(object):"""Base class for constraints. Constraints are built by the CpModel through the Add<XXX> methods.
@@ -4129,7 +4235,7 @@ It is only valid if the variable has a Boolean domain (0 or 1).
self.__index=len(constraints)self.__constraint=constraints.add()
- defOnlyEnforceIf(self,boolvar):
+ defOnlyEnforceIf(self,*boolvar):"""Adds an enforcement literal to the constraint. This method adds one or more literals (that is, a boolean variable or its
@@ -4141,23 +4247,18 @@ It is only valid if the variable has a Boolean domain (0 or 1).
BoolOr, BoolAnd, and linear constraints all support enforcement literals. Args:
- boolvar: A boolean literal or a list of boolean literals.
+ *boolvar: One or more Boolean literals. Returns: self. """
-
- ifcmh.is_integral(boolvar)andint(boolvar)==1:
- # Always true. Do nothing.
- pass
- elifisinstance(boolvar,list):
- forbinboolvar:
- ifcmh.is_integral(b)andint(b)==1:
- pass
- else:
- self.__constraint.enforcement_literal.append(b.Index())
- else:
- self.__constraint.enforcement_literal.append(boolvar.Index())
+ forlitinExpandGeneratorOrTuple(boolvar):
+ if(isinstance(lit,bool)and
+ bool(lit))or(cmh.is_integral(lit)andint(lit)==1):
+ # Always true. Do nothing.
+ pass
+ else:
+ self.__constraint.enforcement_literal.append(lit.Index())returnselfdefIndex(self):
@@ -4194,9 +4295,9 @@ model.Add(x + 2 * y == 5).OnlyEnforceIf(b.Not())
Constraint(constraints)
defOnlyEnforceIf(self,*boolvar):"""Adds an enforcement literal to the constraint. This method adds one or more literals (that is, a boolean variable or its
@@ -4228,23 +4329,18 @@ model.Add(x + 2 * y == 5).OnlyEnforceIf(b.Not())
BoolOr, BoolAnd, and linear constraints all support enforcement literals. Args:
- boolvar: A boolean literal or a list of boolean literals.
+ *boolvar: One or more Boolean literals. Returns: self. """
-
- ifcmh.is_integral(boolvar)andint(boolvar)==1:
- # Always true. Do nothing.
- pass
- elifisinstance(boolvar,list):
- forbinboolvar:
- ifcmh.is_integral(b)andint(b)==1:
- pass
- else:
- self.__constraint.enforcement_literal.append(b.Index())
- else:
- self.__constraint.enforcement_literal.append(boolvar.Index())
+ forlitinExpandGeneratorOrTuple(boolvar):
+ if(isinstance(lit,bool)and
+ bool(lit))or(cmh.is_integral(lit)andint(lit)==1):
+ # Always true. Do nothing.
+ pass
+ else:
+ self.__constraint.enforcement_literal.append(lit.Index())returnself
@@ -4263,7 +4359,7 @@ must be enforced. If it is false, then the constraint is ignored.
Args
-
boolvar: A boolean literal or a list of boolean literals.
+
*boolvar: One or more Boolean literals.
Returns
@@ -4283,9 +4379,9 @@ must be enforced. If it is false, then the constraint is ignored.
Index(self):
-
+ View Source
-
defIndex(self):
+
defIndex(self):"""Returns the index of the constraint in the model."""returnself.__index
@@ -4305,9 +4401,9 @@ must be enforced. If it is false, then the constraint is ignored.
Proto(self):
-
+ View Source
-
defProto(self):
+
defProto(self):"""Returns the constraint protobuf."""returnself.__constraint
@@ -4329,9 +4425,9 @@ must be enforced. If it is false, then the constraint is ignored.
IntervalVar:
-
+ View Source
-
classIntervalVar(object):
+
classIntervalVar(object):"""Represents an Interval variable. An interval variable is both a constraint and a variable. It is defined by
@@ -4441,9 +4537,9 @@ intervals into the schedule.
IntervalVar(model, start, size, end, is_present_index, name)
def__init__(self,model,start,size,end,is_present_index,name):self.__model=model# As with the IntVar::__init__ method, we hack the __init__ method to# support two use cases:
@@ -4481,9 +4577,9 @@ intervals into the schedule.
Index(self):
-
+ View Source
-
defIndex(self):
+
defIndex(self):"""Returns the index of the interval constraint in the model."""returnself.__index
@@ -4503,9 +4599,9 @@ intervals into the schedule.
Proto(self):
-
+ View Source
-
defProto(self):
+
defProto(self):"""Returns the interval protobuf."""returnself.__ct.interval
@@ -4525,9 +4621,9 @@ intervals into the schedule.
Name(self):
-
+ View Source
-
defName(self):
+
defName(self):returnself.__ct.name
@@ -4544,9 +4640,9 @@ intervals into the schedule.
StartExpr(self):
@@ -4605,9 +4701,9 @@ intervals into the schedule.
ObjectIsATrueLiteral(literal):
-
+ View Source
-
defObjectIsATrueLiteral(literal):
+
defObjectIsATrueLiteral(literal):"""Checks if literal is either True, or a Boolean literals fixed to True."""ifisinstance(literal,IntVar):proto=literal.Proto()
@@ -4637,9 +4733,9 @@ intervals into the schedule.
ObjectIsAFalseLiteral(literal):
-
+ View Source
-
defObjectIsAFalseLiteral(literal):
+
defObjectIsAFalseLiteral(literal):"""Checks if literal is either False, or a Boolean literals fixed to False."""ifisinstance(literal,IntVar):proto=literal.Proto()
@@ -4670,9 +4766,9 @@ intervals into the schedule.
CpModel:
-
+ View Source
-
classCpModel(object):
+
classCpModel(object):"""Methods for building a CP model. Methods beginning with:
@@ -4783,21 +4879,22 @@ intervals into the schedule.
# General Integer Constraints.
- defAddAllDifferent(self,expressions):
+ defAddAllDifferent(self,*expressions):"""Adds AllDifferent(expressions). This constraint forces all expressions to have different values. Args:
- expressions: a list of integer affine expressions.
+ *expressions: simple expressions of the form a * var + constant. Returns: An instance of the `Constraint` class. """ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
+ expanded=ExpandGeneratorOrTuple(expressions)model_ct.all_diff.exprs.extend(
- [self.ParseLinearExpression(x)forxinexpressions])
+ [self.ParseLinearExpression(x)forxinexpanded])returnctdefAddElement(self,index,variables,target):
@@ -4852,6 +4949,44 @@ intervals into the schedule.
model_ct.circuit.literals.append(lit)returnct
+ defAddMultipleCircuit(self,arcs):
+ """Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+ The direct graph where arc #i (from tails[i] to head[i]) is present iff
+ literals[i] is true must satisfy this set of properties:
+ - #incoming arcs == 1 except for node 0.
+ - #outgoing arcs == 1 except for node 0.
+ - for node zero, #incoming arcs == #outgoing arcs.
+ - There are no duplicate arcs.
+ - Self-arcs are allowed except for node 0.
+ - There is no cycle in this graph, except through node 0.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError(
+ 'AddMultipleCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.routes.tails.append(tail)
+ model_ct.routes.heads.append(head)
+ model_ct.routes.literals.append(lit)
+ returnct
+
defAddAllowedAssignments(self,variables,tuples_list):"""Adds AllowedAssignments(variables, tuples_list).
@@ -5181,42 +5316,72 @@ intervals into the schedule.
model_ct.enforcement_literal.append(self.GetOrMakeBooleanIndex(a))returnct
- defAddBoolOr(self,literals):
- """Adds `Or(literals) == true`."""
+ defAddBoolOr(self,*literals):
+ """Adds `Or(literals) == true`: Sum(literals) >= 1."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.bool_or.literals.extend(
- [self.GetOrMakeBooleanIndex(x)forxinliterals])
+ model_ct.bool_or.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])returnct
- defAddBoolAnd(self,literals):
+ defAddAtLeastOne(self,*literals):
+ """Same as `AddBoolOr`: `Sum(literals) >= 1`."""
+ returnself.AddBoolOr(*literals)
+
+ defAddAtMostOne(self,*literals):
+ """Adds `AtMostOne(literals)`: `Sum(literals) <= 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.at_most_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddExactlyOne(self,*literals):
+ """Adds `ExactlyOne(literals)`: `Sum(literals) == 1`."""
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ model_ct.exactly_one.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])
+ returnct
+
+ defAddBoolAnd(self,*literals):"""Adds `And(literals) == true`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.bool_and.literals.extend(
- [self.GetOrMakeBooleanIndex(x)forxinliterals])
+ model_ct.bool_and.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])returnct
- defAddBoolXOr(self,literals):
+ defAddBoolXOr(self,*literals):"""Adds `XOr(literals) == true`. In contrast to AddBoolOr and AddBoolAnd, it does not support .OnlyEnforceIf(). Args:
- literals: the list of literals in the constraint.
+ *literals: the list of literals in the constraint. Returns: An `Constraint` object. """ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.bool_xor.literals.extend(
- [self.GetOrMakeBooleanIndex(x)forxinliterals])
+ model_ct.bool_xor.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])returnctdefAddMinEquality(self,target,exprs):
- """Adds `target == Min(variables)`."""
+ """Adds `target == Min(exprs)`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]model_ct.lin_max.exprs.extend(
@@ -5226,7 +5391,7 @@ intervals into the schedule.
returnctdefAddMaxEquality(self,target,exprs):
- """Adds `target == Max(variables)`."""
+ """Adds `target == Max(exprs)`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]model_ct.lin_max.exprs.extend(
@@ -5261,12 +5426,14 @@ intervals into the schedule.
model_ct.int_mod.target.CopyFrom(self.ParseLinearExpression(target))returnct
- defAddMultiplicationEquality(self,target,expressions):
- """Adds `target == variables[0] * .. * variables[n]`."""
+ defAddMultiplicationEquality(self,target,*expressions):
+ """Adds `target == expressions[0] * .. * expressions[n]`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.int_prod.exprs.extend(
- [self.ParseLinearExpression(expr)forexprinexpressions])
+ model_ct.int_prod.exprs.extend([
+ self.ParseLinearExpression(expr)
+ forexprinExpandGeneratorOrTuple(expressions)
+ ])model_ct.int_prod.target.CopyFrom(self.ParseLinearExpression(target))returnct
@@ -5680,11 +5847,13 @@ intervals into the schedule.
defModelStats(self):"""Returns a string containing some model statistics."""
- returnpywrapsat.CpSatHelper.ModelStats(self.__model)
+ returnswig_helper.CpSatHelper.SerializedModelStats(
+ self.__model.SerializeToString())defValidate(self):"""Returns a string indicating that the model is invalid."""
- returnpywrapsat.CpSatHelper.ValidateModel(self.__model)
+ returnswig_helper.CpSatHelper.SerializedValidateModel(
+ self.__model.SerializeToString())defExportToFile(self,file):"""Write the model as a protocol buffer to 'file'.
@@ -5697,7 +5866,8 @@ intervals into the schedule.
Returns: True if the model was correctly written. """
- returnpywrapsat.CpSatHelper.WriteModelToFile(self.__model,file)
+ returnswig_helper.CpSatHelper.SerializedWriteModelToFile(
+ self.__model.SerializeToString(),file)defAssertIsBooleanVariable(self,x):ifisinstance(x,IntVar):
@@ -5752,9 +5922,9 @@ intervals into the schedule.
CpModel()
@@ -5772,9 +5942,9 @@ intervals into the schedule.
NewIntVar(self, lb, ub, name):
-
+ View Source
-
defNewIntVar(self,lb,ub,name):
+
defNewIntVar(self,lb,ub,name):"""Create an integer variable with domain [lb, ub]. The CP-SAT solver is limited to integer variables. If you have fractional
@@ -5826,9 +5996,9 @@ encode them as integers.
NewIntVarFromDomain(self, domain, name):
-
+ View Source
-
defNewIntVarFromDomain(self,domain,name):
+
defNewIntVarFromDomain(self,domain,name):"""Create an integer variable from a domain. A domain is a set of integers specified by a collection of intervals.
@@ -5877,9 +6047,9 @@ For example, model.NewIntVarFromDomain(cp_model.
NewBoolVar(self, name):
-
+ View Source
-
defNewBoolVar(self,name):
+
defNewBoolVar(self,name):"""Creates a 0-1 variable with the given name."""returnIntVar(self.__model,Domain(0,1),name)
@@ -5899,9 +6069,9 @@ For example, model.NewIntVarFromDomain(cp_model.
NewConstant(self, value):
-
+ View Source
-
defNewConstant(self,value):
+
defNewConstant(self,value):"""Declares a constant integer."""returnIntVar(self.__model,self.GetOrMakeIndexFromConstant(value),None)
@@ -5922,9 +6092,9 @@ For example, model.NewIntVarFromDomain(cp_model.
AddLinearConstraint(self, linear_expr, lb, ub):
-
+ View Source
-
defAddLinearConstraint(self,linear_expr,lb,ub):
+
defAddLinearConstraint(self,linear_expr,lb,ub):"""Adds the constraint: `lb <= linear_expr <= ub`."""returnself.AddLinearExpressionInDomain(linear_expr,Domain(lb,ub))
@@ -5944,9 +6114,9 @@ For example, model.NewIntVarFromDomain(cp_model.
AddLinearExpressionInDomain(self, linear_expr, domain):
defAddLinearExpressionInDomain(self,linear_expr,domain):"""Adds the constraint: `linear_expr` in `domain`."""ifisinstance(linear_expr,LinearExpr):ct=Constraint(self.__model.constraints)
@@ -5988,9 +6158,9 @@ For example, model.NewIntVarFromDomain(cp_model.
Add(self, ct):
-
+ View Source
-
defAdd(self,ct):
+
defAdd(self,ct):"""Adds a `BoundedLinearExpression` to the model. Args:
@@ -6017,7 +6187,7 @@ For example, model.NewIntVarFromDomain(cp_model.
@@ -6034,26 +6204,27 @@ For example, model.NewIntVarFromDomain(cp_model.
def
- AddAllDifferent(self, expressions):
+ AddAllDifferent(self, *expressions):
-
+ View Source
-
defAddAllDifferent(self,expressions):
+
defAddAllDifferent(self,*expressions):"""Adds AllDifferent(expressions). This constraint forces all expressions to have different values. Args:
- expressions: a list of integer affine expressions.
+ *expressions: simple expressions of the form a * var + constant. Returns: An instance of the `Constraint` class. """ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
+ expanded=ExpandGeneratorOrTuple(expressions)model_ct.all_diff.exprs.extend(
- [self.ParseLinearExpression(x)forxinexpressions])
+ [self.ParseLinearExpression(x)forxinexpanded])returnct
@@ -6066,7 +6237,7 @@ For example, model.NewIntVarFromDomain(cp_model.
Args
-
expressions: a list of integer affine expressions.
+
*expressions: simple expressions of the form a * var + constant.
Returns
@@ -6086,9 +6257,9 @@ For example, model.NewIntVarFromDomain(cp_model.
AddElement(self, index, variables, target):
-
+ View Source
-
defAddElement(self,index,variables,target):
+
defAddElement(self,index,variables,target):"""Adds the element constraint: `variables[index] == target`."""ifnotvariables:
@@ -6121,9 +6292,9 @@ For example, model.NewIntVarFromDomain(cp_model.
AddCircuit(self, arcs):
-
+ View Source
-
defAddCircuit(self,arcs):
+
defAddCircuit(self,arcs):"""Adds Circuit(arcs). Adds a circuit constraint from a sparse list of arcs that encode the graph.
@@ -6187,6 +6358,95 @@ number of nodes - 1.
defAddMultipleCircuit(self,arcs):
+ """Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+ The direct graph where arc #i (from tails[i] to head[i]) is present iff
+ literals[i] is true must satisfy this set of properties:
+ - #incoming arcs == 1 except for node 0.
+ - #outgoing arcs == 1 except for node 0.
+ - for node zero, #incoming arcs == #outgoing arcs.
+ - There are no duplicate arcs.
+ - Self-arcs are allowed except for node 0.
+ - There is no cycle in this graph, except through node 0.
+
+ Args:
+ arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+ literal). The arc is selected in the circuit if the literal is true.
+ Both source_node and destination_node must be integers between 0 and the
+ number of nodes - 1.
+
+ Returns:
+ An instance of the `Constraint` class.
+
+ Raises:
+ ValueError: If the list of arcs is empty.
+ """
+ ifnotarcs:
+ raiseValueError(
+ 'AddMultipleCircuit expects a non-empty array of arcs')
+ ct=Constraint(self.__model.constraints)
+ model_ct=self.__model.constraints[ct.Index()]
+ forarcinarcs:
+ tail=cmh.assert_is_int32(arc[0])
+ head=cmh.assert_is_int32(arc[1])
+ lit=self.GetOrMakeBooleanIndex(arc[2])
+ model_ct.routes.tails.append(tail)
+ model_ct.routes.heads.append(head)
+ model_ct.routes.literals.append(lit)
+ returnct
+
+
+
+
+
Adds a multiple circuit constraint, aka the "VRP" constraint.
+
+
The direct graph where arc #i (from tails[i] to head[i]) is present iff
+literals[i] is true must satisfy this set of properties:
+
+
+
#incoming arcs == 1 except for node 0.
+
#outgoing arcs == 1 except for node 0.
+
for node zero, #incoming arcs == #outgoing arcs.
+
There are no duplicate arcs.
+
Self-arcs are allowed except for node 0.
+
There is no cycle in this graph, except through node 0.
+
+
+
Args
+
+
+
arcs: a list of arcs. An arc is a tuple (source_node, destination_node,
+literal). The arc is selected in the circuit if the literal is true.
+Both source_node and destination_node must be integers between 0 and the
+number of nodes - 1.
defAddAllowedAssignments(self,variables,tuples_list):"""Adds AllowedAssignments(variables, tuples_list). An AllowedAssignments constraint is a constraint on an array of variables,
@@ -6287,9 +6547,9 @@ variables.
AddForbiddenAssignments(self, variables, tuples_list):
defAddForbiddenAssignments(self,variables,tuples_list):"""Adds AddForbiddenAssignments(variables, [tuples_list]). A ForbiddenAssignments constraint is a constraint on an array of variables
@@ -6368,9 +6628,9 @@ variables.
):
defAddInverse(self,variables,inverse_variables):"""Adds Inverse(variables, inverse_variables). An inverse constraint enforces that if `variables[i]` is assigned a value
@@ -6579,9 +6839,9 @@ if they are empty.
AddReservoirConstraint(self, times, level_changes, min_level, max_level):
defAddReservoirConstraintWithActive(self,times,level_changes,actives,min_level,max_level):"""Adds Reservoir(times, level_changes, actives, min_level, max_level).
@@ -6824,9 +7084,9 @@ than the max level.
AddMapDomain(self, var, bool_var_array, offset=0):
defAddMapDomain(self,var,bool_var_array,offset=0):"""Adds `var == i + offset <=> bool_var_array[i] == true for all i`."""fori,bool_varinenumerate(bool_var_array):
@@ -6863,9 +7123,9 @@ than the max level.
AddImplication(self, a, b):
-
+ View Source
-
defAddImplication(self,a,b):
+
defAddImplication(self,a,b):"""Adds `a => b` (`a` implies `b`)."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
@@ -6886,23 +7146,103 @@ than the max level.
def
- AddBoolOr(self, literals):
+ AddBoolOr(self, *literals):
@@ -6938,27 +7280,29 @@ than the max level.
def
- AddBoolXOr(self, literals):
+ AddBoolXOr(self, *literals):
-
+ View Source
-
defAddBoolXOr(self,literals):
+
defAddBoolXOr(self,*literals):"""Adds `XOr(literals) == true`. In contrast to AddBoolOr and AddBoolAnd, it does not support .OnlyEnforceIf(). Args:
- literals: the list of literals in the constraint.
+ *literals: the list of literals in the constraint. Returns: An `Constraint` object. """ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
- model_ct.bool_xor.literals.extend(
- [self.GetOrMakeBooleanIndex(x)forxinliterals])
+ model_ct.bool_xor.literals.extend([
+ self.GetOrMakeBooleanIndex(x)
+ forxinExpandGeneratorOrTuple(literals)
+ ])returnct
@@ -6972,7 +7316,7 @@ than the max level.
Args
-
literals: the list of literals in the constraint.
+
*literals: the list of literals in the constraint.
Returns
@@ -6992,10 +7336,10 @@ than the max level.
AddMinEquality(self, target, exprs):
defAddMinEquality(self,target,exprs):
+ """Adds `target == Min(exprs)`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]model_ct.lin_max.exprs.extend(
@@ -7007,7 +7351,7 @@ than the max level.
-
Adds target == Min(variables).
+
Adds target == Min(exprs).
@@ -7020,10 +7364,10 @@ than the max level.
AddMaxEquality(self, target, exprs):
defAddMaxEquality(self,target,exprs):
+ """Adds `target == Max(exprs)`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]model_ct.lin_max.exprs.extend(
@@ -7034,7 +7378,7 @@ than the max level.
-
Adds target == Max(variables).
+
Adds target == Max(exprs).
@@ -7047,9 +7391,9 @@ than the max level.
AddDivisionEquality(self, target, num, denom):
-
+ View Source
-
defAddDivisionEquality(self,target,num,denom):
+
defAddDivisionEquality(self,target,num,denom):"""Adds `target == num // denom` (integer division rounded towards 0)."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
@@ -7074,9 +7418,9 @@ than the max level.
AddAbsEquality(self, target, expr):
-
+ View Source
-
defAddAbsEquality(self,target,expr):
+
defAddAbsEquality(self,target,expr):"""Adds `target == Abs(var)`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
@@ -7101,9 +7445,9 @@ than the max level.
AddModuloEquality(self, target, var, mod):
-
+ View Source
-
defAddModuloEquality(self,target,var,mod):
+
defAddModuloEquality(self,target,var,mod):"""Adds `target = var % mod`."""ct=Constraint(self.__model.constraints)model_ct=self.__model.constraints[ct.Index()]
@@ -7125,24 +7469,26 @@ than the max level.
def
- AddMultiplicationEquality(self, target, expressions):
+ AddMultiplicationEquality(self, target, *expressions):
@@ -7155,9 +7501,9 @@ than the max level.
NewIntervalVar(self, start, size, end, name):
-
+ View Source
-
defNewIntervalVar(self,start,size,end,name):
+
defNewIntervalVar(self,start,size,end,name):"""Creates an interval variable from start, size, and end. An interval variable is a constraint, that is itself used in other
@@ -7232,9 +7578,9 @@ expression.
NewFixedSizeIntervalVar(self, start, size, name):
defNewFixedSizeIntervalVar(self,start,size,name):"""Creates an interval variable from start, and a fixed size. An interval variable is a constraint, that is itself used in other
@@ -7293,9 +7639,9 @@ expression.
NewOptionalIntervalVar(self, start, size, end, is_present, name):
defNewOptionalIntervalVar(self,start,size,end,is_present,name):"""Creates an optional interval var from start, size, end, and is_present. An optional interval variable is a constraint, that is itself used in other
@@ -7381,9 +7727,9 @@ inactive interval is simply ignored by all constraints.
NewOptionalFixedSizeIntervalVar(self, start, size, is_present, name):
defNewOptionalFixedSizeIntervalVar(self,start,size,is_present,name):"""Creates an interval variable from start, and a fixed size. An interval variable is a constraint, that is itself used in other
@@ -7447,9 +7793,9 @@ inactive interval is simply ignored by all constraints.
AddNoOverlap(self, interval_vars):
-
+ View Source
-
defAddNoOverlap(self,interval_vars):
+
defAddNoOverlap(self,interval_vars):"""Adds NoOverlap(interval_vars). A NoOverlap constraint ensures that all present intervals do not overlap
@@ -7498,9 +7844,9 @@ in time.
AddNoOverlap2D(self, x_intervals, y_intervals):
defAddNoOverlap2D(self,x_intervals,y_intervals):"""Adds NoOverlap2D(x_intervals, y_intervals). A NoOverlap2D constraint ensures that all present rectangles do not overlap
@@ -7561,9 +7907,9 @@ optional.
AddCumulative(self, intervals, demands, capacity):
defAddCumulative(self,intervals,demands,capacity):"""Adds Cumulative(intervals, demands, capacity). This constraint enforces that:
@@ -7634,9 +7980,9 @@ positive integer value or variable.
CopyFrom(self, other_model):
-
+ View Source
-
defCopyFrom(self,other_model):
+
defCopyFrom(self,other_model):"""Reset the model, and creates a new one from a CpModelProto instance."""self.__model.CopyFrom(other_model.Proto())
@@ -7662,9 +8008,9 @@ positive integer value or variable.
GetBoolVarFromProtoIndex(self, index):