Rounding Non-LinearExpr with google or-tools SAT solver

与世无争的帅哥 提交于 2020-07-10 10:27:07

问题


Using CP-SAT of google or-tools I'm trying to write this constraint:

q >= (50x + 100y + 150z + 200k + 250p + 300v) / (x + y + z + k + p + v)

Where q is a simple integer.

The thing is I need to round the right side of the equation (let's call it expression) as follows:

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 I need to round the expression

(50x + 100y + 150z + 200k + 250p + 300v) / (x + y + z + k + p + v)

So that it gets one of the following values:

{50, 100, 150, 200, 250, 300}

Let's review 2 cases:

Case 1

q = 180 and expression = 176.

Although the condition 180 >= 176 is true, after rounding up 176 to 200 the tested condition should be 180 >= 200 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 210 >= 218 is false, after rounding down 218 to 200 the tested condition should be 210 >= 200 which is true.

So for q = 210 and expression = 218 I would like the condition to return true.


I got a great answer here for resolving this challenge over a linear expression but now I need to resolve it for a non-linear expression.

Any suggestions?


回答1:


Let's rephrase

you have an integer variable e with a value between 0 and 300. You want to round it to the nearest multiple of 50

if you do:

(e div 50) * 50

you will get the max multiple of 50 less or equal to e

(70 / 50) * 50 -> 50
(99 / 50) * 50 -> 50
(102 / 50) * 50 -> 100

To get a round to nearest, you need to add 25 to e before the division

((e + 25) div 50) * 50

Which will do the correct rounding

((70 + 25) / 50) * 50 -> 50
((99 + 25) / 50) * 50 -> 100
((102 + 25) / 50) * 50 -> 100

with the correct or-tools CP-SAT python code:

shifted_e = model.NewIntVar(25, 325, 'shifted_e')
model.Add(shifted_e == e + 25)
multiple_of_fifty = model.NewIntVar(0, 6, 'multiple_of_fifty')
model.AddDivisionEquality(multiple_of_fifty, shifted_e, 50)
result = model.NewIntVar(0, 300, 'result')
model.Add(result = multiple_of_fifty * 50)



回答2:


if a and b are positive then

a div b >= q

is equivalent to

a >= q * b

now, your example does not specify how to round (nearest or down)

if you want to round down

q * (x + y + z + k + p + v) <= (50x + 100y + 150z + 200k + 250p + 300v)

If you want to round to nearest, you need to add q / 2 in the right place

 q * (x + y + z + k + p + v) <= (50x + 100y + 150z + 200k + 250p + 300v + q / 2)

Now, if you want the other direction

a div b <= q

is equivalent to

a <= q * b + q - 1

The rest of the transformation is the same.



来源:https://stackoverflow.com/questions/62804600/rounding-non-linearexpr-with-google-or-tools-sat-solver

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!