Materiały pomocnicze do ćwiczeń laboratoryjnych T1 część II
Transkrypt
Materiały pomocnicze do ćwiczeń laboratoryjnych T1 część II
Politechnika Gdańska Wydział Elektrotechniki i Automatyki Katedra Inżynierii Systemów Sterowania Metody optymalizacji Narzędzia optymalizacji w środowisku MATLAB Materiały pomocnicze do ćwiczeń laboratoryjnych T1 część II Opracowanie: Piotr Hirsch, mgr inż. Kazimierz Duzinkiewicz, dr hab. inż. Gdańsk, 04.2016 1. Wstęp. Do wykonania zadań laboratoryjnych niezbędna jest podstawowa znajomość środowiska programowego MATLAB w zakresie obejmowanym na przedmiocie Technologie Informatyczne. Ten materiał pomocniczy koncentruje się na przypomnieniu i rozszerzeniu wiedzy na temat sposobów implementacji plików funkcyjnych (w skrócie funkcji) i ich wykorzystaniu w celach optymalizacji. Kolejnym zagadnieniem jest omówienie możliwości pakietu Optimization Toolbox. Jest to dodatek do środowiska MATLAB, który zawiera metody i algorytmy optymalizacji dla szerokiej klasy problemów. 2. Funkcje w narzędziach optymalizacji Aby wywołać procedurę optymalizacyjną trzeba przekazać jej funkcję kryterialną i funkcje ograniczeń, o ile takie występują. W niektórych przypadkach użytkownik powinien przedstawić także funkcje zwracające jakobian lub hessian problemu. Istnieją dwa podstawowe sposoby implementacji takich funkcji. Pierwszy z nich dotyczy tworzenia plików funkcyjnych, które, w celu odróżnienia od funkcji zaimplementowanych w środowisku, określa się mianem funkcji zewnętrznych. Podstawowa składnia implementacji funkcji w środowisku MATLAB wygląda następująco: function [argumenty wyjściowe] = nazwa_funkcji(argumenty wejściowe) ciąg instrukcji end Słowo kluczowe function na początku M-pliku wskazuje na to, że dany skrypt traktowany będzie jako funkcja, w tym celu należy go zapisać z nazwą identyczną z nazwą funkcji. Funkcja posiadać może wiele lub zero argumentów wejściowych jak i wyjściowych. W typowych przypadkach nie musimy zakańczać definicji funkcji słowem kluczowym end. Staje się to konieczne dopiero, gdy implementujemy funkcje zagnieżdżone. Istotnym jest fakt, że funkcje w środowisku MATLAB operują na swoich własnych workspace, czyli przestrzeniach roboczych, w których przechowywane są wszelkie dane i zmienne. Oznacza to, że funkcja nie posada dostępu do danych zapisanych w bazowej przestrzeni roboczej, o ile nie są to zmienne globalne. W przypadku, gdy funkcja nie zwraca argumentów wyjściowych, może zostać zapisana w następującej postaci: function nazwa_funkcji(argumenty wejściowe) ciąg instrukcji Skrypt zawierający definicję funkcji można rozbudować o dodatkowe funkcje lokalne. Działanie takie może być podyktowane np. chęcią tworzenia tylko jednego pliku do obsługi całej procedury optymalizacyjnej. Większość procedur optymalizacyjnych z pakietu Optimization toolbox przyjmuje zmienne typu function_handle. Z tego powodu, żeby przekazać do takiej procedury funkcję zapisaną w postaci pliku funkcyjnego, wykorzystać należy operator @: procedura_optymalizacyjna(@funkcja_kryterialna, pozostale_argumenty) w tym wypadku @ tworzy function_handle do pliku funkcja_kryerialna.m. Drugim sposobem implementacji funkcji jest zastosowanie tak zwanych funkcji anonimowych. Funkcje te nie są przechowywane w pliku, a w postaci zmiennej o typie function_handle. Oznacza to, że znajdują się w przestrzeni roboczej tak jak zmienne, ale zachowują się jak funkcje. Funkcje anonimowe definiujemy bezpośrednio w kodzie z wykorzystaniem operatora @: funkcja_anonimowa=@(argumenty)instrukcja; Sposób ten wykorzystywany jest najczęściej do definiowania prostych funkcji kryterialnych. W wielu przypadkach, gdy funkcja którą chcemy wykorzystać przyjmuje argumenty w postaci function_handle, nie zachodzi potrzeba tworzenia zmiennej w przestrzeni roboczej do przechowywania funkcji anonimowej. Możliwe jest utworzenie tymczasowej funkcji anonimowej wewnątrz wyrażenia: procedura_optymalizacyjna(@(argumenty_f_anonimowej)f_anonimowa, ... pozostale_argumenty) Funkcje przekazywane do procedur optymalizacyjnych zaimplementowanych w Optimization toolbox powinny przyjmować tylko jeden argument. Oznacza to, że w przypadku funkcji wielu zmiennych, zmienne te muszą znajdować się w pojedynczym wektorze lub macierzy. Rozważmy funkcję przyjmującą argumenty x, y i z postaci: f(x) = 3*(x – y)4 + 4*(x + z)2 / (1 + x2 + y2 + z2) + cosh(x – 1) + tanh(y + z). Funkcję tą zapisać można tak, żeby przyjmowała jeden argument w postaci wektora xin = [x;y;z]: function f = f_kryterialna(xin) f = 3*(xin(1)-xin(2))^4 + 4*(xin(1)+xin(3))^2/(1+norm(xin)^2) ... + cosh(xin(1)-1) + tanh(xin(2)+xin(3)); Często spotkać się można z potrzebą przekazania do funkcji kryterialnej dodatkowych parametrów, których nie chcemy jednak traktować jako zmienne w optymalizacji. Istnieje kilka mechanizmów, które to umożliwiają. Jednym z nich jest wykorzystanie zmiennych globalnych definiowanych z użyciem słowa kluczowego global, jednak nie jest to polecana procedura, ze względu na kłopoty nad zapanowaniem nad tym rodzaje zmiennych. Drugi sposób opiera się o wykorzystanie funkcji anonimowych. Przyjmijmy funkcję kryterialną postaci: function y = parameterfun(x,a,b,c) 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; Wykorzystując poznane mechaniki definiowania funkcji anonimowych, możemy w prosty sposób przekształcić parameterfun do funkcji z jednym argumentem i wykorzystać ją w procedurze optymalizacyjnej: a = 4; b = 2; c = 4; % Przypisanie parametrów f = @(x)parameterfun(x,a,b,c); procedura_optymalizacyjna(f,pozostale_argumenty) Trzeci sposób wykorzystuje mechanizm przekazywania przez funkcje z pakietu Optimization toolbox dodatkowych informacji do funkcji kryterialnej. Załóżmy, że wszelkie dodatkowe parametry znajdują się w strukturze parametry, która w szczególności może mieć postać wektora. W takim wypadku funkcja kryterialna parameterfun przyjmuje postać: function y = parameterfun(x,parametry) a = parametry(1); b = parametry(2); c = parametry(3); 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; Strukturę parametry umieszczamy w wywołaniu procedury optymalizacyjnej jako ostatni argument, niezależnie od tego, czy wykorzystujemy wszystkie poprzednie. Przykładowe wywołania procedury fmincon dla tego przypadku: [x,fval]=fmincon(@parameterfun,x0,[],[],Aeq,Beq,lb,ub,[],[],parametry) Środowisko MATLAB pozwala użytkownikowi na elastyczne zarządzanie liczbą argumentów wyjściowych i wejściowych funkcji. Oznacza to, że możliwe jest wywołanie funkcji bez podawania jej pełnej listy parametrów, oraz że funkcja zwracać może tylko tyle argumentów wyjściowych, ile jest od niej oczekiwanych. Poleceniami umożliwiającymi obsługę zmiennej liczby argumentów są nargin i nargout, które, użyte w ciele funkcji, zwracają odpowiednio liczbę podanych argumentów wejściowych i żądanych wyjściowych. Przykład funkcji obsługującej niepełną liczbę argumentów wejściowych: function y=pow(x,a) if nargin<2 a=2; end y=x.^a; przykładowe wywołania: >> pow(4) ans = 16 >> pow(4,2) ans = 16 3. Optimization toolbox W Tabeli I przedstawiono spis wybranych procedur optymalizacyjnych zaimplementowanych w Optimization toolbox, wraz z określeniem do jakiego rodzaju programowania (zwyczajowa nazwa używana w odniesieniu do metod optymalizacji komputerowej) dana metoda jest przeznaczona. W kolumnie drugiej tabeli przedstawiono zapis matematyczny danego problemu. Przyjęte oznaczenia zakładają, że x jest wektorem zmiennych optymalizowanych a f(x) stanowi funkcję kryterialną. Tabela 1. Zbiór procedur optymalizacyjnych Rodzaj programowania Nieliniowe jednej zmiennej Nieliniowe wielu zmiennych bez ograniczeń Zapis matematyczny min 𝑓(𝑥) 𝑥 𝑥1 < 𝑥 < 𝑥2 min 𝑓(𝑥) 𝑥 Funkcja w Optimization toolbox wersja 3.0 fminbnd fminunc fminsearch min 𝑓(𝑥) 𝑥 Nieliniowe wielu zmiennych z ograniczeniami Liniowe najmniejszych kwadratów z ograniczeniami Nieliniowe najmniejszych kwadratów 𝑐(𝑥) ≤ 0, 𝑐𝑒𝑞 (𝑥) = 0 𝐴 ∙ 𝑥 ≤ 𝑏, 𝐴𝑒𝑞 ∙ 𝑥 = 𝑏𝑒𝑞 𝑥𝑙𝑏 < 𝑥 < 𝑥𝑢𝑏 min‖𝐶 ∙ 𝑥 − 𝑑‖22 fmincon 𝑥 𝐴 ∙ 𝑥 ≤ 𝑏, 𝐴𝑒𝑞 ∙ 𝑥 = 𝑏𝑒𝑞 𝑥𝑙𝑏 < 𝑥 < 𝑥𝑢𝑏 1 min ‖𝐹(𝑥)‖22 𝑥 2 𝑥𝑙𝑏 < 𝑥 < 𝑥𝑢𝑏 min 𝑓 𝑇 𝑥 lsqlin lsqnonlin 𝑥 Liniowe Kwadratowe 𝐴 ∙ 𝑥 ≤ 𝑏, 𝐴𝑒𝑞 ∙ 𝑥 = 𝑏𝑒𝑞 𝑥𝑙𝑏 < 𝑥 < 𝑥𝑢𝑏 1 min 𝑥 𝑇 𝐻𝑥 + 𝑓 𝑇 𝑥 𝑥 2 𝐴 ∙ 𝑥 ≤ 𝑏, 𝐴𝑒𝑞 ∙ 𝑥 = 𝑏𝑒𝑞 𝑥𝑙𝑏 < 𝑥 < 𝑥𝑢𝑏 linprog quadprog Układ równań nieliniowych jednej zmiennej 𝑓(𝑎) = 0 fzero Układ równań nieliniowych wielu zmiennych 𝐹(𝑥) = 0 n równań n zmiennych fsolve Definiując problem optymalizacji należy zadbać o jego właściwe zaimplementowanie względem wybranej procedury. Zapis f(x) w Tabeli I oznacza funkcję skalarną, F(x) funkcję wektorową, a fTx funkcję liniową, którą podaje się jako wektor współczynników f. Macierz A i wektor b to odpowiednio lewa i prawa strona ograniczeń liniowych mniejszościowych. Macierz Aeq i wektor beq stanowią natomiast lewą i prawą stronę ograniczeń liniowych równościowych. Oznaczenia xlb i xub to odpowiednio większościowe i mniejszościowe warunki brzegowe. Funkcje c(x) i ceq(x) to ograniczenia nieliniowe mniejszościowe i równościowe. Wszystkie te zapisy stanowią standardowe formy przedstawiania problemów optymalizacji, jeśli napotkany problem posiada inną postać, to należy go przekształcić do postaci standardowej. Poszczególne procedury różnią się między sobą składnią, głównie ilością przyjmowanych argumentów (czasem kolejnością). W Tabeli II przedstawiono ogólną składnie wybranych procedur: Tabela II. Zbiór wybranych procedur optymalizacyjnych Procedura Składnia fminbnd [X,FVAL,EXITFLAG] =fminbnd(FUN,x1,x2,OPTIONS) fminunc [X,FVAL,EXITFLAG] = fminunc(FUN,X0,OPTIONS) fminsearch [X,FVAL,EXITFLAG] = fminsearch(FUN,X0,OPTIONS) fmincon [X,FVAL,EXITFLAG] = fmincon(FUN,X0,A,B,Aeq,Beq,LB,UB,NONLCON,OPTIONS) lsqlin [X,RESNORM,RESIDUAL,EXITFLAG] = lsqlin(C,d,A,b,Aeq,beq,LB,UB,X0,OPTIONS) lsqnonlin [X,RESNORM,RESIDUAL,EXITFLAG] = lsqnonlin(FUN,X0,LB,UB,OPTIONS) linprog [X,FVAL,EXITFLAG] = linprog(f,A,b,Aeq,beq,LB,UB) quadprog [X,FVAL,EXITFLAG] = quadprog(H,f,A,b,Aeq,beq,LB,UB,X0,OPTIONS) fzero [X,FVAL,EXITFLAG] = fzero(FUN,X0,OPTIONS) fsolve [X,FVAL,EXITFLAG] = fsolve(FUN,X0,OPTIONS) Według oznaczeń przyjętych w Tabeli II FUN odpowiada za funkcję kryterialną (typ danych to function_handle); OPTIONS to struktura zawierająca opcje optymalizacji, tworzona za pomocą polecenia optimoptions; X0 oznacza punkt startowy; NONLCON to oznaczenie funkcji zwracającej wartości nieliniowych ograniczeń nierównościowych i równościowych; pozostałe oznaczenia są zgodne z tymi z Tabeli I. Argumenty wyjściowe określają się następująco: X jest rozwiązaniem optymalizacji, czyli zawiera optymalne wartości zmiennych; FVAL to wartość funkcji kryterialnej w punkcie optymalnym; EXITFLAG flaga wystawiana przez procedurę, która określa przyczynę zakończenia optymalizacji, jej wartości różnią się w zależności od procedury; RESNORM to wartość kryterium dla problemów najmniejszych kwadratów; RESIDUAL stanowi wektor residuów problemów najmniejszych kwadratów. Oprócz wymienionych, poszczególne funkcje zwracać mogą różne dodatkowe wartości, takie jak gradient lub hessian w punkcie optymalnym. Wywołując poszczególne procedury nie musimy podawać wszystkich argumentów wejściowych. W takim wypadku przyjmują one domyślne wartości. Nie można jednak pomijać żadnego argumentu, jeśli chcemy wykorzystać argument znajdujący się za nim (np. NONLCON znajduje się za A w procedurze fmincon), musimy podać wtedy pusty argument: []. Poleceniem optimoptions możemy tworzyć i modyfikować strukturę z opcjami optymalizacji. Każda procedura posiada swój domyślny zestaw opcji i wystarczy jedynie, że modyfikować będziemy interesujące nas opcje. Ogólna postać polecenia optimoptions wygląda następująco: OPTIONS = optimoptions(SOLVER,'PARAM1',VALUE1,...) Przykładowe wywołanie optimoptions, które ustala próg tolerancji na minimalną zmianę zmiennych optymalizowanych, maksymalną liczbę iteracji i wyświetlanie szczegółów iteracji w command window dla procedury fminunc: options = optimoptions('fminunc', 'TolX', 0.01, 'MaxIter', ... 1000, 'display', 'iter') Każda procedura oprócz ogólnych opcji zawiera także swoje własne opcje szczegółowe np. dotyczące wyboru algorytmu. W Tabeli III przedstawiono wybrane, najczęściej modyfikowane opcje. Tabela III. Zbiór wybranych opcji Nazwa opcji Argument Display określa poziom szczegółowości wyświetlanych w command window informacji: off lub none – brak iter – wyświetla informacje po każdej iteracji i informacje końcowe iter-detailed – wyświetla to co iter plus rozbudowaną informacje techniczną na koniec notify – wyświetla powiadomienie jeśli procedura optymalizacji się nie powiedzie final/final-detailed – wyświetla informacje końcowe/rozbudowane informacje końcowe Diagnostics wyświetla informacje o rozwiązywanym problemie optymalizacji on – włączone off – domyślnie wyłączone MaxFunEvals dodatnia liczba naturalna, określa maksymalną liczbę ewaluacji funkcji kryterialnej MaxIter dodatnia liczba naturalna, określa maksymalną liczbę iteracji TolCon tolerancja na naruszenie ograniczeń TolFun próg tolerancji na zmianę funkcji kryterialnej TolX próg tolerancji na zmianę zmiennych optymalizowanych GradObj gradient funkcji kryterialnej definiowany przez użytkownika on – funkcja kryterialna zwraca wartość gradientu off – gradient jest domyślnie przybliżany w oparciu o metodę różnic skończonych DerivativeCheck sprawdza poprawność zdefiniowanego przez użytkownika gradientu poprzez porównanie go do przybliżenia uzyskanego w oparci o metodę różnic skończonych on – porównanie włączone off – porównanie domyślnie wyłączone Optimization toolbox wykorzystywać można w sposób klasyczny, to jest własnoręcznie tworzyć skrypty optymalizacyjne w oparciu o procedury przybornika, lub poprzez graficzną aplikację o nazwie Optimization App, wywoływaną poleceniem optimtool.