How to stack variables together in cvxpy? - python

I want to solve an optimisation problem using cvxpy.
Suppose I want to use log_sum_exp function to build a constraint like this:
m >= log(1 + exp(m+z))
The syntax of cvxpy allows me to create a vector variable x = [z,m] of dimension 2 and apply matrix multiplication to create a vector of expressions 0, z+m:
import cvxpy
x = cvxpy.Variable(2)
coeff = np.array([
[0,0],
[1,1]
])
constraints = [ x[1] >= cvxpy.log_sum_exp(coeff * x)]
When coding like this, I lose some part of the logic because I want different names for different parts of my variable array. Is there some way to use the log_sum_exp transform more explicitly, like
z = cvxpy.Variable()
m = cvxpy.Variable()
constraints = [ m >= cvxpy.log_sum_exp([0, m+z]) ]
?
I couldn't find any hints in the official docs. Thanks!

As sascha pointed out, one of the manual pages
Functions in CVXPY
contains the answer. In particular, I can give an example of using log_sum_exp without matrix multiplication. Note that it is not possible to construct a correct problem within DCP (disciplined convex programming) framework using only operators exp and log because you will obtain concave function applied to convex one, which is considered as undefined behaviour. One should use a built-in constructor instead.
If you want to encode the constraint
F0 >= log( exp(F1) + exp(F2) + ... + exp(Fn) )
where F1, F2, ..., Fn are some convex expressions, and F0 is a concave expression,
then instead of introducing slack variables, one can type
import cvxpy
... # Define variables and functions
constraints = [
...,
something >= cvxpy.log_sum_exp(
cvxpy.vstack(
F1,
F2,
...,
Fn
)
)
]
... # Solve the optimisation problem
Note that vstack can be used both in multiple-argument style:
cvxpy.vstack(z, u)
and in list-style (but not tuples)
cvxpy.vstack([z,u])

Related

Using a matrix multiplication operator in a sympy expression

I am trying to implement a function using a Sympy expression with multiple parameters. For example, I used the following code:
import sympy
a = sympy.symbols("a")
ad = sympy.symbols("ad")
x = sympy.symbols("x")
c = sympy.symbols("c")
f = (ad*a)*c + x
func = sympy.lambdify((a,ad,x,c),f)
And what I would like to evaluate is the following:
func(M_A,M_B,0,1)
When I use two matrices M_A and M_B, the function performs just an element-wise multiplication, but I need it to be a matrix multiplication for the objects a and ad. I do know that it is possible to do so when I define the variables using MatrixSymbol instead of symbols, but this is not possible in my case as I have implemented a scenario which uses diagonal matrices where element-wise or matrix multiplication would not make a difference. Further, it is also possible to do something like this with normal symbols
x_vars = [symbols("x"+i) for i in range(1,4)]
trans_mat = np.random.random([3,3])
y_vars = trans_mat.dot(x_vars)
which just does not seem to work when I am using MatrixSymbol.
So, I was thinking if I could just compute the expression and perform all the manipulations using the regular symbols and at the end replace all the multiplication operators with numpy.matmul. Please let me know if this is possible somehow, or any other suggestion which can help is also welcome.
Thanks!
Doing help(func) we can see the code produced by lambdify:
Help on function _lambdifygenerated:
_lambdifygenerated(a, ad, x, c)
Created with lambdify. Signature:
func(a, ad, x, c)
Expression:
a*ad*c + x
Source code:
def _lambdifygenerated(a, ad, x, c):
return a*ad*c + x
That's a straightforward translation to python/numpy. Sounds like you want (a#ad)*c+x.

How to create an OR constraint in Pyomo?

