При использовании линейного решателя (например, CPLEX) обычный подход состоит в том, чтобы превратить это в линейное ограничение с двоичной переменной, указывающей, какой из двух случаев применим.
param eps;
param beta;
param bignum = 1e5;
var z_s_1 binary;
# will have value 0 when z_v <= eps, else 1
var z_s = z_s_1*beta;
var z_v >= 0;
s.t. Define_z_s_1_a: z_s_1 * eps <= z_v;
# so if z_v < eps then z_s_1 must be 0 and hence z_s = 0
s.t. Define_z_s_1_b: z_s_1 * bignum >= z_v - eps;
# so if z_v > eps, then z_s_1 must be > 0 so must be 1,
# and hence z_s = beta.
Пара соображений:
Если вы хотите быть математически точным, когда z_v
равно eps точно, z_s_1
может принимать любое значение, и, следовательно, z_s
может быть 0 или beta
. Но, учитывая ограничения компьютерной арифметики, нам обычно не нужно терять сон из-за строгого и нестрогого неравенства.
Это предотвратит решения с z_v > bignum+eps
, поэтому bignum
должно быть достаточно большим, чтобы допустимые значения z_v
. Однако, если вы сделаете его слишком большим, вы можете столкнуться с проблемами с машинной арифметикой. Например, рассмотрим следующий пример:
option solver cplex;
param bignum = 1e6;
var x binary;
minimize of: x;
s.t. c1: bignum*x >= 1;
solve;
display x;
Оценивая это вручную, поскольку x
является двоичным и bignum*x
> = 1, мы можем видеть, что x
должно быть 1. Однако, выполняя это через AMPL / CPLEX, я вместо этого получаю решение x=0
даже если это нарушает c1
.
Причина этого в том, что эти решатели обычно допускают небольшой допуск для «целочисленных» переменных. Следовательно, он принимает решение x=1e-10
как "достаточно близкое" к целому числу. Это удовлетворяет c1
с x*bignum >= 1
, но затем округляет x
до нуля. Это может сбить с толку, если вы этого не ожидаете! Итак, выясните, какое наименьшее значение для bignum
будет выполнять эту работу, основываясь на наибольшем вероятном значении для z_v
, и внимательно проверьте результаты. Возможно, вам придется повозиться с параметрами допуска.
AMPL также предлагает некоторую поддержку логических ограничений с CPLEX , но я менее знаком с ними, поэтому я не уверен, предлагают ли они альтернативное решение этой проблемы.