我创建了一个需要很长时间才能运行的函数f
。约束在f
例程结束时计算。如何在不评估f
两次的情况下将这些约束返回给cobyla?
import numpy as np
from scipy.optimize import fmin_cobyla as mini
def f(x, returncons=True):
if returncons: return x[1] - x[0]
else: return (x[0] - 2)**2 + 4 * (x[1] -x[0]**2)**2
x_opt = mini(f, [1., 1.], args=(False,), cons=f)
答案 0 :(得分:1)
这是实施Paul Panzer的建议,它依赖于{3}这是一个Python 3功能。我们不能直接将此装饰器应用于目标函数,因为它接收一个NumPy数组,该数组是可变的,因此不可清除。所以我们需要两个功能:
func_with_cons
根据标量参数计算目标和约束。f
调用func_with_cons
并根据returncons
参数返回目标或约束。 请注意,我们在consargs
的调用中需要fmin_cobyla
参数,因为没有它,相同的额外参数args
将被传递给约束函数。
from scipy.optimize import fmin_cobyla as mini
from functools import lru_cache
@lru_cache(maxsize=32)
def func_with_cons(x0, x1):
return (x0 - 2)**2 + 4 * (x1 -x0**2)**2, x0 - x1
def f(x, returncons=True):
value, cons = func_with_cons(x[0], x[1])
return cons if returncons else value
func_with_cons.cache_clear()
x_opt = mini(f, (1., 1.), cons=f, args=(False,), consargs=())
print(x_opt)
print(func_with_cons.cache_info())
输出:
[ 1.14491021 1.14491021]
CacheInfo(hits=41, misses=32, maxsize=32, currsize=32)
所以,缓存有效。我将约束从x1-x0更改为x0-x1以表明它也有效(原始约束x1-x0满足此函数的全局最小值,因此它对结果没有影响)。
缓存大小可以小得多:使用maxsize=2
我们将有40次点击(与上述大小相比,41次)。
这是实施Jakob Lovern的建议。函数f将约束存储在全局变量中,函数cons从中检索它。使用全局有明显的缺点,但话说再次,这适用于Python 2.7。
def f(x):
global stored_cons
stored_cons = x[0] - x[1]
return (x[0] - 2)**2 + 4 * (x[1] -x[0]**2)**2
def cons(x):
return stored_cons
x0 = [1., 1.]
f(x0) # called to initialize stored_cons
x_opt = mini(f, x0, cons=cons)
这会返回[ 1.14491021, 1.14491021]
,因为约束不允许全局最小值[2,4]。