One (niezbyt ładne, ale mam nadzieję, że praca) możliwość obejścia tego problemu byłoby dać solver funkcję, która ma tylko korzenie w ograniczonej regionie, który jest kontynuowany w sposób zapewniający, że Solver jest odepchnięto w odpowiednim regionie (trochę jak here, ale w wielu wymiarach).
co można zrobić, aby osiągnąć to (przynajmniej dla prostokątnych ograniczeń) jest wdrożenie constrainedFunction
że jest liniowo kontynuowane począwszy od wartości granicznej swojej funkcji:
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)
Możesz przekazać tę funkcję x
wartość, funkcja f
, którą chcesz kontynuować, a także dwie macierze lower
i upper
o takim samym kształcie, jak x
, nadające dolny i górny margines we wszystkich wymiarach. Teraz możesz przekazać tę funkcję zamiast oryginalnej funkcji solverowi, aby znaleźć korzenie.
Stromość kontynuacji jest po prostu brana jako wartość graniczna, aby zapobiec skokom w górę przy zmianie znaku na granicy. Aby zapobiec korzeniom poza ograniczonym regionem, niektóre małe wartości są dodawane/odejmowane do dodatnich/ujemnych wartości granicznych. Zgadzam się, że nie jest to bardzo dobry sposób na poradzenie sobie z tym, ale wydaje się, że działa.
Oto dwa przykłady. Zarówno początkowe odgadnięcie znajduje się poza ograniczonym regionem, ale także znaleziony właściwy root w ograniczonym regionie.
Znalezienie korzeniami wielowymiarowy cosinus zamocowanym do [-2, -1] x [1, 2] otrzymujemy:
from scipy import optimize as opt
opt.root(constrainedFunction, x0=np.zeros(2),
args=(np.cos, np.asarray([-2., 1.]), np.asarray([-1, 2.])))
otrzymujemy:
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])
ta działa także dla funkcji nie są przekątna:
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.])))
daje:
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])
Może się mylę, ale w linku, który opublikowałeś, tuż pod 'Scalar' możesz znaleźć 'Multidimensional', który wygląda tak, jak szukasz: https://docs.scipy.org/doc/scipy/reference /optimize.html#multidimensional –
@JanZeiseweis O ile widzę, nie ma opcji użycia ograniczeń w żadnym z wielowymiarowych rozwiązań, które są wymienione. Zgaduję, o to właśnie pyta Wolpertinger. – jotasi
@jotasi To prawda, całkowicie o tym zapomniałem. Dzięki –