cvxpy: преобразование нелинейного ограничения в эквивалентное линейное ограничение - PullRequest
1 голос
/ 21 апреля 2020

Контекст: я являюсь разработчиком PyPortfolioOpt , библиотеки оптимизации портфеля python, и я пытаюсь позволить пользователям добавлять ограничения к проблеме максимального отношения Шарпа.

В настоящее время пользователи могут передавать свои ограничения в виде лямбда-функции, например, чтобы все веса были больше 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) в функцию лямбда-ограничения, чтобы создать действительное ограничение cvxpy, я передаю его cp.Problem и решаю его.

Проблема, с которой я столкнулся, заключается в том, что для максимизации коэффициента Шарпа требуется замена переменных. Ограничения вида Ax ~ b (где ~ обозначает либо равенство, либо неравенство) должны стать Ax ~ k * b, где k - неотрицательная переменная оптимизации.

Одна вещь, которую я пытался, состояла в том, чтобы передать w / k в лямбда-функция. Тогда это приведет к ограничению 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: как я могу преобразовать объект ограничения cvxpy (уже создан) представление w / k >= 0.01 в объекте ограничения cvxpy, представляющем w >= k * 0.01?

Или, если это не удалось, есть ли способ, которым я могу изменить это? Я бы хотел оставить API лямбда-функции.

1 Ответ

2 голосов
/ 24 апреля 2020

Возможно, есть какой-то API для разложения уже созданного экземпляра ограничения, чтобы я мог вставить переменную?

Ограничения являются неизменяемыми по своей конструкции. Неизменность упрощает большую часть логики CVXPY c.

Почему бы не создать новое ограничение? Вы можете, конечно, проверить левую и правую стороны ограничения. Прямо сейчас это можно сделать, проверив атрибут args (см. https://github.com/cvxgrp/cvxpy/blob/master/cvxpy/constraints/nonpos.py#L97).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...