Округление Non-LinearExpr с помощью SAT-решателя google or-tools

Используя CP-SAT Google or-tools, я пытаюсь напишите это ограничение:

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

Где q - простое целое число.

Дело в том, что мне нужно округлить правую часть уравнения (назовем ее expression) следующим образом:

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;
}

Поэтому мне нужно округлить выражение

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

Чтобы он получил одно из следующих значений:

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

Рассмотрим 2 случая:

Случай 1

q = 180 и expression = 176.

Хотя условие 180 >= 176 равно true, после округления от 176 до 200 проверяемое условие должно быть 180 >= 200, то есть false.

Итак, для q = 180 и expression = 176 я хотел бы, чтобы условие возвращало false.


Случай 2

q = 210 и expression = 218.

Хотя условие 210 >= 218 равно false, после округления 218 до 200 проверяемое условие должно быть 210 >= 200, то есть true.

Итак, для q = 210 и expression = 218 я хотел бы, чтобы условие возвращало true.


У меня есть отличный ответ здесь для решения этой проблемы за линейное выражение, но теперь мне нужно разрешить его для нелинейного выражения.

Какие-либо предложения?


person forhas    schedule 08.07.2020    source источник
comment
Переменные положительные?   -  person Laurent Perron    schedule 09.07.2020
comment
@LaurentPerron Да, переменные положительные   -  person forhas    schedule 09.07.2020
comment
Так что выражение всегда ‹= 15   -  person Laurent Perron    schedule 09.07.2020
comment
@LaurentPerron Я немного изменил данные, теперь я имею дело с полным выражением. Я написал более короткую версию раньше, чтобы попытаться сделать ее проще.   -  person forhas    schedule 09.07.2020


Ответы (2)


Перефразируем

у вас есть целочисленная переменная e со значением от 0 до 300. Вы хотите округлить ее до ближайшего кратного 50

если вы это сделаете:

(e div 50) * 50

вы получите максимальное кратное 50, меньшее или равное e

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

Чтобы округлить до ближайшего, вам нужно добавить 25 к e перед делением

((e + 25) div 50) * 50

Что сделает правильное округление

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

с правильным кодом Python CP-SAT or-tools:

numerator = model.NewIntVar(...)
model.Add(numerator == 50x + 100y + 150z + 200k + 250p + 300v)
denom = model.NewIntVar(...)
model.Add(denom == 50x + 100y + 150z + 200k + 250p + 300v)
e = model.NewIntVar(0, 300, 'e')
model.AddDivisionEquality(e, numerator, denom)

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)
person Laurent Perron    schedule 09.07.2020
comment
Спасибо. Теперь я понимаю идею добавления 25 к е перед делением. В вашем решении CP-SAT e означает выражение, которое мне нужно округлить (верно?). У меня проблемы с определением самого выражения, поскольку это нелинейное выражение. - person forhas; 12.07.2020
comment
Я добавил код для определения e. Я считаю, что можно использовать только одно деление. Мне нужно это записать. - person Laurent Perron; 28.07.2020

если a и b положительны, то

a div b >= q

эквивалентно

a >= q * b

теперь в вашем примере не указано, как округлять (ближайший или вниз)

если вы хотите округлить

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

Если вы хотите округлить до ближайшего, вам нужно добавить q / 2 в нужном месте

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

Теперь, если вы хотите другое направление

a div b <= q

эквивалентно

a <= q * b + q - 1

В остальном трансформация такая же.

person Laurent Perron    schedule 09.07.2020
comment
Мне нужно округлить выражение (50x + 100y + 150z + 200k + 250p + 300v) / (x + y + z + k + p + v). Я согласен с тем, что div b ›= q эквивалентен a› = q * b, но, учитывая мое ограничение округления, я не могу понять, как это мне помогает. Вы можете объяснить? - person forhas; 09.07.2020
comment
Первая строка: Я хочу написать это ограничение q ‹= (50x + 100y + 150z + 200k + 250p + 300v) / (x + y + z + k + p + v). Это именно то, что я сделал. - person Laurent Perron; 09.07.2020
comment
В любом случае, a = 50x + 100y + 150z + 200k + 250p + 300v, b = 50 * (x + y + z + k + p + v) + 25. c = a / b. ты хочешь с * 50 - person Laurent Perron; 09.07.2020
comment
Обратите внимание, что мой вопрос касается того, как написать это ограничение с помощью CP-SAT Google or-tools. Во-вторых, извините, но я не понимаю математику, почему вы умножили знаменатель на 50 и прибавили 25? - person forhas; 09.07.2020
comment
Я изменил направление знака, q ›= выражение. Ваше предложение - добавить к выражению q / 2? Посмотрите на второй пример в моем вопросе (случай 2), я считаю, что ваше предложение не решает его. - person forhas; 09.07.2020
comment
В своем ответе я добавил другое направление неравенства. - person Laurent Perron; 09.07.2020