2015-05-27 19 views
6

Próbuję znaleźć lokalne minimum funkcji, a parametry mają stałą sumę. Na przykład,Optymalizacja R z ograniczeniami równości i nierówności

Fx = 10 - 5x1 + 2x2 - x3

i warunki są następujące

x1 + x2 + x 3 = 15

(x1 x2, x3)> = 0

Gdzie suma x1, x2 i x3 ma znaną wartość i wszystkie są większe od zera. W R, to wyglądać tak,

Fx = function(x) {10 - (5*x[1] + 2*x[2] + x[3])} 
opt = optim(c(1,1,1), Fx, method = "L-BFGS-B", lower=c(0,0,0), upper=c(15,15,15)) 

Próbowałem też użyć nierówności z constrOptim zmusić sumę naprawy. Nadal uważam, że może to być prawdopodobna praca, ale nie byłem w stanie sprawić, by działała. Jest to uproszczony przykład rzeczywistego problemu, ale wszelka pomoc byłaby bardzo doceniana.

Odpowiedz

6

Przy tej okazji optim nie będzie działać w sposób oczywisty, ponieważ masz ograniczenia równości. constrOptim nie będzie działać z tego samego powodu (próbowałem przekonwertować równość na dwie nierówności, tj. Większą i mniejszą niż 15, ale to nie zadziałało z constrOptim).

Istnieje jednak pakiet dedykowany do tego rodzaju problemów i jest to Rsolnp.

go używać w następujący sposób:

#specify your function 
opt_func <- function(x) { 
    10 - 5*x[1] + 2 * x[2] - x[3] 
} 

#specify the equality function. The number 15 (to which the function is equal) 
#is specified as an additional argument 
equal <- function(x) { 
    x[1] + x[2] + x[3] 
} 

#the optimiser - minimises by default 
solnp(c(5,5,5), #starting values (random - obviously need to be positive and sum to 15) 
     opt_func, #function to optimise 
     eqfun=equal, #equality function 
     eqB=15, #the equality constraint 
     LB=c(0,0,0), #lower bound for parameters i.e. greater than zero 
     UB=c(100,100,100)) #upper bound for parameters (I just chose 100 randomly) 

wyjściowa:

> solnp(c(5,5,5), 
+  opt_func, 
+  eqfun=equal, 
+  eqB=15, 
+  LB=c(0,0,0), 
+  UB=c(100,100,100)) 

Iter: 1 fn: -65.0000  Pars: 14.99999993134 0.00000002235 0.00000004632 
Iter: 2 fn: -65.0000  Pars: 14.999999973563 0.000000005745 0.000000020692 
solnp--> Completed in 2 iterations 
$pars 
[1] 1.500000e+01 5.745236e-09 2.069192e-08 

$convergence 
[1] 0 

$values 
[1] -10 -65 -65 

$lagrange 
    [,1] 
[1,] -5 

$hessian 
      [,1]  [,2]  [,3] 
[1,] 121313076 121313076 121313076 
[2,] 121313076 121313076 121313076 
[3,] 121313076 121313076 121313076 

$ineqx0 
NULL 

$nfuneval 
[1] 126 

$outer.iter 
[1] 2 

$elapsed 
Time difference of 0.1770101 secs 

$vscale 
[1] 6.5e+01 1.0e-08 1.0e+00 1.0e+00 1.0e+00 

Tak powstałe optymalnymi wartościami są:

$pars 
[1] 1.500000e+01 5.745236e-09 2.069192e-08 

co oznacza, że ​​pierwszy parametr jest 15 i reszta zero i zero. Jest to rzeczywiście minimum globalne w twojej funkcji, ponieważ x2 dodaje się do funkcji, a 5 * x1 ma znacznie większy (negatywny) wpływ niż x3 na wynik. Wybór 15, 0, 0 jest rozwiązaniem i globalnym minimum dla funkcji zgodnie z ograniczeniami.

Funkcja działała świetnie!

4

Jest to właściwie problem programowania liniowego, więc naturalnym podejściem byłoby użycie liniowego programatora, takiego jak pakiet lpSolve. Trzeba zapewnić obiektywną funkcję i matrycę wiązania i solver zrobi resztę:

library(lpSolve) 
mod <- lp("min", c(-5, 2, -1), matrix(c(1, 1, 1), nrow=1), "=", 15) 

Następnie można uzyskać dostęp do optymalnego rozwiązania, a wartość obiektywną (dodając stały termin 10, który nie jest dostarczany do Solver):

mod$solution 
# [1] 15 0 0 
mod$objval + 10 
# [1] -65 

liniowy solver programowanie powinno być znacznie szybciej niż ogólny nieliniowej optymalizacji solver i nie powinien mieć problemów ze zwróceniem dokładnie optymalnego rozwiązania (zamiast pobliskiego punktu, które mogą być obarczone błędami zaokrągleń).

+1

Niezły! Kiedy PO mówi: "To jest uproszczony przykład prawdziwego problemu", to myślę, że rzeczywisty problem może być nieliniowy. Tak więc, aby upewnić się, zasugerowałem metodę nieliniową (która działa mimo to, nawet jeśli jest wolniejsza). Zapewnienie gradientu (prostego w tym przypadku) czyni go jeszcze szybszym, jeśli prędkość jest problemem. W każdym razie, nie mam na myśli złego, to naprawdę dobrze, że dodałaś tę odpowiedź, zdecydowanie pomocna. – LyzandeR

Powiązane problemy