问题
I'm creating a constraint (in Java) using or-tools SAT solver:
IntVar x, y, z;
IntVar[] variables = new IntVar{x, y, z};
int[] multiplier = new int{2, 3, 3};
LinearExpr expression = LinearExpr.scalProd(variables, multiplier); //2x + 3y + 3z
model.addLessThan(expression, q);
Where q
is some given integer.
The thing is that I need to round the expression result. Something like:
if(expression < 25) {
expression = 0;
} else if(expression < 75) {
expression = 50;
} else if(expression < 125) {
expression = 100;
} else if(expression < 175) {
expression = 150;
} else if(expression < 225) {
expression = 200;
} else if(expression < 275) {
expression = 250;
} else {
expression = 300;
}
So that the value of the expression
(which should be used in the addLessThan
constraint) is one of the following:
0, 50, 100, 150, 200, 250, 300
Let's review 2 cases:
Case 1
q = 180
and expression = 176
.
Although the condition 176 < 180
is true
, after rounding up 176 to 200 the tested condition should be 200 < 180
which is false
.
So for q = 180
and expression = 176
I would like the condition to return false
.
Case 2
q = 210
and expression = 218
.
Although the condition 218 < 210
is false
, after rounding down 218 to 200 the tested condition should be 200 < 210
which is true
.
So for q = 210
and expression = 218
I would like the condition to return true
.
How can I achieve that?
回答1:
To elaborate on my comment (code in Python):
roundedExpr = model.NewIntVarFromDomain(cp_model.Domain.FromValues([0, 50, 100, 150, 200, 250, 300]), "roundedExpr")
b1 = model.NewBoolVar("< 25")
model.Add(expression < 25).OnlyEnforceIf(b1)
model.Add(roundedExpr == 0).OnlyEnforceIf(b1)
...
b7 = model.NewBoolVar(">= 275")
model.Add(expression >= 275).OnlyEnforceIf(b7)
model.Add(roundedExpr == 300).OnlyEnforceIf(b7)
model.AddBoolOr([b1, b2, b3, ..., b7])
来源:https://stackoverflow.com/questions/62646674/rounding-linearexpr-with-google-or-tools-sat-solver