Хотя алгоритм SLSQP
в scipy.optimize.minimize
хорош, у него есть куча ограничений. Первый из них - это решатель QP
, поэтому он работает для уравнений, которые хорошо вписываются в квадратичную парадигму программирования. Но что произойдет, если у вас есть функциональные ограничения? Кроме того, scipy.optimize.minimize
не является глобальным оптимизатором, поэтому вам часто нужно начинать очень близко к конечным результатам.
Существует ограниченный пакет нелинейной оптимизации (называемый mystic
), который существует почти столько же, сколько и scipy.optimize
- я бы предложил его в качестве решения для любой ограниченной ограниченной нелинейной оптимизации.
Например, ваша проблема, если я понимаю ваш псевдо-код, выглядит примерно так:
import numpy as np
M = 10
N = 3
Q = 10
C = 10
# let's be lazy, and generate s and u randomly...
s = np.random.randint(-Q,Q, size=(M,N,N))
u = np.random.randint(-Q,Q, size=(M,N))
def percentile(p, x):
x = np.sort(x)
p = 0.01 * p * len(x)
if int(p) != p:
return x[int(np.floor(p))]
p = int(p)
return x[p:p+2].mean()
def objective(x, p=5): # inverted objective, to find the max
return -1*percentile(p, [np.dot(np.atleast_2d(u[i]), x)[0] for i in range(0,M-1)])
def constraint(x, p=95, v=C): # 95%(xTsx) - v <= 0
x = np.atleast_2d(x)
return percentile(p, [np.dot(np.dot(x,s[i]),x.T)[0,0] for i in range(0,M-1)]) - v
bounds = [(0,1) for i in range(0,N)]
Так, чтобы справиться с вашей проблемой в mystic
, вам просто нужно указать границы и ограничения.
from mystic.penalty import quadratic_inequality
@quadratic_inequality(constraint, k=1e4)
def penalty(x):
return 0.0
from mystic.solvers import diffev2
from mystic.monitors import VerboseMonitor
mon = VerboseMonitor(10)
result = diffev2(objective, x0=bounds, penalty=penalty, npop=10, gtol=200, \
disp=False, full_output=True, itermon=mon, maxiter=M*N*100)
print result[0]
print result[1]
Результат выглядит примерно так:
Generation 0 has Chi-Squared: -0.434718
Generation 10 has Chi-Squared: -1.733787
Generation 20 has Chi-Squared: -1.859787
Generation 30 has Chi-Squared: -1.860533
Generation 40 has Chi-Squared: -1.860533
Generation 50 has Chi-Squared: -1.860533
Generation 60 has Chi-Squared: -1.860533
Generation 70 has Chi-Squared: -1.860533
Generation 80 has Chi-Squared: -1.860533
Generation 90 has Chi-Squared: -1.860533
Generation 100 has Chi-Squared: -1.860533
Generation 110 has Chi-Squared: -1.860533
Generation 120 has Chi-Squared: -1.860533
Generation 130 has Chi-Squared: -1.860533
Generation 140 has Chi-Squared: -1.860533
Generation 150 has Chi-Squared: -1.860533
Generation 160 has Chi-Squared: -1.860533
Generation 170 has Chi-Squared: -1.860533
Generation 180 has Chi-Squared: -1.860533
Generation 190 has Chi-Squared: -1.860533
Generation 200 has Chi-Squared: -1.860533
Generation 210 has Chi-Squared: -1.860533
STOP("ChangeOverGeneration with {'tolerance': 0.005, 'generations': 200}")
[-0.17207128 0.73183465 -0.28218955]
-1.86053344078
mystic
является очень гибким и может обрабатывать любой тип ограничений (например, Равенство, неравенство), включая символические и функциональные ограничения. Я указал ограничения как «штрафы» выше, что является традиционным способом, поскольку они применяют штраф к цели при нарушении ограничения. mystic
также обеспечивает нелинейные преобразования ядра, которые ограничивают пространство решений путем сокращения пространства допустимых решений (т. Е. Путем пространственного преобразования или преобразования ядра).
В качестве примера приведено решение mystic
решения проблемы, которая ломает множество решателей QP, поскольку ограничения не являются формой матрицы ограничений. Это оптимизирует конструкцию сосуда высокого давления.
"Pressure Vessel Design"
def objective(x):
x0,x1,x2,x3 = x
return 0.6224*x0*x2*x3 + 1.7781*x1*x2**2 + 3.1661*x0**2*x3 + 19.84*x0**2*x2
bounds = [(0,1e6)]*4
# with penalty='penalty' applied, solution is:
xs = [0.72759093, 0.35964857, 37.69901188, 240.0]
ys = 5804.3762083
from mystic.symbolic import generate_constraint, generate_solvers, simplify
from mystic.symbolic import generate_penalty, generate_conditions
equations = """
-x0 + 0.0193*x2 <= 0.0
-x1 + 0.00954*x2 <= 0.0
-pi*x2**2*x3 - (4/3.)*pi*x2**3 + 1296000.0 <= 0.0
x3 - 240.0 <= 0.0
"""
cf = generate_constraint(generate_solvers(simplify(equations)))
pf = generate_penalty(generate_conditions(equations), k=1e12)
if __name__ == '__main__':
from mystic.solvers import diffev2
from mystic.math import almostEqual
from mystic.monitors import VerboseMonitor
mon = VerboseMonitor(10)
result = diffev2(objective, x0=bounds, bounds=bounds, constraints=cf, penalty=pf, \
npop=40, gtol=50, disp=False, full_output=True, itermon=mon)
assert almostEqual(result[0], xs, rel=1e-2)
assert almostEqual(result[1], ys, rel=1e-2)
Найти это, и примерно 100 примеров нравится, здесь: https://github.com/uqfoundation/mystic.
Я автор, поэтому я слегка пристрастен. Однако смещение очень слабое. mystic
является и зрелым, и хорошо поддержанным, и не имеет себе равных в способности решать жестко ограниченные задачи нелинейной оптимизации.
Вопросы, предлагающие нам рекомендовать или находить инструмент, библиотеку или любимый внешний ресурс вне темы для переполнения стека, поскольку они склонны привлекать упрямые ответы и спам. Вместо этого опишите проблему и то, что было сделано до сих пор, чтобы ее решить. – jonrsharpe
Несомненно. Когда я начал эту проблему, у меня была только одна оценка точки для u и s, и я смог решить проблему выше с помощью cvxpy. Я понял, что вместо одной оценки для u и s у меня было все распределение значений, поэтому я хотел изменить свою целевую функцию, чтобы я мог использовать весь дистрибутив. Описание проблемы выше - моя попытка включить эту информацию в значимый путь. cvxpy не может быть использован для решения этой проблемы, я пробовал scipy.optimize.anneal, но я не могу установить границы на неизвестные значения. Я тоже посмотрел на целлюлозу, но это не допускает нелинейных ограничений. – akhil