CVXPY set Z to 1 if B is positive - python

So here's the problem. I have this variable Z which follows the following rule:
I'm guessing Z should be defined as so:
Z = cvxpy.Variable(shape=shape_j_t, name="Z", boolean=True)
So Z is constrained(?) to the balance "B". How do I inform the solver that Z should be 1 if B is positive and 0 otherwise? Especially given that B itself is composed of other cvxpy.Variables.

The general approach, assuming a-priori knowledge about bounds (which are needed in general) on B looks like:
b <= UB * z
b >= LB * z
z in {0, 1}
which describes:
z = 0 <-> b = 0
z = 1 <-> LB <= b <= UB
But this is just something general and these things usually are designed having the full model in mind. Here we don't know what you are doing exactly. Sometimes we don't need equivalence but just implication (e.g. ignore the LB-constraint...)
Maybe it's not trivial to define the notion of positive balance as you only got inequalities and using LB=0 would express non-negativity, but not strict positiveness. For the latter, some a-priori definition of some epsilon (e.g. 0.001) would be needed.

Related

Extending a LP using Python

Hello good day to you all.
I have a small problem in which I assign locations at which demands to return goods to a lets say distribution centre occur. In order to handle this demand at these locations, we have to install certain technologies (A and B). We can only install as much of B as we have of A, or 0 of B. So, if B = 2, then A must be 2 as well. However, B can never be lets say B = 1 if A = 2. It can be B = 0 and A = 2.
Now the problem occurs in which I would like some help. If coded this in Python and it works for individual locations. But if I want to extend it to cover all locations, I run into errors... Below the code of the small problem:
# Create a new model
m = gp.Model("mip1")
BigM = 100
q = locations[i]
# Create parameters
cost_A = 20000
cost_B = 13500
cost_transport = 0.007
cap_A = 400000
cap_B = 500000
# Create variables
x = m.addVar(lb=0, ub=3, vtype=GRB.INTEGER, name="A")
y = m.addVar(lb=0, ub=3, vtype=GRB.INTEGER, name="B")
z = m.addVar(lb=0, vtype=GRB.INTEGER, name="flow_1")
a = m.addVar(vtype=GRB.BINARY, name="BigM")
# Set objective to minimize cost
m.setObjective(cost_A * x + cost_B * y + cost_transport * z, GRB.MINIMIZE)
# Add constraint: amount of UBC
m.addConstr(z == q, "accept returned demand")
# Add constraint: capacity
m.addConstr(z <= cap_A * x + cap_B * y, "capacity of locations")
# Add constraint: only B if location exists/has A
m.addConstr(y <= x, "B constraint_1")
# Add constraint: only B if location exists/has A
m.addConstr(x - y <= BigM * a, "B constraint_2")
# Add constraint: only B if location exists/has A
m.addConstr(y <= BigM * (1 - a), "B constraint_3")
# Optimize model
m.optimize()
This model above creates output on how many A and B to install at a certain location, given the demand at that location. This ofcourse is very simple. However, I now want to extend this problem considering multiple locations and that is where I run into errors... KeyError: (0, 1), KeyError: (1, 1), KeyError: (1) and KeyError: (0) all have been there already..
I thought it would be "simply" making addVars and addConstraints, but then you need to assigns sets etc.. I am actually quite lost in the process. Is there anybody who could please help me out?
Thank you all very much in advance for your time and consideration.
P.S. it does not have to be solved by solvers like Gurobi, if you know anything else I am happy to hear!
Yes, you are going to have to tear down most of that and introduce sets... :). My Gurobi syntax is weak, so here are a few things to get you started in pseudocode.
You will need a couple of sets
T = {A, B}
L = {LA, Chicago, NY} # for example
You need a variable to assign (this is an assignment problem) a quantity of tech T at location L...
X[tech, loc] # domain non-neg integers, right?
Then you can re-construct your constraints & such above using summations over the indices as appropriate. I'm sure there are a bunch of Gurobi examples to help with that. Start VERY small so you can troubleshoot.
You will need a constraint for your conditions on tech B. You didn't say if that constraint was global or enforced by location. Let's assume it is by location (the harder case). You then need another indicator variable to indicate whether they are equal or not.
Eq[loc] # indicate whether B=A at particular location, binary var
Then you can use that with Big M to control the equality by location by making 3 constraints per location
X[B, loc] <= X[A, loc]
X[A, loc] - X[B, loc] <= (1 - Eq[loc]) * M
X[B, loc] <= Eq[loc] * M

