2017-05-16 1 views
13

와 다 변수 비선형 솔버, 당신은 어떻게 x의 기능 설정 제약의 뿌리를 찾을 수 있습니까? 예 : x의 각 구성 요소에 대한 범위.파이썬 : 함수 입력 벡터 <code>x</code>를 받아 같은 길이의 벡터를 반환 <code>f(x)</code> 감안할 때 제약

놀랍게도 이에 대한 유용한 정보를 많이 찾을 수 없었습니다. Optimization and Root finding algorithms에 대한 scipy 목록에는 brentq과 같은 스칼라 함수에 대한 몇 가지 옵션이있는 것 같습니다. 하지만 다 변수의 경우 이러한 옵션을 지원하는 알고리즘을 찾을 수 없습니다.

물론 반환 된 벡터의 각 구성 요소를 제곱 한 다음 differential_evolution과 같은 최소화 기 (실제로 생각한 유일한 단 하나)와 같은 방법으로 해결할 수 있습니다. 뉴턴 알고리즘의 2 차 수렴을 없애기 때문에 이것이 좋은 전략이라고 상상할 수는 없습니다. 또한 나는 이것이 정말로 공통적 인 문제 일 것이기 때문에 이것에 대한 선택권이없는 것 같아서 정말 놀랍다. 내가 놓친 게 있니?

+0

어쩌면 내가 틀렸지 만 게시 한 링크에서 '스칼라'바로 아래에서 '다차원'을 찾을 수 있습니다. 찾고있는 것 : https://docs.scipy.org/doc/scipy/reference /optimize.html#multidimensional –

+1

@JanZeiseweis는 지금까지 내가 볼 수있는대로 나열된 다차원 솔버의에 제약을를 사용하는 옵션이 없습니다. Wolpertinger가 물어 보는 것 같아요. – jotasi

+0

@jotasi 사실 그건 완전히 잊어 버렸습니다. 원칙적으로 감사 –

답변

5

솔버에게에만 제한된 지역에 뿌리를두고 기능을 제공하는 것이이 문제를 해결하려면 (특히 좋은 그러나 희망 작동하지 않는) 옵션을 하나하고는 해결사가 보장하는 방식으로 계속 적절한 지역으로 밀려났습니다 (here과 같지만 다차원입니다).

하나가이 (직사각형 제약 적어도) 선형 함수의 경계 값부터 계속 된 constrainedFunction을 구현하는 것입니다 달성하기 위해 할 수있는 무엇 :

import numpy as np 

def constrainedFunction(x, f, lower, upper, minIncr=0.001): 
    x = np.asarray(x) 
    lower = np.asarray(lower) 
    upper = np.asarray(upper) 
    xBorder = np.where(x<lower, lower, x) 
    xBorder = np.where(x>upper, upper, xBorder) 
    fBorder = f(xBorder) 
    distFromBorder = (np.sum(np.where(x<lower, lower-x, 0.)) 
         +np.sum(np.where(x>upper, x-upper, 0.))) 
    return (fBorder + (fBorder 
         +np.where(fBorder>0, minIncr, -minIncr))*distFromBorder) 

이 기능을 전달할 수있는 x 값을 지정하고 계속 진행하려는 함수 f과 모든 모양에서 상한 및 하한을 지정하는 x과 같은 모양의 lowerupper의 두 배열을 사용할 수 있습니다. 이제 원래 함수가 아닌이 함수를 해석기에 전달하여 근본을 찾을 수 있습니다.

경계의 가파른 점프는 국경에서 기호 변경에 대한 급격한 점프를 방지하기 위해 순간적으로 경계 값으로 사용됩니다. 제한된 영역 외부의 루트를 방지하기 위해 일부 작은 값이 양수/음수 경계 값에 더 해지고/빼집니다. 나는 이것이 이것을 처리하는 아주 좋은 방법이 아니라는 것에 동의하지만, 작동하는 것처럼 보인다.

다음은 두 가지 예입니다. 두 가지 모두에 대해 초기 추측은 구속 된 영역 외부에 있지만 구속 된 영역의 올바른 루트가 발견됩니다.구속 다차원 코사인 뿌리 찾기

[-2, -1] X [1, 2] 준다 :

from scipy import optimize as opt 

opt.root(constrainedFunction, x0=np.zeros(2), 
     args=(np.cos, np.asarray([-2., 1.]), np.asarray([-1, 2.]))) 

준다 :이 또한 기능 작동

fjac: array([[ -9.99999975e-01, 2.22992740e-04], 
     [ 2.22992740e-04, 9.99999975e-01]]) 
    fun: array([ 6.12323400e-17, 6.12323400e-17]) 
message: 'The solution converged.' 
    nfev: 11 
    qtf: array([ -2.50050470e-10, -1.98160617e-11]) 
     r: array([-1.00281376, 0.03518108, -0.9971942 ]) 
    status: 1 
success: True 
     x: array([-1.57079633, 1.57079633]) 

그런 대각선되지 않습니다

def f(x): 
    return np.asarray([0., np.cos(x.sum())]) 

