2

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?

forhas
  • 11,551
  • 21
  • 77
  • 111
  • 1
    I guess you could create a boolean for each case, create another intvar and set that value based on that, there should be a better way though – Stradivari Jun 29 '20 at 21:44
  • @Stradivari I just updated the question with 2 examples. I'm not sure I'm getting you – forhas Jun 30 '20 at 05:42

1 Answers1

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])
Stradivari
  • 2,626
  • 1
  • 9
  • 21
  • Thanks for that, I was able to implement it. Do you happen to know how can I implement such a solution if the expression is non-linear? I asked it in a separated question: https://stackoverflow.com/questions/62804600/rounding-non-linearexpr-with-google-or-tools-sat-solver – forhas Jul 08 '20 at 22:29