Originally posted by: SystemAdmin
You are facing numerical problems. Internally CPLEX uses double precision floating point numbers to represent all values, even integral values. When you export your model to an LP file and solve it explicitly with the interactive optimizer you get something like this:
Variable Name Solution Value y(
{1,2
}) 0.000010 y(
{1,3
}) 0.000000 y(
{1,5
}) 0.999998 y(
{2,4
}) 0.000002 y(
{3,4
}) 1.000000 y(
{5,6
}) 0.000002 x(
{1,2
}) -9.800000 x(
{1,3
}) -0.200000 x(
{1,5
}) 10.000000 x(
{2,4
}) 2.200000 x(
{3,4
}) 2.800000 x(
{5,6
}) -2.400000
As you can see, the boolean variable 'y({1,2})' has value 1e-5 which is close to zero. By default, CPLEX considers values for integer variables as integer if their absolute value does not exceed 1e-5. So what you have here is y({1,2}) = 1e-5, so CPLEX considers this as integral 0. On the other hand you have x({1,2}) = -9.8 and -9.8 >= 1e-5 * M, so the constraint is satisfied. As you can see, the problem is numerical roundoff, i.e., the fact that y({1,2}) is considered as 0 but is not quite 0. There are two ways to work around this problem:
1. Change CPLEX's integrality tolerance from 1e-5 to something smaller. This can be changed in a settings file by changing "Mathematical Programming"->"Mixed Integer Programming"->"Tolerances"->"Integrality Tolerance". Setting this to 1e-9 gave consistent results for me.
2. Use indicator constraints. Instead of defining your own 'M' you can rewrite the constraint
sum(s in I[i]) x[s] - sum(s in J[i]) x[s] == D[i]; forall (s in S)
{ x[s] <= M * y[s]; x[s] >= - M * y[s];
}
to read
sum(s in I[i]) x[s] - sum(s in J[i]) x[s] == D[i]; forall (s in S)
{ y[s] == 0 => x[s] == 0;
}
This uses the "implication" logical constraint (see
here) and says "if y is 0 then x must also be 0". This does not use an explicit big M in the formulation and is less likely to suffer from numerical issues.
#DecisionOptimization#OPLusingCPLEXOptimizer