opt.root(constrainedFunction, x0=np.zeros(2), 
     args=(f, np.asarray([-2., 2.]), np.asarray([-1, 4.]))) 

을 제공합니다

이미 떨어져 교차 한 수있는 무언가를 제안의 위험에서
fjac: array([[ 0.00254922, 0.99999675], 
     [-0.99999675, 0.00254922]]) 
    fun: array([ 0.00000000e+00, 6.12323400e-17]) 
message: 'The solution converged.' 
    nfev: 11 
    qtf: array([ 1.63189544e-11, 4.16007911e-14]) 
     r: array([-0.75738638, -0.99212138, -0.00246647]) 
    status: 1 
success: True 
     x: array([-1.65863336, 3.22942968]) 
+0

멋진 답변에 감사드립니다. 이 트릭으로 기존 솔버에 연결하는 방법을 정말 좋아합니다.저는 현재 두 가지 답변이 모두 마음에 들기 때문에 당신이나 쿠엔틴에게 현상금을 제공할지 여부를 논의하고 있습니다. – Wolpertinger

+0

@Wolpertinger 기꺼이 도와 드리겠습니다. 솔직히, 나는 이것에 대한 scipy 함수를 빌드하는 것처럼 보이지 않는다는 것에 놀라움을 금치 못했다. 내 생각에 일반적인 제약 (몇 가지 간격뿐만 아니라) 문제를 해결할뿐만 아니라 멋진 API 디자인을 갖는 것은 다소 어려울 것입니다. – jotasi

8

당신이 제약 최적화를 처리하려는 경우, 당신은 여기에 scipy.optimize

보다 훨씬 쉽게 패키지에 대한 링크입니다 손쉬운 lirbary, 사용할 수 있습니다

https://pypi.python.org/pypi/facile/1.2

예를 들어 쉬운 라이브러리를 사용하는 방법은 다음과 같습니다. 여기서 작성한 내용은 수정해야합니다. 이는 일반적인 것입니다. 오류가 발생하면 어느 것을 말해주십시오.

import facile 

# Your vector x 

x = [ facile.variable('name', min, max) for i in range(Size) ] 


# I give an example here of your vector being ordered and each component in a range 
# You could as well put in the range where declaring variables 

for i in range(len(x)-1): 
    facile.constraint(x[i] < x[i+1]) 
    facile.constraint(range[i,0] < x[i] < range[i,1]) #Supposed you have a 'range' array where you store the range for each variable 


def function(...) 
# Define here the function you want to find roots of 


# Add as constraint that you want the vector to be a root of function 
facile.constraint(function(x) == 0) 


# Use facile solver 
if facile.solve(x): 
    print [x[i].value() for i in range(len(x))] 
else: 
    print "Impossible to find roots" 
+0

+1 그리고 귀하의 답변, 특히 새로운 예를 들어 주셔서 감사합니다. 나는 이것이 나의 모범을 위해 작동하는지 시험해 볼 것이다. – Wolpertinger

+0

하나 더 질문 :이 복잡한 숫자를 처리 할 수 ​​있습니까? (그렇지 않다면 나는 단지 실재와 허수 부를 분리 할 것이다) – Wolpertinger

+0

좋은 질문 ... 나는 그것이 가능하다고 생각하지 않는다. 변수를 선언 할 때 사용할 형식을 미리 정할 때 인수를 사용할 수 있습니다. 아마도 복소수가 포함될 수 있습니다. 문서에는 아무 것도 없습니다. –

2

, 나는이 그냥 scipy.minimize으로 가능해야한다 생각합니다. 캐치는 함수 인수가 벡터/목록 일 수 있습니다 하나의 인수 하지만이 있어야한다는 것입니다.

그래서 F (x, y)가 단지 (z) 여기서, Z = [X, Y, f는해진다. 당신이 건너하지 않은 경우 유용 할 수

좋은 예는 here이다.

# Specify a (lower, upper) tuple for each component of the vector  
bnds = [(0., 1.) for i in len(x)] 

을 그리고 minimizebounds 매개 변수로 사용 : 당신이 경계를 부과하려는 경우 당신이 언급 한 바와 같이

, × 1 벡터를 들어, 사용할 수 있습니다.

+0

나는 이것을 초기에 upvoted했지만, 어쨌든 이것은 단지 최적화가 아니라 루트 발견이 아니라는 것을 놓쳤습니다. 그래서 나는 실제로 질문에 답하는 것 같지 않습니다. 이것은 최적화에 관한 것이 아니라 명시 적입니다. – Wolpertinger

+0

아, 미안 해요. 간단한 수정이 있습니다. ** 당신의 기능이 무엇이든 가져 가라. 그리고 그것이 현재 돌아 오는 것의 절대 값 **을 돌려 주도록하라. 함수가 0으로 최소화되기 때문에 이것은 당신에게 당신의 뿌리를 줄 것입니다. 나는. 'f (x ** 3)'는 단지'return abs (x ** 3)'가됩니다. –

+1

* * 명시 적으로 말하자면, 뉴튼의 알고리즘의 2 차 수렴을 없애기 때문에 나는 그것을 원하지 않는다고 말한 ... – Wolpertinger

관련 문제