2014-09-23 139 views
1

我使用COBYLA在约束条件下对线性目标函数进行成本最小化。我通过为每个包含一个约束来实现下限和上限。scipy - 为什么COBYLA不尊重约束?

import numpy as np 
import scipy.optimize 

def linear_cost(factor_prices): 
    def cost_fn(x): 
     return np.dot(factor_prices, x) 
    return cost_fn 


def cobb_douglas(factor_elasticities): 
    def tech_fn(x): 
     return np.product(np.power(x, factor_elasticities), axis=1) 
    return tech_fn 

def mincost(targets, cost_fn, tech_fn, bounds): 

    n = len(bounds) 
    m = len(targets) 

    x0 = np.ones(n) # Do not use np.zeros. 

    cons = [] 

    for factor in range(n): 
     lower, upper = bounds[factor] 
     l = {'type': 'ineq', 
      'fun': lambda x: x[factor] - lower} 
     u = {'type': 'ineq', 
      'fun': lambda x: upper - x[factor]} 
     cons.append(l) 
     cons.append(u) 

    for output in range(m): 
     t = {'type': 'ineq', 
      'fun': lambda x: tech_fn(x)[output] - targets[output]} 
     cons.append(t) 

    res = scipy.optimize.minimize(cost_fn, x0, 
            constraints=cons, 
            method='COBYLA') 

    return res 

COBYLA不尊重上限或下限约束,但它确实尊重技术约束。

>>> p = np.array([5., 20.]) 
>>> cost_fn = linear_cost(p) 

>>> fe = np.array([[0.5, 0.5]]) 
>>> tech_fn = cobb_douglas(fe) 

>>> bounds = [[0.0, 15.0], [0.0, float('inf')]] 

>>> mincost(np.array([12.0]), cost_fn, tech_fn, bounds) 
     x: array([ 24.00010147, 5.99997463]) 
message: 'Optimization terminated successfully.' 
    maxcv: 1.9607782064667845e-10 
    nfev: 75 
    status: 1 
success: True 
    fun: 239.99999999822359 

为什么COBYLA不尊重第一个因素约束(即上限@ 15)?

回答

3

COBYLA 实际上尊重你给的所有界限。

问题在于cons列表的构建。 即,Python(和Javascript)中lambda和其他内部作用域函数中变量的绑定是词汇,并且不像您假设的那样工作:http://eev.ee/blog/2011/04/24/gotcha-python-scoping-closures/循环完成后,变量lowerupper的值分别为0inf ,变量factor的值为1,这些值是所有lambda函数都使用的值。

一个解决方法是变量的特定值显式地绑定到虚设关键字参数:

for factor in range(n): 
    lower, upper = bounds[factor] 
    l = {'type': 'ineq', 
     'fun': lambda x, a=lower, i=factor: x[i] - a} 
    u = {'type': 'ineq', 
     'fun': lambda x, b=upper, i=factor: b - x[i]} 
    cons.append(l) 
    cons.append(u) 

for output in range(m): 
    t = {'type': 'ineq', 
     'fun': lambda x, i=output: tech_fn(x)[i] - targets[i]} 
    cons.append(t) 

的第二种方式是增加一个工厂函数产生lambda表达式。

+0

哇。这是Python首次接受我的范围。 – MikeRand 2014-09-23 11:11:36