From 9671190059ef16760089d6b0a2ef8230fe02f286 Mon Sep 17 00:00:00 2001 From: Jeremy Saklad Date: Sat, 16 Oct 2021 10:22:31 -0500 Subject: [PATCH] Add BoneMarketModel.AddDivisionApproximateExponentiationEquality This method combines two common operations, avoiding the need for intermediate variables at the call site. --- bonemarketsolver/objects/bone_market_model.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bonemarketsolver/objects/bone_market_model.py b/bonemarketsolver/objects/bone_market_model.py index fa115f3..cab48b1 100644 --- a/bonemarketsolver/objects/bone_market_model.py +++ b/bonemarketsolver/objects/bone_market_model.py @@ -22,6 +22,22 @@ Set `upto` to a value that is unlikely to come into play. Each parameter is interpreted as a BoundedLinearExpression, and a layer of indirection is applied such that each Constraint in the returned tuple can accept an enforcement literal.""" return self.AddAllowedAssignments((target, var), ((int(base**exp), base) for base in range(upto + 1))) + def AddDivisionApproximateExponentiationEquality(self, target, num, denom, exp, upto): + """Adds `target == (num // denom)**exp` using a lookup table. + +Set `upto` to a value that is unlikely to come into play. + +`target`, `num`, and `denom` are interpreted as a BoundedLinearExpression, and a layer of indirection is applied such that each Constraint in the returned tuple can accept an enforcement literal.""" + quotient = self.NewIntVar(f'{repr(target)} == ({repr(num)} // {repr(denom)})**{repr(exp)}: quotient') + intermediate_num, num_constraint = self.NewIntermediateIntVar(num, f'{repr(target)} == ({repr(num)} // {repr(denom)})**{repr(exp)}: num', lb = 0) + intermediate_denom, denom_constraint = self.NewIntermediateIntVar(denom, f'{repr(target)} == ({repr(num)} // {repr(denom)})**{repr(exp)}: denom', lb = 1) + intermediate_target, target_constraint = self.NewIntermediateIntVar(target, f'{repr(target)} == ({repr(num)} // {repr(denom)})**{repr(exp)}: target') + + super().AddDivisionEquality(quotient, intermediate_num, intermediate_denom) + super().AddAllowedAssignments((intermediate_target, quotient), ((int(base**exp), base) for base in range(upto + 1))) + + return (num_constraint, denom_constraint, target_constraint) + def AddDivisionEquality(self, target, num, denom): """Adds `target == num // denom` (integer division rounded towards 0).