OBLICZENIA OPTYMALIZACYJNE W MATLABIE
Definicje pojęć, na przykładzie projektowania iteracyjnego w oparciu o przebieg charakterystyki T(f) T f
Definicje pojęć FUNKCJA CELU (objective function) (funkcjonał) = miara rozbieżności ch-ki idealnej oraz faktycznej (na danym etapie obliczeń iteracyjnych).
Definicje pojęć Parametry dobierane parametry projektowe poszukiwane w procesie optymalizacyjnym (np. parametry materiałowe, wymiarowe, systemowe, sygnałowe, ekonomiczne, układowe, itp.)
Definicje pojęć WIĘZY (constraints) (warunki ograniczające) równania lub nierówności nakładane na parametry dobierane
Toolbox optimization umożliwia: Programowanie liniowe Programownie nieliniowe Dopasowywanie krzywych analitycznych Optymalizację binarną Optymalizację wielokryterialną Optymalizację minimaksową
Optimization Toolbox GUI Polecenie optimtool aktywuje GUI (interfejs graficzny użytkownika) dla wprowadzania danych do obliczeń z wykorzystaniem toolboxu optimization
Podział podstawowy wbudowanych algorytmów optymalizacyjnych: Medium Scale lub Large-Scale Bez ustawienia opcji: Large scale(on/off) zastosowana będzie wersja domyślna dla danego algorytmu; każdy solver ma przy tym do wyboru jeden z kilku algorytmów; niektóre z nich nie dopuszczają w/w wyboru.
LARGE SCALE Metodologia large scale nie wymaga przechowywania ani operowania na pełnych macierzach. Jest tak dzięki bazowaniu na tzw. macierzach rzadkich i wewnętrznym operowaniu na nich z użyciem specjalnej Algebry macierzy rzadkich (sparse). Oznacza to znaczne zmniejszenie czasu obliczeń oraz zajętości pamięci, ale możliwe jest tylko w problemach liniowych, a nie jest np. w fundamentalnej metodyce sprzężonych gradientów.
MEDIUM-SCALE W przeciwieństwie, metodologia medium-scale tworzy pełne macierze i stosuje klasyczną algebrę liniową macierzy. Jeśli problem optymalizacyjny jest znaczny macierze te znacząco obciążają pamięć i ich przetwarzanie jest bardzo czasochłonne.
FUNKCJA FMINCON realizuje poszukiwanie minimum funkcjonału zależnego od szukanego wektora niewiadomej przy różnych typach więzów: F x
Więzy Nieliniowe: typu nierównościowego: C(x) <= 0 lub typu równościowego: Ceq(x) = 0 Wielkości c,ceq należy definiować jako wektory (!!!) lewych stron, przy zerach po stronie prawej (!!!)
oraz/lub Więzy Liniowe opisane macierzami liczbowymi: a, b, aeq, beq, lb, ub: a*x <= b aeq*x = beq lb <= x <= ub
SKŁADNIA (prawostronna): x = fmincon(@fun,x0,a,b) x = fmincon(@fun,x0,a,b,aeq,beq) x = fmincon(@fun,x0,a,b,aeq,beq,lb,ub) x = fmincon(@fun,x0,a,b,aeq,beq,lb,ub,@nonlcon) X = fmincon(@fun,x0,a,b,aeq,beq,lb,ub,@nonlcon,options)
SKŁADNIA (lewostronna): [x,fval] = fmincon(...) [x,fval,exitflag] = fmincon(...) [x,fval,exitflag,output] = fmincon(...) [x,fval,exitflag,output,lambda] = fmincon(...) [x,fval,exitflag,output,lambda,grad] = fmincon(...) [x,fval,exitflag,output,lambda,grad,hessian] = fmincon(...)
ZNACZENIA PODSTAWOWYCH PARAMETRÓW FORMALNYCH WYWOŁANIA FUNKCJI FMINCON: @fun uchwyt do funkcji celu (zwykle zdefiniowanej w m-pliku typu function). m-plik pobiera wektor x i zwraca skalar. np..: x = fmincon(@myfun,x0,a,b) gdzie: function f = myfun(x) f =... % obliczenia wartości funkcji f dla danego x.
Można też użyć uchwytu do funkcji anonimowej np.: x = fmincon(@(x)norm(x)^2,x0,a,b);
M-plik funkcji celu może też obliczać równocześnie gradient funkcji celu a jego wykorzystanie jest uwarunkowane ustawieniem opcji: options = optimset('gradobj','on')
Przykładowo: function [f,g] = myfun(x) f =... % oblicza wartość funkcji celu g =... % wartość gradientu funkcji celu
Parametr przekazujący więzy nieliniowe x = fmincon(@myfun,x0,a,b,aeq,beq,lb,ub,@mycon) mycon.m jest m-plikiem który zwraca lewe strony nierówności (i/lub równości) stanowiącym więzy NIELINIOWE. np: function [c,ceq] = mycon(x) c =... % oblicza lewe strony dla więzów nieliniowych typu <= ceq =... % lewe strony dla więzów nieliniowych typu =
Opcja z gradientem więzów nieliniowych Jeśli options = optimset('gradconstr','on') to fmincon może pobierać z tego samego pliku wartości gradientu więzów nieliniowych:
Opcja z gradientem więzów nieliniowych function [c,ceq,gc,gceq] = mycon(x) c =... % ceq =... % if nargout > 2 % mycon wywoływane z %czterema wartościami wyjściowymi GC =... % Gradienty więzów niel. typu <= GCeq =... % typu =
output struktura zawierająca informacje o przebiegu obliczeń optymalizacyjnych w trakcie oraz po ich zakończeniu. Elementy tej danej strukturalnej to np.: iterations - liczba wykonanych iteracji algorithm - typ zastosowanego algorytmu stepsize końcowy rozmiar kroku dla niewiadomej.
Wybrane opcje ustawialne przez użytkownika, przy użyciu polecenia optimset: GradObj MaxFunEvals max liczba obliczeń funkcji celu MaxIter max liczba iteracji TolFun tolerancja f. celu TolCon tolerancja więzów TolX tolerancja określenia wartości rozwiązania
Ograniczenia: Operujemy tylko na wartościach rzeczywistych fmincon działa tylko dla funkcji mających ciągłe pierwsze pochodne cząstkowe Uzyskuje się rozwiązania dla minimów lokalnych
Ustawianie opcji dla sposobu wykonywania obliczeń optymalizacyjnych. optimset fmincon zwraca wykaz wartości składowych struktury options oraz ich domniemanych wartości. options = optimset('param1',value1,'param2',value2,...) ustawia wybrane wartości. Niewymienione składowe zachowują wartości domyślne. Podobnie działa podstawienie [].
Przykład optymalizacji z więzami nieliniowymi Niech dana jest minimalizowana funkcja dwóch zmiennych f(x1,x2) = exp(x1) * *(4*x1*x1+2*x2*x2+4*x1*x2+2*x2+1)
z więzami: X1*x2-x1-x2+1.5<0 -x1*x2-10<0
Zakładamy co jest (jednym!!!) szukanym wektorem x X(1) = x1 X(2) = x2
Etap 1: Piszemy M-plik objfun.m dla funkcji celu function f = objfun(x) f1 = exp(x(1))*(4*x(1)^2 + 2*x(2)^2 f2=4*x(1)*x(2) + 2*x(2) + 1); f=f1+f2
Etap 2: Piszemy M-plik confun.m dla więzów. function [c, ceq] = confun(x) % więzy nierównościowe c = [1.5 + x(1)*x(2) - x(1) - x(2); -x(1)*x(2) - 10]; % więzy równościowe ceq = [];
Etap 3: Aktywujemy procedurę optymalizacyjną. x0 = [-1;1]; % Przekazujemy opcjonalną % wartość startową options = optimset('largescale','off'); [x, fval] =... fmincon(@objfun,x0,[],[],[],[],[],[],@confun, options)
Uzyskujemy przykładowy wynik obliczeń: x = -9.5474 1.0474 fval = 0.0236
Przykład z wykonywaniem obliczeń gradientów domyślnie wersja medium-scale liczy wartości gradientów numerycznie metodą różnic skończonych, zaś wersja large-scale wymaga wprowadzenia (do m-pliku liczącego funkcję celu) wzorów analitycznych do obliczania gradientów
Etap 1: piszemy M-plik obliczający wartość funkcji celu oraz gradient tej funkcji function [f,g] = objfungrad(x) f = exp(x(1))*(4*x(1)^2+2*x(2)^2+ 4*x(1)*x(2)+2*x(2)+1); % Gradient funkcji celu t = exp(x(1))*(4*x(1)^2+2*x(2)^2+ 4*x(1)*x(2)+2*x(2)+1); G = [ t + exp(x(1)) * (8*x(1) + 4*x(2)), exp(x(1))*(4*x(1)+4*x(2)+2)];
Etap 2: Piszemy M-plik obliczający wektory więzów nieliniowych oraz macierz gradientu tych więzów function [c,ceq,dc,dceq] = confungrad(x) c(1) = 1.5 + x(1) * x(2) - x(1) - x(2); %Więzy %nieliniowe c(2) = -x(1) * x(2)-10; % Gradient tych więzów DC= [x(2)-1, -x(2); x(1)-1, -x(1)]; % Zaś przy braku więzów nieliniowych typu %równościowego: ceq=[]; DCeq = [ ];
Uwaga: Skoro wprowadziliśmy możliwość analitycznego obliczania gradientów w funkcjach objfungrad.m oraz confungrad.m, to musimy przekazać o tym informację aby odpowiednie wzory zostały w ogóle przez procedurę fmincon użyte!!!: Robi się to poleceniem: options = optimset(options,'gradobj','on', 'GradConstr','on');
Etap 3: Aktywujemy procedurę optymalizacyjną: x0 = [-1,1]; % Punkt startowy dla niewiadomej options = optimset('largescale','off'); options = optimset(options,'gradobj','on', 'GradConstr','on'); [x,fval] = fmincon(@objfungrad,x0,[],[],[],[],lb,ub,... @confungrad,options)
x = -9.5474 1.0474 fval = 0.0236 Otrzymujemy:
Dobór wartości startowych dla poszukiwanej niewiadomej w procesie optymalizacyjnym jest sprawą zasadniczą!!! Najlepiej jeśli wartości są przynajmniej współmierne z przewidywanym wynikiem końcowym. Procedura fmincon prowadzi zwykle do znalezienia najbliższego minimum lokalnego!!!
Algorytmy dostępne w fmincon 'interior-point' 'sqp' 'active-set' 'trust-region-reflective' (default) Możemy (ale nie musimy) wybrać algorytm poleceniem: options = optimset('algorithm','sqp');
Rekomendacje przy ewentualnym doborze algorytmu Zaczynamy od algorytmu 'interior-point'. Jeśli nie jest pozytywnie to próbujemy następnie zastosować algorytm 'sqp', a następnie 'activeset. Stosujemy 'trust-region-reflective jeśli jest to możliwe; w tym przypadku problem musi mieć: funkcję celu liczącą również gradienty; możliwe są więzy tylko liniowe równościowe lub typu bounds, ale nie obu tych typów na raz.
Uwagi przydatne przy ewentualnym doborze algorytmu dla fmincon 'interior-point' radzi z dużymi rzadkimi modelami, jak też z małymi ale gęstymi. Algorytm spełnia więzy w trakcie całych iteracji oraz wykrywa wyniki typu NaN lub Inf; jest algorytmem typu largescale. 'sqp (sequential quadratic programming) spełnia warunki ograniczeń bezpośrednich w trakcie wszystkich iteracji; wykrywa wyniki typu NaN lub Inf; przy tym nie jest algorytmem typu largescale. 'active-set' może stosować duże przyrosty (kroki), dzięki czemu wzrasta prędkość poszukiwań; radzi sobie niekiedy z więzami nonsmooth ; przy tym nie jest algorytmem typu large-scale.
Przekazywanie ekstra parametrów dla solver a fmincon zagnieżdżanie we wspólnym, dodatkowym m-pliku typu function, którego parametrami formalnymi wywołania są dane/zmienne dodatkowo potrzebne w obliczeniach: /a/ m-pliku liczącego funkcję celu, /b/ linii kodu z wywołaniem fmincon np.: function [x,fval] = runnested(a,b,c,x0) [x,fval] = fminunc(@nestedfun,x0); % Nested function that computes the objective function function y = nestedfun(x) y = (a - b*x(1)^2 + x(1)^4/3)*x(1)^2 + x(1)*x(2) +... (-c + c*x(2)^2)*x(2)^2; end end
Optymalizacja binarna --- Bintprog minimalizujemy iloczyn f*x przy więzach liniowych opisanych macierzami a, b, aeq, beq f, b, beq - wektory, A i Aeq macierze, zaś rozwiązanie X jest wektorem binarnym.
Składnia: x = bintprog(f) x = bintprog(f,a,b) x = bintprog(f,a,b,aeq,beq) x = bintprog(f,a,b,aeq,beq,x0) x = bintprog(f,a,b,aeq,beq,x0,options) [x, fval] = bintprog(...) [x,fval,exitflag] = bintprog(...) [x,fval,exitflag,output] = bintprog(...)
Exitflag liczba całkowita zwracana przez bintprog, określająca samoocenę powodu zakończenia obliczeń: 0 przekroczono założoną wartość maksymalną ilości iteracji 1 proces zbieżny i rozwiązany poprawnie 2 problem optymalizacyjny oceniony jako źle sformułowany 5 - przekroczono założoną wartość maksymalną czasu obliczeń
Algorytm stosowany przez bintprog to odmiana programowania liniowego (simplexu). Obliczenia prowadzone są w przestrzeni liczb rzeczywistych (z ograniczeniem wartości [0,1]), po czym przesuwa się kolejne składowe szukanego wektora znalezione rozwiązanie do bliższego o wartości binarnej. Nie jest to więc na ogół rozwiązanie optymalne, ale za to binarne.
Przykład: Minimalizujemy funkcjonał F(x1,x2,x3,x4) = -9*x1-5*x2-6*x3-4*x4 gdzie x1, x2, x3, x4 są szukane jako liczby binarne.
Znane więzy to: 6*x1+3*x2+5*x3+2*x4 < 9 x3+x4 < 1 -x1+x3 < 0 -x2+x4 < 0
Wprowadzamy: f = [-9; -5; -6; -4]; A = [6 3 5 2; 0 0 1 1; -1 0 1 0; 0-1 0 1]; b = [9; 1; 0; 0]; Aktywujemy obliczenia: x = bintprog(f,a,b) Wynik: x = [1;1;0;0]
FUNKCJA LSQCURVEFIT realizuje znajdowanie współczynników które występują w zapisie analitycznym krzywej ciągłej, tak aby krzywa ta była optymalnie dopasowana do dyskretnego zbioru punktów (np. danych pomiarowych), w sensie średniokwadratowym.
FUNKCJA LSQCURVEFIT Załóżmy że przez dobór składowych wektora x krzywa ciągła określona pewną funkcją: G=G(x) przebiegnie jak najbliżej dyskretnego zbiór punktów opisanych parą znanych wektorów xdata (wektor dla osi odciętych), oraz ydata (wektor dla osi rzędnych). Oznaczałoby to zbliżenie wartości G(i) = ydata(i) dzięki trafnemu doborowi składowych x(k) wektora x. Dobór taki jest celem optymalizacji realizowanej przez funkcję lsqcurvefit. W trakcie obliczeń minimalizowana jest suma kwadratów odchyłek punktów danych od kolejno korygowanego przebiegu krzywej ciągłej.
Składnia: x = lsqcurvefit(fun,x0,xdata,ydata,lb,ub,options) [x,resnorm,residual,exitflag,output] = lsqcurvefit(...) Fun jest uchwytem do m-pliku który dla danej kolejnej wartości wektora x oblicza sumę kwadratów odchyłek punktów danych od kolejno korygowanego (przez zmiany wektora x)przebiegu krzywej ciągłej.
Algorytmy stosowane przez lsqcurvefit: Przez domniemanie lsqcurvefit używa opcji Large-Scale Optimization i opiera się na modyfikacji algorytmu Newtona. W każdej iteracji rozwiązywany jest układ równań liniowych o dużych rozmiarach, którego przybliżone rozwiązanie uzyskuje się metodą sprzężonych gradientów.
Przy wymuszeniu wersji Medium-Scale, lsqcurvefit stosuje algorytm LineSearchType Levenberg-Marquardt a z liniowym przeszukiwaniem. Alternatywnie można wybrać algorytm Gaussa-Newtona przez ustawienie opcji LevenbergMarquardt jako 'off' (przy LargeScale jako 'off').
Domyślny algorytm LineSearchType jest opcjonalnie ustawiony na 'quadcubic', co stanowi połączenie interpolacji oraz ekstrapolacji wielomianów kwadratowych i trzeciego stopnia. Można użyć tylko wielomianów kubicznych przez ustawienie opcji LineSearchType jako 'cubicpoly'; skutkuje to szybszą zbieżnością, ale ma sens tylko gdy wprowadzamy analityczne obliczanie gradientu.
Przykład użycia lsqcurvefit: Dla danych wektorów xdata and ydata, chcemy obliczyć współczynniki x(1) oraz x(2) szukanego wektora x, tak aby znaleźć najlepsze dopasowanie do krzywej ciągłej określonej przez funkcję: x(1)*exp(x(2)*xdata(i))
Szukana jest więc optymalna (minimalna) wartość funkcjonału: F(x,xdata, ydata) = Suma (i) (x(1)*exp(x(2)*xdata)- ydata) 2 W przestrzeni dwuwymiarowej wektora x, przy czym sumowanie obejmuje wszystkie punkty dane
Przyjmujemy punkt startowy do obliczeń niewiadomej x, np.: x0 = [100; -1];
Tworzymy M-plik który ma zwracać wartości funkcji F: function F = myfun(x,xdata) F = x(1)*exp(x(2)*xdata);
Następnie wywołujemy procedurę optymalizacyjną: % Podajemy wartości uzyskane eksperymentalnie: xdata = [0.9 1.5 13.8 19.8 24.1 28.2 35.2 60.3 74.6 81.3]; ydata = [455.2 428.6 124.1 67.3 43.2 28.1 13.1-0.4-1.3-1.5]; x0 = [100; -1] % Punkt startowy [x,resnorm] = lsqcurvefit(@myfun,x0,xdata,ydata)
Uwaga: w momencie wywołania lsqcurvefit, xdata oraz ydata muszą być znane i mieć taki sam rozmiar.
Uzyskujemy: x = 498.8309-0.1013 resnorm = 9.5049
Przykładowe zadania optymalizacyjne
1/ Dobrać ilość identycznych urządzeń kupowanych od M producentów z K krajów, jeśli ze względów strategicznych z krajów tych kupujemy nie więcej niż odpowiednio: 40, 45, 50 procent całości, a z każdej firmy co najmniej 5 procent. Znane są ceny u poszczególnych producentów, dążymy do minimalizacji łącznych kosztów zakupu, a nie możemy wydać więcej niż dysponowane środki finansowe. /fmincon/
2/ Dane są współrzędne płaszczyznowe określające lokalizację dwóch stacji bazowych. Wyznaczyć optymalne położenie trzeciej stacji, jeśli chcemy aby suma kwadratów odległości od dwóch stacji istniejących była jak najmniejsza.
3/ W zadaniu /2/ dodać wymóg aby stacja trzecia nie była bliżej niż dany dystans L do żadnej z dwóch istniejących.
4/ Dobrać lokalizację trzeciej stacji bazowej telefonii komórkowej, zakładając że jej minimalna odległość oraz maksymalna odległość do dwóch stacji istniejących są dane; przy tym minimalizujemy straty mocy (czyli odwrotność kwadratu odległości) przy transmisji do stacji bardziej odległej. /fmincon/
5/ Dla danego histogramu z pomiarów serii podzespołów, określić oba parametry normalnego rozkładu prawdopodobieństwa, który dopasowujemy do tego histogramu w sensie średniokwadratowym. /lsqcurvefit/
6/ Dla danych M próbek pomiarowych w funkcji czasu dopasować do nich ciągłą harmoniczną funkcję czasu przez dobór amplitudy, częstotliwości oraz przesunięcia fazy. /lsqcuvefit/
7/ Dobrać przydział trzech procesorów do trzech procesów. Znane są czasy obsługi dla każdej z dziewięciu możliwych par. Celem jest minimalizacja sumy czasów obsługi. /bintprog/
7/ Dobrać rozdział n procesów do m procesorów w sieci, znając wszystkie miary efektywności obsługi oraz dodatkowo wymagając aby wskazane grupy procesów nie były ustawione w kolejkę do tego samego procesora. Dodatkowo rozpatrzeć to samo zadanie po wprowadzeniu określonych priorytetów dla kolejności obsługi. /bintprog/