Zadanie 4: Programowanie liniowe
Transkrypt
Zadanie 4: Programowanie liniowe
Informatyka, studia dzienne, mgr II st. semestr II Metody obliczeniowe optymalizacji 2013/2014 Prowadzący: mgr inż. Łukasz Chomątek Data oddania: poniedziałek, 12:15 Ocena: Mateusz Grotek 186816 Paweł Tarasiuk 186875 Zadanie 4: Programowanie liniowe∗ 1. Cel Celem niniejszego zadania jest analiza dwufazowej metody sympleks, w ramach której przygotowana została jej implementacja. Program powinien wykrywać sytuacje patologiczne (brak rozwiązań, rozwiązania niejednoznaczne). Sugerowanym dodatkowym elementem funkcjonalności jest wypisywanie postaci kolejnych tablic sympleksowych w czytelny sposób. 2. Rozwiązanie zadania i opis programu Klasyczna metoda sympleks pozwala na znajdywanie ekstremów funkcji liniowej na wielościanie wypukłym, tj. na podzbiorze przestrzeni będącym iloczynem skończonej liczby takich zbiorów, których brzeg stanowi w zadanej przestrzeni hiperpłaszczyznę. Tak zdefiniowany iloczyn zbiorów nazywany jest zbiorem rozwiązań dopuszczalnych, zaś punkty realizujące szukane optimum – rozwiązaniami optymalnymi. Wspomniane powyżej zbiory mogą zostać opisane jako nierówności nieostre. Aby zastosować najpopularniejszą wersję klasycznej metody sympleks należy sprowadzić problem do postaci układu nierówności, w którym wszystkie zmienne decyzyjne (współrzędne kartezjańskiego układu współrzędnych opisującego zadaną przestrzeń) były nieujemne, oraz spełniony był pewien układ nierówności. Każdy taki układ może zostać tak przekształcony, aby ∗ SVN: http://serce.ics.p.lodz.pl/svn/labs/moo/lc_pn_1215/ wladcywszechswiata@125 1 zbiór rozwiązań dopuszczalnych był zbiorem ograniczonym, a wszystkie nierówności były typu „≤” – jest to osiągane np. poprzez podstawianie zmiennych pomocniczych zależnych liniowo od zmiennych decyzyjnych z ujemnym współczynnikiem kierunkowym. Niech n – liczba zmiennych decyzyjnych, m – liczba nierówności. Weźmy dowolną i-tą nierówność (i ∈ {1, . . . , m}) postaci ai1 x1 + . . . + ain xn ≤ bi gdzie aij to pewne współczynniki rzeczywiste, j ∈ {1, . . . , n}. Dla każdego rozwiązania dopuszczalnego (x1 , . . . , xn ) da się wskazać pewną taką liczbę nieujemną si , że: ai1 x1 + . . . + ain xn + 1si = bi . Po wprowadzeniu zmiennych bilansujących dostajemy układ równań, w którym chcemy znaleźć takie rozwiązania, dla których wszystkie wartości zmiennych decyzyjnych oraz zmiennych bilansujących są nieujemne, oraz funkcja optymalności przyjmuje najbardziej pożądaną wartość (minimalną bądź maksymalną). Zauważmy, że skoro funkcja optymalności ma być funkcją liniową, a zbiór rozwiązań dopuszczalnych jest wielościanem, to przynajmniej jeden z wierzchołków wielościanu stanowi rozwiązanie optymalne. Wierzchołki wielościanu będą w tym wypadku reprezentowane przez rozwiązania bazowe układu równań, tj. takie, dla których co najwyżej m zmiennych ma wartość inną niż 0. Konkretne kroki klasycznej metoda sympleks wyznaczającej maksimum funkcji liniowej mogą zostać zapisane w języku Octave następująco: # zred_A -- wartości zmiennych dla rozważanego wierzchołka # zred_b -- wartość funkcji celu dla rozważanego wierzchołka # A -- współczynniki tabeli sympleksowej # b -- wyrazy wolne tabeli sympleksowej # bazowe -- numery zmiennych bazowych (w metodzie klasycznej zaczynamy od samych # zmiennych bilansujących) function wyjscie=metoda_sympleks(zred_A, zred_b, A, b, bazowe, nazwy, \ kod_warunku, komunikat, faza1) [kr, z] = size(A); zd = z - kr; sprawdzone = []; iteracje = 0; # zazwyczaj: dopóki któryś współczynnik jest ujemny while eval(kod_warunku) # w klasycznym podejściu kod_warunku to po prostu "min(zred_A) < 0" # sprawdzam, czy dany zestaw zmiennych bazowych nie był analizowany wcześniej for k = [1:size(sprawdzone)(1)] if sprawdzone(k, :) == bazowe display(’Brak rozwiazania zadania programowania linowego (nie da się spełnić warunku; zapętlenie)’); exit(); endif endfor # zapamiętuję bieżący zestaw zmiennych bazowych sprawdzone = [sprawdzone; bazowe]; # wyznaczam zmienną wychodzącą z bazy # delty -- współczynniki optymalności (z bazy wyjdzie zmienna z największym # współczynnikiem) delty = -zred_A; for i = [1:kr] delty(bazowe(i)) = -Inf; endfor 2 [najwieksza_delta, wchodzaca] = max(delty); # w klazycznym podejściu, delta powinna być dodatnia # jednak w fazie I chcemy usunąć zmienne sztuczne z bazy za wszelką cenę (choćby ujemnych delt!) if najwieksza_delta <= 0 && ! faza1 display(’Brak rozwiazania zadania programowania linowego (nie da się spełnić warunku)’); exit(); endif # wyznaczam zmienną wchodzącą do bazy # ilorazy -- ilorazy wyjścia (z bazy wyjdzie zmienna z najmniejszym dodatnim # ilorazem wyjścia) ilorazy = b ./ A(:, wchodzaca); wychodzaca_bazowa = -1; for wiersz = [1:kr] if A(wiersz, wchodzaca) != 0 && ilorazy(wiersz) > 0 \ && (wychodzaca_bazowa == -1 || ilorazy(wiersz) < ilorazy(wychodzaca_bazowa)) wychodzaca_bazowa = wiersz; endif endfor if wychodzaca_bazowa == -1 display(’Brak rozwiazania zadania programowania linowego (kolumna zerowa?)’); exit(); endif wychodzaca = bazowe(wychodzaca_bazowa); # element centralny centralny = [wychodzaca_bazowa, wchodzaca]; # normalizacja wiersza wskazanego przez element centralny mnoznik = 1 / A(centralny(1), centralny(2)); A(centralny(1), :) *= mnoznik; b(centralny(1)) *= mnoznik; # krok metody Gaussa (kolumna z nową zmienną bazową musi zawierać jedną jedynkę # i same zera) for wiersz = [1:kr] if wiersz != centralny(1) mnoznik = -A(wiersz, centralny(2)); A(wiersz, :) += mnoznik .* A(centralny(1), :); b(wiersz) += mnoznik * b(centralny(1)); endif endfor mnoznik = -zred_A(centralny(2)); zred_A += mnoznik .* A(centralny(1), :); zred_b += mnoznik * b(centralny(1)); # aktualizacja informacji o zmiennych bilansujących for i = [1:kr] if bazowe(i) == wychodzaca bazowe(i) = wchodzaca; endif endfor # wypisanie komunikatów bazowe_napis = ’’; for i = [1:kr] bazowe_napis = cstrcat(bazowe_napis, cell2mat(nazwy(bazowe(i))), ’ ’); endfor disp(cstrcat(komunikat, bazowe_napis)); rysuj_tabelke(nazwy, zred_A, zred_b, A, b); iteracje += 1; endwhile # obliczenie współczynników optymalności po skończonej pracy delty = -zred_A; for kolumna = [1:z] for wiersz = [1:kr] delty(kolumna) += zred_A(bazowe(wiersz)) .* A(wiersz, kolumna); endfor endfor 3 # jeżeli współczynnik optymalności dla jakiejś zmiennej niebazowej wynosi 0 # (czyli zer jest więcej niż zmiennych bazowych), to rozwiązanie jest niejednoznaczne jednoznaczne = sum(delty == 0) <= zd; wyjscie = {zred_A, zred_b, A, b, bazowe, iteracje, jednoznaczne}; endfunction Klasyczna metoda sympleks pozwala rozwiązywać zadania programowania liniowego, lecz samo przekształcanie problemu tak, aby zbiór rozwiązań optymalnych był ograniczony i aby punkt (0, 0, 0) był właściwym wierzchołkiem startowym jest łatwe do wykonania ręcznie, lecz kłopotliwe do zapisania w postaci ogólnego algorytmu. Ten problem rozwiązywany jest poprzez zastosowanie dwufazowej metody sympleks, która polega na tym, że przed samym szukaniem rozwiązania optymalnego wykonywana jest dodatkowo „pierwsza faza rozwiązania”, czyli szukanie odpowiedniego wierzchołka startowego. Druga faza jest już dokładnie tym samym, co klasyczna metoda sympleks, tyle że zaczynamy od tabeli sympleks która od razu wskazuje na dobry wierzchołek startowy (powstaje ona w wyniku przekształceń z pierwszej fazy). Dodatkowo, pierwsza faza pozwala wykryć przypadki układów sprzecznych (może to być interpretowane jako porażka przy szukaniu wierzchołka startowego). Pierwsza faza polega na tym, że do każdego równania dodajemy dodatkowe zmienne sztuczne (poza ewentualnymi zmiennymi bilansującymi) i zamiast maksymalizacji funkcji celu minimalizujemy sumę zmiennych sztucznych (czyli maksymalizujemy liczbę przeciwną do tej sumy). Zaczynamy jednak od wierzchołka, gdzie wszystkie zmienne sztuczne są zerami, więc w tymczasowej funkcji celu podstawiamy je za pomocą kombinacji zmiennych decyzyjnych, bilansujących i wyrazów wolnych wynikających z poszczególnych równości. Jest to realizowane poprzez następujące sumy po kolumnach: zred_A = -[sum(A(:, 1:zd), 1), zeros(1, kr)]; zred_b = -sum(b, 1); gdzie kr – liczba równości, zd – liczba zmiennych przed dodaniem zmiennych sztucznych. Jeżeli po przeprowadzeniu metody sympleks z pierwszej fazy okaże się, że maksymalna wartość liczby przeciwnej do sumy zmiennych sztucznych (zred b) jest ujemna, to pierwotne zadanie programowania liniowego jest sprzeczne. Ostatecznie, rozwiązanie dwufazowej metody sympleks jest jednoznaczne, gdy otrzymano rozwiązania jednoznaczne w obu fazach oraz zred b po pierwszej fazie nie jest zerem. 3. Wyniki 3.1. Typowe zadanie programowania liniowego Zaczniemy od typowego zadania ze zbioru zadań do ekonometrii matematycznej. 12x1 + 12x2 + 9x3 → „Max” 4 3x1 + 5x2 + 4x3 + s1 = 2400 3x1 + 5x2 + 1x3 + s2 = 2000 10x1 + 5x2 + 6x3 + s3 = 2400 x1 , x2 , x3 , s1 , s2 , s3 ≥ 0 Wywołanie naszego programu wygląda następująco: c = [ 12, 12, 9, 0, 0, 0 ]; A = [ 3, 5, 4, 1, 0, 0; 3, 2, 1, 0, 1, 0; 10, 5, 6, 0, 0, 1 ]; b = [ 2400; 2000; 2400 ]; dwufazowy_sympleks(c, A, b); Na standardowe wyjście wypisane zostały tabele sympleksowe oraz wynik: I FAZA (szukanie wierzchołka startowego) Początkowa tabela (ze zmiennymi bilansującymi) x1 x2 x3 x4 x5 x6 y1 y2 y3 -16 -12 -11 -1 -1 -1 0 0 0 | -6.8e+03 -------------------------------------------------------------------------------------------+----------3 5 4 1 0 0 1 0 0 | 2.4e+03 3 2 1 0 1 0 0 1 0 | 2e+03 10 5 6 0 0 1 0 0 1 | 2.4e+03 Faza I, zmienne bazowe: y1 y2 x1 x1 x2 x3 x4 x5 x6 y1 y2 y3 0 -4 -1.4 -1 -1 0.6 0 0 1.6 | -2.96e+03 ----------------------------------------------------------------------------------------------------+-----------0 3.5 2.2 1 0 -0.3 1 0 -0.3 | 1.68e+03 0 0.5 -0.8 0 1 -0.3 0 1 -0.3 | 1.28e+03 1 0.5 0.6 0 0 0.1 0 0 0.1 | 240 Faza I, zmienne bazowe: x2 y2 x1 x1 x2 x3 x4 x5 x6 y1 y2 y3 0 0 1.11 0.143 -1 0.257 1.14 0 1.26 | -1.04e+03 ----------------------------------------------------------------------------------------------------+-----------0 1 0.629 0.286 0 -0.0857 0.286 0 -0.0857 | 480 0 0 -1.11 -0.143 1 -0.257 -0.143 1 -0.257 | 1.04e+03 1 0 0.286 -0.143 0 0.143 -0.143 0 0.143 | 0 Faza I, zmienne bazowe: x2 x5 x1 x1 x2 x3 x4 x5 x6 y1 y2 y3 0 0 6.66e-16 -5.55e-17 0 0 1 1 1 | 0 ----------------------------------------------------------------------------------------------------+-----------0 1 0.629 0.286 0 -0.0857 0.286 0 -0.0857 | 480 0 0 -1.11 -0.143 1 -0.257 -0.143 1 -0.257 | 1.04e+03 1 0 0.286 -0.143 0 0.143 -0.143 0 0.143 | 0 Faza I, zmienne bazowe: x4 x5 x1 x1 x2 x3 x4 x5 x6 y1 y2 y3 0 1.94e-16 7.88e-16 0 0 -1.67e-17 1 1 1 | 9.33e-14 ----------------------------------------------------------------------------------------------------+-----------0 3.5 2.2 1 0 -0.3 1 0 -0.3 | 1.68e+03 0 0.5 -0.8 0 1 -0.3 0 1 -0.3 | 1.28e+03 1 0.5 0.6 0 0 0.1 0 0 0.1 | 240 Faza I, zmienne bazowe: x4 x5 x6 x1 x2 x3 x4 x5 x6 y1 y2 y3 1.67e-16 2.78e-16 8.88e-16 0 0 0 1 1 1 | 1.33e-13 -------------------------------------------------------------------------------------------+----------3 5 4 1 0 0 1 0 0 | 2.4e+03 3 2 1 0 1 0 0 1 0 | 2e+03 10 5 6 0 0 1 0 0 1 | 2.4e+03 II FAZA (powrót do zagadnienia pierwotnego) Wierzchołek startowy: [0 0 0 2.4e+03 2e+03 2.4e+03] x1 x2 x3 x4 x5 x6 5 -12 -12 -9 0 0 0 | 0 -------------------------------------------------------+---------3 5 4 1 0 0 | 2.4e+03 3 2 1 0 1 0 | 2e+03 10 5 6 0 0 1 | 2.4e+03 Faza II, zmienne bazowe: x4 x5 x1 x1 x2 x3 x4 x5 x6 0 -6 -1.8 0 0 1.2 | 2.88e+03 -------------------------------------------------------------+----------0 3.5 2.2 1 0 -0.3 | 1.68e+03 0 0.5 -0.8 0 1 -0.3 | 1.28e+03 1 0.5 0.6 0 0 0.1 | 240 Faza II, zmienne bazowe: x2 x5 x1 x1 x2 x3 x4 x5 x6 0 0 1.97 1.71 0 0.686 | 5.76e+03 -------------------------------------------------------------+----------0 1 0.629 0.286 0 -0.0857 | 480 0 0 -1.11 -0.143 1 -0.257 | 1.04e+03 1 0 0.286 -0.143 0 0.143 | 0 Wierzchołek optymalny: [0 480 0 0 1.04e+03 0] Maksimum: 5.76e+03 Jest to rozwiązanie jednoznaczne Liczba kroków fazy I: 5 Liczba kroków fazy II: 2 Nazwy zmiennych innych niż zmienne sztuczne zostały nadane automatycznie, więc zamiast s1 , s2 , s3 program posługuje się nazwami x4 , x5 , x6 . 3.2. Przypadek do testowania metody dwufazowej Dla testowania dwufazowej metody sympleks nie musimy zastanawiać się nad pierwotnym podziałem na zmienne decyzyjne i bilansujące – po prostu szukamy najlepszego rozwiązania bazowego z dodatnimi wartościami zmiennych. Weźmy zadanie programowania linowego: 7x1 + 2x2 + −3x3 − x4 → „Max” ( 8x1 + 3x2 − 5x3 + x4 = 4 3x1 + 1x2 − 2x3 − x4 = 1 x1 , x2 , x3 , x4 ≥ 0 Zauważmy, że nie sposób wskazać tu trywialny wierzchołek startowy (nie da się np. podstawić samych zer pod zmienne decyzyjne i odpowiednich liczb pod zmienne bilansujące, bo nie ma tu nawet takiego podziału). Dla dwufazowej metody sympleks nie jest to problem: I FAZA (szukanie wierzchołka startowego) Początkowa tabela (ze zmiennymi bilansującymi) x1 x2 x3 x4 y1 y2 -11 -4 7 0 0 0 | -5 -------------------------------+-----8 3 -5 1 1 0 | 4 3 1 -2 -1 0 1 | 1 Faza I, zmienne bazowe: y1 x1 x1 x2 x3 x4 y1 y2 0 -0.333 -0.333 -3.67 0 3.67 | -1.33 -------------------------------------------------+--------- 6 0 1 0.333 0.333 0.333 -0.667 3.67 -0.333 1 0 -2.67 0.333 | | 1.33 0.333 Faza I, zmienne bazowe: x4 x1 x1 x2 x3 x4 y1 y2 0 5.55e-17 5.55e-17 0 1 1 | 0 -------------------------------------------------------------+----------0 0.0909 0.0909 1 0.273 -0.727 | 0.364 1 0.364 -0.636 0 0.0909 0.0909 | 0.455 II FAZA (powrót do zagadnienia pierwotnego) Wierzchołek startowy: [0.455 0 0 0.364] x1 x2 x3 x4 0 0.455 -1.55 0 | 2.82 ---------------------------------+--------0 0.0909 0.0909 1 | 0.364 1 0.364 -0.636 0 | 0.455 Faza II, zmienne bazowe: x3 x1 x1 x2 x3 x4 0 2 0 17 | 9 -----------------+----0 1 1 11 | 4 1 1 0 7 | 3 Wierzchołek optymalny: [3 0 4 0] Maksimum: 9 Jest to rozwiązanie jednoznaczne Liczba kroków fazy I: 2 Liczba kroków fazy II: 1 3.3. Przypadek niejednoznaczny Weźmy zadanie programowania liniowego: x1 + x2 + x3 → „Max” ( x1 = 0 x1 + x2 + x3 = 1 x1 , x2 , x3 ≥ 0 Rozwiązanie widać jak na dłoni i jest nim cały odcinek łączący dwa wierzchołki. Program wypisuje stosowny komunikat I FAZA (szukanie wierzchołka startowego) Początkowa tabela (ze zmiennymi bilansującymi) x1 x2 x3 y1 y2 -2 -1 -1 0 0 | -1 ---------------------+----1 0 0 1 0 | 0 1 1 1 0 1 | 1 Faza I, zmienne bazowe: y1 x1 x1 x2 x3 y1 y2 0 1 1 0 2 | 1 ---------------------+----0 -1 -1 1 -1 | -1 1 1 1 0 1 | 1 Faza I, zmienne bazowe: x2 x1 x1 x2 x3 y1 y2 0 0 0 1 1 | 0 ---------------------+----0 1 1 -1 1 | 1 1 0 0 1 0 | 0 7 II FAZA (powrót do zagadnienia pierwotnego) Wierzchołek startowy: [0 1 0] x1 x2 x3 0 0 0 | 1 -------------+----0 1 1 | 1 1 0 0 | 0 Wierzchołek optymalny: [0 1 0] Maksimum: 1 Jest to potencjalnie jedno z wielu rozwiązań Liczba kroków fazy I: 2 Liczba kroków fazy II: 0 3.4. Przypadek sprzeczny Weźmy fałszywe zadanie programowania liniowego: x1 + x2 + x3 → „Max” ( x1 + x 2 + x3 = 0 x1 + x 2 + x3 = 1 x1 , x2 , x3 ≥ 0 Program wypisuje następujące wyjście: I FAZA (szukanie wierzchołka startowego) Początkowa tabela (ze zmiennymi bilansującymi) x1 x2 x3 y1 y2 -2 -2 -2 0 0 | -1 ---------------------+----1 1 1 1 0 | 0 1 1 1 0 1 | 1 Faza I, zmienne bazowe: y1 x1 x1 x2 x3 y1 y2 0 0 0 0 2 | 1 ---------------------+----0 0 0 1 -1 | -1 1 1 1 0 1 | 1 Faza I, zmienne bazowe: y1 x2 x1 x2 x3 y1 y2 0 0 0 0 2 | 1 ---------------------+----0 0 0 1 -1 | -1 1 1 1 0 1 | 1 Faza I, zmienne bazowe: y1 x1 x1 x2 x3 y1 y2 0 0 0 0 2 | 1 ---------------------+----0 0 0 1 -1 | -1 1 1 1 0 1 | 1 Brak rozwiazania zadania programowania linowego (nie da się spełnić warunku; zapętlenie) 4. Wnioski Dwufazowa metoda sympleks jest bardzo wygodnym podejściem do numerycznego rozwiązywania zadań programowania liniowego. Asymptotyczna 8 złożoność obliczeniowa pozostaje taka sama jak w przypadku problemów gotowych do zastosowania klasycznej metody sympleks. Kolejną zaletą metody sympleks, która pozostaje zachowana w metodzie dwufazowej jest to, że błędy obliczeniowe są niewielkie (podobnie jak w przypadku rozwiązywania układów równań metodą Gaussa, które generuje znacznie mniejsze błędy niż np. metoda wyznaczników). Jednakże, w przeciwieństwie do klasycznej metody sympleks, tutaj można podstawić dowolne zadanie programowania liniowego. Dwufazowa metoda sympleks dostarcza nam bowiem automatyczne mechanizmy wykrywania zadań sprzecznych oraz znajdywania wierzchołków startowych, tak aby zawsze poruszać się po wierzchołkach wielościanu ograniczonego. Fakt, że kod programu realizujący klasyczną metodę sympleks może być wspólny dla obu faz (tak jak zostało to zrealizowane w niniejszym projekcie) przypuszczalnie czyni dwufazową metodę sympleks najbardziej wygodnym sposobem wykrywania przypadków sprzecznych i dostosowywania do metody sympleks zadań programowania linowego, w których rozwiązanie składające się z samych zer nie musi należeć do zbioru rozwiązań dopuszczalnych. Literatura [1] dr inż. Jacek Rogowski, Materiały do kursu z „Badań operacyjnych i ekonometrii matematycznej” dla drugiego roku studiów zamawianych 2013/2014. [2] dr inż. Arkadiusz Tomczyk, Materiały do wykładów z „Metod obliczeniowych optymalizacji”. [3] John W. Eaton, GNU Octave - Documentation. 9