Search code examples
pythonoptimizationconvex-optimizationcvxpy

Conditional Constraints


Is there a way in cvxpy to have a conditional constraint, I am looking at a simple convex portfolio optimization problem like this one.

from cvxpy import *
import numpy as np

np.random.seed(1)
n = 10

Sigma = np.random.randn(n, n) 
Sigma = Sigma.T.dot(Sigma)
w = Variable(n)

mu = np.abs(np.random.randn(n, 1))
ret = mu.T*w

risk = quad_form(w, Sigma)

orig_w  = [0.15,0.2,0.2,0.2,0.2,0.05,0.0,0.0,0.0,0.0]

lambda_ret = Parameter(sign='positive')
lambda_ret = 5

lambda_risk = Parameter(sign='positive')
lambda_risk = 1

constraints = [sum_entries(w) == 1, w >= 0]

prob = Problem(Maximize(lambda_ret * ret - lambda_risk * risk ),constraints)

prob.solve()

and I am trying to introduce a constraint that will only apply to certain scenarios

sum_entries([ w[i]-orig_w[i] if w[i]-orig_w[i] >= 0 else 0 for i in range(n)]) >= some threshold

In this python pseudo code I would like to only control positive weight changes.

I looked through the cvxpy functions but nothing seemed to be able to do that.


Solution

  • In general, often manual formulation and integer-programming approaches are needed. There is no support for if-else descriptions in any modelling-tool i know of.

    Your constraint:

    cvx.sum_entries([ w[i]-orig_w[i] if w[i]-orig_w[i] >= 0 else 0 for i in range(n)]) >= some threshold
    

    is equivalent to:

    cvx.sum_entries([ cvx.pos(w[i]-orig_w[i]) for i in range(n)]) >= some threshold
    

    This uses cvxpy's function pos:

    pos(x) <-> max{x,0} x inR
    

    (I did not check DCP-compatibility nor syntax; take this as general hint)

    Remark:

    cvx.sum_entries([ cvx.pos(w[i]-orig_w[i]) for i in range(n)]) >= some threshold
    

    looks pretty unnatural to what you would usually do in cvxpy:

    cvx.sum_entries(cvx.pos(w-orig_w)) >= some threshold
    

    (vectorized form: much more performant and usually more clear)