Оптимизация массива Python с двумя ограничениями

#python #numpy #optimization #scipy #scipy-optimize

#python #numpy #оптимизация #scipy #scipy-оптимизировать

Вопрос:

У меня проблема оптимизации, когда я пытаюсь найти массив, который должен оптимизировать две функции одновременно.

В минимальном примере ниже у меня есть два известных массива w x и неизвестный массив y . Я инициализирую массив y , содержащий только 1s.

Затем я указываю функцию np.sqrt(np.sum((x-np.array)**2) и хочу найти массив y , в котором

np.sqrt(np.sum((x-y)**2) подходы 5

np.sqrt(np.sum((w-y)**2) подходы 8

Приведенный ниже код можно использовать для успешной оптимизации y в отношении одного массива, но я хотел бы найти решение, которое оптимизирует y в отношении обоих x и y одновременно, но я не уверен, как указать два ограничения.

y должно состоять только из значений, превышающих 0.

Есть идеи о том, как это сделать?

 w = np.array([6, 3, 1, 0, 2])
x = np.array([3, 4, 5, 6, 7])
y = np.array([1, 1, 1, 1, 1])

def func(x, y):

    z = np.sqrt(np.sum((x-y)**2)) - 5
    return  np.zeros(x.shape[0],)   z

r = opt.root(func, x0=y, method='hybr')
print(r.x)
# array([1.97522498 3.47287981 5.1943792  2.10120135 4.09593969])

print(np.sqrt(np.sum((x-r.x)**2)))
# 5.0
  

Ответ №1:

Одним из вариантов является использование scipy.optimize.minimize вместо root , здесь у вас есть несколько параметров решателя, и некоторые из них (ie SLSQP ) позволяют указать несколько ограничений. Обратите внимание, что я изменил имена переменных, чтобы это x был массив, который вы хотите оптимизировать, y и z определить ограничения.

 from scipy.optimize import minimize
import numpy as np

x0 = np.array([1, 1, 1, 1, 1])
y = np.array([6, 3, 1, 0, 2])
z = np.array([3, 4, 5, 6, 7])

constraint_x = dict(type='ineq',
                    fun=lambda x: x)   # fulfilled if > 0
constraint_y = dict(type='eq',
                    fun=lambda x: np.linalg.norm(x-y) - 5)  # fulfilled if == 0
constraint_z = dict(type='eq',
                    fun=lambda x: np.linalg.norm(x-z) - 8)  # fulfilled if == 0

res = minimize(fun=lambda x: np.linalg.norm(x), constraints=[constraint_y, constraint_z], x0=x0,
               method='SLSQP', options=dict(ftol=1e-8))  # default 1e-6

print(res.x)                    # [1.55517124 1.44981672 1.46921122 1.61335466 2.13174483]
print(np.linalg.norm(res.x-y))  # 5.00000000137866
print(np.linalg.norm(res.x-z))  # 8.000000000930026
  

Это минимизатор, поэтому, помимо ограничений, он также требует минимизации функции, я выбрал только норму y , но установка функции на константу (т. Е. лямбда x: 1) также сработала бы.
Также обратите внимание, что ограничения не выполняются в точности, вы можете повысить точность, установив необязательный аргумент ftol на меньшее значение, т.Е. 1e-10 .
Для получения дополнительной информации см. Также Документацию и соответствующие разделы для каждого решателя.