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.