Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.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 SLSQP最小化中不尊重约束导致的数学域错误_Python_Scipy_Mathematical Optimization - Fatal编程技术网

Python scipy SLSQP最小化中不尊重约束导致的数学域错误

Python scipy SLSQP最小化中不尊重约束导致的数学域错误,python,scipy,mathematical-optimization,Python,Scipy,Mathematical Optimization,考虑一个简单的问题: max log(x) subject to x >= 1e-4 要解决问题,请使用scipy.optimize.minimize: import numpy as np from scipy.optimize import minimize from math import log def func(x): return log(x[0]) def func_deriv(x): return np.array([1 / x[0]]) cons

考虑一个简单的问题:

max log(x)
subject to x >= 1e-4
要解决问题,请使用
scipy.optimize.minimize

import numpy as np
from scipy.optimize import minimize
from math import log

def func(x):
    return log(x[0])

def func_deriv(x):
    return np.array([1 / x[0]])

cons = ({'type': 'ineq',
         'fun' : lambda x: x[0] - 1e-4,
         'jac' : lambda x: np.array([1])})
minimize(func, [1.0], jac=func_deriv, constraints=cons, method='SLSQP')
脚本遇到
ValueError
,因为
log(x)
的计算结果为负值
x
。即使不满足约束,也会对函数值进行求值


我知道在
minimize()
中使用
bounds
可以避免这个问题,但这只是我原来问题的简化。在我最初的问题中,约束
x>=1e-4
不能很容易地表示为
x
的边界,而是形式
g(x)>=C
,因此
bounds
没有帮助。

如果我们只关心
x>ε
的函数值,就可以定义一个扩展域的安全函数

log
函数为例。可以使用另一个立方函数扩展
log
,同时使桥点ε平滑:

safe_log(x) = log(x) if x > ε else a * (x - b)**3
要计算
a
b
,我们必须满足:

log(ε) = a * (ε - b)**3
1 / ε = 3 * a * (ε - b)**2
因此,安全日志功能:

eps = 1e-3

def safe_log(x):
    if x > eps:
        return log(x)
    logeps = log(eps)
    a = 1 / (3 * eps * (3 * logeps * eps)**2)
    b = eps * (1 - 3 * logeps)
    return a * (x - b)**3
看起来是这样的:


如果我们只关心ε
x>的函数值,就有可能定义一个扩展域的安全函数

log
函数为例。可以使用另一个立方函数扩展
log
,同时使桥点ε平滑:

safe_log(x) = log(x) if x > ε else a * (x - b)**3
要计算
a
b
,我们必须满足:

log(ε) = a * (ε - b)**3
1 / ε = 3 * a * (ε - b)**2
因此,安全日志功能:

eps = 1e-3

def safe_log(x):
    if x > eps:
        return log(x)
    logeps = log(eps)
    a = 1 / (3 * eps * (3 * logeps * eps)**2)
    b = eps * (1 - 3 * logeps)
    return a * (x - b)**3
看起来是这样的:


我总是为此目的使用边界,即使牺牲额外的变量或约束(但我通常使用比scipy.optimize更高级的算法)。例如,在你的情况下,我会添加
y=g(x)
,然后在
y
上加上边界。相反,您可能会返回(非常)负的约束函数值(即不可行)。@ErwinKalvelagen这是一个解决方案,但我必须提出一个修改版本的
log(x)
,该版本非常负,即使
x
略小于零,也可以派生。我可以问一下你通常使用什么高级算法吗?@peter我想他指的是商业工具,如Knitro、Baron、Conopt和co(或者通常是AMPL支持的NLP解算器)。你可以研究的开源替代方案是ipopt(如果你的问题是凸的,也可以是其他的)。是的,你需要制作你自己的安全日志函数。如果使用if语句,这并不十分困难。通常我使用大规模稀疏解算器,包括Conopt、ipopt等(取决于客户端使用的内容)。对于那些解算器来说,添加方程和变量的代价通常很低。我总是为此使用边界,即使牺牲额外的变量或约束(但我通常使用比scipy.optimize更高级的算法)。例如,在你的情况下,我会添加
y=g(x)
,然后在
y
上加上边界。相反,您可能会返回(非常)负的约束函数值(即不可行)。@ErwinKalvelagen这是一个解决方案,但我必须提出一个修改版本的
log(x)
,该版本非常负,即使
x
略小于零,也可以派生。我可以问一下你通常使用什么高级算法吗?@peter我想他指的是商业工具,如Knitro、Baron、Conopt和co(或者通常是AMPL支持的NLP解算器)。你可以研究的开源替代方案是ipopt(如果你的问题是凸的,也可以是其他的)。是的,你需要制作你自己的安全日志函数。如果使用if语句,这并不十分困难。通常我使用大规模稀疏解算器,包括Conopt、ipopt等(取决于客户端使用的内容)。对于那些解算器来说,添加方程和变量的代价通常很低。