Linear Programming, max function (if statement) - linear-programming

I have a value x, which is a combination of decision variables.
I need to calculate a cost, which only triggers if x > 100. So cost = MAX(x - 100, 0) * 20.
Is there any way to do this in linear programming?
I've tried creating two binary variables (y1 & y2), in which y1 = 1 when x <= 100 & y2 = 1 when x > 100 & y1 + y2 = 1, from this website - https://uk.mathworks.com/matlabcentral/answers/693740-linear-programming-with-conditional-constraints. However, my excel solver is still giving non-linearity complaints...
Any advice on how I can fix this?

The objective
min cost = max(x-100,0)*20
can be implemented in an LP as:
min cost = y*20
y >= x - 100
x >= 0, y >= 0
There is no need for binary variables.

Related

lp_solve return uniform solution

Can lp_solve return a unifrom solution? (Is there a flag or something that will force this kinf of behavior?)
Say that I have this:
max: x + y + z + w;
x + y + z + w <= 100;
Results in:
Actual values of the variables:
x 100
y 0
z 0
w 0
However, I would like to have something like:
Actual values of the variables:
x 25
y 25
z 25
w 25
This is an oversimplyfied example, but the idea is that if the variables have the same factor in the objective function, then the result should idealy be more uniform and not everything for one, and the other what is left.
Is this possible to do? (I've tested other libs and some of them seem to do this by default like the solver on Excel or Gekko for Python).
EDIT:
For instance, Gekko has already this behavior without me especifing anything...
from gekko import GEKKO
m = GEKKO()
x1,x2,x3,x4 = [m.Var() for i in range(4)]
#upper bounds
x1.upper = 100
x2.upper = 100
x3.upper = 100
x4.upper = 100
# Constrain
m.Equation(x1 + x2 + x3 + x4 <= 100)
# Objective
m.Maximize(x1 + x2 + x3 + x4)
m.solve(disp=False)
print(x1.value, x2.value, x3.value, x4.value)
>> [24.999999909] [24.999999909] [24.999999909] [24.999999909]
You would need to explicitly model this (as another objective). A solver does nothing automatically: it just finds a solution that obeys the constraints and optimizes the objective function.
Also, note that many linear solvers will produce so-called basic solutions (corner points). So "all variables in the middle" does not come naturally at all.
The example in Gekko ended on [25,25,25,25] because of how the solver took a step towards the solution from an initial guess of [0,0,0,0] (default in Gekko). The problem is under-specified so there are an infinite number of feasible solutions. Changing the guess values gives a different solution.
from gekko import GEKKO
m = GEKKO()
x1,x2,x3,x4 = m.Array(m.Var,4,lb=0,ub=100)
x1.value=50 # change initial guess
m.Equation(x1 + x2 + x3 + x4 <= 100)
m.Maximize(x1 + x2 + x3 + x4)
m.solve(disp=False)
print(x1.value, x2.value, x3.value, x4.value)
Solution with guess values [50,0,0,0]
[3.1593723566] [32.280209196] [32.280209196] [32.280209196]
Here is one method with equality constraints m.Equations([x1==x2,x1==x3,x1==x4]) to modify the problem to guarantee a unique solution that can be used by any linear programming solver.
from gekko import GEKKO
m = GEKKO()
x1,x2,x3,x4 = m.Array(m.Var,4,lb=0,ub=100)
x1.value=50 # change initial guess
m.Equation(x1 + x2 + x3 + x4 <= 100)
m.Maximize(x1 + x2 + x3 + x4)
m.Equations([x1==x2,x1==x3,x1==x4])
m.solve(disp=False)
print(x1.value, x2.value, x3.value, x4.value)
This gives a solution:
[25.000000002] [25.000000002] [25.000000002] [25.000000002]
QP Solution
Switching to a QP solver allows a slight penalty for deviations but doesn't consume a degree of freedom.
from gekko import GEKKO
m = GEKKO()
x1,x2,x3,x4 = m.Array(m.Var,4,lb=0,ub=100)
x1.value=50 # change initial guess
m.Equation(x1 + x2 + x3 + x4 <= 100)
m.Maximize(x1 + x2 + x3 + x4)
penalty = 1e-5
m.Minimize(penalty*(x1-x2)**2)
m.Minimize(penalty*(x1-x3)**2)
m.Minimize(penalty*(x1-x4)**2)
m.solve(disp=False)
print(x1.value, x2.value, x3.value, x4.value)
Solution with QP penalty
[24.999998377] [25.000000544] [25.000000544] [25.000000544]

Reverse engineering - Is this a cheap 3D distance function?

I am reverse engineering a game from 1999 and I came across a function which looks to be checking if the player is within range of a 3d point for the triggering of audio sources. The decompiler mangles the code pretty bad but I think I understand it.
// Position Y delta
v1 = * (float * )(this + 16) - LocalPlayerZoneEntry - > y;
// Position X delta
v2 = * (float * )(this + 20) - LocalPlayerZoneEntry - > x;
// Absolute value
if (v1 < 0.0)
v1 = -v1;
// Absolute value
if (v2 < 0.0)
v2 = -v2;
// What is going on here?
if (v1 <= v2)
v1 = v1 * 0.5;
else
v2 = v2 * 0.5;
// Z position delta
v3 = * (float * )(this + 24) - LocalPlayerZoneEntry - > z;
// Absolute value
if (v3 < 0.0)
v3 = -v3;
result = v3 + v2 + v1;
// Radius
if (result > * (float * )(this + 28))
return 0.0;
return result;
Interestingly enough, when in game, it seemed like the triggering was pretty inconsistent and would sometimes be quite a bit off depending on from which side I approached the trigger.
Does anyone have any idea if this was a common algorithm used back in the day?
Note: The types were all added by me so they may be incorrect. I assume that this is a function of type bool.
The best way to visualize a distance function (a metric) is to plot its unit sphere (the set of points at unit distance from origin -- the metric in question is norm induced).
First rewrite it in a more mathematical form:
N(x,y,z) = 0.5*|x| + |y| + |z| when |x| <= |y|
= |x| + 0.5*|y| + |z| otherwise
Let's do that for 2d (assume that z = 0). The absolute values make the function symmetric in the four quadrants. The |x| <= |y| condition makes it symmetric in all the eight sectors. Let's focus on the sector x > 0, y > 0, x <= y. We want to find the curve when N(x,y,0) = 1. For that sector it reduces to 0.5x + y = 1, or y = 1 - 0.5x. We can go and plot that line. For when x > 0, y > 0, x > y, we get x = 1 - 0.5y. Plotting it all gives the following unit 'circle':
For comparison, here is an Euclidean unit circle overlaid:
In the third dimension it behaves like a taxicab metric, effectively giving you a 'diamond' shaped sphere:
So yes, it is a cheap distance function, though it lacks rotational symmetries.

How to write constraints to check whether a variable is bounded between two values

Does anyone know what is a good way to indicate whether a model variable is bounded between certain values? For example, indicator1 = 1 when 0<= variable x <=200 else 0, indicator2 = 1 when 200<= variable x <= 300.
One use case of this is to calculate weight dependent shipping cost, e.g. if the shipment weighs less than 200 lbs then it costs $z/lb; if the shipment weighs more than 200lb and less than 300 lbs then it costs $y/lb.
Minimize W1*z + W2*y
Weight = W1 + W2
0 <= W1 <= 200*X1
200*X2 <= W2 <= 300*X2
X1+ X2 = 1
X1, X2 binary
Weight, W1, W2 >= 0
Above is the formulation I came up with for this situation. However, now I have more than 200 buckets of values to check, so this formulation does not seem efficient enough. I am wondering whether there are better ways to model this?
This problem can also be modeled as a Generalized Disjunctive Program (GDP). It's more verbose, but more descriptive.
from pyomo.environ import *
from pyomo.gdp import *
m = ConcreteModel()
m.total_weight_cost = Var(domain=NonNegativeReals)
m.weight = Var(domain=NonNegativeReals)
m.weight_buckets = RangeSet(2)
m.weight_bucket_lb = Param(m.weight_buckets, initialize={1: 0, 2: 200})
m.weight_bucket_ub = Param(m.weight_buckets, initialize={1: 200, 2: 300})
m.weight_bucket_cost = Param(m.weight_buckets, initialize={1: z, 2: y})
m.weight_bucket_disjunction = Disjunction(expr=[
[m.total_weight_cost == m.weight_bucket_cost[bucket] * m.weight,
m.weight_bucket_lb[bucket] <= m.weight,
m.weight <= m.weight_bucket_ub[bucket]
for bucket in m.weight_buckets]
])
TransformationFactory('gdp.bigm').apply_to(m)
SolverFactory('gurobi').solve(m, tee=True)
m.display()

linear distribution in c++ using rand()

I am writing a function that generates n random numbers x such that xmin < x < xmax. This is easy to do with uniform distribution using rand().
int points[n];
for (int i = 0; i < n; i++) {
points[i] = rand() % (xmax - xmin) + xmin;
}
However, I would like to control the distribution so that the probability of a given x value is px = (px2 * (x - xmin) + px1 * (xmax - x)) / (xmax - xmin), where px1 and px2 are constants. In other words, a linear distribution.
I can fake this by partitioning the interval into sufficiently small discrete intervals and using the algorithm above for each one, with n proportional to the average probability across the subinterval. However, I would prefer to apply a continuous distribution across the interval. Can this be done, either using rand() or with another approach?
For PDF proportional to some linear function, CDF will be proportional to x squared . Thus, sampling would require sqrt(), something along the lines
x = xmin + sqrt(urand())*(xmax - xmin);
y = ymin + sqrt(urand())*(ymax - ymin);
where urand() is U(0,1) RNG (probably equal to rand()/RAND_MAX, but I've abandoned rand() and moved to C++11 long time ago)
UPDATE
If you want to use your p1 and p2 (assuming they are probabilities such that p1+p2=1), there would be a bit of modification, first to select which branch to sample:
r1 = urand();
if (r1 < p2) // range [0...p2), first branch
x = xmin + sqrt(urand())*(xmax-xmin);
else // range [p2...1), range length is 1-p2=p1
x = xmax - sqrt(urand())*(xmax-xmin);
Similar sampling for y

How do I encode Manhattan distance in Mixed Integer Programming

Lets have two points, (x1, y1) and (x2,y2)
dx = |x1 - x2|
dy = |y1 - y2|
D_manhattan = dx + dy where dx,dy >= 0
I am a bit stuck with how to get x1 - x2 positive for |x1 - x2|, presumably I introduce a binary variable representing the polarity, but I am not allowed multiplying a polarity switch to x1 - x2 as they are all unknown variables and that would result in a quadratic.
If you are minimizing an increasing function of |x| (or maximizing a decreasing function, of course),
you can always have the aboslute value of any quantity x in a lp as a variable absx such as:
absx >= x
absx >= -x
It works because the value absx will 'tend' to its lower bound, so it will either reach x or -x.
On the other hand, if you are minimizing a decreasing function of |x|, your problem is not convex and cannot be modelled as a lp.
For all those kind of questions, it would be much better to add a simplified version of your problem with the objective, as this it often usefull for all those modelling techniques.
Edit
What I meant is that there is no general solution to this kind of problem: you cannot in general represent an absolute value in a linear problem, although in practical cases it is often possible.
For example, consider the problem:
max y
y <= | x |
-1 <= x <= 2
0 <= y
it is bounded and has an obvious solution (2, 2), but it cannot be modelled as a lp because the domain is not convex (it looks like the shape under a 'M' if you draw it).
Without your model, it is not possible to answer the question I'm afraid.
Edit 2
I am sorry, I did not read the question correctly. If you can use binary variables and if all your distances are bounded by some constant M, you can do something.
We use:
a continuous variable ax to represent the absolute value of the quantity x
a binary variable sx to represent the sign of x (sx = 1 if x >= 0)
Those constraints are always verified if x < 0, and enforce ax = x otherwise:
ax <= x + M * (1 - sx)
ax >= x - M * (1 - sx)
Those constraints are always verified if x >= 0, and enforce ax = -x otherwise:
ax <= -x + M * sx
ax >= -x - M * sx
This is a variation of the "big M" method that is often used to linearize quadratic terms. Of course you need to have an upper bound of all the possible values of x (which, in your case, will be the value of your distance: this will typically be the case if your points are in some bounded area)