cvxpy:将非线性约束转换为等效线性约束

时间:2020-04-21 07:40:28

标签: python cvxpy convex-optimization

上下文:我是python投资组合优化库PyPortfolioOpt的开发人员,我正试图允许用户为最大Sharpe比率问题添加约束。

当前,用户可以将其约束作为lambda函数传递,例如,使所有权重大于1%:

ef = EfficientFrontier(mu, S)  # mu and S are expected return and covariance
ef.add_constraint(lambda w: w >= 0.01)  # example new constraint
ef.min_volatility()  # optimise with constraint

在后端,我将cvxpy变量w = cp.Variable(n)传递给约束lambda函数,以创建有效的cvxpy约束,然后将其传递给cp.Problem并解决。

我遇到的麻烦是最大化Sharpe比率需要您进行变量替换。形式为Ax ~ b的约束(其中~表示相等或不相等)必须变为Ax ~ k * b,其中k是非负优化变量。

我尝试的一件事是将w / k传递给lambda函数。然后,这将导致约束w / k >= 0.01,我希望该约束等效于w >= k * 0.01,但可悲的是,这给出了:

DCPError: Problem does not follow DCP rules. Specifically:
The following constraints are not DCP:
0.01 <= var2817 / Promote(var2818, (20,)) , because the following subexpressions are not:
|--  var2817 / Promote(var2818, (20,))

然后,我认为我也许可以采用非线性约束constr = (w / k >= 0.01)并将其乘以k来得到k * constr = (w >= 0.01 * k),但是不能在cvxpy中乘以约束。

TL; DR:如何将表示w / k >= 0.01的cvxpy约束对象(已实例化)转换为表示w >= k * 0.01的cvxpy约束对象?

或者失败了,我有什么办法可以重新设计它?我想保留lambda函数API。

1 个答案:

答案 0 :(得分:2)

也许有一些API可以分解已经实例化的约束,以便我可以放入变量?

约束在设计上是不可变的。不变性简化了CVXPY的大部分逻辑。

为什么不构造新的约束?您当然可以检查约束的左侧和右侧。现在,可以通过检查args属性(请参见https://github.com/cvxgrp/cvxpy/blob/master/cvxpy/constraints/nonpos.py#L97)来完成此操作。