scipy最小值求解器带有约束条件。

39
假设我有一个矩阵。
arr = array([[0.8, 0.2],[-0.1, 0.14]])

使用目标函数

def matr_t(t):
    return array([[t[0], 0],[t[2]+complex(0,1)*t[3], t[1]]]

def target(t):
    arr2 = matr_t(t)
    ret = 0
    for i, v1 in enumerate(arr):
          for j, v2 in enumerate(v1):
               ret += abs(arr[i][j]-arr2[i][j])**2
    return ret

现在我想在假设 t[i] 是实数的情况下最小化这个目标函数,且类似于 t[0]+t[1]=1 的条件成立。

2个回答

67

这个限制

t[0] + t[1] = 1

这将是一个等式约束(type='eq'),您需要创建一个函数使其等于零:

def con(t):
    return t[0] + t[1] - 1

然后你需要创建一个约束的字典(如果有多个,则为字典列表):

cons = {'type':'eq', 'fun': con}

我从未尝试过,但我相信为了保持代码的真实性,你可以使用:

con_real(t):
    return np.sum(np.iscomplex(t))

同时让你的cons包括两个约束条件:

cons = [{'type':'eq', 'fun': con},
        {'type':'eq', 'fun': con_real}]

然后,您将cons输入到minimize中:

scipy.optimize.minimize(func, x0, constraints=cons)

@user1943296 不太确定如何实现,如果您的输入很复杂,输出也可能会很复杂。第一个限制条件可能意味着t.imag.sum()为零,因为我们只将其与实数1进行比较,但我的编辑显示了更明确的限制条件。 - askewchan
如果我想要 con >0,<0,>=0或<=0,该怎么做呢?我发现 type 只有两种类型 ineqeq - wyx
从文档中可以得知,等式约束表示约束函数结果必须为零,而不等式约束表示它必须是非负的。请注意,COBYLA仅支持不等式约束。因此你可以重写你的等式/不等式约束来表达这个意思。@wyx - doc

2

不必编写自定义约束函数,您可以构造一个scipy.optimize.LinearConstraint对象,并将其作为约束传递。它的构造要求上下界;独立变量向量的长度必须与传递给目标函数的变量长度相同,因此像t[0] + t[1] = 1这样的约束应该被重新表述为以下形式(因为t的长度为4,可以从其在matr_t()中的操作中看出):

constraint

另外,minimize 也会在实数空间上进行优化,因此 t[i] 是实数的限制已经嵌入到算法中。那么完整代码如下:

import numpy as np
from scipy.optimize import minimize, LinearConstraint

def matr_t(t):
    return np.array([[t[0], 0],[t[2]+complex(0,1)*t[3], t[1]]]

def target(t):
    arr2 = matr_t(t)
    ret = 0
    for i, v1 in enumerate(arr):
          for j, v2 in enumerate(v1):
               ret += abs(arr[i][j]-arr2[i][j])**2
    return ret

arr = np.array([[0.8, 0.2],[-0.1, 0.14]])
linear_constraint = LinearConstraint([[1, 1, 0, 0]], [1], [1])
result = minimize(target, x0=[0.5, 0.5, 0, 0], constraints=[linear_constraint])

x_opt = result.x            # array([ 0.83,  0.17, -0.1 , 0.])
minimum = result.fun        # 0.0418

对于一个更深入的例子,让我们使用经济学中常见的问题Cobb-Douglas效用最大化作为说明性示例。这实际上是一个受限制的最大化问题,但由于minimize是一个最小化函数,它必须被强制转换为最小化问题(只需否定目标函数)。此外,为了将约束传递为scipy.optimize.LinearConstraint对象,我们必须编写具有下限和上限的约束条件。因此,优化问题如下所示:

problem

在这个函数中,有两个变量 xy;其余的都是超参数,必须从外部提供(alpha、beta、pxpyB)。其中只有 alpha 和 beta 是目标函数的参数,因此它们必须通过 minimizeargs= 参数传递给它(在下面的示例中为 alphas)。
优化问题解决了 xy 值,使得目标函数在约束条件下达到最小值。它们必须作为单个对象(在下面的函数中为 variables)传递给目标函数。如前所述,我们必须对这些变量(目标函数的 xy)进行合理的猜测,以便算法收敛。
from scipy.optimize import minimize, LinearConstraint

def obj_func(variables, hyperparams):
    x, y = variables
    alpha, beta = hyperparams
    return - x**alpha * y**beta

B, px, py, alphas = 30, 2, 5, [1/3, 2/3]
linear_constraint = LinearConstraint([[px, py], [1, 0], [0, 1]], [-np.inf, 0, 0], [B, np.inf, np.inf])
result = minimize(obj_func, x0=[1, 1], args=alphas, constraints=[linear_constraint])

x_opt, y_opt = result.x     # 4.9996, 4.000
optimum = result.fun        # 4.3088

result.x 是最小化值,result.fun 是局部最小值。

Cobb-Douglas 有一个封闭形式的解决方案,在示例输入中,正确的解决方案是 (x_opt, y_opt) = (5, 4)minimize 的结果与此不完全相等,但由于 minimize 是迭代算法,这是它停止之前所能达到的最接近值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接