约束优化,其中约束被计算为目标函数的一部分

时间:2017-12-08 00:32:37

标签: python optimization scipy

我创建了一个需要很长时间才能运行的函数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)

1 个答案:

答案 0 :(得分:1)

LRU缓存

这是实施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]。