MIP: Adding a Variable to Indicate Equality

I am trying to build a MIP model in the OR Tools Python API. I have two expressions x and y and want to make a variable b that is equal to 1 when x == y and 0 otherwise. What I've tried doing so far is adding the constraint that -M(1 - b) <= x - y <= M(1 - b) for some big value of M, which forces b to be 0 if x != y. Where I am stuck is adding a constraint that forces b to be 1 if x == y. I think I would want something such as x - y >= 1 - b or y - x >= 1 - b, but I don't know how to logically combine constraints like this. Any suggestions on how to do this? Or for some totally different approach?
I think the following expressions would work for you:
b <= x - y + 1
b <= y - x + 1
b >= 1-x + 1-y - 1
b >= y + x - 1
Please note that depending on the nature of the model, the CP-SAT solver could prove competitive. And it provides reification and half-reification natively.
Please have a look at
[Specific answer] https://github.com/google/or-tools/blob/master/ortools/sat/doc/channeling.md
[Introduction] https://developers.google.com/optimization/cp/cp_solver#cp-sat_example
[CP-SAT recipes] https://github.com/google/or-tools/blob/master/ortools/sat/doc/index.md

inverted indicator constraint in gurobipy

I am a beginner in gurobipy. I would like to add an inverted indicator constraint.
Indicator constraint is nothing but depending on a binary variable a constraint does or does not hold.
In gurobipy this is written as
model.addConstr((x == 1) >> (y + z <= 5))
where x is a binary variable, y and z are integer variables. This statement says that if x is True then the constraint y+z <= 5 holds.
But I would like to have an inverted constraint like this.
If y+z <= 5 then x == 1. But gurobi does not allow the lhs part of the statement to be an inequality. It can only be a binary variable equal to a constant (0 or 1).
So the inverted statement throws an error.
model.addConstr((y + z <= 5) >> (x == 1))
Any ideas how to rewrite such a conditional constraint in gurobipy?!
The implication
y+z ≤ 5 ⇒ x = 1
can be rewritten as:
x = 0 ⇒ y+z ≥ 6
This can be directly implemented as an indicator constraint.
This is based on propositional logic. This is called transposition:
A ⇒ B
⇔
not B ⇒ not A
So in theory we have
y+z ≤ 5 ⇒ x = 1
⇔
x = 0 ⇒ y+z > 5
If x and y are integers we can say x = 0 ⇒ y+z ≥ 6 If they are continuous variables you could do: x = 0 ⇒ y+z ≥ 5.0001 (in practice I would do: x = 0 ⇒ y+z ≥ 5 and keep things ambiguous at y+z = 5).
This is kind of a standard trick when using indicator constraints. It seems not everyone is aware of or appreciates this.
The indicator syntax is
binary expression >> linear constraint
So your constraint is invalid. You need a different model that forces x to 1 when y + z ≤ 5. Assuming y, z are non-negative integers, try 6x + y + z ≥ 6.
I think the best way to go with this one is to use the big-M approach
Let reconsider the problem you are trying to model
If y+z <= 5 then x == 1
It is equivalent to if y+z-5 <= 0 then x==1
From here we need a logic that will turn on and off the variable x depending on the condition on the y+z-5
y + z - 5 <= M(1-x)
will do the trick. Note that the x will need to be 1 for the relationship to hold if y+z-5 <= 0 which is what we want. Similarly, x will be turned off (set to 0) if y+z-5 >= 0
I hope this helps

Differences between complex number implementations in Haskell and Python

