Avoid extraneous intermediate variables

Intermediate variables should not be necessary if the equivalent
expression is a constant or a variable with the same bounds.

This change reduces the total number of variables in the model.

The documentation of BoneMarketModel.NewIntermediateIntVar has been
tweaked to allow for any number of constraints.
This commit is contained in:
Jeremy Saklad 2022-01-02 17:28:58 -06:00
parent 40e34bb43c
commit 15317f6298
Signed by: Jeremy Saklad
GPG Key ID: 9CA2149583EDBF84
1 changed files with 12 additions and 4 deletions

View File

@ -99,18 +99,26 @@ Each parameter is interpreted as a BoundedLinearExpression, and a layer of indir
return intermediate
@singledispatchmethod
def NewIntermediateIntVar(self, expression: cp_model.LinearExpr, name: str, *, lb: Integral = cp_model.INT32_MIN, ub: Integral = cp_model.INT32_MAX) -> tuple[cp_model.IntVar, cp_model.Constraint]:
"""Creates an integer variable equivalent to the given expression and returns a tuple consisting of the variable and constraint for use with enforcement literals.
def NewIntermediateIntVar(self, expression: cp_model.LinearExpr, name: str, *, lb: Integral = cp_model.INT32_MIN, ub: Integral = cp_model.INT32_MAX) -> tuple:
"""Creates an integer variable equivalent to the given expression and returns a tuple consisting of the variable and constraints for use with enforcement literals.
`equality` must be either a LinearExp or a unary partialmethod that accepts a target integer variable and returns Constraints."""
intermediate: Final[cp_model.IntVar] = super().NewIntVar(lb, ub, name)
return (intermediate, self.Add(intermediate == expression))
# If expression is either an integer variable with the specified bounds or an integer constant, just pass it through
if isinstance(expression, cp_model.IntVar) and (lambda domain : domain == [lb, ub] or domain[0] == domain[1])(cp_model.IntVar.Proto(expression).domain):
return (expression, ())
else:
intermediate: Final[cp_model.IntVar] = super().NewIntVar(lb, ub, name)
return (intermediate, self.Add(intermediate == expression))
@NewIntermediateIntVar.register
def _(self, expression: partialmethod, name: str, *, lb: Integral = cp_model.INT32_MIN, ub: Integral = cp_model.INT32_MAX) -> tuple:
intermediate: Final[cp_model.IntVar] = super().NewIntVar(lb, ub, name)
return (intermediate, expression.__get__(self)(intermediate))
@NewIntermediateIntVar.register
def _(self, expression: Integral, *args, **kwargs) -> tuple:
return (self.NewConstant(expression), ())
def NewIntVar(self, name: str, *, lb: Integral = cp_model.INT32_MIN, ub: Integral = cp_model.INT32_MAX) -> cp_model.IntVar:
return super().NewIntVar(lb, ub, name)