I am trying to build a MIP model in Pyomo and having trouble creating an Or constraint. An OR constraint r = or{x1, ..., xn} states that the binary resultant variable r should be 1 if and only if any of the operand variables x1, ..., xn is equal to 1. I failed no such function that can create OR constraint in Pyomo, so I use my own code
m = ConcreteModel()
m.r = Var(within=Binary)
m.x1 = Var(within=Binary)
m.x2 = Var(within=Binary)
m.or_constraint = Constraint(expr=m.r==min(sum(m.x1, m.x2), 1)
Then ran the code and got the error msg that variables m.x1 and m.x2 should be initialized. I initialized them with 1 and found that m.or_constraint degraded to force m.r equal to 1. In other words, m.or_constraint just used m.x1 and m.x2 initial value to build the constraint and never updated in the process of solving the MIP problem.
I tried different expressions in Pyomo to create this constraint, like call a rule function in the constraint definition. However, every time I got the same result.
Could you direct me to create OR constraint in Pyomo?
The relation
y = x(1) or x(2) or ... or x(n) ( same as y = max{x(i)} )
y, x(i) ∈ {0,1} ( all binary variables )
can be formulated as a set of n+1 linear inequalities
y <= sum(i, x(i))
y >= x(i) for all i
It is also possible to write this as just two constraints:
y <= sum(i,x(i))
y >= sum(i,x(i))/n
The first version is tighter, however. That is the one I typically use.
Note: the first version is so tight that we even can relax y to be continuous between 0 and 1. Whether this is advantageous for the solver, requires a bit of experimentation. For the second version, it is required that y is binary.
Actually, there is another way to create a 'or' statement by using Pyomo with Binary(only for two constraints).
Obj: Min(OF)=f(x)
s.t. x<=A or x<=B
We can add a binary Number(Y) to form this model.M is a number which great enough(100000).
Obj: Min(OF)=f(x,y)
s.t. X<= A+M*y
X<=B+(1-Y)M
Y=0,1

Eliminate equality constraints in a pyomo model

I want to eliminate linear equality constraints on integral variables in a pyomo model by substitution. For instance, I wish to transform the model
by substituting
( * )
to
Is there a way to perfom such a substitution in a pyomo model? I will be able to obtain ( * ) by computing the solution space of the corresponding system of linear diophantine equations in the form y = const_vec + susbtitution_matrix * eta, where in our example we have
const_vec = np.array([1,0,0])
substitution_matrix = np.array([[-1,0],
[1,0],
[0,1]])
What you are describing is generally referred to as "variable aggregation." As you indicate, there are four basic steps:
Identify the linear equality equations you want to remove
Compute the substitution map
Deactivate the equality constraints that you want to remove
Substitute variables on all remaining constraints
It sounds like you have 1 and 2 under control. For 3, assuming you identified a Constraint m.c you want to deactivate, you just need to call m.c.deactivate().
For 4, you will want to generate new expressions for the remaining Constraint "body" expressions (variables only appear in the body and not in the lower/upper bounds). For current Pyomo releases (through 5.4.x), you can perform variable substitution by leveraging the clone_expression(). You need to generate a "substitution map": a dict that maps the id() of the variables you want to the new expression you want to use. For example:
from pyomo.core.base.expr import clone_expression
m = ConcreteModel()
m.y = Var([1,2,3])
m.eta = Var([1,2])
# ...
m.c = Constraint(expr=m.y[1]**2 + m.y[3]**2 <= 4)
# ...
substitution_map = {
id(m.y[1]): 1 - m.eta[1],
id(m.y[2]): m.eta[1],
id(m.y[3]): m.eta[2],
}
m.c = (m.c.lower, clone_expression(m.c.body, substitute=substitution_map), m.c.upper)
Finally, the disclaimers:
Setting the constraint with this syntax should work with recent Pyomo releases (I tested back through 5.1)
This approach technically violates one of the assumptions in the current Pyomo expression system (it generates potentially "entangled" expressions: expressions that share common sub-trees). While not "good", it shouldn't cause troubles, unless you do additional transformations / expression manipulation.
Pyomo 5.5 will have a new expression system that will likely have a different mechanism for manipulating / substituting variables.

compute x-component of vector in sympy

I'm sure this is a really basic question, but I've googled and haven't found it. Supposed I have a vector in sympy
z = 3*x + 4*y
How do I compute the x-component of the vector (i.e. the 3)? z/x doesn't give it (there's still the y-part), nor does z[x] or z.x. Surely there's a way to do this, right?
Is it as simple as:
>>> from sympy.abc import x, y
>>> z = 3*x + 4*y
>>> z.coeff(x)
3
I think that calling this expression a vector is somewhat incorrect. Indeed, if you keep in your mind the assumption that x and y are some base vectors, it will work in your mind. However the library will not provide any vector-like functionality because it does not know that you want to treat this as vectors.
For vector with all the nice helper methods you can use the diffgeom submodule of sympy which provides predefined R^2 and R^3 spaces with numerous coordinate systems.
However, for your case pattern matching seems a much more natural choice. After all pattern matching is one of the basic building blocks of CASes like Mathematica and others.
In SymPy as in all other CASes you work with symbolic expressions which are basically big trees with operators at each node and some symbols at the leafs. You can match trees against some predefined patterns much in the same way in which you can use regex on strings. In sympy you use Wild to do that:
x, y = Symbols("x y")
a, b = Wild('a', exclude=[x, y]), Wild('b', exclude=[x, y])
(2*x + 3*y).match(a*x + b*y)
For the special case of linear combinations check coeff which is described in the other answer.
See: https://github.com/sympy/sympy/wiki/Idioms-and-Antipatterns#wild-and-match

Two dimensional Optimization (minimization) in Python (using scipy.optimize)

I am trying to optimize (minimize) a two dimensional function E(n,k) defined as follows:
error=lambda x,y,w: (math.log(abs(Tformulated(x,y,w))) - math.log(abs(Tw[w])))**2 + (math.atan2(Tformulated(x,y,w).imag,Tformulated(x,y,w).real) - math.atan2(Tw[w].imag,Tw[w].real))**2
where Tformulated is obtained as follows :
def Tformulated(n,k,w):
z=1j
L=1
C=0.1
RC=(w*L)/C
n1=complex(1,0)
n3=complex(1,0)
n2=complex(n,k)
FP=1/(1-(((n2-n1)/(n2+n1))*((n2-n3)/(n2+n3))*math.exp(-2*z*n2*RC)))
Tform=((2*n2*(n1+n3))/((n2+n1)*(n2+n3)))*(math.exp(-z*(n2-n1)*RC))*FP
return Tform
and Tw is a list previously calculated having complex valued elements.
What I am exactly trying to do is for each value of w (used in "error x,y,w ....") I want to minimize the function "error" for the values of x & y. w ranges from 1 to 2048. So, it is basically a 2D minimization problem. I have tried programming on my part (though I am getting stuck at what method to use and how to use it); my code is as follows :
temp=[]
i=range(5)
retval = fmin_powell(error , x ,y, args=(i) , maxiter=100 ,maxfun=100)
temp.append(retval)
I am not sure even if fmin_powell is the correct way to go.
Here's a simplest example:
from scipy.optimize import fmin
def minf(x):
return x[0]**2 + (x[1]-1.)**2
print fmin(minf,[1,2])
[out]:
Optimization terminated successfully.
Current function value: 0.000000
Iterations: 44
Function evaluations: 82
[ -1.61979362e-05 9.99980073e-01]
A possible gotcha here is that the minimization routines are expecting a list as an argument. See the docs for all the gory details. Not sure if you can minimize complex-valued functions directly, you might need to consider the real and imaginary parts separately.

Categories

Resources