I'm trying to map the complex number functionality in Python, to Data.Complex in Haskell, but I've reached a point where they differ, and I am unsure as to why.
In python:
>>> x = 3j
3j
>>> x.real
0.0
>>> x.imag
3.0
In Haskell:
> import Data.Complex
> let j n = 0 :+ n
> let x = j 3.0
> realPart x
0.0
> imagPart x
3.0
So far they look the same. Looks like operating on them doesn't differ much either:
Python:
>>> y = 1 + x
(1+3j)
>>> y.real
1.0
>>> y.imag
3.0
Haskell:
> let y = 1 + x
> realPart y
1.0
> imagPart y
3.0
In isolation + - * / ** all seem to work the same way. However this operation yields two different results:
>>> z = (y - 1) ** 2
(-9+0j)
>>> z.real
-9.0
>>> z.imag
0.0
But in Haskell:
> let z = (y - 1) ** 2
> realPart z
-9.000000000000002
> imagPart z
1.1021821192326181e-15
Why is this?
In Haskell, (**) for Complex is essentially
a ** b = exp (b * log a)
which has many opportunities for bad rounding errors to creep in. (I don't know enough Python to check what it would do with an analogous log-then-exp expression; the thing I tried complained that it wasn't ready to handle log(3j).) It has a bunch of special cases to thwart rounding errors, but none check for a fully-real integer exponent. You might consider this a bug or infelicity and report it to the folks in charge of the Complex type as another special case worth adding to the implementation of (**).
In the meantime, if you know your exponent is integral, you can use (^) (for positive numbers only) or (^^) instead:
Data.Complex> (0 :+ 3) ^ 2
(-9.0) :+ 0.0
Although the results given by the two languages are different, they aren't very different (as others have indicated in the comments). So you might guess that it's just a matter of slightly different implementations -- and you'd be right.
Daniel Wagner indicates that in Haskell, the ** operator is defined as
a ** b = exp (b * log a)
Haskell does some special casing, but most of the time, the operation relies on the general-purpose definitions of exp and log for complex numbers.
In Python, it's a little different: powers are calculated using a polar representation. This approach involves using a different set of general-purpose functions -- most of them basic trigonometric functions over ordinary floating point numbers -- and does almost no special-casing. It's not clear to me that this approach is better overall, but it does happen to give a more correct answer in the particular case you've chosen.
Here's the core of the implementation:
vabs = hypot(a.real,a.imag);
len = pow(vabs,b.real);
at = atan2(a.imag, a.real);
phase = at*b.real;
if (b.imag != 0.0) {
len /= exp(at*b.imag);
phase += b.imag*log(vabs);
}
r.real = len*cos(phase);
r.imag = len*sin(phase);
Here, a is the base and b is the exponent. vabs and at give the polar representation of a, such that
a.real = vabs * cos(at)
a.imag = vabs * sin(at)
And as you can see in the last two lines of code, len and phase give the corresponding polar representation of the result, r.
When b is real, the if block isn't executed, and this simplifies to De Moivre's formula. I can't find a canonical formula covering the complex or imaginary cases, but it appears to be pretty simple!

What is this operator *= -1

I'm going through some Python activities and was given example code with this operator: y *= -1
I had a look through the relevant Python docs, to no avail.
I know y += 1, for example, is short for y = y + 1. So is this y = y * -1 y equals y times -1 maybe?
Closest thing in Python docs I could find is this: x * y: product of x and y
Is this it?
In the vast majority of the cases
y *= <expr>
is the same as
y = y * <expr>
but in the general case, it is interpreted as:
y = imul(y, <expr>)
which is then equivalent to:
y = y.__imul__(<expr>)
if y's type overrides __imul__.
This means that if y's type overrides the inplace multiplication operator, y*=<expr> is performed inplace, while y=y*<expr> is not.
EDIT
It might not be immediately clear why the assignment is needed, i.e. why it is intrepreted as y = imul(y, <expr>), and not just imul(y, <expr>).
The reason is that it makes a lot of sense for the following two scenarios to give the same result:
c = a * b
and
c = a
c *= b
Now, this of course works if a and b are of the same type (e.g. floats, numpy arrays, etc.), but if they aren't, it is possible for the result of the operation to have the type of b, in which case the operation cannot be an inplace operation of a, thus the result needs to be assigned to a, in order to achieve the correct behavior.
For example, this works, thanks to the assignment:
from numpy import arange
a = 2
a *= arange(3)
a
=> array([0, 2, 4])
Whereas if the assignment is dropped, a remains unchanged:
a = 2
imul(a, arange(3))
=> array([0, 2, 4])
a
=> 2
Yes that's correct. It just means multiply the left-hand value by negative the right-hand value. They're both arithmetic operators that differ simply by operation and expression binding, so I believe +/* are parallel everywhere else in overloads.
y = y * -1

Categories

Resources