2014-09-23 112 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