Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 绘图Scipy optimize.最小化每次迭代的收敛结果?_Python_Matplotlib_Optimization_Scipy_Minimize - Fatal编程技术网

Python 绘图Scipy optimize.最小化每次迭代的收敛结果?

Python 绘图Scipy optimize.最小化每次迭代的收敛结果?,python,matplotlib,optimization,scipy,minimize,Python,Matplotlib,Optimization,Scipy,Minimize,我想使用scipy.optimize.minimize对我的优化例程执行一些测试,特别是在多次测试中绘制每次迭代的收敛或目标函数 假设我有以下线性约束二次优化问题: 最小化:x|i Q|ij x|j+a | x|i| 受制于:sumx_i=1 我可以将其编码为: def _fun(x, Q, a): c = np.einsum('i,ij,j->', x, Q, x) p = np.sum(a * np.abs(x)) return c + p def _const

我想使用scipy.optimize.minimize对我的优化例程执行一些测试,特别是在多次测试中绘制每次迭代的收敛或目标函数

假设我有以下线性约束二次优化问题:

最小化:x|i Q|ij x|j+a | x|i|

受制于:sumx_i=1

我可以将其编码为:

def _fun(x, Q, a):
    c = np.einsum('i,ij,j->', x, Q, x)
    p = np.sum(a * np.abs(x))
    return c + p
def _constr(x):
    return np.sum(x) - 1
我将在scipy中实施优化,具体如下:


我看到有一个回调参数,但在每次迭代中只接受一个参数值参数。在一个更为深奥的情况下,如果我可能需要向回调函数提供其他参数,我如何利用它?

我解决这个问题的方法是使用一个通用回调缓存对象,每次都从回调函数引用它。假设您要进行20次测试,并在同一图表中绘制每次迭代后的目标函数。您将需要一个外部循环来运行20个测试,但我们将在稍后创建它

首先,让我们创建一个类,该类将为我们存储所有迭代目标函数值,以及一些额外的比特和片段:

class OpObj(object):
    def __init__(self, Q, a):
        self.Q, self.a = Q, a
        rv = np.random.rand()
        self.x_0 = np.array([rv, (1-rv)/2, (1-rv)/2])
        self.f = np.full(shape=(500,), fill_value=np.NaN)
        self.count = 0
    def _fun(self, x):
        return _fun(x, self.Q, self.a)
还可以添加一个回调函数来处理该类obj。现在不要担心它有不止一个参数,因为我们稍后会解决这个问题。只需确保第一个参数是解决方案变量

def cb(xk, obj=None):
    obj.f[obj.count] = obj._fun(xk)
    obj.count += 1
所有这些都是使用对象的函数和值来更新自身,计算每次迭代的次数。此函数将在每次迭代后调用

把这些放在一起,我们还需要两件事:1一些MatPloting来进行绘图,并修复回调,使其只有一个参数。我们可以用一个装饰器来实现这一点,这正是functools partial所做的。它返回的函数的参数比原始函数少。最后的代码如下所示:

import matplotlib.pyplot as plt
import scipy.optimize as op
import numpy as np
from functools import partial

Q = np.array([[1.0, 0.75, 0.45], [0.75, 1.0, 0.60], [0.45, 0.60, 1.0]])
a = 1.0

def _fun(x, Q, a):
    c = np.einsum('i,ij,j->', x, Q, x)
    p = np.sum(a * np.abs(x))
    return c + p
def _constr(x):
    return np.sum(x) - 1

class OpObj(object):
    def __init__(self, Q, a):
        self.Q, self.a = Q, a
        rv = np.random.rand()
        self.x_0 = np.array([rv, (1-rv)/2, (1-rv)/2])
        self.f = np.full(shape=(500,), fill_value=np.NaN)
        self.count = 0
    def _fun(self, x):
        return _fun(x, self.Q, self.a)

def cb(xk, obj=None):
    obj.f[obj.count] = obj._fun(xk)
    obj.count += 1

fig, ax = plt.subplots(1,1)
x = np.linspace(1,500,500)
for test in range(20):
    op_obj = OpObj(Q, a)
    x_soln = op.minimize(_fun, op_obj.x_0, args=(Q, a), method='SLSQP',
                         constraints={'type': 'eq', 'fun': _constr},
                         callback=partial(cb, obj=op_obj))
    ax.plot(x, op_obj.f)

ax.set_ylim((1.71,1.76))
plt.show()
import matplotlib.pyplot as plt
import scipy.optimize as op
import numpy as np
from functools import partial

Q = np.array([[1.0, 0.75, 0.45], [0.75, 1.0, 0.60], [0.45, 0.60, 1.0]])
a = 1.0

def _fun(x, Q, a):
    c = np.einsum('i,ij,j->', x, Q, x)
    p = np.sum(a * np.abs(x))
    return c + p
def _constr(x):
    return np.sum(x) - 1

class OpObj(object):
    def __init__(self, Q, a):
        self.Q, self.a = Q, a
        rv = np.random.rand()
        self.x_0 = np.array([rv, (1-rv)/2, (1-rv)/2])
        self.f = np.full(shape=(500,), fill_value=np.NaN)
        self.count = 0
    def _fun(self, x):
        return _fun(x, self.Q, self.a)

def cb(xk, obj=None):
    obj.f[obj.count] = obj._fun(xk)
    obj.count += 1

fig, ax = plt.subplots(1,1)
x = np.linspace(1,500,500)
for test in range(20):
    op_obj = OpObj(Q, a)
    x_soln = op.minimize(_fun, op_obj.x_0, args=(Q, a), method='SLSQP',
                         constraints={'type': 'eq', 'fun': _constr},
                         callback=partial(cb, obj=op_obj))
    ax.plot(x, op_obj.f)

ax.set_ylim((1.71,1.76))
plt.show()