2014-09-23 8 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 목록의 구성에 있습니다. 은 즉, 파이썬 (자바 스크립트)에서 람다 및 기타 내부 범위의 기능 변수의 바인딩 어휘, 그리고 방식으로 행동하지 않는 당신은 가정 루프가 완료 http://eev.ee/blog/2011/04/24/gotcha-python-scoping-closures/ 후, 변수 lowerupper0inf이 , 변수 factor은 값이 1이고이 값은 모든 람다 함수에서 사용되는 값입니다.

한 가지 해결 방법은 명시 적으로 더미 키워드 인수로 변수의 특정 값을 결합하는 것이다

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) 

번째 방법은 람다를 생성하는 공장 기능을 추가하는 것이다.

+0

와우. 파이썬의 범위가 나에게 잡힌 것은 이번이 처음입니다. – MikeRand