scipy.optimize.minimize (COBYLA и SLSQP) игнорирует ограничения, инициированные внутри цикла for

Я использую scipy.optimize.minimize для решения сложной модели оптимизации коллектора (SQSLP и COBYLA, поскольку проблема ограничена как границами, так и уравнениями ограничений). Существует одна переменная решения в день (хранение), и выбросы из резервуара рассчитываются как функция изменения запасов в рамках целевой функции. Затем применяются штрафы, основанные на выпусках и штрафах за хранение, с целью минимизации штрафов (целевая функция - это сумма всех штрафов). Я добавил некоторые ограничения в эту модель, чтобы ограничить изменение хранилища до пределов физической системы, которые являются разницей между переменной решения x (t + 1) и x (t), а также зависят от притоков на этом временном шаге I ( т). Эти ограничения добавляются в список словарей ограничений с помощью цикла for. Ограничения, добавленные вне этой функции цикла for, как должны. Однако ограничений, связанных со временем, которые инициируются в цикле for, нет.

Очевидно, проблема сложна, поэтому я воссоздал более простую версию, чтобы проиллюстрировать проблему. Эта задача имеет четыре переменные решения и стремится минимизировать целевую функцию (которую я назвал функцией) с ограничениями устойчивого состояния (I = приток должен быть равен x = отток) и неотрицательности (т.е. отток x не может быть отрицательным):

    import numpy as np
    from scipy.optimize import minimize

    def function(x):
        return -1*(18*x[0]+16*x[1]+12*x[2]+11*x[3])

    I=np.array((20,50,50,80))
    x0=I

    cons=[]
    steadystate={'type':'eq', 'fun': lambda x: x.sum()-I.sum() }
    cons.append(steadystate)


    for t in range (4):
        def const(x):    
            y=x[t]
            return y
        cons.append({'type':'ineq', 'fun': const})

    out=minimize(function, x0, method="SLSQP", constraints=cons)
    x=out["x"]

Ограничения, инициированные в цикле for, являются ограничениями неотрицательности, но оптимизация дает отрицательные значения для переменных решения. Тем не менее, он придерживается постоянного ограничения.

Когда я вычисляю проблему, используя следующий код, значения ограничиваются правильно:

    import numpy as np
    from scipy.optimize import minimize

    def function(x):
        return -1*(18*x[0]+16*x[1]+12*x[2]+11*x[3])

    I=np.array((20,50,50,80))
    x0=I

    cons=[]
    steadystate1={'type':'eq', 'fun': lambda x: x.sum()-I.sum() }
    cons.append(steadystate1)


    nonneg0 = {'type':'ineq', 'fun': lambda x: x[0]}
    nonneg1= {'type':'ineq', 'fun': lambda x: x[1]} 
    nonneg2 = {'type':'ineq', 'fun': lambda x: x[2]} 
    nonneg3 = {'type':'ineq', 'fun': lambda x: x[3]} 
    cons.append(nonneg0)
    cons.append(nonneg1)
    cons.append(nonneg2)
    cons.append(nonneg3)

    out=minimize(function, x0, method="SLSQP", constraints=cons)
    x=out["x"]

Есть идеи, где я ошибаюсь? Я видел аналогичные ограничения в других приложениях, поэтому не могу понять, но предполагаю, что это что-то простое. У меня есть сотни ограничений, которые нужно инициировать в моей полномасштабной версии этого кода, поэтому их написание, как во втором примере, не будет идеальным.


comment
Вам не нужно создавать отдельные функции ограничения неотрицательности для каждого элемента в x - просто передайте одну функцию ограничения, которая возвращает весь вектор параметров: nonneg = {'type':'ineq', 'fun': lambda x: x}   -  person ali_m    schedule 11.03.2016
comment
Спасибо, в этом есть смысл. Однако в моем полном коде мне нужен цикл for для генерации уравнений ограничений. Я думаю, решение VallyN должно работать.   -  person Kingle    schedule 11.03.2016


Ответы (1)


Я действительно не знаю Python, но знаю, как решить вашу проблему. В вашем первом фрагменте const функция использует ссылку на сам t (поскольку внутренняя функция имеет общую область видимости с внешней), таким образом создавая эквивалент:

cons[0] = {'type':'ineq', 'fun': lambda x: x[t]}
cons[1] = {'type':'ineq', 'fun': lambda x: x[t]} 
cons[2] = {'type':'ineq', 'fun': lambda x: x[t]} 
cons[3] = {'type':'ineq', 'fun': lambda x: x[t]}

что неправильно. Это можно исправить с помощью карри:

import numpy as np
from scipy.optimize import minimize

def function(x):
    return -1*(18*x[0]+16*x[1]+12*x[2]+11*x[3])

I=np.array((20,50,50,80))
x0=I

cons=[]
steadystate={'type':'eq', 'fun': lambda x: x.sum()-I.sum() }
cons.append(steadystate)

def f(a):
    def g(x):
        return x[a]
    return g

for t in range (4):
    cons.append({'type':'ineq', 'fun': f(t)})

out=minimize(function, x0, method="SLSQP", constraints=cons)
x=out["x"]

Под занавесками этот подход создает новую ссылку на значение, хранящееся в t (когда вы передаете его в качестве аргумента в f), и сохраняет эту ссылку для использования в g, теперь генерируя серию правильных функций.

person weaknespase    schedule 09.03.2016
comment
Спасибо, это работает. Я попробую реализовать аналогичный метод для своего более сложного кода. - person Kingle; 11.03.2016