<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl">
	<id>https://wiki.otwartaedukacja.pl/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin</id>
	<title>Otwarta edukacja - Wkład użytkownika [pl]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.otwartaedukacja.pl/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin"/>
	<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Specjalna:Wk%C5%82ad/Admin"/>
	<updated>2026-05-21T23:20:42Z</updated>
	<subtitle>Wkład użytkownika</subtitle>
	<generator>MediaWiki 1.38.2</generator>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Procesor_i_j%C4%99zyk_maszynowy_-_wprowadzenie&amp;diff=172</id>
		<title>Procesor i język maszynowy - wprowadzenie</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Procesor_i_j%C4%99zyk_maszynowy_-_wprowadzenie&amp;diff=172"/>
		<updated>2022-11-07T20:26:20Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Projektujemy procesor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Informacje o module:&lt;br /&gt;
* Poziom: Podstawowy&lt;br /&gt;
* Profil: Dla techników i inżynierów&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Struktura komputera ==&lt;br /&gt;
&lt;br /&gt;
W sklepach z zabawkami można dostać skarbonki w kształcie zwierzęcia, które po wrzuceniu monety w otwór na głowie zamyka usta, jakby coś połykało. W działaniu takiej skarbonki można wyróżnić kilka operacji: wrzucona moneta naciska na przedłużenie szczęki (1), szczęka zamyka się i moneta spada (2), szczęka otwiera się i skarbonka wraca do punktu początkowego (0). Zauważmy, że aby scharakteryzować działanie skarbonki, wystarczy opisać ją w pewnych wybranych momentach czasu. Opis taki nazywamy stanem urządzenia. W naszym przypadku możemy wyróżnić stany: podstawowy (0), wrzucona moneta (1), zamknięta szczęka (2). Samo działanie poza tymi wybranymi momentami nas nie interesuje - w takim opisie czas zmienia się skokowo (mówimy, że &#039;&#039;&#039;czas ma charakter dyskretny&#039;&#039;&#039;). Jest to oczywiście pewne uproszczenie, ale pozwala na dokonanie opisu w sposób bardzo ścisły.&lt;br /&gt;
&lt;br /&gt;
=== Komputer jest urządzeniem posiadającym pamięć ===&lt;br /&gt;
&lt;br /&gt;
Pamięcią&amp;amp;nbsp;nazwiemy urządzenie, którego stan w kolejnych momentach czasu możemy odczytać. Przykładem tak rozumianej pamięci może być zwykły notes. Możemy przeglądając go odczytać umieszczone tam zapiski. Zapiski te stanowią stan notesu. Tego typu pamięć ma jednak pewną wadę - zapis nie daje się łatwo zmieniać i nie może to być wykonane automatycznie. Pamięć komputera poza możliwością zmiany stanu musi charakteryzować się możliwością łatwego określenia zasad tych zmian tak, aby mogło to odbywać się automatycznie. Sposób automatycznej zmiany stanu można określić podając dla każdego stanu stan następny (po zmianie).&lt;br /&gt;
&lt;br /&gt;
Pamięć prawdziwych komputerów składa się z bardzo prostych elementów elektronicznych. Mogą się one znajdować w jednym z dwóch stanów: 0 lub 1. Stan jest reprezentowany przez wysokość napięcia (wysokie napięcie = 1, niskie = 0). Elementów takich jest za to bardzo dużo. Wielkość pamięci mierzy się w bitach (jeden element dwustanowy = 1 bit). Osiem bitów nazywa się bajtem. 1024 bajty to kilobajt (kB), a 1024 kilobajty to 1 megabajt (MB). Obecnie komputery mają przeważnie 8, 16, 32, 64 lub 128 MB pamięci.&lt;br /&gt;
&lt;br /&gt;
=== Procesor dokonuje zmian stanu pamięci ===&lt;br /&gt;
&lt;br /&gt;
Oczywiście zmiany pamięci nie wykonują się same z siebie. Potrzebny jest element który w sposób automatyczny wykona je zgodnie z instrukcjami. Po to właśnie komputer wyposażony jest w procesor, dokonujący zmian pamięci (stanu) w kolejnych momentach czasu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:Pamiec_procesor.png]]&lt;br /&gt;
&lt;br /&gt;
Procesor jest układem elektronicznym przetwarzającym sygnały odczytane z pamięci. W jednym momencie odczytuje stan pamięci i oblicza stan następny. W następnym momencie zmienia się stan pamięci na wypracowany przez procesor.&lt;br /&gt;
&lt;br /&gt;
Kolejne chwile czasu (w których następuje zmiana stanu) wyznacza generator sygnałów elektrycznych zwany zegarem. Częstotliwość generowanego sygnału jest podstawowym parametrem określającym szybkość komputera (mówimy że procesor działa z szybkością 100MHz, 200MHz, itd..)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Teoretycznie rzecz biorąc następny stan pamięci zależy od stanu aktualnego całej pamięci. Jak wspomnieliśmy jednak, pamięć komputera jest bardzo duża. Dla uproszczenia konstrukcji procesory wykonuje się więc w ten sposób, że mogą one odczytywać i zmieniać jedynie mały fragment pamięci. Nie ma to większego wpływu na funkcjonalność komputera (zamiast zmienić stan wszystkich elementów równocześnie, zmienia się je po kolei). Sytuację tą można porównać do poruszania się w układzie współrzędnych tylko wzdłuż osi układu. W jednym kroku zmienia się tylko jedna współrzędna, ale nie ogranicza to zasięgu naszego ruchu (dla takich modeli często mówi się o przestrzeni stanów).&lt;br /&gt;
&lt;br /&gt;
=== Procesor - serce komputera ===&lt;br /&gt;
&lt;br /&gt;
Cykl działania procesora można więc określić w sposób następujący:&lt;br /&gt;
&lt;br /&gt;
#. Odczyt fragmentu pamięci (komórki, słowa).&lt;br /&gt;
#. Wykonanie operacji (+wyznaczenie następnego stanu tego fragmentu pamięci).&lt;br /&gt;
#. Zapis nowych wartości do pamięci.&lt;br /&gt;
#. Wyznaczenie nowego fragmentu pamięci do pobrania.&lt;br /&gt;
&lt;br /&gt;
Poszczególne operacje są wykonywane w takt zegara komputera. Każdy z powyższych punktów może być wykonywany w kilku taktach, ale teoretycznie możliwe jest wykonanie jednego cyklu tylko w dwóch taktach (punkty 2,3 i 4 mogą być wykonane w jednym kroku). Zależy to od budowy procesora.&lt;br /&gt;
&lt;br /&gt;
Jednym z najistotniejszych pomysłów na jakie wpadli konstruktorzy komputera jest&amp;amp;nbsp;&amp;lt;u&amp;gt;zapis instrukcji dla procesora w pamięci komputera&amp;lt;/u&amp;gt;. Aby procesor mógł sam odczytywać rozkazy (instrukcje) z pamięci i efektywnie działać zgodnie z przedstawionym powyżej schematem trzeba było przyjąć kilka dodatkowych założeń:&lt;br /&gt;
&lt;br /&gt;
#. Wszystkie instrukcje otrzymują swoje kody (załóżmy, że wszystkie informacje zapisane w pamięci są liczbami). Wraz z niektórymi z tych kodów są pamiętane parametry instrukcji (zob. przykład poniżej).&lt;br /&gt;
&lt;br /&gt;
#. Wszystkie komórki pamięci zostają ponumerowane (0,1,2,...). Mówimy, że komórki są adresowane.&lt;br /&gt;
&lt;br /&gt;
#. Wydziela się fragmenty pamięci w których będą pamiętane:* &lt;br /&gt;
* wynik ostatniej instrukcji (rozkazu)&lt;br /&gt;
* kod wykonywanej instrukcji&lt;br /&gt;
* numer komórki (adres) zawierającej kod kolejnego rozkazu do wykonania&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Te fragmenty pamięci nazywamy rejestrami. Rejestry zazwyczaj stanowią część procesora i nie są adresowane tak jak reszta pamięci. W konkretnych realizacjach procesorów ilość rejestrów jest większa (zazwyczaj jednak nie więcej niż 10). Ta wewnętrzna złożoność procesora jest jedną z przyczyn, dla których pewne operacje wymagają więcej niż dwóch taktów zegara.&lt;br /&gt;
&lt;br /&gt;
== Projektujemy procesor ==&lt;br /&gt;
&lt;br /&gt;
Budowę procesora najlepiej pokazać na przykładzie. W tym celu zaprojektujemy prosty, przykładowy procesor. Przyjmujemy, że procesor zawiera rejestry:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;akumulator&amp;amp;nbsp;&#039;&#039;- wynik operacji&lt;br /&gt;
* &#039;&#039;licznik -&amp;amp;nbsp;&#039;&#039;adres kolejnej operacji&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dodatkowo mamy rejestry pomocnicze, które są używane przez procesor do przechowywania aktualnie wykonywanej instrukcji:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;instrukcji -&amp;amp;nbsp;&#039;&#039;kod pobranego rozkazu&lt;br /&gt;
* &#039;&#039;parametru -&amp;amp;nbsp;&#039;&#039;parametr operacji&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Każda instrukcja zajmuje w pamięci dwa bajty (kod + parametr). Po pobraniu kodu rozkazu lub parametru licznik automatycznie zwiększa się o jeden (czyli wskazuje na następny rozkaz).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Procesor.png]]&lt;br /&gt;
&lt;br /&gt;
Procesor działa powtarzając trzy operacje (każdy rozkaz jest wykonywany w czasie trzech taktów zegara):&lt;br /&gt;
&lt;br /&gt;
1. pobranie kodu instrukcji (z miejsca wskazanego przez licznik, zwiększa się o 1)&lt;br /&gt;
&lt;br /&gt;
2. pobranie parametru (z miejsca wskazanego przez licznik, zwiększa się o 1)&lt;br /&gt;
&lt;br /&gt;
3. wykonanie operacji&lt;br /&gt;
&lt;br /&gt;
tak długo, aż napotka rozkaz STOP.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nasz procesor wykonuje następujące instrukcje:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| align=center style=&amp;quot;border-top:0.2pt double #808080;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;nazwa&#039;&#039;&#039;&lt;br /&gt;
| align=center style=&amp;quot;border-top:0.2pt double #808080;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;kod&#039;&#039;&#039;&lt;br /&gt;
| align=center style=&amp;quot;border-top:0.2pt double #808080;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;parametr&#039;&#039;&#039;&lt;br /&gt;
| align=center style=&amp;quot;border:0.2pt double #808080;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;opis&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | POBIERZ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 1&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres danej&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | przepisuje zawartość wskazanej komórki pamięci do akumulatora&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | APOBIERZ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 2&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres pamięci&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | przepisz do akumulatora zawartość komórki o adresie wskazanym przez&amp;amp;nbsp;adres pamięci&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | WPISZ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 3&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres danej&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | zapisuje zawartość akumulatora do wskazanej komórki pamięci&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | DODAJ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 4&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres danej&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | dodaje zawartość wskazanej komórki do zawartości akumulatora&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | USTAW&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 5&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | liczba&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | ustaw zawartość akumulatora na&amp;amp;nbsp;liczba&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | SKOCZ_DO&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 6&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | wpisz&amp;amp;nbsp;adres&amp;amp;nbsp;do licznika&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | ZERO&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 7&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | gdy akumulator zawiera zero, wpisz&amp;amp;nbsp;adres&amp;amp;nbsp;do licznika&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | STOP&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 0&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 0&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | zatrzymaj&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
Spróbujmy napisać prosty program. Przyjmiemy, że adresy rozkazów zaczynają się od 0, a adresy danych od 100. Pierwsza komórka pamięci (adres 100) zawiera ilość liczb do zsumowania, druga będzie zawierać wynik, a trzecia będzie używana przez nas do adresowania. Następne zawierają liczby do zsumowania.&lt;br /&gt;
&lt;br /&gt;
Program w postaci symbolicznej będzie wyglądał następująco:&lt;br /&gt;
&lt;br /&gt;
0: USTAW LICZBY ; adres liczb do zsumowania&lt;br /&gt;
&lt;br /&gt;
2: WPISZ ADRES ; ustawienie komórki wskazującej sumowaną liczbę&lt;br /&gt;
&lt;br /&gt;
4: USTAW 0 ; zerowanie&lt;br /&gt;
&lt;br /&gt;
6: WPISZ WYNIK ; zapisanie wyniku&lt;br /&gt;
&lt;br /&gt;
8:A: POBIERZ ILOSC ; ilość liczb do zsumowania&lt;br /&gt;
&lt;br /&gt;
10: ZERO K ; nie ma już liczb do zsumowania&lt;br /&gt;
&lt;br /&gt;
12: DODAJ -1 ; zmniejsz ilość&lt;br /&gt;
&lt;br /&gt;
14: WPISZ ILOSC ; zapisz nową ilość&lt;br /&gt;
&lt;br /&gt;
16: APOBIERZ ADRES ; pobranie kolejnej liczby&lt;br /&gt;
&lt;br /&gt;
18: DODAJ WYNIK ; dodanie dotychczasowej sumy&lt;br /&gt;
&lt;br /&gt;
20: WPISZ WYNIK ; zapis wyniku&lt;br /&gt;
&lt;br /&gt;
22: POBIERZ ADRES ; pobranie adresu&lt;br /&gt;
&lt;br /&gt;
24: DODAJ 1 ; zwiększenie o 1&lt;br /&gt;
&lt;br /&gt;
26: WPISZ ADRES ; zapisanie nowego adresu&lt;br /&gt;
&lt;br /&gt;
28: SKOCZ_DO A ; powtórzenie dla następnej liczby&lt;br /&gt;
&lt;br /&gt;
30:K: STOP&lt;br /&gt;
&lt;br /&gt;
W powyższym zapisie mamy pięć kolumn:&lt;br /&gt;
&lt;br /&gt;
* adres w pamięci (z dwukropkiem)&lt;br /&gt;
* opcjonalni: symboliczny zapis adresu (też z dwukropkiem)&lt;br /&gt;
* kod instrukcji&lt;br /&gt;
* parametr&lt;br /&gt;
* komentarz (po średniku)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zamiast pisać kody instrukcji i adresy użyliśmy symboli. Podobnie zostały przedstawione adresy instrukcji (A, K).&lt;br /&gt;
&lt;br /&gt;
Wartość symboli:&lt;br /&gt;
&lt;br /&gt;
LICZBY = 103&lt;br /&gt;
&lt;br /&gt;
ADRES = 102&lt;br /&gt;
&lt;br /&gt;
WYNIK = 101&lt;br /&gt;
&lt;br /&gt;
ILOSC = 100&lt;br /&gt;
&lt;br /&gt;
A = 8&lt;br /&gt;
&lt;br /&gt;
K = 30&lt;br /&gt;
&lt;br /&gt;
Początek pamięci wygląda następująco (na początku wiersza podano adres pierwszej z komórek):&lt;br /&gt;
&lt;br /&gt;
0: 5; 103; 3; 102; 5; 0; 3;101;1; 100;&lt;br /&gt;
&lt;br /&gt;
10: 7; 30;4; -1; 3;100;2;102;4;101;&lt;br /&gt;
&lt;br /&gt;
20: 3;101;22:1;102;4;1;3;102;6;8;0&lt;br /&gt;
&lt;br /&gt;
Dla ćwiczenia spróbuj zamienić kody symbolami i porównaj z podanym wcześniej zapisem.&lt;br /&gt;
&lt;br /&gt;
Spróbuj określić zawartość komórek o adresie powyżej 100 i prześledzić jak będą się one zmieniały wraz z wykonywaniem programu.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Procesor_i_j%C4%99zyk_maszynowy_-_wprowadzenie&amp;diff=171</id>
		<title>Procesor i język maszynowy - wprowadzenie</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Procesor_i_j%C4%99zyk_maszynowy_-_wprowadzenie&amp;diff=171"/>
		<updated>2022-11-07T20:25:02Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Projektujemy procesor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Informacje o module:&lt;br /&gt;
* Poziom: Podstawowy&lt;br /&gt;
* Profil: Dla techników i inżynierów&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Struktura komputera ==&lt;br /&gt;
&lt;br /&gt;
W sklepach z zabawkami można dostać skarbonki w kształcie zwierzęcia, które po wrzuceniu monety w otwór na głowie zamyka usta, jakby coś połykało. W działaniu takiej skarbonki można wyróżnić kilka operacji: wrzucona moneta naciska na przedłużenie szczęki (1), szczęka zamyka się i moneta spada (2), szczęka otwiera się i skarbonka wraca do punktu początkowego (0). Zauważmy, że aby scharakteryzować działanie skarbonki, wystarczy opisać ją w pewnych wybranych momentach czasu. Opis taki nazywamy stanem urządzenia. W naszym przypadku możemy wyróżnić stany: podstawowy (0), wrzucona moneta (1), zamknięta szczęka (2). Samo działanie poza tymi wybranymi momentami nas nie interesuje - w takim opisie czas zmienia się skokowo (mówimy, że &#039;&#039;&#039;czas ma charakter dyskretny&#039;&#039;&#039;). Jest to oczywiście pewne uproszczenie, ale pozwala na dokonanie opisu w sposób bardzo ścisły.&lt;br /&gt;
&lt;br /&gt;
=== Komputer jest urządzeniem posiadającym pamięć ===&lt;br /&gt;
&lt;br /&gt;
Pamięcią&amp;amp;nbsp;nazwiemy urządzenie, którego stan w kolejnych momentach czasu możemy odczytać. Przykładem tak rozumianej pamięci może być zwykły notes. Możemy przeglądając go odczytać umieszczone tam zapiski. Zapiski te stanowią stan notesu. Tego typu pamięć ma jednak pewną wadę - zapis nie daje się łatwo zmieniać i nie może to być wykonane automatycznie. Pamięć komputera poza możliwością zmiany stanu musi charakteryzować się możliwością łatwego określenia zasad tych zmian tak, aby mogło to odbywać się automatycznie. Sposób automatycznej zmiany stanu można określić podając dla każdego stanu stan następny (po zmianie).&lt;br /&gt;
&lt;br /&gt;
Pamięć prawdziwych komputerów składa się z bardzo prostych elementów elektronicznych. Mogą się one znajdować w jednym z dwóch stanów: 0 lub 1. Stan jest reprezentowany przez wysokość napięcia (wysokie napięcie = 1, niskie = 0). Elementów takich jest za to bardzo dużo. Wielkość pamięci mierzy się w bitach (jeden element dwustanowy = 1 bit). Osiem bitów nazywa się bajtem. 1024 bajty to kilobajt (kB), a 1024 kilobajty to 1 megabajt (MB). Obecnie komputery mają przeważnie 8, 16, 32, 64 lub 128 MB pamięci.&lt;br /&gt;
&lt;br /&gt;
=== Procesor dokonuje zmian stanu pamięci ===&lt;br /&gt;
&lt;br /&gt;
Oczywiście zmiany pamięci nie wykonują się same z siebie. Potrzebny jest element który w sposób automatyczny wykona je zgodnie z instrukcjami. Po to właśnie komputer wyposażony jest w procesor, dokonujący zmian pamięci (stanu) w kolejnych momentach czasu.&lt;br /&gt;
&lt;br /&gt;
[[Plik:Pamiec_procesor.png]]&lt;br /&gt;
&lt;br /&gt;
Procesor jest układem elektronicznym przetwarzającym sygnały odczytane z pamięci. W jednym momencie odczytuje stan pamięci i oblicza stan następny. W następnym momencie zmienia się stan pamięci na wypracowany przez procesor.&lt;br /&gt;
&lt;br /&gt;
Kolejne chwile czasu (w których następuje zmiana stanu) wyznacza generator sygnałów elektrycznych zwany zegarem. Częstotliwość generowanego sygnału jest podstawowym parametrem określającym szybkość komputera (mówimy że procesor działa z szybkością 100MHz, 200MHz, itd..)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Teoretycznie rzecz biorąc następny stan pamięci zależy od stanu aktualnego całej pamięci. Jak wspomnieliśmy jednak, pamięć komputera jest bardzo duża. Dla uproszczenia konstrukcji procesory wykonuje się więc w ten sposób, że mogą one odczytywać i zmieniać jedynie mały fragment pamięci. Nie ma to większego wpływu na funkcjonalność komputera (zamiast zmienić stan wszystkich elementów równocześnie, zmienia się je po kolei). Sytuację tą można porównać do poruszania się w układzie współrzędnych tylko wzdłuż osi układu. W jednym kroku zmienia się tylko jedna współrzędna, ale nie ogranicza to zasięgu naszego ruchu (dla takich modeli często mówi się o przestrzeni stanów).&lt;br /&gt;
&lt;br /&gt;
=== Procesor - serce komputera ===&lt;br /&gt;
&lt;br /&gt;
Cykl działania procesora można więc określić w sposób następujący:&lt;br /&gt;
&lt;br /&gt;
#. Odczyt fragmentu pamięci (komórki, słowa).&lt;br /&gt;
#. Wykonanie operacji (+wyznaczenie następnego stanu tego fragmentu pamięci).&lt;br /&gt;
#. Zapis nowych wartości do pamięci.&lt;br /&gt;
#. Wyznaczenie nowego fragmentu pamięci do pobrania.&lt;br /&gt;
&lt;br /&gt;
Poszczególne operacje są wykonywane w takt zegara komputera. Każdy z powyższych punktów może być wykonywany w kilku taktach, ale teoretycznie możliwe jest wykonanie jednego cyklu tylko w dwóch taktach (punkty 2,3 i 4 mogą być wykonane w jednym kroku). Zależy to od budowy procesora.&lt;br /&gt;
&lt;br /&gt;
Jednym z najistotniejszych pomysłów na jakie wpadli konstruktorzy komputera jest&amp;amp;nbsp;&amp;lt;u&amp;gt;zapis instrukcji dla procesora w pamięci komputera&amp;lt;/u&amp;gt;. Aby procesor mógł sam odczytywać rozkazy (instrukcje) z pamięci i efektywnie działać zgodnie z przedstawionym powyżej schematem trzeba było przyjąć kilka dodatkowych założeń:&lt;br /&gt;
&lt;br /&gt;
#. Wszystkie instrukcje otrzymują swoje kody (załóżmy, że wszystkie informacje zapisane w pamięci są liczbami). Wraz z niektórymi z tych kodów są pamiętane parametry instrukcji (zob. przykład poniżej).&lt;br /&gt;
&lt;br /&gt;
#. Wszystkie komórki pamięci zostają ponumerowane (0,1,2,...). Mówimy, że komórki są adresowane.&lt;br /&gt;
&lt;br /&gt;
#. Wydziela się fragmenty pamięci w których będą pamiętane:* &lt;br /&gt;
* wynik ostatniej instrukcji (rozkazu)&lt;br /&gt;
* kod wykonywanej instrukcji&lt;br /&gt;
* numer komórki (adres) zawierającej kod kolejnego rozkazu do wykonania&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Te fragmenty pamięci nazywamy rejestrami. Rejestry zazwyczaj stanowią część procesora i nie są adresowane tak jak reszta pamięci. W konkretnych realizacjach procesorów ilość rejestrów jest większa (zazwyczaj jednak nie więcej niż 10). Ta wewnętrzna złożoność procesora jest jedną z przyczyn, dla których pewne operacje wymagają więcej niż dwóch taktów zegara.&lt;br /&gt;
&lt;br /&gt;
== Projektujemy procesor ==&lt;br /&gt;
&lt;br /&gt;
Budowę procesora najlepiej pokazać na przykładzie. W tym celu zaprojektujemy prosty, przykładowy procesor. Przyjmujemy, że procesor zawiera rejestry:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;akumulator&amp;amp;nbsp;&#039;&#039;- wynik operacji&lt;br /&gt;
* &#039;&#039;licznik -&amp;amp;nbsp;&#039;&#039;adres kolejnej operacji&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dodatkowo mamy rejestry pomocnicze, które są używane przez procesor do przechowywania aktualnie wykonywanej instrukcji:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;instrukcji -&amp;amp;nbsp;&#039;&#039;kod pobranego rozkazu&lt;br /&gt;
* &#039;&#039;parametru -&amp;amp;nbsp;&#039;&#039;parametr operacji&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Każda instrukcja zajmuje w pamięci dwa bajty (kod + parametr). Po pobraniu kodu rozkazu lub parametru licznik automatycznie zwiększa się o jeden (czyli wskazuje na następny rozkaz).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Procesor.png]]&lt;br /&gt;
&lt;br /&gt;
Procesor działa powtarzając trzy operacje (każdy rozkaz jest wykonywany w czasie trzech taktów zegara):&lt;br /&gt;
&lt;br /&gt;
1. pobranie kodu instrukcji (z miejsca wskazanego przez licznik, zwiększa się o 1)&lt;br /&gt;
&lt;br /&gt;
2. pobranie parametru (z miejsca wskazanego przez licznik, zwiększa się o 1)&lt;br /&gt;
&lt;br /&gt;
3. wykonanie operacji&lt;br /&gt;
&lt;br /&gt;
tak długo, aż napotka rozkaz STOP.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nasz procesor wykonuje następujące instrukcje:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
| align=center style=&amp;quot;border-top:0.2pt double #808080;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;nazwa&#039;&#039;&#039;&lt;br /&gt;
| align=center style=&amp;quot;border-top:0.2pt double #808080;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;kod&#039;&#039;&#039;&lt;br /&gt;
| align=center style=&amp;quot;border-top:0.2pt double #808080;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;parametr&#039;&#039;&#039;&lt;br /&gt;
| align=center style=&amp;quot;border:0.2pt double #808080;padding:0.049cm;&amp;quot; | &#039;&#039;&#039;opis&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | POBIERZ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 1&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres danej&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | przepisuje zawartość wskazanej komórki pamięci do akumulatora&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | APOBIERZ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 2&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres pamięci&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | przepisz do akumulatora zawartość komórki o adresie wskazanym przez&amp;amp;nbsp;adres pamięci&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | WPISZ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 3&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres danej&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | zapisuje zawartość akumulatora do wskazanej komórki pamięci&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | DODAJ&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 4&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres danej&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | dodaje zawartość wskazanej komórki do zawartości akumulatora&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | USTAW&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 5&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | liczba&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | ustaw zawartość akumulatora na&amp;amp;nbsp;liczba&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | SKOCZ_DO&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 6&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | wpisz&amp;amp;nbsp;adres&amp;amp;nbsp;do licznika&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | ZERO&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 7&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | adres&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | gdy akumulator zawiera zero, wpisz&amp;amp;nbsp;adres&amp;amp;nbsp;do licznika&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | STOP&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 0&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:none;padding:0.049cm;&amp;quot; | 0&lt;br /&gt;
| style=&amp;quot;border-top:none;border-bottom:0.2pt double #808080;border-left:0.2pt double #808080;border-right:0.2pt double #808080;padding:0.049cm;&amp;quot; | zatrzymaj&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
Spróbujmy napisać prosty program. Przyjmiemy, że adresy rozkazów zaczynają się od 0, a adresy danych od 100. Pierwsza komórka pamięci (adres 100) zawiera ilość liczb do zsumowania, druga będzie zawierać wynik, a trzecia będzie używana przez nas do adresowania. Następne zawierają liczby do zsumowania.&lt;br /&gt;
&lt;br /&gt;
Program w postaci symbolicznej będzie wyglądał następująco:&lt;br /&gt;
&lt;br /&gt;
0: USTAW LICZBY ; adres liczb do zsumowania&lt;br /&gt;
&lt;br /&gt;
2: WPISZ ADRES ; ustawienie komórki wskazującej sumowaną liczbę&lt;br /&gt;
&lt;br /&gt;
4: USTAW 0 ; zerowanie&lt;br /&gt;
&lt;br /&gt;
6: WPISZ WYNIK ; zapisanie wyniku&lt;br /&gt;
&lt;br /&gt;
8:A: POBIERZ ILOSC ; ilość liczb do zsumowania&lt;br /&gt;
&lt;br /&gt;
10: ZERO K ; nie ma już liczb do zsumowania&lt;br /&gt;
&lt;br /&gt;
12: DODAJ -1 ; zmniejsz ilość&lt;br /&gt;
&lt;br /&gt;
14: WPISZ ILOSC ; zapisz nową ilość&lt;br /&gt;
&lt;br /&gt;
16: POBIERZ ADRES ; pobranie kolejnej liczby&lt;br /&gt;
&lt;br /&gt;
18: DODAJ WYNIK ; dodanie dotychczasowej sumy&lt;br /&gt;
&lt;br /&gt;
20: WPISZ WYNIK ; zapis wyniku&lt;br /&gt;
&lt;br /&gt;
22: POBIERZ ADRES ; pobranie adresu&lt;br /&gt;
&lt;br /&gt;
24: DODAJ 1 ; zwiększenie o 1&lt;br /&gt;
&lt;br /&gt;
26: WPISZ ADRES ; zapisanie nowego adresu&lt;br /&gt;
&lt;br /&gt;
28: SKOCZ_DO A ; powtórzenie dla następnej liczby&lt;br /&gt;
&lt;br /&gt;
30:K: STOP&lt;br /&gt;
&lt;br /&gt;
W powyższym zapisie mamy pięć kolumn:&lt;br /&gt;
&lt;br /&gt;
* adres w pamięci (z dwukropkiem)&lt;br /&gt;
* opcjonalni: symboliczny zapis adresu (też z dwukropkiem)&lt;br /&gt;
* kod instrukcji&lt;br /&gt;
* parametr&lt;br /&gt;
* komentarz (po średniku)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zamiast pisać kody instrukcji i adresy użyliśmy symboli. Podobnie zostały przedstawione adresy instrukcji (A, K).&lt;br /&gt;
&lt;br /&gt;
Wartość symboli:&lt;br /&gt;
&lt;br /&gt;
LICZBY = 103&lt;br /&gt;
&lt;br /&gt;
ADRES = 102&lt;br /&gt;
&lt;br /&gt;
WYNIK = 101&lt;br /&gt;
&lt;br /&gt;
ILOSC = 100&lt;br /&gt;
&lt;br /&gt;
A = 8&lt;br /&gt;
&lt;br /&gt;
K = 30&lt;br /&gt;
&lt;br /&gt;
Początek pamięci wygląda następująco (na początku wiersza podano adres pierwszej z komórek):&lt;br /&gt;
&lt;br /&gt;
0: 5; 103; 3; 102; 5; 0; 3;101;1; 100;&lt;br /&gt;
&lt;br /&gt;
10: 7; 30;4; -1; 3;100;2;102;4;101;&lt;br /&gt;
&lt;br /&gt;
20: 3;101;22:1;102;4;1;3;102;6;8;0&lt;br /&gt;
&lt;br /&gt;
Dla ćwiczenia spróbuj zamienić kody symbolami i porównaj z podanym wcześniej zapisem.&lt;br /&gt;
&lt;br /&gt;
Spróbuj określić zawartość komórek o adresie powyżej 100 i prześledzić jak będą się one zmieniały wraz z wykonywaniem programu.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=RSA&amp;diff=170</id>
		<title>RSA</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=RSA&amp;diff=170"/>
		<updated>2022-09-30T14:27:01Z</updated>

		<summary type="html">&lt;p&gt;Admin: rsa&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Algorytm RSA jest jednym z najważniejszych algorytmów związanych z bezpieczeństwem.&lt;br /&gt;
&lt;br /&gt;
== Podstawy teoretyczne ==&lt;br /&gt;
&lt;br /&gt;
# Funkcja Eulera:  fi(n) - ilość liczb całkowitych dodatnich mniejszych od n i względnie pierwszych z n.  1.1. fi(n) = n-1, gdy n jest liczbą pierwszą (bo każda liczba jest względnie pierwsza z liczbą pierwszą).  1.2. Gdy n =p*q, gdzie p, q - liczby pierwsze, fi(n) = (p-1)*(q-1)  Dowód:&lt;br /&gt;
#* wszystkich liczb mniejszych od n jest p*q-1&lt;br /&gt;
#* liczby mające z n wspólny podzielnik p: p, 2*p, 3*p, ... (q-1)*p - jest ich q-1&lt;br /&gt;
#* liczby mające z n wspólny podzielnik q: q, 2*q, 3*q, ... (p-1)*q - jest ich p-1&lt;br /&gt;
#* a więc: fi(n) = p*q - (p-1) - (q-1) -1 = p*q - p - q + 1 = (p-1) * (q-1) = fi(p)*fi(q)&lt;br /&gt;
# Twierdzenie Eulera:  Dla każdych (a, n), takich, że gcd(a,n) = 1 mamy (a^fi(n)) mod n =1  ^ oznacza potęgowanie  gcd = największy wspólny podzielnik  mod = reszta z dzielenia (modulo), ale określona na liczbach dodatnich (-1 mod 10 = 9 !!!).  Dowód:&lt;br /&gt;
#* R = {r1, r2,... rfi(n) } - zbiór liczb całkowitych dodatnich, mniejszych od n i względnie pierwszych z n (residuów) (zob. Funkcję Eulera)&lt;br /&gt;
#* jeśli każdą z liczb ri pomnożymy przez a modulo n ( (ri * a) mod n ), otrzymamy fi(n) różnych wyników; gdyby bowiem zachodziło: ri * a mod n = rj * a mod n = r, mielibyśmy (ri-rj)*a mod n =0, a więc a i n nie byłyby względnie pierwsze.&lt;br /&gt;
#* mamy więc (a*r1)*(a*r2)*....*(a*rfi(n)) = r1*r2*...*rfi(n)  czyli (a^fi(n) mod n) * r1*r2*...*rfi(n) = r1*r2*...*rfi(n)  a po uproszczeniu a^fi(n) mod n = 1&lt;br /&gt;
# Szyfr wykładniczy polega na szyfrowaniu poprzez potęgowanie modulo n.  C = M^e mod n  Odszyfrowanie można wykonać poprzez potęgowanie używając innego wykładnika (klucza)!:  M=C^d mod n  Powyższe równania są swoją odwrotnością (czyli pomnożenie ich daje w wyniku 1, albo inaczej  (M^e mod n) ^d mod n = M), pod warunkiem, że e*d mod fi(n) = 1  Dowód:&lt;br /&gt;
#* (M^e mod n) ^d mod n = M^(e*d) mod n&lt;br /&gt;
#* ale:e*d = t * fi(n) +1&lt;br /&gt;
#* mamy więc M^e*d mod n = M^(t*fi(n)+1) mod n = M*M^(t*fi(n) mod n = M* (M^(t*fi(n)) mod n) mod n&lt;br /&gt;
#* na mocy twierdzenia Eulera mamy M^(t*fi(n)) mod n = ((M^fi(n) mod n)^t) mod n = 1^t mod n = 1&lt;br /&gt;
#* a więc M^(e*d) mod n = (M*1) mod n = M&lt;br /&gt;
# Generowanie kluczy:&lt;br /&gt;
#* wybieramy d względnie pierwsze z fi(n)&lt;br /&gt;
#* obliczamy e = inv(d, fi(n))  gdzie inv = odwrotność, czyli (x * inv(x, fi(n)) ) mod fi(n)=1&lt;br /&gt;
&lt;br /&gt;
Najprostsza implementacja (Python):&amp;lt;syntaxhighlight lang=&amp;quot;py3&amp;quot;&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
import primesieve&lt;br /&gt;
from random import randint&lt;br /&gt;
&lt;br /&gt;
def gen_prime(min, max):&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Eratosthenes sieve http://code.activestate.com/recipes/117119/&lt;br /&gt;
https://github.com/hickford/primesieve-python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
  prime_list = primesieve.primes(min, max)&lt;br /&gt;
  while (not prime_list):&lt;br /&gt;
    min=max&lt;br /&gt;
    max+=100&lt;br /&gt;
    prime_list = generate_primes(min, max)&lt;br /&gt;
  n=randint(0, len(prime_list)-1)&lt;br /&gt;
  return prime_list[n]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# The greatest common divisor (GCD) - Euclides&lt;br /&gt;
def gcd(x, y):&lt;br /&gt;
  while y != 0:&lt;br /&gt;
    (x, y) = (y, x % y)&lt;br /&gt;
  return x&lt;br /&gt;
&lt;br /&gt;
# result == x: a*x mod n == 1, 0 &amp;lt; a &amp;lt; n&lt;br /&gt;
# extended Euclides&lt;br /&gt;
# https://anh.cs.luc.edu/331/notes/xgcd.pdf&lt;br /&gt;
def inv(a,n):&lt;br /&gt;
  v0 = 0&lt;br /&gt;
  v1 = 1&lt;br /&gt;
  r0=n&lt;br /&gt;
  r1=a&lt;br /&gt;
  while r1 != 0:&lt;br /&gt;
    d = r0 // r1&lt;br /&gt;
    (r0, r1) = r1, r0 - d * r1&lt;br /&gt;
    (v0, v1) = v1, v0 - d * v1&lt;br /&gt;
  if v0&amp;gt;0:&lt;br /&gt;
    return v0&lt;br /&gt;
  else:&lt;br /&gt;
    return v0+n&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def rsa_keys(p, q): # p&amp;lt;q&lt;br /&gt;
  # return: d, e, p * q&lt;br /&gt;
  n=p*q&lt;br /&gt;
  fi=(q-1)*(p-1)&lt;br /&gt;
  # wybieramy d wzglednie pierwsze wzgledem fi z przedzialu [q + 1 .. n-1] &lt;br /&gt;
  d=q+1&lt;br /&gt;
  wd=-1&lt;br /&gt;
  while (wd != 1 ) and (d&amp;lt;n):&lt;br /&gt;
    wd=gcd(d, fi)&lt;br /&gt;
    if wd != 1:&lt;br /&gt;
      d+=1&lt;br /&gt;
  if wd != 1:&lt;br /&gt;
    print(&#039;nie znaleziono kluczy&#039;)&lt;br /&gt;
    exit(-1)&lt;br /&gt;
  e = inv(d, fi)&lt;br /&gt;
  return (d, e, n)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def rsa(M, d, n):&lt;br /&gt;
  return (M ** d) % n&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__==&amp;quot;__main__&amp;quot;:&lt;br /&gt;
  # przykładowe dane startowe&lt;br /&gt;
  min=779&lt;br /&gt;
  d=88&lt;br /&gt;
  # liczby pierwsze&lt;br /&gt;
  p=gen_prime(min,min+d)&lt;br /&gt;
  q=gen_prime(p,p+d)&lt;br /&gt;
  # klucze&lt;br /&gt;
  d, e, n = rsa_keys(p, q)&lt;br /&gt;
  print (&#039;d=%s, e=%s, n=%s&#039; % (d, e, n))&lt;br /&gt;
  # test&lt;br /&gt;
  M=input(&#039;Liczba=&#039;)&lt;br /&gt;
  Mcrypt=rsa(M,d,n)&lt;br /&gt;
  print(&amp;quot;zaszyfrowana=%s&amp;quot; % Mcrypt)&lt;br /&gt;
  print(&amp;quot;odszyfrowana=%s&amp;quot; % rsa(Mcrypt,e,n))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Ta implementacja nie nadaje się do praktycznego zastosowania, gdyż program działa zbyt wolno, a przy generowaniu kluczy nie są sprawdzane dodatkowe wymogi odpowiedniej złożoności. Powyższy program służy jedynie do zilustrowania algorytmu. W praktyce stosuje się gotowe biblioteki takie jak OpenSSL.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytmy&amp;diff=169</id>
		<title>Algorytmy</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytmy&amp;diff=169"/>
		<updated>2022-09-30T14:19:17Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[Proste sortowanie tablic]]&lt;br /&gt;
* [[Algorytm Simplex]]&lt;br /&gt;
* [[RSA]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=168</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=168"/>
		<updated>2022-09-30T05:51:24Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy rozwiązywania układów równań i nierówności liniowych.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z: wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:  xi ≥ di, wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
----Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie współczynniki funkcji celu [c] są mniejsze lub równe zeru (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: skoro wszystkie wartości zmiennych decyzyjnych X są większe lub równe zeru, to jeśli i-ty element [c] (c[i]) jest większy od zera, zwiększenie współrzędnej i (x[i]&amp;gt;0) powoduje zwiększenie funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były mniejsze lub równe zeru (przy szukaniu maksimum).&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą mniejsze lub równe zeru, albo nie uda się znaleźć przekształcenia dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[3,4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uwaga! Wartości zmiennych w ostatniej kolumnie dotyczą zmiennych bazowych. Jeśli zmienna decyzyjna nie jest obecna w bazie - oznacza to, że w rozwiązaniu jej wartość wynosi zero (0).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
===== Analiza działania algorytmu =====&lt;br /&gt;
Dla tablicy z jedną zmienną decyzyjną x1 i jedną zmienną luzu (x2) wartość funkcji celu będzie wynosić (x1/x1 – z dzielenia wiersza przez x1, a następnie odejmowanie wiersza):&lt;br /&gt;
&lt;br /&gt;
z = 0-b1*c1*x1/x1&lt;br /&gt;
&lt;br /&gt;
czyli (zgodnie z oczekiwaniem):&lt;br /&gt;
&lt;br /&gt;
z=-b1*c1&lt;br /&gt;
&lt;br /&gt;
Przykład:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; |Tablica 1&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;5,00&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|c&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;3&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;5,00&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
|5,00&lt;br /&gt;
|-&lt;br /&gt;
|c&lt;br /&gt;
|0,00&lt;br /&gt;
| -1,00&lt;br /&gt;
| -5,00&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że jeśli c1 byłoby &amp;lt;0 – zadanie nie miałoby rozwiązania dla liczb dodatnich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weźmy teraz pod uwagę dowolną tablicę Simplex w której została do zredukowania jedna kolumna ze zmienną decyzyjną. Na przykład odpowiadająca nierówności 2*x3&amp;lt;=3, oraz czynnikowi x3*4 w funkcji celu (kolumna x3, wiersz 2):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|x1&lt;br /&gt;
|x2&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|s1&lt;br /&gt;
|s2&lt;br /&gt;
|&#039;&#039;&#039;s3&#039;&#039;&#039;&lt;br /&gt;
|b&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|8,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|1,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|4,50&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
| -22,50&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;5&amp;quot; |Wiersz 2 podzielony przez a[2][2] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,5&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,5&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
| -1,00&lt;br /&gt;
|5,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|4,50&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|1,50&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
| -2,00&lt;br /&gt;
| -28,50&lt;br /&gt;
|}&lt;br /&gt;
Wykonanie redukcji zmienia wynik funkcji celu o b[2] podzielone przez x3[2] i pomnożone przez c z kolumny x3 (c[2]). Czyli najpierw wyliczamy ile co najwyżej może wynosić x3, a następnie odejmowana jest ta wartość od wyniku funkcji celu (przy liczeniu maksimum wynik jest uzyskiwany ze znakiem minus), po przemnożeniu przez odpowiedni współczynnik (c[2] – czyli 4).&lt;br /&gt;
&lt;br /&gt;
Czyli redukcja działa dokładnie tak, jakbyśmy to zrobili bez automatu. Tak samo algorytm Simplex zadziałałby, gdyby dodać kolumnę z jedną wartością dla dowolnej wielkości tablicy.&lt;br /&gt;
&lt;br /&gt;
Zastanówmy się na koniec – co się stanie, jeśli dodana kolumna x3 będzie zawierać wartości różne od zera 0 w więcej niż jednym wierszu. Prześledźmy zmiany tablicy od samego początku:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;S3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;min. dla X1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|1,00&lt;br /&gt;
|2,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|9,00&lt;br /&gt;
|9,00&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|2,00&lt;br /&gt;
|5,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 2&lt;br /&gt;
|dla x2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|7,00&lt;br /&gt;
|2,80&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;6,00&#039;&#039;&#039;&lt;br /&gt;
|5,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-4,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][1] – czyli -2.5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,20&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,80&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 3&lt;br /&gt;
|dla x3&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,40&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;3,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-20,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[2][2] – czyli 3&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,33&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 4&lt;br /&gt;
|dla s1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|8,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-30,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][2] – czyli 0,4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|4,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-32,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Baza dla tego przykładu zmienia się następująco (s1,s2,s3) → (x1,s2,s3)→(x1,x2,s3)→(x1,x2,x3)→(s1,x2,x3)&lt;br /&gt;
&lt;br /&gt;
Zmienna x3 wchodzi do bazy w „Tablicy 4”. Do tego momentu kolumna x3 nie wpływa na resztę tablicy (poza oczywiście uwzględnieniem w wartości funkcji celu). Wtedy wyliczana jest wartość x3 przez podzielenie ograniczenia (b[2]) przez współczynnik (x3[2]).&lt;br /&gt;
&lt;br /&gt;
Gdyby jednak w tablicy pojawiła się liczba 1 w polu x3[1] - wtedy w miejsce x1+2*x2&amp;lt;9 mielibyśmy x1+2*x2+x3&amp;lt;9. Wtedy przy redukcji kolumny x2 – odpowiadającej wierszowi z wstawioną jedynką – zostanie ona „przeliczona” na wartości 0,2 i 0,4 (Tablica 3, wiersz 0 i 1) – co w tablicy 4 skutkuje zmniejszeniem b[0] i b[1] w tablicy 4 (odpowiednio 2*0,2 oraz 2*0,4).&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;S3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;min. dla X1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,00&lt;br /&gt;
| -1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|1,00&lt;br /&gt;
|2,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|9,00&lt;br /&gt;
|9,00&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|2,00&lt;br /&gt;
|5,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla x2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
| -0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|7,00&lt;br /&gt;
|2,80&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;6,00&#039;&#039;&#039;&lt;br /&gt;
|5,00&lt;br /&gt;
| -1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -4,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][1] – czyli -2.5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,20&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,80&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 3&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla x3&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
|0,40&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,40&lt;br /&gt;
| -0,20&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;3,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,60&lt;br /&gt;
|0,20&lt;br /&gt;
| -2,40&lt;br /&gt;
|0,00&lt;br /&gt;
| -20,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[2][2] – czyli 3&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,33&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 4&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla s1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|0,20&lt;br /&gt;
| -0,07&lt;br /&gt;
|3,00&lt;br /&gt;
|7,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
| -0,20&lt;br /&gt;
|0,40&lt;br /&gt;
| -0,13&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
| -2,40&lt;br /&gt;
| -0,87&lt;br /&gt;
| -26,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][2] – czyli 0,4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,17&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;7,50&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,50&lt;br /&gt;
| -0,17&lt;br /&gt;
|7,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
| -0,17&lt;br /&gt;
|3,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
| -0,83&lt;br /&gt;
| -27,50&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
To zmniejszenie (b[0], b[1]) należy interpretować jako wyliczenie wpływu x3 na x1 i x2 we wspomnianej wyżej nierówności (wiersz 1). Jak to policzylibyśmy bez tablicy? Przyjmując x1+2*x2+x3 = 9 (wiersz 1) i x3=2 (6/2 - wiersz 2). Jeśli w ostatecznym wyniku x1=0, to x2=(9-2)/2 =3.5. Czyli dokładnie tyle, ile wylicza algorytm.&lt;br /&gt;
[[Plik:Simplex3.ods|mały]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=167</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=167"/>
		<updated>2022-09-30T04:09:57Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy rozwiązywania układów równań i nierówności liniowych.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z: wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:  xi ≥ di, wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
----Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie współczynniki funkcji celu [c] są mniejsze lub równe zeru (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: skoro wszystkie wartości zmiennych decyzyjnych X są większe lub równe zeru, to jeśli i-ty element [c] (c[i]) jest większy od zera, zwiększenie współrzędnej i (x[i]&amp;gt;0) powoduje zwiększenie funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były mniejsze lub równe zeru (przy szukaniu maksimum).&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą mniejsze lub równe zeru, albo nie uda się znaleźć przekształcenia dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uwaga! Wartości zmiennych w ostatniej kolumnie dotyczą zmiennych bazowych. Jeśli zmienna decyzyjna nie jest obecna w bazie - oznacza to, że w rozwiązaniu jej wartość wynosi zero (0).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
===== Analiza działania algorytmu =====&lt;br /&gt;
Dla tablicy z jedną zmienną decyzyjną x1 i jedną zmienną luzu (x2) wartość funkcji celu będzie wynosić (x1/x1 – z dzielenia wiersza przez x1, a następnie odejmowanie wiersza):&lt;br /&gt;
&lt;br /&gt;
z = 0-b1*c1*x1/x1&lt;br /&gt;
&lt;br /&gt;
czyli (zgodnie z oczekiwaniem):&lt;br /&gt;
&lt;br /&gt;
z=-b1*c1&lt;br /&gt;
&lt;br /&gt;
Przykład:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; |Tablica 1&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;5,00&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|c&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;3&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;5,00&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
|5,00&lt;br /&gt;
|-&lt;br /&gt;
|c&lt;br /&gt;
|0,00&lt;br /&gt;
| -1,00&lt;br /&gt;
| -5,00&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że jeśli c1 byłoby &amp;lt;0 – zadanie nie miałoby rozwiązania dla liczb dodatnich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weźmy teraz pod uwagę dowolną tablicę Simplex w której została do zredukowania jedna kolumna ze zmienną decyzyjną. Na przykład odpowiadająca nierówności 2*x3&amp;lt;=3, oraz czynnikowi x3*4 w funkcji celu (kolumna x3, wiersz 2):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|x1&lt;br /&gt;
|x2&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|s1&lt;br /&gt;
|s2&lt;br /&gt;
|&#039;&#039;&#039;s3&#039;&#039;&#039;&lt;br /&gt;
|b&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|8,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|1,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|4,50&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
| -22,50&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;5&amp;quot; |Wiersz 2 podzielony przez a[2][2] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,5&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,5&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
| -1,00&lt;br /&gt;
|5,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|4,50&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|1,50&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
| -2,00&lt;br /&gt;
| -28,50&lt;br /&gt;
|}&lt;br /&gt;
Wykonanie redukcji zmienia wynik funkcji celu o b[2] podzielone przez x3[2] i pomnożone przez c z kolumny x3 (c[2]). Czyli najpierw wyliczamy ile co najwyżej może wynosić x3, a następnie odejmowana jest ta wartość od wyniku funkcji celu (przy liczeniu maksimum wynik jest uzyskiwany ze znakiem minus), po przemnożeniu przez odpowiedni współczynnik (c[2] – czyli 4).&lt;br /&gt;
&lt;br /&gt;
Czyli redukcja działa dokładnie tak, jakbyśmy to zrobili bez automatu. Tak samo algorytm Simplex zadziałałby, gdyby dodać kolumnę z jedną wartością dla dowolnej wielkości tablicy.&lt;br /&gt;
&lt;br /&gt;
Zastanówmy się na koniec – co się stanie, jeśli dodana kolumna x3 będzie zawierać wartości różne od zera 0 w więcej niż jednym wierszu. Prześledźmy zmiany tablicy od samego początku:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;S3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;min. dla X1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|1,00&lt;br /&gt;
|2,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|9,00&lt;br /&gt;
|9,00&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|2,00&lt;br /&gt;
|5,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 2&lt;br /&gt;
|dla x2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|7,00&lt;br /&gt;
|2,80&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;6,00&#039;&#039;&#039;&lt;br /&gt;
|5,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-4,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][1] – czyli -2.5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,20&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,80&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 3&lt;br /&gt;
|dla x3&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,40&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;3,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-20,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[2][2] – czyli 3&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,33&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 4&lt;br /&gt;
|dla s1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|8,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-30,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][2] – czyli 0,4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|4,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-32,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Baza dla tego przykładu zmienia się następująco (s1,s2,s3) → (x1,s2,s3)→(x1,x2,s3)→(x1,x2,x3)→(s1,x2,x3)&lt;br /&gt;
&lt;br /&gt;
Zmienna x3 wchodzi do bazy w „Tablicy 4”. Do tego momentu kolumna x3 nie wpływa na resztę tablicy (poza oczywiście uwzględnieniem w wartości funkcji celu). Wtedy wyliczana jest wartość x3 przez podzielenie ograniczenia (b[2]) przez współczynnik (x3[2]).&lt;br /&gt;
&lt;br /&gt;
Gdyby jednak w tablicy pojawiła się liczba 1 w polu x3[1] - wtedy w miejsce x1+2*x2&amp;lt;9 mielibyśmy x1+2*x2+x3&amp;lt;9. Wtedy przy redukcji kolumny x2 – odpowiadającej wierszowi z wstawioną jedynką – zostanie ona „przeliczona” na wartości 0,2 i 0,4 (Tablica 3, wiersz 0 i 1) – co w tablicy 4 skutkuje zmniejszeniem b[0] i b[1] w tablicy 4 (odpowiednio 2*0,2 oraz 2*0,4).&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;S3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;min. dla X1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,00&lt;br /&gt;
| -1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|1,00&lt;br /&gt;
|2,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|9,00&lt;br /&gt;
|9,00&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|2,00&lt;br /&gt;
|5,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla x2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
| -0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|7,00&lt;br /&gt;
|2,80&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;6,00&#039;&#039;&#039;&lt;br /&gt;
|5,00&lt;br /&gt;
| -1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -4,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][1] – czyli -2.5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,20&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,80&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 3&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla x3&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
|0,40&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,40&lt;br /&gt;
| -0,20&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;3,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,60&lt;br /&gt;
|0,20&lt;br /&gt;
| -2,40&lt;br /&gt;
|0,00&lt;br /&gt;
| -20,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[2][2] – czyli 3&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,33&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 4&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla s1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|0,20&lt;br /&gt;
| -0,07&lt;br /&gt;
|3,00&lt;br /&gt;
|7,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
| -0,20&lt;br /&gt;
|0,40&lt;br /&gt;
| -0,13&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
| -2,40&lt;br /&gt;
| -0,87&lt;br /&gt;
| -26,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][2] – czyli 0,4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,17&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;7,50&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,50&lt;br /&gt;
| -0,17&lt;br /&gt;
|7,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
| -0,17&lt;br /&gt;
|3,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
| -0,83&lt;br /&gt;
| -27,50&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
To zmniejszenie (b[0], b[1]) należy interpretować jako wyliczenie wpływu x3 na x1 i x2 we wspomnianej wyżej nierówności (wiersz 1). Jak to policzylibyśmy bez tablicy? Przyjmując x1+2*x2+x3 = 9 (wiersz 1) i x3=2 (6/2 - wiersz 2). Jeśli w ostatecznym wyniku x1=0, to x2=(9-2)/2 =3.5. Czyli dokładnie tyle, ile wylicza algorytm.&lt;br /&gt;
[[Plik:Simplex3.ods|mały]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=166</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=166"/>
		<updated>2022-09-29T22:15:06Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Analiza działania algorytmu */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy rozwiązywania układów równań i nierówności liniowych.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z: wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:  xi ≥ di, wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
----Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie współczynniki funkcji celu [c] są mniejsze lub równe zeru (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: skoro wszystkie wartości zmiennych decyzyjnych X są większe lub równe zeru, to jeśli i-ty element [c] (c[i]) jest większy od zera, zwiększenie współrzędnej i (x[i]&amp;gt;0) powoduje zwiększenie funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były mniejsze lub równe zeru (przy szukaniu maksimum).&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą mniejsze lub równe zeru, albo nie uda się znaleźć przekształcenia dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uwaga! Wartości zmiennych w ostatniej kolumnie dotyczą zmiennych bazowych. Jeśli zmienna decyzyjna nie jest obecna w bazie - oznacza to, że w rozwiązaniu jej wartość wynosi zero (0).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
===== Analiza działania algorytmu =====&lt;br /&gt;
Dla tablicy z jedną zmienną decyzyjną x1 i jedną zmienną luzu (x2) wartość funkcji celu będzie wynosić (x1/x1 – z dzielenia wiersza przez x1, a następnie odejmowanie wiersza):&lt;br /&gt;
&lt;br /&gt;
z = 0-b1*c1*x1/x1&lt;br /&gt;
&lt;br /&gt;
czyli (zgodnie z oczekiwaniem):&lt;br /&gt;
&lt;br /&gt;
z=-b1*c1&lt;br /&gt;
&lt;br /&gt;
Przykład:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;4&amp;quot; |Tablica 1&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;5,00&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|c&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;3&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;5,00&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
|5,00&lt;br /&gt;
|-&lt;br /&gt;
|c&lt;br /&gt;
|0,00&lt;br /&gt;
| -1,00&lt;br /&gt;
| -5,00&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że jeśli c1 byłoby &amp;lt;0 – zadanie nie miałoby rozwiązania dla liczb dodatnich.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Weźmy teraz pod uwagę dowolną tablicę Simplex w której została do zredukowania jedna kolumna ze zmienną decyzyjną. Na przykład odpowiadająca nierówności 2*x3&amp;lt;=3, oraz czynnikowi x3*4 w funkcji celu (kolumna x3, wiersz 2):&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|x1&lt;br /&gt;
|x2&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|s1&lt;br /&gt;
|s2&lt;br /&gt;
|&#039;&#039;&#039;s3&#039;&#039;&#039;&lt;br /&gt;
|b&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|8,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|1,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|4,50&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
| -22,50&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;5&amp;quot; |Wiersz 2 podzielony przez a[2][2] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,5&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,5&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
| -1,00&lt;br /&gt;
|5,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|4,50&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|1,50&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
| -2,00&lt;br /&gt;
| -28,50&lt;br /&gt;
|}&lt;br /&gt;
Wykonanie redukcji zmienia wynik funkcji celu o b[2] podzielone przez x3[2] i pomnożone przez c z kolumny x3 (c[2]). Czyli najpierw wyliczamy ile co najwyżej może wynosić x3, a następnie odejmowana jest ta wartość od wyniku funkcji celu (przy liczeniu maksimum wynik jest uzyskiwany ze znakiem minus), po przemnożeniu przez odpowiedni współczynnik (c[2] – czyli 4).&lt;br /&gt;
&lt;br /&gt;
Czyli redukcja działa dokładnie tak, jakbyśmy to zrobili bez automatu. Tak samo algorytm Simplex zadziałałby, gdyby dodać kolumnę z jedną wartością dla dowolnej wielkości tablicy.&lt;br /&gt;
&lt;br /&gt;
Zastanówmy się na koniec – co się stanie, jeśli dodana kolumna x3 będzie zawierać wartości różne od zera 0 w więcej niż jednym wierszu. Prześledźmy zmiany tablicy od samego początku:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;S3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;min. dla X1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|1,00&lt;br /&gt;
|2,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|9,00&lt;br /&gt;
|9,00&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|2,00&lt;br /&gt;
|5,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 2&lt;br /&gt;
|dla x2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|7,00&lt;br /&gt;
|2,80&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;6,00&#039;&#039;&#039;&lt;br /&gt;
|5,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-4,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][1] – czyli -2.5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,20&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,80&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 3&lt;br /&gt;
|dla x3&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,40&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;3,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-20,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[2][2] – czyli 3&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,33&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 4&lt;br /&gt;
|dla s1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|8,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-30,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][2] – czyli 0,4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|4,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-32,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Baza dla tego przykładu zmienia się następująco (s1,s2,s3) → (x1,s2,s3)→(x1,x2,s3)→(x1,x2,x3)→(s1,x2,x3)&lt;br /&gt;
&lt;br /&gt;
Zmienna x3 wchodzi do bazy w „Tablicy 4”. Do tego momentu kolumna x3 nie wpływa na resztę tablicy (poza oczywiście uwzględnieniem w wartości funkcji celu). Wtedy wyliczana jest wartość x3 przez podzielenie ograniczenia (b[2]) przez współczynnik (x3[2]).&lt;br /&gt;
&lt;br /&gt;
Gdyby jednak w tablicy pojawiła się liczba 1 w polu x3[1] - wtedy w miejsce x1+2*x2&amp;lt;9 mielibyśmy x1+2*x2+x3&amp;lt;9. Wtedy przy redukcji kolumny x2 – odpowiadającej wierszowi z wstawioną jedynką – zostanie ona „przeliczona” na wartości 0,2 i 0,4 (Tablica 3, wiersz 0 i 1) – co w tablicy 4 skutkuje zmniejszeniem b[0] i b[1] w tablicy 4 (odpowiednio 2*0,2 oraz 2*0,4).&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;S3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;min. dla X1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,00&lt;br /&gt;
| -1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|1,00&lt;br /&gt;
|2,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|9,00&lt;br /&gt;
|9,00&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|2,00&lt;br /&gt;
|5,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla x2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|1,00&lt;br /&gt;
| -0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|7,00&lt;br /&gt;
|2,80&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;6,00&#039;&#039;&#039;&lt;br /&gt;
|5,00&lt;br /&gt;
| -1,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -4,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][1] – czyli -2.5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,20&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,80&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 3&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla x3&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
|0,40&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,40&lt;br /&gt;
| -0,20&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;3,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,60&lt;br /&gt;
|0,20&lt;br /&gt;
| -2,40&lt;br /&gt;
|0,00&lt;br /&gt;
| -20,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[2][2] – czyli 3&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,33&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tablica 4&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|dla s1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|0,20&lt;br /&gt;
| -0,07&lt;br /&gt;
|3,00&lt;br /&gt;
|7,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
| -0,20&lt;br /&gt;
|0,40&lt;br /&gt;
| -0,13&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
| -2,40&lt;br /&gt;
| -0,87&lt;br /&gt;
| -26,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][2] – czyli 0,4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,17&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;7,50&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,50&lt;br /&gt;
| -0,17&lt;br /&gt;
|7,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
| -0,17&lt;br /&gt;
|3,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
| -0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
| -2,50&lt;br /&gt;
| -0,83&lt;br /&gt;
| -27,50&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
To zmniejszenie (b[0], b[1]) należy interpretować jako wyliczenie wpływu x3 na x1 i x2 we wspomnianej wyżej nieruchomości (wiersz 1). Jak to policzylibyśmy bez tablicy? Przyjmując x1+2*x2+x3 = 9 (wiersz 1) i x3=2 (6/2 - wiersz 2). Jeśli w ostatecznym wyniku x1=0, to x2=(9-2)/2 =3.5. Czyli dokładnie tyle, ile wylicza algorytm.&lt;br /&gt;
[[Plik:Simplex3.ods|mały]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex3.ods&amp;diff=165</id>
		<title>Plik:Simplex3.ods</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex3.ods&amp;diff=165"/>
		<updated>2022-09-29T22:14:35Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Przykład z analizy w arkuszu kalkulacyjnym.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=164</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=164"/>
		<updated>2022-09-29T22:07:56Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Przykładowa implementacja */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy rozwiązywania układów równań i nierówności liniowych.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z: wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:  xi ≥ di, wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
----Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie współczynniki funkcji celu [c] są mniejsze lub równe zeru (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: skoro wszystkie wartości zmiennych decyzyjnych X są większe lub równe zeru, to jeśli i-ty element [c] (c[i]) jest większy od zera, zwiększenie współrzędnej i (x[i]&amp;gt;0) powoduje zwiększenie funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były mniejsze lub równe zeru (przy szukaniu maksimum).&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą mniejsze lub równe zeru, albo nie uda się znaleźć przekształcenia dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uwaga! Wartości zmiennych w ostatniej kolumnie dotyczą zmiennych bazowych. Jeśli zmienna decyzyjna nie jest obecna w bazie - oznacza to, że w rozwiązaniu jej wartość wynosi zero (0).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
===== Analiza działania algorytmu =====&lt;br /&gt;
Dla tablicy z jedną zmienną decyzyjną x1 i jedną zmienną luzu (x2) wartość funkcji celu będzie wynosić (x1/x1 – z dzielenia wiersza przez x1, a następnie odejmowanie wiersza):&lt;br /&gt;
&lt;br /&gt;
z = 0-b1*c1*x1/x1&lt;br /&gt;
&lt;br /&gt;
czyli (zgodnie z oczekiwaniem):&lt;br /&gt;
&lt;br /&gt;
z=-b1*c1&lt;br /&gt;
&lt;br /&gt;
Przykład:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że jeśli c1 byłoby &amp;lt;0 – zadanie nie miałoby rozwiązania dla liczb dodatnich.&lt;br /&gt;
&lt;br /&gt;
Uwaga: Teoretycznie funkcja celu może zawierać dodatnie i ujemne współczynniki. Jednak algorytm Simplex może nie znaleźć ekstremem dla takich danych. Na szczęście w praktyce sytuacji w której pojawiają się ujemne współczynniki raczej się nie spotyka.&lt;br /&gt;
&lt;br /&gt;
Weźmy teraz pod uwagę dowolną tablicę Simplex w której została do zredukowania jedna kolumna ze zmienną decyzyjną. Na przykład odpowiadająca nierówności 2*x3&amp;lt;=3, oraz czynnikowi x3*4 w funkcji celu (kolumna x3, wiersz 2):&lt;br /&gt;
&lt;br /&gt;
Wykonanie redukcji zmienia wynik funkcji celu o b[2] podzielone przez x3[2] i pomnożone przez c z kolumny x3 (c[2]). Czyli najpierw wyliczamy ile co najwyżej może wynosić x3, a następnie odejmowana jest ta wartość od wyniku funkcji celu (przy liczeniu maksimum wynik jest uzyskiwany ze znakiem minus), po przemnożeniu przez odpowiedni współczynnik (c[2] – czyli 4).&lt;br /&gt;
&lt;br /&gt;
Czyli redukcja działa dokładnie tak, jakbyśmy to zrobili bez automatu. Tak samo algorytm Simplex zadziałałby, gdyby dodać kolumnę z jedną wartością dla dowolnej wielkości tablicy.&lt;br /&gt;
&lt;br /&gt;
Zastanówmy się na koniec – co się stanie, jeśli dodana kolumna x3 będzie zawierać wartości różne od zera 0 w więcej niż jednym wierszu. Prześledźmy zmiany tablicy od samego początku:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 1&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;x1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;x3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;s2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;S3&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;b&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;min. dla X1&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;4,00&#039;&#039;&#039;&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|1,00&lt;br /&gt;
|2,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|9,00&lt;br /&gt;
|9,00&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|2,00&lt;br /&gt;
|5,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[0][0] – czyli 2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,50&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 2&lt;br /&gt;
|dla x2&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;2,50&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|7,00&lt;br /&gt;
|2,80&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|3,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;6,00&#039;&#039;&#039;&lt;br /&gt;
|5,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-4,00&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][1] – czyli -2.5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;1&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;-0,20&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,80&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 3&lt;br /&gt;
|dla x3&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,40&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;3,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|6,00&lt;br /&gt;
|2,00&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|5,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-20,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 0 podzielony przez a[2][2] – czyli 3&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&#039;&#039;&#039;2&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,00&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;0,33&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039;2,00&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 4&lt;br /&gt;
|dla s1&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;0,40&#039;&#039;&#039;&lt;br /&gt;
|0,20&lt;br /&gt;
|0,00&lt;br /&gt;
|3,40&lt;br /&gt;
|8,50&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,20&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,40&lt;br /&gt;
|0,00&lt;br /&gt;
|2,80&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,20&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,40&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-30,80&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
| colspan=&amp;quot;7&amp;quot; |Wiersz 1 podzielony przez a[1][2] – czyli 0,4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;8&amp;quot; |Tablica 5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|0&lt;br /&gt;
|2,50&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|1,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|8,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|0,50&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,50&lt;br /&gt;
|0,00&lt;br /&gt;
|4,50&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&#039;&#039;&#039;1,00&#039;&#039;&#039;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,33&lt;br /&gt;
|2,00&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|s&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-0,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|0,00&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-2,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-1,67&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&amp;lt;nowiki&amp;gt;-32,50&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
Baza dla tego przykładu zmienia się następująco (s1,s2,s3) → (x1,s2,s3)→(x1,x2,s3)→(x1,x2,x3)→(s1,x2,x3)&lt;br /&gt;
&lt;br /&gt;
Zmienna x3 wchodzi do bazy w „Tablicy 4”. Do tego momentu kolumna x3 nie wpływa na resztę tablicy (poza oczywiście uwzględnieniem w wartości funkcji celu). Wtedy wyliczana jest wartość x3 przez podzielenie ograniczenia (b[2]) przez współczynnik (x3[2]).&lt;br /&gt;
&lt;br /&gt;
Gdyby jednak w tablicy pojawiła się liczba 1 w polu x3[1] - wtedy w miejsce x1+2*x2&amp;lt;9 mielibyśmy x1+2*x2+x3&amp;lt;9. Wtedy przy redukcji kolumny x2 – odpowiadającej wierszowi z wstawioną jedynką – zostanie ona „przeliczona” na wartości 0,2 i 0,4 (Tablica 3, wiersz 0 i 1) – co w tablicy 4 skutkuje zmniejszeniem b[0] i b[1] w tablicy 4 (odpowiednio 2*0,2 oraz 2*0,4).&lt;br /&gt;
&lt;br /&gt;
To zmniejszenie (b[0], b[1]) należy interpretować jako wyliczenie wpływu x3 na x1 i x2 we wspomnianej wyżej nieruchomości (wiersz 1). Jak to policzylibyśmy bez tablicy? Przyjmując x1+2*x2+x3 = 9 (wiersz 1) i x3=2 (6/2 - wiersz 2). Jeśli w ostatecznym wyniku x1=0, to x2=(9-2)/2 =3.5. Czyli dokładnie tyle, ile wylicza algorytm.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Logika_i_instrukcje_warunkowe&amp;diff=163</id>
		<title>Logika i instrukcje warunkowe</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Logika_i_instrukcje_warunkowe&amp;diff=163"/>
		<updated>2022-09-29T01:13:13Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Informacje o module:&lt;br /&gt;
&lt;br /&gt;
* Poziom: Podstawowy&lt;br /&gt;
* Profil: Dla wszystkich&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Czy komputery się mylą? ==&lt;br /&gt;
&lt;br /&gt;
Często słyszymy o spektakularnych skutkach błędów oprogramowania. Ostatnio mieliśmy w USA kilka wypadków (w tym jeden śmiertelny) spowodowanych przez programy, którym powierzono prowadzenie samochodów bez kierowcy. Bardziej poprawne jest mówienie o błędach programistów – ostatnio raczej o tym, że nie wszystko zostało w programach uwzględnione. Tak było z samochodem, który „nie zobaczył” naczepy, gdyż miała ona stosunkowo duży prześwit pod spodem, a czujniki były oślepione słońcem. Pomijając awarie sprzętowe, &#039;&#039;&#039;komputery działają bezbłędnie&#039;&#039;&#039;!&lt;br /&gt;
&lt;br /&gt;
W pewnym sensie bezbłędne są także programy – inaczej nie przeszłyby przez kompilację. Nie zawsze robią to czego oczekujemy, ale zawsze to co programista zakodował!&lt;br /&gt;
&lt;br /&gt;
Co zatem znaczy, że program jest poprawny?&lt;br /&gt;
&lt;br /&gt;
Dla programisty znaczy to, że:&lt;br /&gt;
# Jest napisany zgodnie z regułami określonymi w specyfikacji języka programowania.&lt;br /&gt;
# Jest sensowny – czyli inaczej mówiąc napisany precyzyjnie. Nie odwołuje się do nie istniejących danych i kończy swe działanie w rozsądnym czasie.&lt;br /&gt;
# Wykonuje dokładnie to, co zamierzył programista (lub zleceniodawca).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten ostatni punkt – choć najważniejszy – jest przedmiotem zainteresowania inżynierii oprogramowania.&lt;br /&gt;
&lt;br /&gt;
Punkt pierwszy – czyli kodowanie zgodnie z regułami wymuszają na nas translatory (gdy translacja prowadzi do uzyskani kodu maszynowego, translator nazywamy kompilatorem) lub interpretery (czyli translatory uruchamiane w procesie uruchamiania programu).&lt;br /&gt;
&lt;br /&gt;
Pisanie programów sensownych jest natomiast sztuką inżynierską, której musimy się nauczyć.&lt;br /&gt;
&lt;br /&gt;
Program musi bardzo precyzyjnie opisać działanie komputera. To jest zasadnicza różnica wobec posługiwania si językiem naturalnym (w naszym wypadku polskim). Gdy komuś powiemy, że coś jedzie drogą – to każdy się domyśli, że chodzi o pojazd, a w razie potrzeby – sprawdzi co dokładnie. Gdybyśmy taką nieokreśloną instrukcję zawarli w komputerze – w najlepszym razie dostaniemy komunikat w rodzaju „nie rozumiem”. &lt;br /&gt;
&lt;br /&gt;
Poprawne wypowiedzi dotyczące rzeczywistości muszą mówić o tym co jest naprawdę. Czyli poprawny = prawdziwy. W komputerze „poprawność” oznacza, że program działa zawsze tak samo i na dodatek zgodnie ze specyfikacją.&lt;br /&gt;
&lt;br /&gt;
Brak sprzeczności oraz determinizm w działaniu wynikają z samej istoty działania komputera. &#039;&#039;&#039;Determinizm&#039;&#039;&#039; oznacza, że dla danych warunków efekt zawsze będzie taki sam. Jeśli komputer nie ulega awarii – to w tym sensie jego obliczenia zawsze są prawdziwe. Jednak źle napisany program może sprawić, że „dane warunki” nie zawsze będą takie same – w szczególności mogą odbiegać od założeń. Jeśli na przykład program odwołuje się do zmiennej, której wartości wcześniej nie zainicjował – to otrzymana wartość zależy od historii działania komputera i można ja uznać za losową.&lt;br /&gt;
&lt;br /&gt;
Także sprzeczność jest łatwa do wprowadzenia. Weźmy na przykład fragment programu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
jeśli a&amp;gt;=b to napisz(‘a&amp;gt;b’);&lt;br /&gt;
jeśli a&amp;lt;=b to napisz(‘a&amp;lt;b’);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Program dla a=b napisze, że &#039;&#039;&#039;a&amp;gt;b&#039;&#039;&#039; i &#039;&#039;&#039;a&amp;lt;b&#039;&#039;&#039; równocześnie. Takie błędy (użycie złego znaku porównania) są bardzo często spotykane. &lt;br /&gt;
&lt;br /&gt;
Jak to ma się do tezy, że w komputerze nie może być sprzeczności? Na poziomie kodu maszynowego nie ma żadnej sprzeczności w działaniu. Komputer wypisuje w określonej sytuacji określony wynik on nawet „nie wie”, że drukowany napis ‘a&amp;gt;b’ zawiera wyrażenie logiczne (dla niego to tylko dana – ciąg bitów). Warto w tym miejscu przypomnieć rozróżnienie języka i metajęzyka (moduł 2 w pierwszej części). &lt;br /&gt;
&lt;br /&gt;
Najczęstszym jednak źródłem uzyskiwania nieoczekiwanych wyników są błędne dane, jakie są przedmiotem obliczeń. Informatycy sformułowali nawet sentencję określającą tą sytuację:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center;&amp;quot;&amp;gt;ŚMIECI NA WEJŚCIU = ŚMIECI NA WYJŚCIU&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To określenie dotyczy także programów, które są daną wejściową dla translatorów. Chcąc uzyskać poprawny program, musimy samemu zachować precyzje i stosować zasady logiki.&lt;br /&gt;
&lt;br /&gt;
== Problem złożoności ==&lt;br /&gt;
&lt;br /&gt;
Pamięć komputera zawiera bity. Co to dokładnie znaczy? Bit to najmniejsza porcja informacji – wybór jednego z dwóch elementów. Najczęściej wybieramy między zerem a jedynką (tak jest w komputerach). Odpowiada to oczywiście wartościom fałsz (zero) i prawda (jeden) w logice.&lt;br /&gt;
&lt;br /&gt;
Zaprojektujmy sobie najprostszy komputer, który komputer, który liczy jedynie sumy wyłączne (XOR) z sygnałów podanych na wejściu. Suma wyłączna (A XOR B) czyli inaczej „albo albo” daje na wynik prawdę, gdy prawda jest na wejściu A albo na wyjściu B, ale nie na obu. Natomiast iloczyn (A i B, A AND B) daje prawdę, gdy zarówno A jak i B mają wartość prawda.&lt;br /&gt;
&lt;br /&gt;
Odpowiedni przykład funkcji przejścia można przetestować na stronie [http://logic.ly/demo/ http://logic.ly/demo/] (trzeba wybrać przykład opisany jako „1-Bit Full Adder”):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sumator.jpg]]&lt;br /&gt;
&lt;br /&gt;
Zmieniając przyciski A i B możemy obserwować co dzieje się na wyjściu – czy pali się lampka Sum. W tym przykładzie mamy dodatkowo sygnały przeniesienia (Carry IN na wejściu i Carry OUT na wyjściu). Umożliwiają one połączenie kaskadowo tych sumatorów dla uzyskania sumy z więcej niż dwóch wejść (wynik Carry OUT łączymy do Carry IN z następnej pary).&lt;br /&gt;
&lt;br /&gt;
Żeby można było mówić o komputerze, a nie tylko o układzie elektronicznym, poszczególnym elementom wejścia i wyjścia muszą odpowiadać komórki pamięci, a wynik obliczeń powinien zostać zapisany w komórkach odpowiadających wyjściu w takt zegara odliczającego instrukcje. &lt;br /&gt;
&lt;br /&gt;
W tak prostym przykładzie mamy 5 jednobitowych komórek pamięci i 5 układów elektronicznych (bramek logicznych). &lt;br /&gt;
&lt;br /&gt;
Jaka zatem powinna być złożoność komputera przetwarzającego informację o złożoności liczonej w milionach bitów? Ogromna. Prostszym jest pytanie postawione od drugiej strony: ile maksymalnie bitów zmieniają za jednym razem współczesne komputery? Jeśli słyszymy, że mamy procesor 64-bitowy, to oznacza właśnie tyle, że naraz może odczytać lub zapisać 64 bity. Większą ilość komórek pamięci można zmienić w wielu kolejnych taktach zegara. Niektóre obliczenia są tak złożone, że takie sekwencyjne (krok po kroku) obliczenia nie skończyłyby się nawet za tysiąc lat.&lt;br /&gt;
&lt;br /&gt;
== Instrukcje warunkowe ==&lt;br /&gt;
&lt;br /&gt;
Nie tylko ograniczenia sprzętowe (budowa komputera) sprawiają, że z zasady obliczenia w komputerze odbywają się w sposób sekwencyjny: instrukcja po instrukcji. Człowiek także nie jest w stanie myśleć równolegle (podobno kobiety mają większą podzielność uwagi – ale to zrównoleglenie też nie jest wielkie ;-)).&lt;br /&gt;
&lt;br /&gt;
Jakie instrukcje są nam potrzebne, aby zapisać dowolny proces obliczeniowy? Okazuje się, że wyliczaniem wartości wyrażeń arytmetycznych i logicznych potrzebujemy jedynie instrukcji warunkowych (wykonaj coś pod warunkiem) oraz mechanizmu pozwalającego przeglądać zbiór danych. Takim mechanizmem są tak zwane pętle (choć może to też być też tak zwany mechanizm rezolucji – dla bardzo zaawansowanych: [https://pl.wikipedia.org/wiki/Rezolucja_(matematyka https://pl.wikipedia.org/wiki/Rezolucja_(matematyka]), [https://pl.wikipedia.org/wiki/Prolog_(język_programowania https://pl.wikipedia.org/wiki/Prolog_(j%C4%99zyk_programowania])). &lt;br /&gt;
&lt;br /&gt;
Dla przykładu z sumą wyłączną ciąg instrukcji wyliczającej XOR dla 4 danych wejściowych (A,B,C,D) może wyglądać następująco:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
jeżeli (A XOR B) to&lt;br /&gt;
  jeżeli (C XOR D) to&lt;br /&gt;
    napisz(‘prawda’);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Proszę zwrócić uwagę na tak zwane wcięcia (odstępy z lewej) – powszechnie stosowane dla większej czytelności programów.&lt;br /&gt;
&lt;br /&gt;
Instrukcje warunkowe są podstawą programowania. Można wykazać, że do takiego zbioru instrukcji daje się sprowadzić wszystkie wyrażenia logiczne! Istnieją języki programowania, które składają się wyłącznie z takich warunkowych instrukcji. Nie ma zaś żadnego bardziej złożonego języka programowania, który nie zawierałby takich instrukcji.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Logiczne myślenie – uwaga metodologiczna: &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zbudowanie przez&amp;amp;nbsp;[http://www.matematycy.interklasa.pl/biografie/matematyk.php?str=boole Boole&#039;a]&amp;amp;nbsp;rachunku logicznego na wzór algebry było bardzo ważnym odkryciem. Wpłynęło jednak na to, że najbardziej naturalną umiejętność człowieka postrzegamy dzisiaj jako rzecz trudną. Nauki logiki nie powinno się zaczynać od operowania na symbolach i wyrażeniach, ale od prostych pytań w rodzaju: co zrobić, aby osiągnąć jakiś efekt. To mogą być proste historie (na przykład: aby włączyć notebooka trzeba podnieść klapę i nacisnąć przycisk, ale jeśli bateria jest rozładowana, musimy włączyć go dodatkowo do prądu). Po dojściu do końca w analizie postawionego problemu, można zapisać działania w odpowiedniej kolejności, uzyskując prosty algorytm.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Zadanie&#039;&#039;&#039;: Napisać program w postaci instrukcji warunkowych JEŚLI, wyliczający ilość dni dowolnego miesiąca w dowolnym roku&lt;br /&gt;
&lt;br /&gt;
html:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&amp;lt;form&amp;gt;&lt;br /&gt;
  rok= &amp;lt;input id=&amp;quot;rok&amp;quot; type=text value=&amp;quot;2016&amp;quot;&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
  miesiąc= &amp;lt;input id=&amp;quot;mies&amp;quot; type=text value=&amp;quot;01&amp;quot;&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
  &amp;lt;input type=&amp;quot;button&amp;quot; onclick=&amp;quot;javascript:licz()&amp;quot; value=&amp;quot;licz&amp;quot;/&amp;gt;&amp;lt;br &amp;gt;&lt;br /&gt;
  dni= &amp;lt;input id=&#039;dni&#039; type=text value=&amp;quot;00&amp;quot; readonly/&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Javascript:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
function licz(){&lt;br /&gt;
  rok=document.getElementById(&#039;rok&#039;).value;&lt;br /&gt;
  mies=document.getElementById(&#039;mies&#039;).value;&lt;br /&gt;
  var dni=&#039;31&#039;;&lt;br /&gt;
  if (mies==&#039;02&#039;) {&lt;br /&gt;
    dni=&#039;28&#039;;&lt;br /&gt;
    if (rok==2016) { dni=&#039;29&#039;; }&lt;br /&gt;
  }&lt;br /&gt;
  if (mies==&#039;04&#039;) { dni=&#039;30&#039;; }&lt;br /&gt;
  if (mies==&#039;06&#039;) { dni=&#039;30&#039;; }&lt;br /&gt;
  if (mies==&#039;09&#039;) { dni=&#039;30&#039;; }&lt;br /&gt;
  if (mies==&#039;01&#039;) { dni=&#039;30&#039;; }&lt;br /&gt;
  document.getElementById(&#039;dni&#039;).value=dni;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Implementacja w JavaScript: [http://codepen.io/pen/ http://codepen.io/pen/] lub [https://jsfiddle.net/ https://jsfiddle.net/] lub [http://jsbin.com/ http://jsbin.com/]&lt;br /&gt;
(dla innych języków: [https://repl.it/ https://repl.it]).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#006600;&amp;quot;&amp;gt;Zadanie domowe: zrobić program dla dowolnych lat.&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Podsumowanie ==&lt;br /&gt;
&lt;br /&gt;
* Komputery działają w sposób deterministyczny – czyli dla danych warunków efekt zawsze będzie taki sam.&lt;br /&gt;
* Poprawność działania komputera nie gwarantuje tego, że obliczenia są wykonywane zgodnie z naszymi oczekiwaniami. Aby to zapewnić, program dostarczany do translatora musi być napisany zgodnie z zasadami logiki.&lt;br /&gt;
* Teoretycznie do tworzenia dowolnych programów wystarczy, by w języku programowania był zawarty interpreter wyrażeń arytmetycznych i logicznych, instrukcje warunkowe i mechanizm przeglądania zbiorów danych.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Proste_sortowanie_tablic&amp;diff=162</id>
		<title>Proste sortowanie tablic</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Proste_sortowanie_tablic&amp;diff=162"/>
		<updated>2022-09-28T23:42:11Z</updated>

		<summary type="html">&lt;p&gt;Admin: Utworzono nową stronę &amp;quot;Sortowanie przez proste wybieranie jest chyba najprostszym algorytmem sortowania. Tablicę dzielimy na dwie części: lewa posortowana i prawa nie posortowana. Wyszukujemy w nie posortowanej części najmniejszy element i zamieniamy z pierwszym elementem nie posortowanej części. Dzięki temu - możemy zwiększyć obszar posortowany o kolejny (ten wybrany) element. Na poniższym rysunku pionowa strzałka czarna wskazuje na pierwszy element nie posortowanej częśc…&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sortowanie przez proste wybieranie jest chyba najprostszym algorytmem sortowania. Tablicę dzielimy na dwie części: lewa posortowana i prawa nie posortowana. Wyszukujemy w nie posortowanej części najmniejszy element i zamieniamy z pierwszym elementem nie posortowanej części. Dzięki temu - możemy zwiększyć obszar posortowany o kolejny (ten wybrany) element. Na poniższym rysunku pionowa strzałka czarna wskazuje na pierwszy element nie posortowanej części, a czerwona - na najmniejszy element tej części. Łuk łączy miejsca zamiany:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sortowanie-wybieranie.png|alt=Sortowanie przez proste wybieranie]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sortowanie przez proste  wstawianie jest podobne do układania kart do gry branych ze stołu w kolejności ich wielkości:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sortowanie kart.png]]&lt;br /&gt;
&lt;br /&gt;
źródło rysunku:  Cormen Thomas H., Leiserson Charles E., Rivest Ronald L, Clifford Stein &amp;quot;Wprowadzenie do algorytmów&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Algorytm  sortowania tabeli przez proste wstawianie polega on na tym, że tabelę dzielimy na dwie części: elementy już posortowane (jak karty w ręce) - to lewa część tabeli. Elementy pozostałe (jak karty na stole) - to prawa część tabeli. Bierzemy kolejne elementy z pozostałych (prawej części) i wstawiamy do lewej tak, by zachować sortowanie.&lt;br /&gt;
&lt;br /&gt;
Dla tabeli zawierającej liczby: &amp;lt;code&amp;gt;9,12,7,11,8,3,&amp;lt;/code&amp;gt; algorytm zadziała następująco:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sortowanie-wstawianie.png|alt=Sortowanie przez proste wstawianie]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:Sortowanie-wstawianie.png&amp;diff=161</id>
		<title>Plik:Sortowanie-wstawianie.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:Sortowanie-wstawianie.png&amp;diff=161"/>
		<updated>2022-09-28T23:38:52Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sortowanie przez proste wstawianie&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:Sortowanie_kart.png&amp;diff=160</id>
		<title>Plik:Sortowanie kart.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:Sortowanie_kart.png&amp;diff=160"/>
		<updated>2022-09-28T23:36:15Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;źródło rysunku:  Cormen Thomas H., Leiserson Charles E., Rivest Ronald L, Clifford Stein &amp;quot;Wprowadzenie do algorytmów&amp;quot;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:Sortowanie-wybieranie.png&amp;diff=159</id>
		<title>Plik:Sortowanie-wybieranie.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:Sortowanie-wybieranie.png&amp;diff=159"/>
		<updated>2022-09-28T23:34:11Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sortowanie przez proste wybieranie&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytmy&amp;diff=158</id>
		<title>Algorytmy</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytmy&amp;diff=158"/>
		<updated>2022-09-28T23:30:54Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[Proste sortowanie tablic]]&lt;br /&gt;
* [[Algorytm Simplex]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=157</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=157"/>
		<updated>2022-09-28T22:52:10Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Algorytm Simplex */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy rozwiązywania układów równań i nierówności liniowych.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z: wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:  xi ≥ di, wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
----Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie współczynniki funkcji celu [c] są mniejsze lub równe zeru (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: skoro wszystkie wartości zmiennych decyzyjnych X są większe lub równe zeru, to jeśli i-ty element [c] (c[i]) jest większy od zera, zwiększenie współrzędnej i (x[i]&amp;gt;0) powoduje zwiększenie funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były mniejsze lub równe zeru (przy szukaniu maksimum).&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą mniejsze lub równe zeru, albo nie uda się znaleźć przekształcenia dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uwaga! Wartości zmiennych w ostatniej kolumnie dotyczą zmiennych bazowych. Jeśli zmienna decyzyjna nie jest obecna w bazie - oznacza to, że w rozwiązaniu jej wartość wynosi zero (0).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=154</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=154"/>
		<updated>2022-09-27T00:53:29Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Postać standardowa problemu */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z: wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:  xi ≥ di, wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
----Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie współczynniki funkcji celu [c] są mniejsze lub równe zeru (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: skoro wszystkie wartości zmiennych decyzyjnych X są większe lub równe zeru, to jeśli i-ty element [c] (c[i]) jest większy od zera, zwiększenie współrzędnej i (x[i]&amp;gt;0) powoduje zwiększenie funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były mniejsze lub równe zeru (przy szukaniu maksimum).&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą mniejsze lub równe zeru, albo nie uda się znaleźć przekształcenia dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=153</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=153"/>
		<updated>2022-09-27T00:43:15Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Równania i nierówności liniowe */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
----------------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Matematyka_obiektowa&amp;diff=152</id>
		<title>Matematyka obiektowa</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Matematyka_obiektowa&amp;diff=152"/>
		<updated>2022-09-25T18:39:27Z</updated>

		<summary type="html">&lt;p&gt;Admin: przypisy&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Często słyszymy, że podstawą informatyki jest matematyka. Tak – ale nie jest to taka matematyka, jaką męczą dzieci w szkole. W przeciwieństwie do matematyki, informatyka w całej swej historii dąży do jak najprostszego i zrozumiałego opisu tworzonych systemów. Nie ma też mowy o jakichkolwiek niedopowiedzeniach. Ma być jasno i precyzyjnie. Dlatego kreowany przez programistów świat wirtualny jest łatwiejszy do zrozumienia niż świat matematycznych abstrakcji.&lt;br /&gt;
&lt;br /&gt;
Może więc należałoby sytuację odwrócić, traktując informatykę jako klucz do zrozumienia matematyki?&lt;br /&gt;
&lt;br /&gt;
=== Czy matematyka jest trudna? ===&lt;br /&gt;
Niektóre teorie czy twierdzenia matematyczne są rzeczywiście bardzo trudne. Jednak na podstawowym poziomie matematyka powinna być bez większych problemów przyswajana przez każdego rozgarniętego człowieka. Dlaczego tak się nie dzieje? Jedną z przyczyn jest przyjęcie przez matematyków zasady „nieoglądowości” – czyli braku odwołań do pojęć jakich używamy w odniesieniu do postrzeganych rzeczy.&lt;br /&gt;
&lt;br /&gt;
Jeszcze w XVII wieku powszechnie uważano, że nasz ogląd świata jest źródłem pojęć z których budujemy sądy matematyczne&amp;lt;ref&amp;gt;Zob. Jerzy Dadaczyński „&#039;&#039;Filozofia matematyki Immanuela. Kanta jako punkt odniesienia filozofii matematyki stowarzyszonych z klasycznymi kierunkami badań podstaw matematyki&#039;&#039;” &amp;lt;nowiki&amp;gt;[https://bazhum.muzhp.pl/media/files/Slaskie_Studia_Historyczno_Teologiczne/Slaskie_Studia_Historyczno_Teologiczne-r1999-t32/Slaskie_Studia_Historyczno_Teologiczne-r1999-t32-s22-36/Slaskie_Studia_Historyczno_Teologiczne-r1999-t32-s22-36.pdf ]&amp;lt;/nowiki&amp;gt;: &#039;&#039;Wymóg nieogladowości dowodów, zawarty we współczesnej metodologii matematyki, który zadomowił się tam ostatecznie od czasów Hilberta, wydaje się oczywisty i niepodważalny. Dziwne może nawet wydać się przypuszczenie, że kiedykolwiek można było wypowiedzieć twierdzenie przeciwne. Był jednak taki okres w dziejach metodologii matematyki − a precyzyjniej: w dziejach filozofii matematyki − kiedy twierdzono, że dowodząc tez matematycznych, nie tylko można, ale wręcz koniecznie trzeba odwoływać się do pewnych form oglądowości, do pewnego rodzaju przedstawień naocznych. Twórcą tego poglądu był Immanuel Kant&#039;&#039;.&amp;lt;/ref&amp;gt;. Oczyszczanie matematyki z odniesień do rzeczywistości i naszych wyobrażeń wiązało się z dążeniem do precyzji i absolutnej pewności. Proces ten został domknięty przez Davida Hilberta&amp;lt;ref&amp;gt;https://encyklopedia.pwn.pl/haslo/Hilbert-David;3911678.html&amp;lt;/ref&amp;gt;, który w celu wykazania niesprzeczności matematyki postulował jej aksjomatyzację – czyli przyjęcie, że każda teoria wynika logicznie z przyjętego zbioru aksjomatów&amp;lt;ref&amp;gt;Cel Hilberta (matematyka z wykazaną zupełnością i niesprzecznością) nie jest osiągalny.&amp;lt;/ref&amp;gt;. Ostatecznie zwyciężył pogląd, że język matematyki jest całkowicie abstrakcyjny&amp;lt;ref&amp;gt;Jak zauważa Jerzy Daczyński (dz.cyt.): „&#039;&#039;współczesne stanowisko można by za pomocą terminologii Kantowskiej oddać następująco: matematyka jest wiedzą czysto pojęciową, w żadnym dowodzie nie można się odwoływać do jakichkolwiek wyobrażeń (empirycznych czy apriorycznych)&#039;&#039;”. Czyli zdania matematyki nie są – jak uważał Kant – sądami syntetycznymi apriori, tylko sądami analitycznymi!&amp;lt;/ref&amp;gt;. Nawet liczby naturalne definiuje się obecnie w oparciu o abstrakcyjną teorię mnogości.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ta sytuacja ma ogromne znaczenie w nauczaniu matematyki. Nauka matematyki to poznawanie świata abstrakcji, co stanowi poważną barierę dla wielu jej adeptów. Na dodatek archaiczna maniera matematyków każe im używać języka naszpikowanego trudnymi do zapamięta symbolami jednoliterowymi (kto dzisiaj zna alfabet grecki?).&lt;br /&gt;
&lt;br /&gt;
=== Matematyka z informatyką ===&lt;br /&gt;
Matematycy posługiwali się odniesieniami do rzeczywistego świata, które okazały się zbędne na pewnym etapie rozwoju tej nauki. Do zobrazowania tej sytuacji można przywołać za Wittgensteinem metaforę drabiny. Matematycy wspinali się po jej szczeblach (z których każdy był bardziej abstrakcyjny), aż na poziom całkowitej abstrakcji. Po odrzuceniu drabiny mamy czystą matematykę. Tylko dlaczego osobom studiującym matematykę odmawia się użycia tej „drabiny”?&lt;br /&gt;
&lt;br /&gt;
Jest to tym bardziej dziwne, że matematycy w swych publikacjach wcale nie są tak pryncypialni. Weźmy na przykład elementarny tekst na temat „rachunku zdań”: http://wazniak.mimuw.edu.pl/index.php?title=Logika_i_teoria_mnogo%C5%9Bci/Wyk%C5%82ad_2:_Rachunek_zda%C5%84 . Próżno w nim szukać na przykład definicji używanego pojęcia „zmienna zdaniowa”. Intuicyjnie rozumiemy, że chodzi o symbol reprezentujący zdanie.&lt;br /&gt;
&lt;br /&gt;
Takie podejście ma zasadniczą wadę: autor zakłada, że czytelnik potrafi trafnie uchwycić znaczenie wprowadzonych pojęć (intuicyjnie, lub poprzez studiowanie innych publikacji). To może być założeniem błędnym.&lt;br /&gt;
&lt;br /&gt;
Połączenie nauki matematyki i programowania sprawia natomiast, że możemy zakładać zrozumienie odwołań do pojęć z dziedziny informatyki. Takie powiązanie matematyki z informatyką nie wiąże się z zagrożeniem, któremu miało zapobiec „oczyszczenie” matematyki z „obrazowości”. Komputery są deterministyczne, a zasada ich działanie daje się opisać przy pomocy elementarnej logiki. Nie ma więc mowy o tym, by powyższy związek był źródłem błędów.&lt;br /&gt;
&lt;br /&gt;
=== Uniwersalność matematyki ===&lt;br /&gt;
Powyżej wspomniano o dwóch różnicach między informatyką i matematyką:&lt;br /&gt;
&lt;br /&gt;
1) silny związek informatyki ze światem rzeczywistym wobec dążenia matematyki do abstrakcji;&lt;br /&gt;
&lt;br /&gt;
2) język informatyki ma być możliwie najbardziej zrozumiały, czego nie oczekujemy od języka matematyki;&lt;br /&gt;
&lt;br /&gt;
Gdyby różnice między informatyką i matematyką sprowadzały się do takich „drobiazgów” – nie byłoby powodu traktować tych dziedzin jako odrębne (i pewnie z czasem nastąpiłoby „ujednolicenie”).&lt;br /&gt;
&lt;br /&gt;
Istnieją jednak różnice o wiele poważniejsze, które można uznać za fundamentalne.&lt;br /&gt;
&lt;br /&gt;
Porównajmy dwa objaśnienia algorytmu Simplex: matematyczne i informatyczne&amp;lt;ref&amp;gt;Marek Mika, „Teoretyczne podstawy programowania liniowego” (&amp;lt;nowiki&amp;gt;http://www.cs.put.poznan.pl/mmika/Teoretyczne%20podstawy%20programowania%20liniowego.pdf&amp;lt;/nowiki&amp;gt; ).&amp;lt;/ref&amp;gt;. Jednym z kluczowych pojęć jest w tym algorytmie wierzchołek wielościanu wielowymiarowego.&lt;br /&gt;
&lt;br /&gt;
Matematyczna definicja wierzchołka (punktu ekstremalnego zbioru wypukłego)&amp;lt;ref&amp;gt;Definicja przytoczona przez Wikipedię pochodzi z John B. Conway: „&#039;&#039;A course in functional analysis&#039;&#039;”.&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Punkt e ∈ K jest punktem ekstremalnym zbioru wypukłego K, gdy równość&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;e = 𝜆𝐱 + (1 − 𝜆) y dla pewnych x,y ∈ K oraz 𝜆 ∈ [0,1] implikuje, że e = x lub e = y .&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
W tej definicji chodzi o to, że jeśli mamy jakiś odcinek (x,y) zawarty w zbiorze wypukłym, to wierzchołkiem może być jedynie jego początek lub koniec. Po tym objaśnieniu - chyba definicja staje się zrozumiała&amp;lt;ref&amp;gt;Wyjaśnienie wypukłości oraz przytoczonej definicji odcinka znajdziesz na blogu &amp;lt;nowiki&amp;gt;https://byc-matematykiem.pl/tajniki-interpolacji-czesc-1/&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;. Tyle, że w kontekście algorytmu Simplex mało użyteczna.&lt;br /&gt;
&lt;br /&gt;
Porównajmy z definicją wierzchołka sformułowaną przez informatyka&amp;lt;ref&amp;gt;[[Algorytm Simplex]]&amp;lt;/ref&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ograniczenia [równania liniowe wielu zmiennych] definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”. W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń. Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi. .&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najważniejszą różnicą między tymi definicjami nie jest użycie jednoliterowych symboli.&lt;br /&gt;
&lt;br /&gt;
Definicja matematyczna w sposób dość typowy używa implikacji do zawężenia zbioru możliwości.&lt;br /&gt;
&lt;br /&gt;
Taka definicja jest bardziej uniwersalna, niż opis informatyka (‘jak to jest zrobione i co z tego wynika’). To wspaniale! Dzięki takiemu dążeniu do uniwersalności, wszystkie twierdzenia mogą znaleźć szersze zastosowanie! Tyle, że informatyka nie interesuje ogólne zastosowanie definicji, ale zastosowanie jej w objaśnieniu algorytmu który chce zaimplementować lub zastosować! Jego definicja zawiera własności wierzchołka, które po przyjęciu ogólniejszej definicji trzeba by dopiero udowodnić!&lt;br /&gt;
&lt;br /&gt;
Czy definicja informatyka jest mniej precyzyjna? Taki zarzut staje się bezprzedmiotowy, jeśli definicja zostanie wprost przełożona na działający poprawnie program. Świat komputera z takim programem jest lokalnym „uniwersum”, które możemy objaśniać poprzez zastosowania (świat realny) lub … matematykę! Informatyk może traktować matematykę tak jak elektronikę: są niezbędne, ale rzadko zachodzi potrzeba zgłębiania ich tajników.&lt;br /&gt;
&lt;br /&gt;
=== Matematyka obiektowa ===&lt;br /&gt;
Współczesny świat budują inżynierowie, dla których – jak się słusznie uważa – matematyka jest podstawą. W szczególności dotyczy to informatyków. Matematyka we współczesnej formie stanowi jedną z barier w kształceniu odpowiedniej ilości programistów. Z drugiej strony – świat kreowany przez programistów jest trudno dostępny dla przeciętnego użytkownika informatycznych produktów. Tu także może pomóc podniesienie ogólnego poziomu znajomości matematyki z uwzględnieniem jej związków z informatyką.&lt;br /&gt;
&lt;br /&gt;
Nadzieję na zmianę tej sytuacji daje podjęcie powszechnej edukacji w zakresie programowania. Niestety wygląda na to, że zmieniono ten z założenia szlachetny przedmiot w naukę programu Scratch. Ten absurd jest już tak ugruntowany, że nawet trudno liczyć na zmianę.&lt;br /&gt;
&lt;br /&gt;
Z powyższej refleksji zrodziła się idea stworzenia „matematyki obiektowej”.&lt;br /&gt;
&lt;br /&gt;
Dlaczego „matematyka obiektowa”? Po co tworzyć nowe terminy, skoro istnieje „matematyka dyskretna”? Termin „matematyka dyskretna” określa zakres (dziedzinę) matematyki związanej z informatyką&amp;lt;ref&amp;gt;Matematyka dyskretna to nauka o strukturach matematycznych zawierających skończoną liczbę elementów. [Ryan T. White, Archana Tikayat Ray „Practical Discrete Mathematics”]&amp;lt;/ref&amp;gt;. Matematyka obiektowa wprowadza język i system pojęć pomocnych w opisaniu i zrozumieniu tej dziedziny wiedzy.&lt;br /&gt;
&lt;br /&gt;
Abstrakcyjna idea obiektów jest łatwą do zrozumienia (przez analogie ze światem realnych obiektów). Współczesne języki programowania w większości mają charakter obiektowy. Można więc w nich tworzyć obiekty, które objaśniają matematyczne pojęcia i twierdzenia.&lt;br /&gt;
&lt;br /&gt;
Obiekty matematyczne są opisywane poprzez definicje związków i działań w nich zachodzących. By zrozumieć ten opis, nierzadko trzeba zgłębić bardziej elementarne teorie i zapamiętać stosowane oznaczenia. Tymczasem obiekty w programowaniu są opisywane w sposób umożliwiający ich natychmiastowe użycie. Do ich zrozumienia często wystarczą przykłady użycia.&lt;br /&gt;
&lt;br /&gt;
Zmiana terminologii wiąże się więc ze zmianą podejścia: zastępujemy teorię (jak to jest zbudowane) przez praktykę (jak tego użyć). O ile w odniesieniu do elementarnych zagadnień takie podejście jest tylko jednym z możliwych&amp;lt;ref&amp;gt;Alternatywne podejście: „Need for Equipping Student Teachers with Language of Mathematics” „&#039;&#039;Znaczenie programu nauczania w budowaniu języka matematyki, który umożliwia uczącym się konstruowanie i przekazywanie wiedzy matematycznej, nie zostało docenione, mimo że od lat dyskutuje się o wyzwaniach pedagogicznych, przed którymi stają uczniowie w nauce matematyki. Nauka języka matematyki jest nie tylko cenna sama w sobie, ale także przydatna w zrozumieniu innych dziedzin wiedzy, zwłaszcza nauk ścisłych. Uważa się, że posługiwanie się narzędziami języka matematyki jest nawet pomocne w nauce języków potocznych, zwłaszcza w nauce gramatyki, rytmiki i wersyfikacji. Oczywiste jest, że rozumienie języka matematyki i jego specjalnych terminów tak płynnie, jak to możliwe, oprócz innych korzyści, uwalnia procesy poznawcze w uczącym się, aby móc podejmować bardziej przydatne czynności, w tym rozwiązywać problem. Dlatego ważne jest, aby programy kształcenia nauczycieli uwzględniały w nim elementy składowe lub elementy matematyki w taki sposób, aby struktura języka matematyki była zrozumiała dla uczniów. W artykule omówiono znaczenie języka matematyki, jego strukturę i znaczenie w kształceniu matematycznym. Sugeruje ponadto sposoby przekazywania nowicjuszom zrozumienia języka matematyki. Mając na uwadze znaczenie języka matematyki w nauczaniu uczenia się, w niniejszym opracowaniu rozważono również strategie, które można zastosować, aby wyposażyć przyszłych nauczycieli w umiejętności i kompetencje niezbędne do radzenia sobie z językiem matematyki”.&#039;&#039;&amp;lt;/ref&amp;gt;, to w przypadku zaawansowanych teorii pragmatyzm staje się często koniecznością (gdy chcemy z nich korzystać, ale nie mamy czasu na ich studiowanie).&lt;br /&gt;
&lt;br /&gt;
=== Semantyka matematyki (refleksja filozoficzna) ===&lt;br /&gt;
Podejście obiektowe może być skuteczne zwłaszcza w matematyce dyskretnej. Czy w ten sposób można opisać całą matematykę?&lt;br /&gt;
&lt;br /&gt;
Najpierw należałoby wyjaśnić – co znaczy „opisać”. Możemy na przykład zrobić zdjęcie dowolnego tekstu czy rysunku i po zeskanowaniu wgrać do komputera. Drugą skrajnością są systemy / programy komputerowe, w których zaimplementowano reguły matematycznej teorii. Interesujące jest jedynie pytanie o tą drugą możliwość. Czyli pytanie - czy można matematykę zredukować do informatyki? Całą matematykę? Odpowiedź na tak postawione pytanie wiąże się z semantyką matematyki.&lt;br /&gt;
&lt;br /&gt;
Jeśli język matematyki jest całkowicie abstrakcyjny, to znaczenie jego zdań możemy ustalić wyłącznie przez odwołanie się do innych zdań matematyki – w tym aksjomatów.&lt;br /&gt;
&lt;br /&gt;
Semantyka referencyjna z odwołaniem do rzeczywistości (np. liczba jako uogólnienie równolicznych zbiorów przedmiotów) groziłaby pozbawieniem matematyki absolutnej pewności.&lt;br /&gt;
&lt;br /&gt;
Takich problemów nie ma, gdy odwołujemy się do rzeczywistości wirtualnej – czyli tworów informatycznych, które dają się zredukować do zdań matematyki.&lt;br /&gt;
&lt;br /&gt;
Gdyby udałoby się zachować jednoznaczne przyporządkowanie konstrukcji matematycznych abstrakcjom (obiektom) informatycznym – można by takie przyporządkowanie uznać za semantykę (referencyjną) języka matematyki. Czy to wykonalne? Konieczne byłaby możliwość zapisania w pamięci komputera odpowiednika dowolnych obiektów matematycznych.&lt;br /&gt;
&lt;br /&gt;
W komputerze można zapisać dowolne obiekty. Jednak może być ich tylko skończona ilość. Nigdy nie będą to więc wszystkie możliwe konstrukcje matematyczne (wynika to z twierdzenia Goedla). Dlatego matematyka nigdy nie zostanie zredukowana do informatyki.&lt;br /&gt;
&lt;br /&gt;
Ten wynik ma ważne konsekwencje semantyczne, filozoficzne i technologiczne.&lt;br /&gt;
&lt;br /&gt;
1. Mamy tu wyjaśnienie dlaczego logicyzm&amp;lt;ref&amp;gt;„W najprostszej postaci aksjomat nieskończoności powiada, że dla każdej liczby naturalnej istnieje jej następnik, zaś aksjomat wyboru postuluje, że dla każdej rodziny zbiorów parami rozłącznych istnieje jej selektor. Nie są to aksjomaty logiczne (postulują one istnienie jakichś obiektów, czego aksjomaty logiki nie robią)”. &amp;lt;nowiki&amp;gt;https://open.uj.edu.pl/mod/book/view.php?id=20&amp;amp;chapterid=112&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt; nie jest możliwy.&lt;br /&gt;
&lt;br /&gt;
2. Możemy w systemie komputerowym zapisać symbol nieskończoności. Jednak ten symbol nie będzie się odnosił do niczego, co istnieje w systemie komputerowym. Nawet gdy stworzymy obiekty pozwalające na operowanie nieskończonością. Z punktu widzenia semantyki to tylko definiowanie nieznanego przez nieznane. Ściśle rzecz biorąc – w poszukiwaniu znaczenia symboli w komputerze możemy dojść do definicji maszyny iteracyjnej&amp;lt;ref&amp;gt;Maszyna iteracyjna to teoretyczny konstrukt Zdzisława Pawlaka. Można ją traktować jako alternatywę dla Maszyny Turinga. Składa się z pamięci (elementu o wielu stanach) i funkcji przejścia – wyliczającej na podstawie stanu pamięci w jakim stanie znajdzie się ona w chwili następnej.&amp;lt;/ref&amp;gt;, albo do „czegoś z zewnątrz”&amp;lt;ref&amp;gt;Ten wynik jest zgodny z poglądami Cantora: &amp;lt;nowiki&amp;gt;https://bazhum.muzhp.pl/media/files/Humanistyka_i_Przyrodoznawstwo/Humanistyka_i_Przyrodoznawstwo-r2004-t10/Humanistyka_i_Przyrodoznawstwo-r2004-t10-s51-68/Humanistyka_i_Przyrodoznawstwo-r2004-t10-s51-68.pdf&amp;lt;/nowiki&amp;gt;&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
3. Konieczność odwołań do „czegoś z zewnątrz” (istnieje coś więcej) to mocny argument przeciw komputacjonizmowi&amp;lt;ref&amp;gt;http://www.filozoficznie.pl/4/40_M_Milkowski_Analiza_tezy_komputacjonizmu.pdf&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Podsumowanie ===&lt;br /&gt;
Matematyka obiektowa absolutnie nie ma być „nową” matematyką, ale nowym jej przedstawieniem – łatwiejszym do przyswojenia. Łączy „oglądowość” z ideą abstrakcji, zastępując odniesienia do rzeczywistości, odniesieniami do świata wirtualnego, opisywanego w języku informatyki. Matematyka postrzegana jako teoretyczne objaśnienie elementów świata maszyn cyfrowych wydaje się łatwiejsza do zrozumienia niż matematyka jako czysto abstrakcyjny system.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo, dzięki komputerom abstrakcyjne obiekty informatyki stają się częścią naszej rzeczywistości. Wzmacnia to efekt „oglądowości” (wyjaśniając pojęcia matematyczne można się odwoływać do komputerowych kreacji).&lt;br /&gt;
&lt;br /&gt;
Obiektowy język informatyki powinien ułatwić nauczanie matematyki - zwłaszcza gdy wzorem krajów skandynawskich zastosujemy kształcenie poprzez udział w zespołach rozwiązujących interdyscyplinarne problemy.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Jerzy Wawro, 2022&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=151</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=151"/>
		<updated>2022-09-25T18:25:43Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1). (Na temat wyboru wiersza i kolumn będzie jeszcze mowa poniżej).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zmienione – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
----------------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” ( https://www.mimuw.edu.pl/~oskar/lecture_13.pdf ), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Przykładowa implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=150</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=150"/>
		<updated>2022-09-25T17:48:23Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowego rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej&amp;lt;ref&amp;gt;Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”  https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/ref&amp;gt;: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&lt;br /&gt;
 ------&lt;br /&gt;
&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
----------------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=149</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=149"/>
		<updated>2022-09-25T17:41:26Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[index.php?title=Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 ------&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
----------------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: https://github.com/j2kun/ opisana w tekście: https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
* Zmienne decyzyjne - decision variables&lt;br /&gt;
* Funkcja celu - objective function&lt;br /&gt;
* Ograniczenia - constraints&lt;br /&gt;
* Zmienne ograniczeń - variable bounds&lt;br /&gt;
* zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
* sąsiad – neighbor&lt;br /&gt;
* iloczyn skalarny - dot product&lt;br /&gt;
* analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
* rozwiązanie (solution)&lt;br /&gt;
* rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
* dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
* sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
* stopnie swobody (degrees of freedom, df)&lt;br /&gt;
* test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
  tableau = initialTableau(c, A, b)&lt;br /&gt;
  while canImprove(tableau):&lt;br /&gt;
    pivot = findPivotIndex(tableau)&lt;br /&gt;
    pivotAbout(tableau, pivot)&lt;br /&gt;
  return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
  tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
  tableau.append([ci for ci in c] + [0])&lt;br /&gt;
  return tableau&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
  lastRow = tableau[-1]&lt;br /&gt;
  return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
  # wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&lt;br /&gt;
  column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
  column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
  # sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&lt;br /&gt;
  if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
    raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
  # sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&lt;br /&gt;
  quotients = [(i, r[-1] / r[column])&lt;br /&gt;
                 for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
  if moreThanOneMin(quotients):&lt;br /&gt;
    raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
  # wybór indeksu wiersza o minimalnym ilorazie&lt;br /&gt;
  row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
  return row, column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
  i,j = pivot&lt;br /&gt;
  pivotDenom = tableau[i][j]&lt;br /&gt;
  tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
  for k,row in enumerate(tableau):&lt;br /&gt;
    if k != i:&lt;br /&gt;
      pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
      tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  b = [4, 9, 3]&lt;br /&gt;
  c = [2, 5]&lt;br /&gt;
  A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
  # add slack variables by hand&lt;br /&gt;
  A[0] += [1, 0, 0]&lt;br /&gt;
  A[1] += [0, 1, 0]&lt;br /&gt;
  A[2] += [0, 0, 1]&lt;br /&gt;
  c += [0, 0, 0]&lt;br /&gt;
  t, v = simplex(c, A, b)&lt;br /&gt;
  print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
  print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
  for w in t:&lt;br /&gt;
    print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
  print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
  print(v)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=148</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=148"/>
		<updated>2022-09-25T17:33:18Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Równania i nierówności liniowe */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
[[index.php?title=Plik:Równania_liniowe.png|alt=Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 A | b&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
 ------&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 c | 0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=147</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=147"/>
		<updated>2022-09-25T17:23:26Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Algorytm Simplex */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania liniowe.png|ramka|alt=Przykład 1|Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - ilość.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
------&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=146</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=146"/>
		<updated>2022-09-25T17:20:30Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Postać standardowa problemu */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania liniowe.png|ramka|alt=Przykład 1|Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
[[Plik:Simplex - ilość.png|mały]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
------&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png|ramka]]&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=145</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=145"/>
		<updated>2022-09-25T15:53:58Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Postać standardowa problemu */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania liniowe.png|ramka|alt=Przykład 1|Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121&#039;&#039;&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 - x3 = 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 - x4 = 300&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
x1, x2, x3, x4 &amp;gt;= 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
[[Plik:Simplex - ilość.png|mały]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
------&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png|ramka]]&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Uczymy_si%C4%99_my%C5%9Ble%C4%87_abstrakcyjnie&amp;diff=144</id>
		<title>Uczymy się myśleć abstrakcyjnie</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Uczymy_si%C4%99_my%C5%9Ble%C4%87_abstrakcyjnie&amp;diff=144"/>
		<updated>2022-09-25T13:05:33Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{|&lt;br /&gt;
|-&lt;br /&gt;
| |Moduł: Podstawy&lt;br /&gt;
|-&lt;br /&gt;
| |Poziom: Podstawowy&lt;br /&gt;
|-&lt;br /&gt;
| |Profil: Dla wszystkich &lt;br /&gt;
|-&lt;br /&gt;
| |Wymagania: Zapoznanie się z modułem 1&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Symbole ==&lt;br /&gt;
&lt;br /&gt;
Każdy użytkownik współczesnych smartfonów i komputerów wie co to są ikony. To takie uproszczone symbole oznaczające różne programy. W zależności od wielkości ikonki można pokazać więcej lub mniej szczegółów. Poniżej mamy szereg symboli psa:&lt;br /&gt;
&lt;br /&gt;
[[Plik:symbol.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left:20px;color:green;&amp;quot;&amp;gt;Pomoc dydaktyczna: karty z rysunkami zwierząt, rzeczy i pojęć - coraz bardziej abstrakcyjnych. Na jednej stronie karty (zakrytej) może być na przykład zdjęcie psa. Na drugiej (odkrytej) kolejne jego schematyczne przedstawienia – aż do najbardziej abstrakcyjnych. Dziecko otrzymując zadanie pogrupowania kart z takimi rysunkami – jak powyżej - może opanować ideę symbolicznego przedstawiania rzeczy. &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
W przypadku symboli należy odróżnić to co one &#039;&#039;&#039;oznaczają&#039;&#039;&#039; – czyli na co wskazują i to co one &#039;&#039;&#039;znaczą&#039;&#039;&#039; – czyli jaką mają pozycję w systemie (jak je rozumiemy, jak wpływają na otoczenie, co nimi wyrażamy, etc).&lt;br /&gt;
&lt;br /&gt;
Na przykład w przypadku ikony – ważne jest to co symbol oznacza - na co wskazuje,&lt;br /&gt;
&lt;br /&gt;
W przypadku znaku drogowego ważniejsze jest jego znaczenie – jak należy go rozumieć, choć czasem oznacza on też miejsce na drodze.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Znak_drogowy.png]]&lt;br /&gt;
&lt;br /&gt;
Zadanie: opisać co oznacza (na co wskazuje) i jakie ma znaczenie (co znaczy, jak wpływa na oglądających go) powyższy znak drogowy. &lt;br /&gt;
&lt;br /&gt;
Nie zawsze rozróżnienie znaczenia i oznaczania jest łatwe tak jak w przypadku znaku drogowego. Należy jednak zdawać sobie sprawę z tego rozróżnienia – bo to jest ważne dla zrozumienia logiki, będącej fundamentem programowania.&lt;br /&gt;
&lt;br /&gt;
== Logika w automatycznych obliczeniach ==&lt;br /&gt;
&lt;br /&gt;
Każdy symbol w programach to także komórka w pamięci, której zawartość wpływa na działanie systemu. Możemy więc mówić, że symbol ma pewne &#039;&#039;&#039;znaczenie&#039;&#039;&#039; (wpływ na system). Czy jednak także coś &#039;&#039;&#039;oznacza&#039;&#039;&#039; – albo inaczej, czy się do czegoś odnosi? A może w systemie komputerowym te odniesienia są jedynie innym sposobem opisu tego, jak zmienna/symbol wpływa na system – czyli jakie ma &#039;&#039;&#039;znaczenie&#039;&#039;&#039; w systemie? Jeśli chodzi o odniesienia do rzeczywistości (co oznacza symbol poza wirtualnym światem komputerów) – to one w samych obliczeniach nie są ważne. Odniesienia te są symbolom nadawane poprzez urządzenia peryferyjne w komputerze, albo człowieka, interpretującego wyniki działania programów. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center;&amp;quot;&amp;gt;&#039;&#039;&#039;W świecie wirtualnym ważne jest wyłącznie znaczenie symboli, a nie to co one oznaczają.&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To jest istota wirtualności! Programowanie komputerów to budowanie struktur wirtualnego świata!&lt;br /&gt;
&lt;br /&gt;
Takie abstrahowanie od rzeczywistości nie jest wyłącznie domeną informatyki! Tak samo wyglądają wytwory artystów i matematyków. Teoretycznie te dziedziny mogą istnieć nawet gdyby nie było żadnej rzeczywistości (poza nośnikiem wytwarzanych treści oczywiście ;-)).&lt;br /&gt;
&lt;br /&gt;
Czy w świecie wirtualnym istnieje pełna „swoboda twórcza”? W świecie rzeczywistym istnieją ograniczenia fizyczne. Nie możemy iść prosto przed siebie, bo zawsze trafimy na jakąś przeszkodę nie do pokonania. Czy takie ograniczenia istnieją również w świecie wirtualnym?&lt;br /&gt;
&lt;br /&gt;
Tak – przyjęto, że poprawne jest myślenie i programowanie (!) &#039;&#039;&#039;zgodne z regułami logiki&#039;&#039;&#039;. Programy komputerowe budowane ściśle według zasad klasycznego rachunku zdań! W komputerach nie ma nic co łamałoby zasady logiki. Funkcja przejścia jest wyrażeniem logicznym:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sys_iteracyjny_logika.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tak ściśle rzecz ujmując jest to zbiór wyrażeń logicznych, z których każde mówi – czy po następnym takcie zegara konkretna komórka pamięci będzie miała wartość 1 lub 0.&lt;br /&gt;
&lt;br /&gt;
== Semantyka języków programowania ==&lt;br /&gt;
&lt;br /&gt;
Funkcja przejścia jest fizyczną realizacją wyrażenia logicznego i liczy się wyłącznie sposób połączenia między wejściem i wyjściem (jak w kolejnych taktach zegara zmienia się stan).&lt;br /&gt;
&lt;br /&gt;
Jednak napisanie złożonego wyrażenia logicznego obejmującego miliony połączeń jest zadaniem trudnym – jeśli nie nadamy fragmentom pamięci jakichś oznaczeń i nie posłużymy się językiem programowania (zbiorem instrukcji), który ma swoją &#039;&#039;&#039;semantykę&#039;&#039;&#039; (czyli znaczenie symboli).&lt;br /&gt;
&lt;br /&gt;
Semantyka to pojęcie z dziedziny lingwistyki (nauki o językach) i dotyczy znaczenia wypowiedzi. Jest to też pojęcie mające zastosowanie w informatyce.&lt;br /&gt;
&lt;br /&gt;
Programując zapisujemy zbiór instrukcji (zdań jakiegoś języka) które odnoszą się do zawartości pamięci komputera. Mało tego – w informatyce tworzy się bardziej abstrakcyjne języki, które są następnie tłumaczone na język prostszy, a dopiero później na coś co nazywa się „językiem maszyny” i jest wpisywane do pamięci komputera. Mamy więc sytuację analogiczną do tej jak w językoznawstwie – gdzie używa się pojęcia „metajęzyk”. Jest to język w którym opisujemy wypowiedzi w innym języku. W polskim podręczniku do języka angielskiego metajęzykiem wobec języka angielskiego jest język polski. W komputerze metajęzykiem dla języka programowania jest najczęściej język maszynowy (nazywany asemblerem), który opisuje znaczenie i oznaczanie (odniesienia do pamięci komputera) użytych przez programistę wyrażeń. Taki proces nazywa się translacją (czyli inaczej tłumaczeniem).&lt;br /&gt;
&lt;br /&gt;
Pisząc program opisujemy w rzeczywistości to jak powinien działać komputer – czyli jaka ma być zawartość pamięci i jakie wyrażenie logiczne wyznaczające na podstawie stanu pamięci stan następny. Jednak dzięki istnieniu translatorów (takich jak Google Translator), możemy posługiwać się językiem bardziej dla nas wygodnym niż asembler i operować abstrakcyjnymi pojęciami, a następnie przetłumaczyć program na „język maszyny” - czyli de facto stworzyć rzeczywisty program.&lt;br /&gt;
&lt;br /&gt;
Nawet pisząc proste wyrażenie logiczne takie jak „&#039;&#039;&#039;a lub b i c&#039;&#039;&#039;” używamy symboli, które są abstrakcyjne. Czyli symbole te mają jakieś znaczenie, ale nie oznaczają niczego konkretnego (nie odnoszą się do niczego poza tym wyrażeniem). Gdy jednak programista opisuje (lub planuje) działanie komputera, to przecież te symbole odnoszą się do komórek pamięci! Nadal więc oznaczanie symboli jest istotne – tyle, że symbole odnoszą się do rzeczywistości wirtualnej.&lt;br /&gt;
&lt;br /&gt;
Mamy więc:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Semantyka.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Posługujemy się symbolami i opisujemy jak ma się zmieniać pamięć. Symbole mogą oznaczać miejsce w pamięci – wtedy to miejsce oznaczone symbolem nazywamy zmienną.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center;&amp;quot;&amp;gt;&#039;&#039;&#039;W PROGRAMACH NAZWA ZMIENNYCH JEST SYMBOLEM&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Zawartość zmiennej jest tym, co ta zmienna oznacza. Symbole jakimi się posługujemy na co dzień odnoszą się najczęściej do rzeczywistości. Zmienne w programach – niekoniecznie. Tym się różni świat realny od wirtualnego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tak naprawdę należałoby mówić o &#039;&#039;&#039;świecie abstrakcyjnym &#039;&#039;&#039;a nie wirtualnym. Gdy mówimy o świecie realnym, poprawne są wypowiedzi sformułowane w sposób zrozumiały (posiadające znaczenie) i mówiące prawdę (oznaczanie). Prawdziwe są te wypowiedzi, które opisują stan faktyczny. Prawdą jest, że „koń pasie się na łące”, gdy rzeczywiście koń pasie się na łące. &lt;br /&gt;
&lt;br /&gt;
W świecie abstrakcyjnym poprawne są te wypowiedzi, które w zrozumiały (dla kompilatora) sposób opisują działanie abstrakcyjnego systemu. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt;&#039;&#039;&#039;Zadanie domowe: zapoznać się z klasyczną definicją prawdy Arystotelesa i nawiązującą do tej definicji teorii Tarskiego &amp;lt;/span&amp;gt;[https://pl.wikipedia.org/wiki/Prawda https://pl.wikipedia.org/wiki/Prawda]&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt;, &amp;lt;/span&amp;gt;&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt;pojęciem metajęzyka &amp;lt;/span&amp;gt;[https://pl.wikipedia.org/wiki/Metajęzyk https://pl.wikipedia.org/wiki/Metaj%C4%99zyk]&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt;oraz pojęciem semantyki referencyjnej &amp;lt;/span&amp;gt;[https://pl.wikipedia.org/wiki/Semantyka_(językoznawstwo)#Semantyka_referencyjna https://pl.wikipedia.org/wiki/Semantyka_(j%C4%99zykoznawstwo)#Semantyka_referencyjna]&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt; &#039;&#039;&#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Obiekty ==&lt;br /&gt;
&lt;br /&gt;
Jednym z najważniejszych pojęć we współczesnej informatyce jest pojęcie obiektu. Kiedyś zmienne oznaczały po prostu fragment pamięci. Obecnie podobnie jak w przypadku hierarchii języków - stosuje się także coraz bardziej złożone struktury pamięci, które są tłumaczone na struktury prostsze. Na przykład uporządkowany zbiór wartości jest przechowywany w strukturze nazywanej listą. Z uwagi na to, że zawartość pamięci jest traktowana jako „&#039;&#039;&#039;dane&#039;&#039;&#039;” dla programów – mówimy o takich strukturach jako o strukturach danych. Najbardziej zaawansowaną strukturą w językach programowania jest obiekt. Jest to struktura, która ma swoje własności (które także mogą być obiektami) i metody zmian tych własności.&lt;br /&gt;
&lt;br /&gt;
Na przykład obiekt opisujący samochód będzie miał własności takie jak drzwi, koła, szyby etc… Metodą zmiany może być komenda uruchomienia wydawana przez przekręcenie kluczyka w stacyjce. &lt;br /&gt;
&lt;br /&gt;
Najczęściej spotykanym przez nas obiektem komputerowym jest dokument HTML – czyli strona internetowa. Ona też ma swoją obiektową strukturę, nazywaną modelem DOM:&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;[https://pl.wikipedia.org/wiki/Obiektowy_model_dokumentu https://pl.wikipedia.org/wiki/Obiektowy_model_dokumentu]&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Analiza przykładu ==&lt;br /&gt;
&lt;br /&gt;
Te teoretyczne rozważania zilustrujmy konkretnym programem. Wykorzystamy język JavaScript używany w przeglądarkach internetowych. Istnieje kilka stron na których można testować takie programy ([http://codepen.io/pen/ http://codepen.io/pen/] lub [https://jsfiddle.net/ https://jsfiddle.net/] lub [http://jsbin.com/ http://jsbin.com/]).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Przykład 1:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[http://jsbin.com/folowenasa/edit?html,css,js,console,output http://jsbin.com/folowenasa/edit?html,css,js,console,output]&lt;br /&gt;
&lt;br /&gt;
Wpiszmy w treść strony jakiś tekst – na przykład „Kliknij tutaj”.&lt;br /&gt;
&lt;br /&gt;
Do znacznika &amp;lt;body&amp;gt; dodajmy własność „onclick” i nadajmy jej wartość „test();”. Będzie to znaczyć, że po kliknięciu na stronie wykona się procedura „test”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;body onclick=&amp;quot;test();&amp;quot;&amp;gt;kliknij tutaj&amp;lt;/body&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Procedura musi zostać napisana – żeby się wykonała:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
function test() {&lt;br /&gt;
  alert(&#039;!&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jakie jest znaczenie i oznaczanie użytych symboli?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| symbol&lt;br /&gt;
| Znaczenie&lt;br /&gt;
| oznaczanie&lt;br /&gt;
|-&lt;br /&gt;
| body&lt;br /&gt;
| Część języka HTML w którym opisujemy strony internetowe. W tym wypadku znacznik używany do ograniczenia całej strony.&lt;br /&gt;
| Oznacza wnętrze (treść) strony.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt; &amp;gt;&lt;br /&gt;
| Dwa symbole określające początek i koniec znacznika. &lt;br /&gt;
| Miejsce w tekście gdzie zaczyna się i kończy znacznik.&lt;br /&gt;
|-&lt;br /&gt;
| /&lt;br /&gt;
| Zmienia znaczenie znacznika (koniec oznaczanego obszaru) – o ile występuje natychmiast po znaku &amp;lt;&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| onclick&lt;br /&gt;
| Własność dodawana do znacznika. Po znaku = nadaje się tej własności wartość.&lt;br /&gt;
| Co się stanie, gdy klikniemy na wskazywane przez znacznik miejsce.&lt;br /&gt;
|-&lt;br /&gt;
| function&lt;br /&gt;
| Symbol używany do zdefiniowania fragmentu kodu (programu) nazywanego funkcją.&lt;br /&gt;
| Definicję jakiejś funkcji.&lt;br /&gt;
|-&lt;br /&gt;
| test&lt;br /&gt;
| Symbol zdefiniowany przez nas – konkretnej funkcji.&lt;br /&gt;
| Definicję konkretnej funkcji test.&lt;br /&gt;
|-&lt;br /&gt;
| alert&lt;br /&gt;
| Wyświetlenie komunikatu&lt;br /&gt;
| Funkcję zdefiniowaną (wbudowaną) w przeglądarce.&lt;br /&gt;
|-&lt;br /&gt;
| {&lt;br /&gt;
| Znaki używane dla interpretera (przeglądarki internetowej) – aby mógł zrozumieć znaczenie tekstu &lt;br /&gt;
| Początek procedury&lt;br /&gt;
|-&lt;br /&gt;
| }&lt;br /&gt;
| Koniec procedury&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| Koniec fragmentu procedury zawierającą instrukcję (zob niżej).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;&lt;br /&gt;
| Cudzysłów oznaczający początek i koniec napisu.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| Znak równości (własność ma określoną wartość)&lt;br /&gt;
|-&lt;br /&gt;
| (&lt;br /&gt;
| Początek miejsca na parametry funkcji&lt;br /&gt;
|-&lt;br /&gt;
| )&lt;br /&gt;
| Koniec miejsca na parametry funkcji&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Więcej informacji: [http://www.w3schools.com/html/html_intro.asp http://www.w3schools.com/html/html_intro.asp] (można wybrać polskie tłumaczenie – jest dość porządne).&lt;br /&gt;
[http://pdf.helion.pl/e14te3/e14te3.pdf http://pdf.helion.pl/e14te3/e14te3.pdf] (rozdział 3.8 i dalej)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nie zawsze rozróżnienie znaczenia i oznaczania jest oczywiste. W przypadku symbolu „/” mamy do czynienia jedynie z modyfikacją znaczenia innego symbolu. Można na siłę określić co on oznacza (miejsce po którym nastąpi nazwa zmodyfikowanego symbolu?) - ale czy to nam jest potrzebne?&lt;br /&gt;
&lt;br /&gt;
Dodatkowego wyjaśnienia wymaga znaczenie symbolu „funkcja” i pojęcia które się za nim kryje.&lt;br /&gt;
&lt;br /&gt;
Funkcja to fragment kodu programu określony nazwą. Zamiast słowa funkcja używa się czasem określenia ‘procedura’, które nie oznacza jednak dokładnie tego samego (wybiegając nieco w przyszłość: funkcja zwraca wartość, procedura nie). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:#6600cc;&amp;quot;&amp;gt;&#039;&#039;&#039;Uwaga metodyczna: używanie praktycznych środowisk programistycznych ma tą przewagę nad zabawami typu Scratch lub Baltie (które raczej są przeznaczone dla szkół podstawowych) – że pozwala doświadczyć czegoś najpiękniejszego w pracy programisty: natychmiast widocznego i użytecznego efektu, którym można się pochwalić.&#039;&#039;&#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Definicja a użycie symbolu ==&lt;br /&gt;
&lt;br /&gt;
Należy odróżnić użycie i definicję symbolu. Symbol „test” jest zastosowany w powyższym przykładzie dwa razy: raz go definiujemy (po słowie function), drugi raz używamy. W pierwszym przypadku ważniejsze jest to co symbol oznacza (definicję procedury) w drugim – co znaczy (taki sposób funkcjonowania strony, że kliknięcie w jej fragment spowoduje wyświetlenie komunikatu).&lt;br /&gt;
&lt;br /&gt;
Czym symbol „alert” różni się od symbolu „test”?&lt;br /&gt;
&lt;br /&gt;
Funkcję „test” musieliśmy zdefiniować. Funkcja „alert” została zdefiniowana przez twórców JavaScript i po prostu możemy jej używać.&lt;br /&gt;
&lt;br /&gt;
Co jeszcze możemy powiedzieć o symbolach? Poza rozróżnienie znaczenia i oznaczania mamy jeszcze sam symbol jako byt (obiekt fizyczny). Znaczek biegnących dzieci jest namalowany na znaku drogowym – najczęściej blaszanym i z użyciem farby.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pomoc dydaktyczna: odróżnienie symbolu od kryjących się pod nim treści można przedstawić za pomocą pudełek w których ukrywamy różne rzeczy. Można na przykład dzieciom zrobić konkurs na symbole oznaczające kosze na różnego rodzaju odpadki (przy okazji uczymy ekologii ;-)).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Kontekst i znaczenie ==&lt;br /&gt;
&lt;br /&gt;
Znaczenie symbolu zależy od kontekstu w którym go używamy. Słowo „alert” oznacza po angielsku alarm. W środowisku przeglądarki internetowej powoduje wyświetlenie komunikatu. Użycie symbolu w powyższym zdaniu jest jego przytoczeniem (cytatem). Po to używamy cudzysłowów. Jeśli w definicji funkcji test zmienimy alert(‘!’) na alert(‘alert’) to nie wykona się dwa razy funkcja „alert”, tylko zostanie wyświetlona (przytoczona) jej nazwa.&lt;br /&gt;
&lt;br /&gt;
Kontekst jest ważny, bo w różnych miejscach ten sam symbol może oznaczać coś innego. Nie należy tego nadużywać (lepiej stosować różne symbole). &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Przykład 2:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
html:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;body&amp;gt;&amp;lt;span style=&amp;quot;color:blue&amp;quot; id=&amp;quot;test&amp;quot; onclick=&amp;quot;test();&amp;quot;&amp;gt; kliknij tutaj&amp;lt;/span&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Javascript:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
function test() { &lt;br /&gt;
  alert(document.getElementById(&amp;quot;test&amp;quot;).style.color); &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
W przykładzie tym użyliśmy nowego znacznika &#039;&#039;&#039;span&#039;&#039;&#039; – którym określamy fragment tekstu. Dodatkowa własność znacznika to style - oznacza ona sposób wyświetlania. W tym wypadku zdefiniowaliśmy kolor jako niebieski. Symbol „test” został użyty na określenie zarówno funkcji jak i fragmentu tekstu w znaczniku span.&lt;br /&gt;
&lt;br /&gt;
Użyliśmy też innej zdefiniowanej funkcji: document.getElementById – która zwraca nam część strony określoną identyfikatorem (własność id). Możemy w JavaScript odnosić się do własności tej części strony. Na przykład document.getElementById(&amp;quot;test&amp;quot;).style.color oznacza odwołanie do stylu i wybranie z tego stylu nazwy koloru.&lt;br /&gt;
&lt;br /&gt;
Możemy ten kolor też w JavaScript zmieniać. Na przykład dodanie instrukcji: document.getElementById(&amp;quot;test&amp;quot;).style.color = &amp;quot;red&amp;quot;; spowoduje zmianę koloru na czerwony.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ćwiczenie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1) próbujmy zmieniać nazwy symbolu &#039;&#039;test&#039;&#039; w różnych miejscach gdzie go użyto. Które z tych zmian mają sens?&lt;br /&gt;
&lt;br /&gt;
2) Dodajmy zmianę koloru na czerwony.&lt;br /&gt;
&lt;br /&gt;
Przy próbach zmiany symbolu może wystąpić taka sytuacja, że odwołujemy się do elementu, którego nie ma (bo na przykład zmieniliśmy id=”test” na id=”test1” a odwołujemy się do „test”). Najczęściej ma to miejsce wskutek pomyłek. Co się wówczas dzieje? Pojawia się &#039;&#039;&#039;symbol pusty&#039;&#039;&#039; (z angielskiego null). Słowo ‘null’ nie oznacza nicości (w komputerze nie ma czegoś takiego), tylko właśnie symbol pusty.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pojęcie symbolu pustego występuje na przykład w grze w domino („mydło”).&#039;&#039;&#039; Wyobraźmy sobie choinkę i prezenty, w pudełkach oznaczane imionami domowników. Te imiona są symbolem oznaczającym prezent dla konkretnej osoby. A co będzie gdy pojawi się pudełko bez symbolu? Może to po prostu ktoś zostawił opakowanie po ozdobach choinkowych? W środku nic nie ma. Mamy przykład symbolu pustego.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To co symbole oznaczają może się zmieniać&#039;&#039;&#039;. Pojęcie zmiennej (pudełko oznaczone symbolem) jest chyba najważniejszym w programowaniu komputerów. W naszym przykładzie symbol „color” znaczy kolor wyświetlania, a oznacza konkretny kolor (‘blue’, lub ‘red’). &lt;br /&gt;
&lt;br /&gt;
== Podsumowanie ==&lt;br /&gt;
&lt;br /&gt;
* Symbole jakich używamy mają swoje znaczenie i mogą coś oznaczać (na coś wskazywać).&lt;br /&gt;
* W logice posługujemy się symbolami abstrakcyjnymi, które nie odnoszą się do konkretnych rzeczy.&lt;br /&gt;
* Komputer działa zgodnie z zasadami logiki. Funkcję przejścia można teoretycznie opisać jako zbiór wyrażeń logicznych.&lt;br /&gt;
* W praktyce posługujemy się językami programowania, które są tłumaczone na język maszynowy przez translator.&lt;br /&gt;
* Symbole w językach programowania mają znaczenie i mogą oznaczać miejsce w pamięci. W tym drugim przypadku mówimy o zmiennych, a miejsce oznaczone tą nazwą nazywamy zmienną.&lt;br /&gt;
* Języki programowania mogą tworzyć hierarchię (bardziej abstrakcyjny może być tłumaczony na bardzie zbliżony do języka maszynowego - asemblera). Odpowiada to podziałowi na język i metajęzyk w językoznawstwie.&lt;br /&gt;
* Struktury pamięci (struktury danych, zmienne) mogą także być złożone i tworzyć obiekty.&lt;br /&gt;
* Obiekt to struktura danych która ma swoje własności i metody zmian tych własności. Przykładem takiej struktury jest dokument HTML.&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_%E2%80%93_program_%E2%80%93_system&amp;diff=143</id>
		<title>Algorytm – program – system</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_%E2%80%93_program_%E2%80%93_system&amp;diff=143"/>
		<updated>2022-09-25T13:03:34Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Od łamigłówki do programu */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{|&lt;br /&gt;
|-&lt;br /&gt;
| |Moduł: Podstawy&lt;br /&gt;
|-&lt;br /&gt;
| |Poziom: Podstawowy&lt;br /&gt;
|-&lt;br /&gt;
| |Profil: Dla wszystkich&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Od łamigłówki do programu ==&lt;br /&gt;
&lt;br /&gt;
Łamigłówka „Wieże Hanoi” (https://pl.wikipedia.org/wiki/Wieże_Hanoi) polega na przełożeniu krążków z pierwszego na trzeci słupek zgodnie z regułami:&lt;br /&gt;
* za każdym razem jeden; &lt;br /&gt;
* nie wolno kłaść większego krążka na mniejszy &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
[[Plik:Hanoi.png]]Pomoc dydaktyczna: klocki Wieże Hanoi.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Oznaczmy liczbami krążki (od najmniejszego do największego).&lt;br /&gt;
&lt;br /&gt;
Opracowujemy plan działania:&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;border-spacing:0;width:3.201cm;border:1px solid black&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| | Lp&lt;br /&gt;
| align=center | działanie&lt;br /&gt;
|-&lt;br /&gt;
|  | 1&lt;br /&gt;
|  | 1-C&lt;br /&gt;
|-&lt;br /&gt;
|  | 2&lt;br /&gt;
|  | 2-B&lt;br /&gt;
|-&lt;br /&gt;
|  | 3&lt;br /&gt;
|  | 1-B&lt;br /&gt;
|-&lt;br /&gt;
|  | 4&lt;br /&gt;
|  | 3-C&lt;br /&gt;
|-&lt;br /&gt;
|  | 5&lt;br /&gt;
|  | 1-A&lt;br /&gt;
|-&lt;br /&gt;
|  | 6&lt;br /&gt;
|  | 2-C&lt;br /&gt;
|-&lt;br /&gt;
|  | 7&lt;br /&gt;
|  | 1-C&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Przetestujmy: https://pl.khanacademy.org/computing/computer-science/algorithms/towers-of-hanoi/e/move-three-disks-in-towers-of-hanoi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#007826;&amp;quot;&amp;gt;Zadanie domowe:&lt;br /&gt;
# Spróbować dla większej ilości klocków. &lt;br /&gt;
# Czy daje się to uogólnić dla n klocków (zadanie bardzo zaawansowane)? &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ułożenie takiego planu działania wymaga &#039;&#039;&#039;abstrakcyjnego myślenia&#039;&#039;&#039;. Abstrakcja – czyli abstrahowanie od fizycznych elementów. Klocki, słupki i działania zmieniają się w abstrakcyjny zapis – na przykład 1-B. Umiejętność abstrakcyjnego myślenia jest najważniejsza dla programisty. Jeśli ktoś tego nie potrafi – nie może być programistą i nigdy nie zrozumie matematyki.&lt;br /&gt;
&lt;br /&gt;
Taki abstrakcyjny plan działania nazywa się &#039;&#039;&#039;algorytmem&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Program&#039;&#039;&#039; to algorytm wykonywany przez &#039;&#039;&#039;automat&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ilustracja: program Hanoi (dołączone do kursu źródła UWAGA! Program został napisany w przestarzałej technologii Flash - może nie działać na nowych przeglądarkach).&lt;br /&gt;
&lt;br /&gt;
[http://otwartaedukacja.pl/programowanie/hanoi/ http://otwartaedukacja.pl/programowanie/hanoi/] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Hanoi_prg.png]]&lt;br /&gt;
&lt;br /&gt;
Każdy program jest uruchamiany w pewnym &#039;&#039;&#039;środowisku&#039;&#039;&#039;. Tutaj środowiskiem są trzy słupki z krążkami. Dla programów (Hanoi, https://pl.khanacademy.org/computing/computer-science/algorithms/towers-of-hanoi/e/move-three-disks-in-towers-of-hanoi) środowiskiem jest przeglądarka internetowa w której uruchomiono program napisany w języku JavaScript.&lt;br /&gt;
&lt;br /&gt;
Przejście od środowiska fizycznego (klocki) do przeglądarki internetowej wydaje się nam czymś naturalnym. To jednak wymaga pewnej refleksji – gdyż w ten sposób wchodzimy do świata wirtualnego. &#039;&#039;&#039;Wirtualny&#039;&#039;&#039; – czyli nie istniejący realnie.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center;&amp;quot;&amp;gt;&#039;&#039;&#039;PROGRAM KOMPUTEROWY TO AUTOMAT DZIAŁAJĄCY W ŚWIECIE WIRTUALNYM&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Robot.png]]&lt;br /&gt;
&lt;br /&gt;
Najważniejszą cechą automatu jest &#039;&#039;&#039;determinizm&#039;&#039;&#039; – czyli kolejne działanie jest ściśle określone i zależy wyłącznie od stanu w jakim znajduje się maszyna. &#039;&#039;&#039;Programowanie maszyn = dążenie do determinizmu&#039;&#039;&#039; (ścisłego określenia co ma się wydarzyć w danym stanie maszyny, a nie tylko co może się wydarzyć).&lt;br /&gt;
&lt;br /&gt;
== System ==&lt;br /&gt;
&lt;br /&gt;
Elementy automatu są powiązane ze sobą w taki sposób, aby w całości uzyskać pożądaną funkcjonalność. Na przykład bankomat składa się z liczarki banknotów, klawiatury, monitora, obudowy, czytnika kart i sterującego wszystkim komputera. Jego podstawową funkcją jest wydawanie pieniędzy. Taki zbiór elementów powiązanych ze sobą w sposób umożliwiający uzyskanie pewnej funkcjonalności nazywa się &#039;&#039;&#039;systemem&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left:1.251cm;margin-right:0cm;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt;Zadanie domowe: zapoznać się z hasłem „System” w Wikipedii: &amp;lt;/span&amp;gt;[https://pl.wikipedia.org/wiki/System https://pl.wikipedia.org/wiki/System]&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Złożone systemy komputerowe uzyskuje się poprzez składanie ich z systemów prostszych (modułów, podprogramów). Idąc w kierunku przeciwnym – do rzeczy coraz prostszych sięgamy do istoty obliczeń. Polski matematyk Zdzisław Pawlak taki najprostszy system nazwał „systemem iteracyjnym”. &lt;br /&gt;
&lt;br /&gt;
Składa się on z pamięci i funkcji przejścia. Pamięć wyraża stan aktualny automatu, a funkcja przejścia determinuje (określa) stan następny.&lt;br /&gt;
&lt;br /&gt;
System iteracyjny:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sys_iteracyjny.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;MASZYNA OBLICZENIOWA = PAMIĘĆ + FUNKCJA PRZEJŚCIA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FUNKCJA PRZEJŚCIA WYZNACZA STAN NASTĘPNY (NOWĄ ZAWARTOŚĆ PAMIĘCI)&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;PROGRAMOWANIE = BUDOWANIE FUNKCJI PRZEJŚCIA&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pawlak posługuje się przykładem kostki do gry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#ff0000;margin-left:2.499cm;margin-right:0cm;&amp;quot;&amp;gt;Pomoc dydaktyczna: kostka do gry lub kostka Rubika&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Kostka.png]]&lt;br /&gt;
&lt;br /&gt;
Przykład programu:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;border-spacing:0;width:6.085cm;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| STAN&lt;br /&gt;
|| NASTĘPNY&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 1&lt;br /&gt;
|| STOP&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 2&lt;br /&gt;
|| STOP&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 3&lt;br /&gt;
|| 1&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 4&lt;br /&gt;
|| 2&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 5&lt;br /&gt;
|| 1&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 6&lt;br /&gt;
|| 2&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
Pytanie: co ten program wylicza?&lt;br /&gt;
&lt;br /&gt;
Odpowiedź: zatrzymuje się na 1 lub 2 w zależności od tego, czy początkowo była ilość parzysta lub nieparzysta oczek.&lt;br /&gt;
&lt;br /&gt;
Pisząc program określamy warunki jego zatrzymania się. Najczęściej jest to zakończenie wykonywania algorytmu (zakończenie obliczeń). &lt;br /&gt;
&lt;br /&gt;
Zadanie domowe: zapoznać się z problemem stopu [https://pl.wikipedia.org/wiki/Problem_stopu https://pl.wikipedia.org/wiki/Problem_stopu]&lt;br /&gt;
&lt;br /&gt;
== Arkusz kalkulacyjny jako środowisko w którym uruchamiamy programy ==&lt;br /&gt;
&lt;br /&gt;
[[Plik:Arkusz.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;KOMÓRKI = PAMIĘĆ&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;REGUŁY = FUNKCJA PRZEJŚCIA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Zmienna ==&lt;br /&gt;
&lt;br /&gt;
W arkuszu kalkulacyjnym wiadomo gdzie zapisać wynik – w tej samej komórce, w której zapisano regułę. W programie musimy zarezerwować miejsce w pamięci. Komórka arkusza kalkulacyjnego ma swoją nazwę. W programie posługujemy się nazwą zmiennej (identyfikatorem).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nazwa komórki = identyfikator zmiennej&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Przykład identyfikatora w języku php: &#039;&#039;&#039;$a1 &#039;&#039;&#039;(użyto identyfikatora zgodnie z konwencją nazywania komórek w arkuszu kalkulacyjnym).&lt;br /&gt;
&lt;br /&gt;
Najprostsze programy to formuły w arkuszu.&lt;br /&gt;
&lt;br /&gt;
Na przykład: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;= $a1 + 10&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Odpowiednia instrukcja w języku php:&lt;br /&gt;
&lt;br /&gt;
$wynik = $a1+10;&lt;br /&gt;
&lt;br /&gt;
Zarezerwowane dwa miejsca w pamięci – zmienne $a1 i $wynik&lt;br /&gt;
&lt;br /&gt;
== Algorytm a program ==&lt;br /&gt;
&lt;br /&gt;
Często spotyka się z wyjaśnieniem, że program jest implementacją algorytmu. Czyli takim zapisem algorytmu, by mogła go wykonać maszyna. To wyjaśnienie wymaga komentarza. Algorytmy jakie spotykamy na co dzień są najczęściej trywialne. Na przykład: aby otworzyć drzwi, włóż klucz do zamka, przekręć w prawo do oporu a następnie naciśnij klamkę.&lt;br /&gt;
&lt;br /&gt;
Jednak algorytmy bywają też bardzo trudne. Nawet najprostszy algorytm sortowania liczb wymaga odrobiny wysiłku intelektualnego, aby go zrozumieć. Naukę programowania często myli się z algorytmiką (czyli układaniem algorytmów), co jest trudne. Dla większości zadań z jakimi spotyka się programista ich trudność można porównać z algorytmem otwierania drzwi (sama czynność jest prostsza, niż jej ścisłe opisanie).&lt;br /&gt;
&lt;br /&gt;
Algorytmika jest trudna. Programowanie jest łatwe. Układanie i implementacja algorytmów wymaga wiedzy, umiejętności i talentu. Programować może każdy. I każdy, kto ma styczność z tworami nowoczesnej techniki to robi (choćby programując programy w telewizorze).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Molier.png]]&lt;br /&gt;
MOLIER „MIESZCZANIN SZLACHCICEM” (w oryginale bohater był zdziwiony, że mówi prozą!)&lt;br /&gt;
&lt;br /&gt;
== Podsumowanie ==&lt;br /&gt;
&lt;br /&gt;
* Programowanie komputerów wymaga abstrakcyjnego myślenia.&lt;br /&gt;
* Układamy algorytmy i zapisujemy je przy pomocy abstrakcyjnych symboli.&lt;br /&gt;
* Programy są uruchamiane w środowisku tworzącym system obliczeniowy.&lt;br /&gt;
* Istotę działania takiego systemu wyjaśnia system iteracyjny.&lt;br /&gt;
* Najprostszym środowiskiem jest arkusz kalkulacyjny.&lt;br /&gt;
* Przechodząc od arkusza do zwykłych programów – wprowadzamy pojęcie zmiennej (zastępujące komórkę arkusza).&lt;br /&gt;
* Programowanie nie jest trudne! Programy pisze każdy użytkownik arkusza kalkulacyjnego (a nawet gdy tylko układa w myśli plan działania)! Trudne natomiast może być układanie algorytmów (czym zajmuje się algorytmika).&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_%E2%80%93_program_%E2%80%93_system&amp;diff=142</id>
		<title>Algorytm – program – system</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_%E2%80%93_program_%E2%80%93_system&amp;diff=142"/>
		<updated>2022-09-25T13:01:35Z</updated>

		<summary type="html">&lt;p&gt;Admin: nieaktywny link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{|&lt;br /&gt;
|-&lt;br /&gt;
| |Moduł: Podstawy&lt;br /&gt;
|-&lt;br /&gt;
| |Poziom: Podstawowy&lt;br /&gt;
|-&lt;br /&gt;
| |Profil: Dla wszystkich&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Od łamigłówki do programu ==&lt;br /&gt;
&lt;br /&gt;
Łamigłówka „Wieże Hanoi” (https://pl.wikipedia.org/wiki/Wieże_Hanoi) polega na przełożeniu krążków z pierwszego na trzeci słupek zgodnie z regułami:&lt;br /&gt;
* za każdym razem jeden; &lt;br /&gt;
* nie wolno kłaść większego krążka na mniejszy &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
[[Plik:Hanoi.png]]Pomoc dydaktyczna: klocki Wieże Hanoi.&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Oznaczmy liczbami krążki (od najmniejszego do największego).&lt;br /&gt;
&lt;br /&gt;
Opracowujemy plan działania:&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;border-spacing:0;width:3.201cm;border:1px solid black&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| | Lp&lt;br /&gt;
| align=center | działanie&lt;br /&gt;
|-&lt;br /&gt;
|  | 1&lt;br /&gt;
|  | 1-C&lt;br /&gt;
|-&lt;br /&gt;
|  | 2&lt;br /&gt;
|  | 2-B&lt;br /&gt;
|-&lt;br /&gt;
|  | 3&lt;br /&gt;
|  | 1-B&lt;br /&gt;
|-&lt;br /&gt;
|  | 4&lt;br /&gt;
|  | 3-C&lt;br /&gt;
|-&lt;br /&gt;
|  | 5&lt;br /&gt;
|  | 1-A&lt;br /&gt;
|-&lt;br /&gt;
|  | 6&lt;br /&gt;
|  | 2-C&lt;br /&gt;
|-&lt;br /&gt;
|  | 7&lt;br /&gt;
|  | 1-C&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Przetestujmy: https://pl.khanacademy.org/computing/computer-science/algorithms/towers-of-hanoi/e/move-three-disks-in-towers-of-hanoi&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#007826;&amp;quot;&amp;gt;Zadanie domowe:&lt;br /&gt;
# Spróbować dla większej ilości klocków. &lt;br /&gt;
# Czy daje się to uogólnić dla n klocków (zadanie bardzo zaawansowane)? &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ułożenie takiego planu działania wymaga &#039;&#039;&#039;abstrakcyjnego myślenia&#039;&#039;&#039;. Abstrakcja – czyli abstrahowanie od fizycznych elementów. Klocki, słupki i działania zmieniają się w abstrakcyjny zapis – na przykład 1-B. Umiejętność abstrakcyjnego myślenia jest najważniejsza dla programisty. Jeśli ktoś tego nie potrafi – nie może być programistą i nigdy nie zrozumie matematyki.&lt;br /&gt;
&lt;br /&gt;
Taki abstrakcyjny plan działania nazywa się &#039;&#039;&#039;algorytmem&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Program&#039;&#039;&#039; to algorytm wykonywany przez &#039;&#039;&#039;automat&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ilustracja: program Hanoi (dołączone do kursu źródła).&lt;br /&gt;
&lt;br /&gt;
[http://otwartaedukacja.pl/programowanie/hanoi/ http://otwartaedukacja.pl/programowanie/hanoi/] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Hanoi_prg.png]]&lt;br /&gt;
&lt;br /&gt;
Każdy program jest uruchamiany w pewnym &#039;&#039;&#039;środowisku&#039;&#039;&#039;. Tutaj środowiskiem są trzy słupki z krążkami. Dla programów (Hanoi, [http://www.zagraj.republika.pl/hanoi.html http://www.zagraj.republika.pl/hanoi.html]) środowiskiem jest przeglądarka internetowa w której uruchomiono program napisany w języku JavaScript.&lt;br /&gt;
&lt;br /&gt;
Przejście od środowiska fizycznego (klocki) do przeglądarki internetowej wydaje się nam czymś naturalnym. To jednak wymaga pewnej refleksji – gdyż w ten sposób wchodzimy do świata wirtualnego. &#039;&#039;&#039;Wirtualny&#039;&#039;&#039; – czyli nie istniejący realnie.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center;&amp;quot;&amp;gt;&#039;&#039;&#039;PROGRAM KOMPUTEROWY TO AUTOMAT DZIAŁAJĄCY W ŚWIECIE WIRTUALNYM&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Robot.png]]&lt;br /&gt;
&lt;br /&gt;
Najważniejszą cechą automatu jest &#039;&#039;&#039;determinizm&#039;&#039;&#039; – czyli kolejne działanie jest ściśle określone i zależy wyłącznie od stanu w jakim znajduje się maszyna. &#039;&#039;&#039;Programowanie maszyn = dążenie do determinizmu&#039;&#039;&#039; (ścisłego określenia co ma się wydarzyć w danym stanie maszyny, a nie tylko co może się wydarzyć).&lt;br /&gt;
&lt;br /&gt;
== System ==&lt;br /&gt;
&lt;br /&gt;
Elementy automatu są powiązane ze sobą w taki sposób, aby w całości uzyskać pożądaną funkcjonalność. Na przykład bankomat składa się z liczarki banknotów, klawiatury, monitora, obudowy, czytnika kart i sterującego wszystkim komputera. Jego podstawową funkcją jest wydawanie pieniędzy. Taki zbiór elementów powiązanych ze sobą w sposób umożliwiający uzyskanie pewnej funkcjonalności nazywa się &#039;&#039;&#039;systemem&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left:1.251cm;margin-right:0cm;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt;Zadanie domowe: zapoznać się z hasłem „System” w Wikipedii: &amp;lt;/span&amp;gt;[https://pl.wikipedia.org/wiki/System https://pl.wikipedia.org/wiki/System]&amp;lt;span style=&amp;quot;color:#007826;&amp;quot;&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Złożone systemy komputerowe uzyskuje się poprzez składanie ich z systemów prostszych (modułów, podprogramów). Idąc w kierunku przeciwnym – do rzeczy coraz prostszych sięgamy do istoty obliczeń. Polski matematyk Zdzisław Pawlak taki najprostszy system nazwał „systemem iteracyjnym”. &lt;br /&gt;
&lt;br /&gt;
Składa się on z pamięci i funkcji przejścia. Pamięć wyraża stan aktualny automatu, a funkcja przejścia determinuje (określa) stan następny.&lt;br /&gt;
&lt;br /&gt;
System iteracyjny:&lt;br /&gt;
&lt;br /&gt;
[[Plik:Sys_iteracyjny.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;MASZYNA OBLICZENIOWA = PAMIĘĆ + FUNKCJA PRZEJŚCIA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;FUNKCJA PRZEJŚCIA WYZNACZA STAN NASTĘPNY (NOWĄ ZAWARTOŚĆ PAMIĘCI)&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;PROGRAMOWANIE = BUDOWANIE FUNKCJI PRZEJŚCIA&#039;&#039;&#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pawlak posługuje się przykładem kostki do gry.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#ff0000;margin-left:2.499cm;margin-right:0cm;&amp;quot;&amp;gt;Pomoc dydaktyczna: kostka do gry lub kostka Rubika&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Plik:Kostka.png]]&lt;br /&gt;
&lt;br /&gt;
Przykład programu:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;border-spacing:0;width:6.085cm;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| STAN&lt;br /&gt;
|| NASTĘPNY&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 1&lt;br /&gt;
|| STOP&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 2&lt;br /&gt;
|| STOP&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 3&lt;br /&gt;
|| 1&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 4&lt;br /&gt;
|| 2&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 5&lt;br /&gt;
|| 1&lt;br /&gt;
|- style=&amp;quot;border:none;padding:0cm;&amp;quot;&lt;br /&gt;
|| 6&lt;br /&gt;
|| 2&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
Pytanie: co ten program wylicza?&lt;br /&gt;
&lt;br /&gt;
Odpowiedź: zatrzymuje się na 1 lub 2 w zależności od tego, czy początkowo była ilość parzysta lub nieparzysta oczek.&lt;br /&gt;
&lt;br /&gt;
Pisząc program określamy warunki jego zatrzymania się. Najczęściej jest to zakończenie wykonywania algorytmu (zakończenie obliczeń). &lt;br /&gt;
&lt;br /&gt;
Zadanie domowe: zapoznać się z problemem stopu [https://pl.wikipedia.org/wiki/Problem_stopu https://pl.wikipedia.org/wiki/Problem_stopu]&lt;br /&gt;
&lt;br /&gt;
== Arkusz kalkulacyjny jako środowisko w którym uruchamiamy programy ==&lt;br /&gt;
&lt;br /&gt;
[[Plik:Arkusz.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;KOMÓRKI = PAMIĘĆ&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;REGUŁY = FUNKCJA PRZEJŚCIA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Zmienna ==&lt;br /&gt;
&lt;br /&gt;
W arkuszu kalkulacyjnym wiadomo gdzie zapisać wynik – w tej samej komórce, w której zapisano regułę. W programie musimy zarezerwować miejsce w pamięci. Komórka arkusza kalkulacyjnego ma swoją nazwę. W programie posługujemy się nazwą zmiennej (identyfikatorem).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nazwa komórki = identyfikator zmiennej&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Przykład identyfikatora w języku php: &#039;&#039;&#039;$a1 &#039;&#039;&#039;(użyto identyfikatora zgodnie z konwencją nazywania komórek w arkuszu kalkulacyjnym).&lt;br /&gt;
&lt;br /&gt;
Najprostsze programy to formuły w arkuszu.&lt;br /&gt;
&lt;br /&gt;
Na przykład: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;= $a1 + 10&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Odpowiednia instrukcja w języku php:&lt;br /&gt;
&lt;br /&gt;
$wynik = $a1+10;&lt;br /&gt;
&lt;br /&gt;
Zarezerwowane dwa miejsca w pamięci – zmienne $a1 i $wynik&lt;br /&gt;
&lt;br /&gt;
== Algorytm a program ==&lt;br /&gt;
&lt;br /&gt;
Często spotyka się z wyjaśnieniem, że program jest implementacją algorytmu. Czyli takim zapisem algorytmu, by mogła go wykonać maszyna. To wyjaśnienie wymaga komentarza. Algorytmy jakie spotykamy na co dzień są najczęściej trywialne. Na przykład: aby otworzyć drzwi, włóż klucz do zamka, przekręć w prawo do oporu a następnie naciśnij klamkę.&lt;br /&gt;
&lt;br /&gt;
Jednak algorytmy bywają też bardzo trudne. Nawet najprostszy algorytm sortowania liczb wymaga odrobiny wysiłku intelektualnego, aby go zrozumieć. Naukę programowania często myli się z algorytmiką (czyli układaniem algorytmów), co jest trudne. Dla większości zadań z jakimi spotyka się programista ich trudność można porównać z algorytmem otwierania drzwi (sama czynność jest prostsza, niż jej ścisłe opisanie).&lt;br /&gt;
&lt;br /&gt;
Algorytmika jest trudna. Programowanie jest łatwe. Układanie i implementacja algorytmów wymaga wiedzy, umiejętności i talentu. Programować może każdy. I każdy, kto ma styczność z tworami nowoczesnej techniki to robi (choćby programując programy w telewizorze).&lt;br /&gt;
&lt;br /&gt;
[[Plik:Molier.png]]&lt;br /&gt;
MOLIER „MIESZCZANIN SZLACHCICEM” (w oryginale bohater był zdziwiony, że mówi prozą!)&lt;br /&gt;
&lt;br /&gt;
== Podsumowanie ==&lt;br /&gt;
&lt;br /&gt;
* Programowanie komputerów wymaga abstrakcyjnego myślenia.&lt;br /&gt;
* Układamy algorytmy i zapisujemy je przy pomocy abstrakcyjnych symboli.&lt;br /&gt;
* Programy są uruchamiane w środowisku tworzącym system obliczeniowy.&lt;br /&gt;
* Istotę działania takiego systemu wyjaśnia system iteracyjny.&lt;br /&gt;
* Najprostszym środowiskiem jest arkusz kalkulacyjny.&lt;br /&gt;
* Przechodząc od arkusza do zwykłych programów – wprowadzamy pojęcie zmiennej (zastępujące komórkę arkusza).&lt;br /&gt;
* Programowanie nie jest trudne! Programy pisze każdy użytkownik arkusza kalkulacyjnego (a nawet gdy tylko układa w myśli plan działania)! Trudne natomiast może być układanie algorytmów (czym zajmuje się algorytmika).&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=141</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=141"/>
		<updated>2022-09-25T08:58:51Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe &amp;lt;ref&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/ &amp;lt;/ref&amp;gt;), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
[[Plik:Równania liniowe.png|ramka|alt=Przykład 1|Przykład 1]]&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz  https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html ):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości&lt;br /&gt;
&lt;br /&gt;
mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: http://smurf.mimuw.edu.pl/node/1121 &amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039; http://smurf.mimuw.edu.pl/node/1122 &#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*4 + x2*2 - x3 = 250&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*3 + x2*6 - x4 = 300&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*12 + x2*15 → max&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1, x2, x3, x4 &amp;gt;= 0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
[[Plik:Simplex - ilość.png|mały]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
------&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
[[Plik:Simplex - przykład 3.png|ramka]]&lt;br /&gt;
&lt;br /&gt;
rysunek dzięki https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line start=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex_-_ilo%C5%9B%C4%87.png&amp;diff=140</id>
		<title>Plik:Simplex - ilość.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex_-_ilo%C5%9B%C4%87.png&amp;diff=140"/>
		<updated>2022-09-25T08:57:46Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ilość kombinacji&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex_-_przyk%C5%82ad_3.png&amp;diff=139</id>
		<title>Plik:Simplex - przykład 3.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex_-_przyk%C5%82ad_3.png&amp;diff=139"/>
		<updated>2022-09-25T08:55:15Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Przykład 3&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:R%C3%B3wnania_liniowe.png&amp;diff=138</id>
		<title>Plik:Równania liniowe.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:R%C3%B3wnania_liniowe.png&amp;diff=138"/>
		<updated>2022-09-25T08:50:20Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Przykład równań / nierówności liniowych&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Elementy_j%C4%99zykoznawstwa_dla_programist%C3%B3w&amp;diff=135</id>
		<title>Elementy językoznawstwa dla programistów</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Elementy_j%C4%99zykoznawstwa_dla_programist%C3%B3w&amp;diff=135"/>
		<updated>2022-09-25T07:55:08Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{|&lt;br /&gt;
|-&lt;br /&gt;
| |Moduł: Elementy językozawstwa dla programistów &lt;br /&gt;
|-&lt;br /&gt;
| |Poziom: Zaawanowany&lt;br /&gt;
|-&lt;br /&gt;
| |Profil: Dla profesjonalistów&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Każda wypowiedź ma swoją strukturę, którą określamy terminem „[https://pl.wikipedia.org/wiki/Syntaktyka_(językoznawstwo syntaktyka]” lub składnia, oraz swoje znaczenie określane terminem „[https://pl.wikipedia.org/wiki/Semantyka_(językoznawstwo) semantyka]”. Obydwie te dziedziny są przedmiotem zainteresowania informatyki – ale ich znaczenie jest zupełnie różne. Semantyka to przedmiot badania sztucznej inteligencji (komunikacja w języku naturalnym, przetwarzanie wiedzy) oraz filozofii informatyki. Badania syntaktyki zostały natomiast wykorzystywane w rozwoju języków programowania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:j_gr2.png]]&lt;br /&gt;
&lt;br /&gt;
Analizy językoznawców wykazały, że zdania dowolnego języka daje się opisać w postaci reguł budowania złożonych wypowiedzi z prostszych struktur. Proces generacji zdań nazywa się też procesem „wywodu”. &lt;br /&gt;
&lt;br /&gt;
Przykład:&lt;br /&gt;
&lt;br /&gt;
[[Plik:j_gr3.png]]&lt;br /&gt;
&lt;br /&gt;
Powstała struktura ma kształt odwróconego drzewa. Dlatego nazywa się ją „drzewem wywodu”.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Gramatyka struktur frazowych ==&lt;br /&gt;
Językoznawca [https://pl.wikipedia.org/wiki/Noam_Chomsky Noam Chomsky] stworzył teorię zwaną gramatyką generatywną (lub gramatyką struktur frazowych) opisującą ten proces generacji (dla zdań w formie podstawowej). Informatycy podążyli dalej w tym kierunku tworząc sztuczne języki i automaty je analizujące (translatory). Podstawą była formalizacja teorii gramatyk, którą w zarysie przedstawiono poniżej.&lt;br /&gt;
&lt;br /&gt;
Gramatyka składa się z: * zbioru symboli terminalnych T (symboli wchodzących w skład wygenerowanych zdań); &lt;br /&gt;
* zbioru symboli nieterminalnych N (zbiór symboli pomocniczych służących do przeprowadzenia generacji, oznacza się je często przez ujęcie w nawiasy ostre &amp;lt;...&amp;gt; &amp;lt;nowiki&amp;gt;= zob. &amp;lt;/nowiki&amp;gt;[https://pl.wikipedia.org/wiki/Notacja Notacja][https://pl.wikipedia.org/wiki/Notacja_BNF  BNF]); &lt;br /&gt;
* symbolu początkowego S (wyróżniony symbol nieterminalny od którego rozpoczyna się wywód); &lt;br /&gt;
* reguł wywodu pozwalających na zastępowanie symboli nieterminalnych przez ciągi symboli terminalnych i nieterminalnych aż do otrzymania samych symboli terminalnych; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Przykład:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dla zdania na powyższym obrazku można zaproponować gramatykę:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
T = { Jan, Zosia, trzyma, ma, czapka, pióro } &lt;br /&gt;
N = { &amp;lt;zdanie&amp;gt;, &amp;lt;fraza rzeczownika&amp;gt;, &amp;lt;fraza czasownika&amp;gt;, &amp;lt;rzeczownik&amp;gt;, &amp;lt;czasownik&amp;gt; } &lt;br /&gt;
S = &amp;lt;zdanie&amp;gt; &lt;br /&gt;
&lt;br /&gt;
reguły wywodu ( ::= oznacza operację zastępowania): &lt;br /&gt;
&lt;br /&gt;
(1) &amp;lt;zdanie&amp;gt; ::= &amp;lt;fraza rzeczownika&amp;gt;&amp;lt;fraza czasownika&amp;gt; &lt;br /&gt;
(2) &amp;lt;fraza rzeczownika&amp;gt; ::= &amp;lt;rzeczownik&amp;gt; &lt;br /&gt;
(3) &amp;lt;fraza czasownika&amp;gt; ::= &amp;lt;czasownik&amp;gt;&amp;lt;fraza rzeczownika&amp;gt; &lt;br /&gt;
(4) &amp;lt;rzeczownik&amp;gt; ::= Jan | Zosia | czapka | pióro (5) &amp;lt;czasownik&amp;gt; ::= trzyma | ma &lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znak &#039;|&#039; oznacza alternatywę - np. można użyć reguły &#039;&#039;&amp;lt;czasownik&amp;gt; ::= trzyma&#039;&#039; lub &#039;&#039;&amp;lt;czasownik&amp;gt; ::= ma&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Wywód przykładowego zdania ( w nawiasach podano numery użytych reguł ): &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
S &#039;&#039;&#039;-(1)-&amp;gt; &#039;&#039;&#039;&amp;lt;fraza rzeczownika&amp;gt; &amp;lt;fraza czasownika&amp;gt; &#039;&#039;&#039;-(2)-&amp;gt; &#039;&#039;&#039;&amp;lt;rzeczownik&amp;gt;&amp;lt;fraza czasownika&amp;gt; &#039;&#039;&#039;-(4)-&amp;gt; &#039;&#039;&#039;Zosia &amp;lt;fraza czasownika&amp;gt; &#039;&#039;&#039;-(3)-&amp;gt;&#039;&#039;&#039; Zosia &amp;lt;czasownik&amp;gt; &amp;lt;fraza rzeczownika&amp;gt; &#039;&#039;&#039;-(5)-&amp;gt;&#039;&#039;&#039; Zosia ma &amp;lt;fraza rzeczownika&amp;gt; &#039;&#039;&#039;-(2)-&amp;gt;&#039;&#039;&#039; Zosia ma &amp;lt;rzeczownik&amp;gt; &#039;&#039;&#039;-(4)-&amp;gt; &#039;&#039;&#039;Zosia ma pióro &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Powyższy wywód można przedstawić w postaci drzewo wywodu, pokazanego na powyższym rysunku. Przy analizie drzewo wywodu nazywane jest też drzewem rozkładu (w jaki sposób zdanie rozkładamy na jego reprezentację). Drzewo to służy następnie wygenerowaniu kodu programu - wykonywanego przez komputer.&lt;br /&gt;
&lt;br /&gt;
Liście tego drzewa stanowią symbole terminalne. Każde poddrzewo drzewa wywodu nazywa się frazą. Ze względu na typ użytych reguł wywodu, gramatyki dzieli się na: &lt;br /&gt;
* &amp;lt;u&amp;gt;regularne&amp;lt;/u&amp;gt;: wszystkie reguły są w postaci A ::= aB, lub A ::= a, gdzie A, B - oznaczają symbole nieterminalne, a - symbol terminalny; &lt;br /&gt;
* &amp;lt;u&amp;gt;bezkontekstowe&amp;lt;/u&amp;gt;: daje się sprowadzić do zbioru takich reguł, że po lewej stronie każdej reguły wywodu znajduje się pojedynczy symbol nieterminalny (zob. [https://pl.wikipedia.org/wiki/Postać_normalna_Greibach postać normalna Greibach])&amp;lt;nowiki&amp;gt;; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* &amp;lt;u&amp;gt;kontekstowe&amp;lt;/u&amp;gt;: reguły wywodu mogą być dowolnej postaci; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mniej formalnie można powiedzieć, że gramatyka bezkontekstowa to taka, że przy analizie wypowiedzi można na podstawie wczytanych symboli dokładnie ustalić którą regułę wywodu należy zastosować. &lt;br /&gt;
&lt;br /&gt;
Zależnie od gramatyki jaka jest konieczna do wygenerowania zdań języka mówimy o językach regularnych, bezkontekstowych i kontekstowych. &lt;br /&gt;
&lt;br /&gt;
Gramatyki regularne opisują między innymi budowę poszczególnych elementów używanych w językach programowania komputerów (identyfikatory, liczby, słowa kluczowe). Instrukcje języków takich jak Pascal pochodzą z języków bezkontekstowych. W praktyce analiza języków programowania odbywa się dwustopniowo. Najpierw tzw. skaner wydziela z wejściowego łańcucha znaków &#039;tokeny&#039;, czyli wspomniane wcześniej proste elementy znaczeniowe. Później &#039;parser&#039; analizuje ciąg tokenów tworząc z nich instrukcje języka. Skaner jest zazwyczaj automatem implementującym gramatykę regularną.&lt;br /&gt;
&lt;br /&gt;
== Języki regularne. Automaty. ==&lt;br /&gt;
&lt;br /&gt;
Tokeny (liczby, napisy, słowa kluczowe), na które skaner dzieli przetwarzany ciąg znaków mają strukturę, którą można opisać gramatyką języków regularnych. Najbardziej naturalną metodą zapisywania konstrukcji języka regularnego są wyrażenia regularne. Użycie znaku * w tym wyrażeniu oznacza powtórzenie &amp;gt;=0 ilość razy poprzedzającego go symbolu.&lt;br /&gt;
&lt;br /&gt;
Przykład: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;margin:auto;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#e6e6e6;border:0.05;&amp;quot; | wyrażenie&amp;amp;nbsp;&lt;br /&gt;
| style=&amp;quot;background-color:#e6e6e6;border:0.05pt;&amp;quot; | przykłady użycia&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border:0.05pt;&amp;quot; | xy*z&amp;amp;nbsp;&lt;br /&gt;
| style=&amp;quot;border:0.05pt;;&amp;quot; | &amp;amp;nbsp;xyyz, xz, xyyyz&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border:0.05pt;&amp;quot; | (xy)*z*&amp;amp;nbsp;&lt;br /&gt;
| style=&amp;quot;border:0.05pt;&amp;quot; | xyxyzzzz, xyzzzz&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Analizę języków regularnych wygodnie jest opisywać (a niekiedy także implementować) jako działanie automatów skończenie-stanowych. Automat skończenie-stanowy to zbiór stanów połączonych ze sobą przy pomocy etykietowanych symbolami łuków (lub innych połączeń). Wyróżniany jest jeden stan jako stan początkowy i zbiór stanów końcowych. &lt;br /&gt;
&lt;br /&gt;
Zadaniem automatu jest analiza ciągu znaków. Jego działanie polega na przechodzeniu od stanu do stanu począwszy od stanu początkowego. Przejście jest możliwe, o ile analizowany symbol (znak) jest identyczny z definicją (etykietą) przejścia. Po przejściu pobierany jest do analizy następny symbol (znak). Jeśli po przetworzeniu całego ciągu znaków automat znajdzie się w stanie końcowym, ciąg należy do języka regularnego (jest akceptowalny przez automat), a stan końcowy wskazuje na to, co ciąg ten oznacza. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Przykład: &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Plik:j_gr1.png]]&lt;br /&gt;
&lt;br /&gt;
Automat akceptujący ciąg symboli: a, ab*, lub ab*c oznaczenia:* okrąg oznacza stan początkowy &lt;br /&gt;
* prostokąty z okrągłymi rogami (niebieskie) - oznaczają stany końcowe &lt;br /&gt;
* prostokąty(pomarańczowe) - pozostałe stany &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Uzupełnieniem tego niniejszego są programy z repozytorium [https://github.com/galicea/eduprog https://github.com/galicea/eduprog]. W podkatalogu lang można znaleźć program &#039;&#039;&#039;autogram&#039;&#039;&#039;, który tworzy automat na podstawie wyrażeń regularnych. Wywołanie dla powyższego przykładu: &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;autogram -a -i &amp;quot;a(&amp;amp;b&amp;amp;)@&#039;&#039;&#039;c&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W wyniku analizy otrzymujemy tabelkę przejść:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;margin:auto;&amp;quot;&lt;br /&gt;
| style=&amp;quot;background-color:#e6e6e6;border:0.05;&amp;quot; |     | a |  b | c&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:2pt;border:0.05;&amp;quot; | 1   |  2|  0|  0&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:2pt;border:0.05;&amp;quot;| 2   |  0|  2|  3&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:2pt;border:0.05;&amp;quot;| 3   |  0|  0|  0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W wierszach są zawarte stany automatu, a w kolumnach symbole wyrażenia. Kolumny opisują do którego stanu automat przejdzie po wczytaniu symbolu. Na przykład w stanie 2 symbol &#039;&#039;&#039;b &#039;&#039;&#039;powoduje pozostanie w tym samym stanie, a symbol &#039;&#039;&#039;c - &#039;&#039;&#039;przejście do końcowego stanu 3 (gdzie już nic nie można przyjąć).&lt;br /&gt;
&lt;br /&gt;
== Gramatyki bezkontekstowe ==&lt;br /&gt;
&lt;br /&gt;
Aby utworzyć drzewo wywodu dla dowolnego zdania zbudowanego w oparciu o gramatykę należałoby po kolei próbować zastosować wszystkie produkcje (poddrzewa), wracając w razie niepowodzenia do wcześniejszego stadium analizy. Ten sposób analizy (analiza z powrotami) jest jednak bardzo nieefektywny. W praktyce na gramatyki bezkontekstowe nakłada się dodatkowe ograniczenia pozwalające jednoznacznie wskazać którą produkcję należy wybrać na podstawie: * dotychczasowego przebiegu analizy (stanu w którym znajduje się analizator (automat)); &lt;br /&gt;
* k symboli na wejściu (w praktyce prawie zawsze k=1); &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Analiza lewostronna (wywód lewostronny) polega na tym, że czytamy kolejne symbole i na tej podstawie decydujemy jaką regułę zastosować. Potrzebna do tego gramatyka jest określana mianem [https://pl.wikipedia.org/wiki/Parser_LL LL(1)] – dla podkreślenia, że chodzi o 1 symbol z lewej strony drzewa wywodu. Taką gramatykę zastosowano w języku Pascal. Drugą metodą analizy jest analiza prawostronna. Polega ona na tym, że wczytujemy kolejne symbole aż do chwili, gdy skompletujemy wszystkie symbole potrzebne do zastosowania reguły wywodu. Decyduje o tym zawsze ostatni wczytany symbol – czyli symbol z prawej strony drzewa wywodu. Stąd określenie [https://pl.wikipedia.org/wiki/Parser_LR LR(1)]. &lt;br /&gt;
&lt;br /&gt;
== Gramatyki LL(1) ==&lt;br /&gt;
&lt;br /&gt;
Gramatyka LL(1) ma tą własność, że każdą produkcję można zidentyfikować na podstawie pierwszego z lewej symbolu po prawej jej stronie. Gramatyki tego typu są najczęściej stosowane przy &#039;ręcznym&#039; konstruowaniu analizatora. Stosuje się przy tym analizę rekurencyjną. Polega ona na tym, że dla każdej produkcji tworzy się procedurę ją analizującą. Procedury te identyfikują i wywołują odpowiednie procedury dla zanalizowania podfrazy. Dokładny opis tej metody analizy można znaleźć w podręczniku N.Wirtha [2]. &lt;br /&gt;
&lt;br /&gt;
Poniżej prosty przykład kalkulatora wyrażeń w języku Python, który zawiera analizator LL(1). W przykładzie założono, że liczby są dodatnie jednocyfrowe, a dostępne działania to tylko mnożenie i dodawanie. Dzięki temu skaner (next_token) to tylko pobieranie kolejnego znaku (znak dolara oznacza koniec wejścia a wykrzyknik błąd). Proszę zauważyć, że wystarczy zawsze sprawdzić jaki jest kolejny token, by zdecydować o następnym kroku analizy. Ta stosunkowo prosta zasada sprawia, że analizatory LL(1) można zaimplementować ‘ręcznie’ - bez programów wspierających – takich jak [https://pl.wikipedia.org/wiki/Yacc Yacc] czy [https://www.gnu.org/software/bison/ Bison].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
class calculator():&lt;br /&gt;
  source=[]&lt;br /&gt;
  digits = (&#039;0&#039;,&#039;1&#039;,&#039;2&#039;,&#039;3&#039;,&#039;4&#039;,&#039;5&#039;,&#039;6&#039;,&#039;7&#039;,&#039;8&#039;,&#039;9&#039;)&lt;br /&gt;
  result=0&lt;br /&gt;
  token=&#039;!&#039;&lt;br /&gt;
&lt;br /&gt;
  def next_token(self):&lt;br /&gt;
    if len(self.source)==0:&lt;br /&gt;
      self.token=&#039;$&#039;&lt;br /&gt;
    else:&lt;br /&gt;
      self.token=self.source[0]&lt;br /&gt;
      del self.source[0]&lt;br /&gt;
&lt;br /&gt;
  def factor(self): # czynnik&lt;br /&gt;
    self.result=0&lt;br /&gt;
    if self.token==&#039;(&#039;:&lt;br /&gt;
      self.next_token()&lt;br /&gt;
      self.expr()&lt;br /&gt;
      if self.token != &#039;)&#039;:&lt;br /&gt;
        self.token=&#039;!&#039;&lt;br /&gt;
      else:&lt;br /&gt;
        self.next_token()&lt;br /&gt;
    elif self.token in self.digits:&lt;br /&gt;
      self.result=int(self.token)&lt;br /&gt;
      self.next_token()&lt;br /&gt;
&lt;br /&gt;
  def term(self): # skladnik&lt;br /&gt;
    self.factor()&lt;br /&gt;
    mem=self.result&lt;br /&gt;
    while self.token==&#039;*&#039;:&lt;br /&gt;
      self.next_token()&lt;br /&gt;
      self.factor()&lt;br /&gt;
      mem=mem*self.result&lt;br /&gt;
    self.result=mem&lt;br /&gt;
&lt;br /&gt;
  def expr(self):&lt;br /&gt;
    self.result=0&lt;br /&gt;
    self.term()&lt;br /&gt;
    mem=self.result&lt;br /&gt;
    while (self.token==&#039;+&#039;):&lt;br /&gt;
      self.next_token()&lt;br /&gt;
      self.term()&lt;br /&gt;
      mem=mem+self.result&lt;br /&gt;
    self.result=mem&lt;br /&gt;
&lt;br /&gt;
  def calc(self,expression):&lt;br /&gt;
    self.source=list(expression)&lt;br /&gt;
    self.next_token()&lt;br /&gt;
    self.expr()&lt;br /&gt;
    if self.token==&#039;$&#039;:&lt;br /&gt;
      return self.result&lt;br /&gt;
    else:&lt;br /&gt;
      return None&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Przykładowe użycie kalkulatora:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
c=calculator()&lt;br /&gt;
res=c.calc(&#039;4*(2+3)&#039;)&lt;br /&gt;
if res != None:&lt;br /&gt;
  print(res)&lt;br /&gt;
else:&lt;br /&gt;
  print(&#039;error&#039;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gramatyki LR(1) &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
W przeciwieństwie do poprzedniej, tą gramatykę stosuje się najczęściej przy użyciu generatorów przy pomocy których konstruuje się analizator. Pouczającym może być analiza takiego generatora. W repozytorium [https://github.com/galicea/eduprog https://github.com/galicea/eduprog], w podkatalogu lang znajduje się moduł u_makerl1 i program autogram wykorzystujący ten moduł generatora. Oprogramowanie jest napisane w języku Pascal (z polskimi komentarzami). Może więc być łatwiejsze w analizie (zwłaszcza, że poniżej podano szczegółowe objaśnienie algorytmu), niż rozbudowane generatory wspomniane wcześniej. &lt;br /&gt;
&lt;br /&gt;
=== Metoda analizy  ===&lt;br /&gt;
&lt;br /&gt;
Analizator jest automatem ze stosem. Oznacza to, że zawiera on pamięć w postaci stosu do której może dopisywać dane dotyczące aktualnego stanu (wkładanie na stos). Możliwe jest także odczytywanie danych w kolejności odwrotnej do tej w jakiej były zapisywane (zdejmowanie ze stosu). Automat pobiera kolejne symbole, wkłada je na stos i zmienia swój stan. Bieżący stan automatu jest zapisywany na stosie wraz z symbolem. Stan automatu opisuje całą zawartość stosu. Jeśli stan ten wskazuje, że na stosie jest pełna fraza - następuje redukcja. Polega ona na zdjęciu ze stosu symboli składających się na tą frazę i zastąpieniu ich symbolem nieterminalnym będący lewą stroną produkcji dającej taką frazę. &lt;br /&gt;
&lt;br /&gt;
Dzięki pamiętaniu stanu na stosie - po redukcji można ustalić nowy stan automatu. Stan zapisany na wierzchołku stosu opisuje bowiem całą jego zawartość i możemy ustalić jaki stan powstanie po dodaniu nowego symbolu. &lt;br /&gt;
&lt;br /&gt;
Analiza kończy się poprawnie, gdy pojawi się symbol sygnalizujący koniec danych, a na stosie znajduje się symbol początkowy gramatyki. &lt;br /&gt;
&lt;br /&gt;
Gramatyka dla takiej metody analizy musi spełniać jeden warunek: prawe części żadnych dwóch produkcji nie mogą być jednakowe (trzeba wiedzieć w oparciu o którą produkcję dokonać analizy). &lt;br /&gt;
&lt;br /&gt;
Ponieważ w trakcie analizy badamy zawsze jeden - ostatni z prawej symbol wywodu - metoda ta, oraz gramatyka noszą nazwę LR(1). &lt;br /&gt;
&lt;br /&gt;
=== Algorytm tworzenia automatu LR(1) ===&lt;br /&gt;
&lt;br /&gt;
1/ Ułożyć gramatykę LR(1) języka. Ponumerować wszystkie produkcje. &lt;br /&gt;
&lt;br /&gt;
2/ Spisać wszystkie możliwe stany automatu. Jeśli dowolną produkcję można przedstawić w postaci X::=PS, to P jest jednym z możliwych stanów automatu. &lt;br /&gt;
&lt;br /&gt;
3/ Utworzyć funkcję zmiany stanu stosu przy akceptacji tokenów. Rozróżniamy dwa rodzaje operacji: przesunięcie i redukcja. Przesunięcie polega na dodaniu tokenu na stos. Po przesunięciu pobierany jest następny token. Redukcja polega na zdjęciu ze stosu pełnej frazy.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PRZESUNIĘCIE:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
1) Jeśli istnieją stany stosu PQ i Qt, to dla tokenu t istnieje przejście od stanu PQ do stanu Qt; (oznacza to przejście do analizy podfrazy będącej bardziej z prawej strony).&lt;br /&gt;
&lt;br /&gt;
2) Jeśli nie zachodzi przypadek 1 - badamy zamiast t wszystkie symbole z których t można wyprowadzić lewostronnie. Oznacza to że jeśli istnieją stany PQ i z QR, oraz z R można wyprowadzić lewostronnie t, to dla tokenu t istnieje przejście od stanu PQ do stanu t;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REDUKCJA: &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dla każdego stanu stosu PQ szukamy najdłuższego łańcucha Q spełniającego warunki: - istnieje produkcja (reguła gramatyczna) r, dla której Q stanowi prawą stronę; - istnieje stan Pl(r), gdzie l(r) oznacza lewą stronę produkcji r; Redukcja r jest wykonywana w sytuacji, gdy przy stanie PQ pojawi się token, dl którego nie można dokonać przesunięcia.# Utworzyć funkcję przejścia do nowego stanu przy redukcji. Jeśli po dołączeniu do stanu ze szczytu stosu lewej strony produkcji r otrzymamy poprawny stan - jest to stan do którego następuje przejście automatu. Jeśli taki stan nie istnieje - następuje próba zanalizowania nowej frazy. Ustalany jest nowy stan opisujący lewą stronę użytej produkcji.&lt;br /&gt;
&lt;br /&gt;
4/ Zbudować automat działający wg. zasady:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
repeat &lt;br /&gt;
  PobierzNastępnySymbol; &lt;br /&gt;
  if symbol=znacznikKońcaDanych i na stosie znajduje się  symbol początkowy then &lt;br /&gt;
    koniec &lt;br /&gt;
  else if dla danego tokenu, oraz aktualnego stanu stosu &lt;br /&gt;
          istnieje przejście zgodne z funkcja przejścia (pkt. 3) then &lt;br /&gt;
    włóż symbol na stos z zaznaczeniem nowego stanu &lt;br /&gt;
  else if istnieje produkcja której prawa strona jest zawarta aktualnie na stosie then &lt;br /&gt;
    wykonaj redukcję, zmieniając stan na wskazany przez  funkcję przejścia zbudowaną w pkt. 4 &lt;br /&gt;
  else &lt;br /&gt;
    wystapił błąd &lt;br /&gt;
until błąd lub koniec;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Szczegółowy opis gramatyk LR(1) można znaleźć w pracy [1].&lt;br /&gt;
&lt;br /&gt;
== Przykład ==&lt;br /&gt;
&lt;br /&gt;
Programem autogram, który zawiera opisany powyżej generator stworzono automat analizujący proste wyrażenia arytmetyczne:&lt;br /&gt;
&lt;br /&gt;
gramatyka (plik gram.lr1):        &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
gramatyka (plik gram.lr1):        stany: &lt;br /&gt;
1: &amp;lt;Z&amp;gt; ::= &amp;lt;W&amp;gt;                 1 : &amp;lt;W&amp;gt; &lt;br /&gt;
2: &amp;lt;W&amp;gt; ::= &amp;lt;W&amp;gt; + &amp;lt;A&amp;gt;           2 : &amp;lt;W&amp;gt;+ &lt;br /&gt;
3: &amp;lt;W&amp;gt; ::= &amp;lt;W&amp;gt; - &amp;lt;A&amp;gt;           3 : &amp;lt;W&amp;gt;+&amp;lt;A&amp;gt; &lt;br /&gt;
4: &amp;lt;W&amp;gt; ::= &amp;lt;A&amp;gt;                 4 : &amp;lt;W&amp;gt;- &lt;br /&gt;
5: &amp;lt;A&amp;gt; ::= &amp;lt;A&amp;gt; * &amp;lt;A&amp;gt;           5 : &amp;lt;W&amp;gt;-&amp;lt;A&amp;gt; &lt;br /&gt;
6: &amp;lt;A&amp;gt; ::= &amp;lt;A&amp;gt; / &amp;lt;A&amp;gt;           6 : &amp;lt;A&amp;gt; &lt;br /&gt;
7: &amp;lt;A&amp;gt; ::= &amp;lt;B&amp;gt;                 7 : &amp;lt;A&amp;gt;* &lt;br /&gt;
8: &amp;lt;B&amp;gt; ::= + &amp;lt;C&amp;gt;               8 : &amp;lt;A&amp;gt;*&amp;lt;A&amp;gt; &lt;br /&gt;
9: &amp;lt;B&amp;gt; ::= - &amp;lt;C&amp;gt;               9 : &amp;lt;A&amp;gt;/ &lt;br /&gt;
10: &amp;lt;B&amp;gt; ::= &amp;lt;C&amp;gt;               10 : &amp;lt;A&amp;gt;/&amp;lt;A&amp;gt; &lt;br /&gt;
11: &amp;lt;C&amp;gt; ::= ( &amp;lt;W&amp;gt; )           11 : &amp;lt;B&amp;gt; &lt;br /&gt;
                              12 : &amp;lt;C&amp;gt; ::= NUM 12 : +&lt;br /&gt;
                              13 : +&amp;lt;C&amp;gt; &lt;br /&gt;
                              14 : - &lt;br /&gt;
                              15 : -&amp;lt;C&amp;gt; &lt;br /&gt;
                              16 : &amp;lt;C&amp;gt; &lt;br /&gt;
                              17 : ( &lt;br /&gt;
                              18 : (&amp;lt;W&amp;gt; &lt;br /&gt;
                              19 : (&amp;lt;W&amp;gt;) &lt;br /&gt;
                              20 : NUM &lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fragmenty tablic sterujących działaniem automatu:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
analiza: &lt;br /&gt;
      |                 tokeny &lt;br /&gt;
stan: | +     -     *     /     (     NUM     EOIN &lt;br /&gt;
------+-------------------------------------------&lt;br /&gt;
0     | 12   14                 17     20 &lt;br /&gt;
1     |  2    4 &lt;br /&gt;
2     | 12   14                 17     20 &lt;br /&gt;
3     | -2   -2     7     9     -2     -2     -2 &lt;br /&gt;
&lt;br /&gt;
liczbami dodatnimi oznaczono nowe stany przy przesunięciu, a ujemnymi numery produkcji użytych do redukcji. &lt;br /&gt;
        EOI = znacznik końca danych &lt;br /&gt;
nowe stany po dokonaniu redukcji: &lt;br /&gt;
numer     | stan &lt;br /&gt;
produkcji | 1     2     3 ...... 16     17     18 &lt;br /&gt;
----------+--------------------------------------&lt;br /&gt;
2         | 1     1     1         1     18     1 &lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zauważ że generator tworzy pewną nadmiarowość. Wynik jego działania można poprawić usuwając dane dotyczące stanów przez które automat nie powinien przechodzić (na przykład w stanie 3 nie może pojawić się symbol &#039;(&#039;). Ten automat wykonuje działania tak długo jak to jest możliwe, zamiast zatrzymywać się przy pierwszej nieprawidłowości. &lt;br /&gt;
&lt;br /&gt;
Na podstawie tego automatu stworzono moduł kalkulatora KALK_LR1.PAS. Dla porównania analogiczny kalkulator zbudowano w oparciu o gramatykę LL(1): KALK_LL1.PAS&lt;br /&gt;
&lt;br /&gt;
== Bibliografia ==&lt;br /&gt;
&lt;br /&gt;
# W.M. Waite, G. Goos &#039;&#039;&amp;quot;Konstrukcja kompilatorów&amp;quot;&#039;&#039; &lt;br /&gt;
# N. Wirth &#039;&#039;&amp;quot;Algorytmy+struktury danych = programy&amp;quot;. &#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=134</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=134"/>
		<updated>2022-09-25T07:52:11Z</updated>

		<summary type="html">&lt;p&gt;Admin: /* Równania i nierówności liniowe */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe[[Algorytm Simplex#sdfootnote1sym|&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;]]), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz &amp;lt;nowiki&amp;gt;https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html&amp;lt;/nowiki&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz]):&lt;br /&gt;
    S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
  for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
    S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
S = [[-1, 2, 100],[1, -0.5, - 10],]&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości&lt;br /&gt;
&lt;br /&gt;
mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: &amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1122&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*4 + x2*2 - x3 = 250&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*3 + x2*6 - x4 = 300&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*12 + x2*15 → max&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1, x2, x3, x4 &amp;gt;= 0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
r&lt;br /&gt;
&lt;br /&gt;
ysunek dzięki &amp;lt;nowiki&amp;gt;https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=133</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=133"/>
		<updated>2022-09-25T07:48:07Z</updated>

		<summary type="html">&lt;p&gt;Admin: Algorytm Simplex&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe[[Algorytm Simplex#sdfootnote1sym|&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;]]), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz &amp;lt;nowiki&amp;gt;https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html&amp;lt;/nowiki&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
S = [&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, - 10],&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości&lt;br /&gt;
&lt;br /&gt;
mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: &amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1122&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*4 + x2*2 - x3 = 250&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*3 + x2*6 - x4 = 300&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*12 + x2*15 → max&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1, x2, x3, x4 &amp;gt;= 0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Każdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: http://smurf.mimuw.edu.pl/node/1121&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
r&lt;br /&gt;
&lt;br /&gt;
ysunek dzięki &amp;lt;nowiki&amp;gt;https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=132</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=132"/>
		<updated>2022-09-25T07:31:31Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe[[Algorytm Simplex#sdfootnote1sym|&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;]]), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz &amp;lt;nowiki&amp;gt;https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html&amp;lt;/nowiki&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
S = [&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, - 10],&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości&lt;br /&gt;
&lt;br /&gt;
mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: &amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1122&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*4 + x2*2 - x3 = 250&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*3 + x2*6 - x4 = 300&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*12 + x2*15 → max&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1, x2, x3, x4 &amp;gt;= 0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;K&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ażdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
r&lt;br /&gt;
&lt;br /&gt;
ysunek dzięki &amp;lt;nowiki&amp;gt;https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=131</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=131"/>
		<updated>2022-09-25T07:19:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe[[Algorytm Simplex#sdfootnote1sym|&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;]]), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz &amp;lt;nowiki&amp;gt;https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html&amp;lt;/nowiki&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
S = [&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, - 10],&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości&lt;br /&gt;
&lt;br /&gt;
mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: &amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1122&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*4 + x2*2 - x3 = 250&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*3 + x2*6 - x4 = 300&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*12 + x2*15 → max&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1, x2, x3, x4 &amp;gt;= 0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;K&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ażdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
r&lt;br /&gt;
&lt;br /&gt;
ysunek dzięki &amp;lt;nowiki&amp;gt;https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=130</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=130"/>
		<updated>2022-09-25T07:10:37Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe[[Algorytm Simplex#sdfootnote1sym|&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;]]), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz &amp;lt;nowiki&amp;gt;https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html&amp;lt;/nowiki&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
  return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
S = [&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, - 10],&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości&lt;br /&gt;
&lt;br /&gt;
mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: &amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1122&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*4 + x2*2 - x3 = 250&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*3 + x2*6 - x4 = 300&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*12 + x2*15 → max&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1, x2, x3, x4 &amp;gt;= 0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;K&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ażdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
r&lt;br /&gt;
&lt;br /&gt;
ysunek dzięki &amp;lt;nowiki&amp;gt;https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
[[Plik:Simplex2.ods|mały|Tablica simplex w arkuszu kalkulacyjnym]]&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex2.ods&amp;diff=129</id>
		<title>Plik:Simplex2.ods</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Plik:Simplex2.ods&amp;diff=129"/>
		<updated>2022-09-25T07:06:34Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Przykład tablicy Simplex w arkuszu kalkulacyjnym&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=128</id>
		<title>Algorytm Simplex</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytm_Simplex&amp;diff=128"/>
		<updated>2022-09-25T06:56:52Z</updated>

		<summary type="html">&lt;p&gt;Admin: Publikacja artykułu&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; =&lt;br /&gt;
Algorytm Simplex jest fascynujący z wielu względów. Począwszy od jego twórcy (to on jest tym studentem z anegdoty, który rozwiązał bardzo trudny problem, sądząc, że to zadanie domowe[[Algorytm Simplex#sdfootnote1sym|&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;]]), a skończywszy na współczesnych opisach algorytmu. Co w nich jest fascynującego? Zanim przejdziesz dalej – spróbuj znaleźć w internecie jakiś opis i zrozumieć na jego podstawie, jak ten algorytm działa i dlaczego. Wspomniane opis można z grubsza podzielić na dwie grupy: opis „techniczny” wyjaśnia jakie działania wykonać na danych, aby osiągnąć wynik. Opis teoretyczny zaś wyjaśnia proste zasady, które Simplex wykorzystuje w taki sposób, że bez studiowania algebry wyższej nie jesteś w stanie tego pojąć. Ewidentnie brakuje informacji, które pozwoliłyby nie tylko używać algorytmu, albo pisać naukowe dzieła na jego temat, ale po prostu go zrozumieć. Mam nadzieję, że poniższy tekst wypełni ten brak.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Problem programowania liniowego&#039;&#039;&#039; ==&lt;br /&gt;
Mamy zbiór warunków (ograniczeń) określonych przez nierówności liniowe oraz funkcję celu, zdefiniowaną także w postaci równania liniowego. Chcemy znaleźć rozwiązanie spełniające warunki ograniczeń i maksymalizujące (lub minimalizujące) funkcję celu – definiowaną także jako funkcja liniowa.&lt;br /&gt;
&lt;br /&gt;
Na przykład produkujemy kosmetyki p1 i p2, które mają składy (liczone w porcjach):&lt;br /&gt;
&lt;br /&gt;
dla p1: s1*4+s2*3&lt;br /&gt;
&lt;br /&gt;
dla p2: s1*2+s2*3&lt;br /&gt;
&lt;br /&gt;
produkt p1 kosztuje 12 zł, a produkt p2 kosztuje 15zł. Mamy na magazynie 250 porcji składnika s1 i 300 składnika s2.&lt;br /&gt;
&lt;br /&gt;
Powyższe zagadnienie możemy opisać następująco.&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
x1*4 + x2*2 &amp;lt; 250&lt;br /&gt;
&lt;br /&gt;
x1*3 + x2*6 &amp;lt; 300&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
x1*12 + x2*15 → max&lt;br /&gt;
&lt;br /&gt;
przy czym x1 i x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Oczywiście x1 to ilość produktu p1 do wyprodukowania z zapasów magazynowych. Natomiast x2 to ilość produktu p2 do wyprodukowania.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Jest to typowe zagadnienie programowania liniowego.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najpopularniejszym algorytmem rozwiązywania problemów programowania liniowego, jest wymyślony w latach czterdziestych XX wieku przez George&#039;a Dantziga algorytm Simplex.&lt;br /&gt;
&lt;br /&gt;
Stosując algorytm Simplex znaleźć rozwiązanie dla powyższego problemu: x1=50 a x2=25, natomiast zarobek wynosi 975zł. W dalszej części tekstu znajdziesz wyjaśnienie jak to zrobić.&lt;br /&gt;
&lt;br /&gt;
== Równania i nierówności liniowe ==&lt;br /&gt;
W algorytmie Simplex rozwiązywane są układy równań i nierówności liniowych. Zanim przejdziemy do algorytmu Simplex, musimy poznać przynajmniej podstawy tego zagadnienia.&lt;br /&gt;
&lt;br /&gt;
Rozważmy prosty układ równań:&lt;br /&gt;
&lt;br /&gt;
(1) x1=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
0 = 1.5*x2 - 90 | odejmujemy stronami&lt;br /&gt;
&lt;br /&gt;
x2 = 90/1.5 = 60&lt;br /&gt;
&lt;br /&gt;
x1=2*60-100=20&lt;br /&gt;
&lt;br /&gt;
Jeśli zamienimy równania na nierówności – rozwiązaniem będzie trójkąt ograniczony prostymi (zamalowany na niebiesko na powyższym rysunku):&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 - 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;W zagadnieniu programowania liniowgo rozwiązujemy tego typu zbiory nierówności z uwzględnieniem dodatkowo zdefiniowanej &#039;&#039;&#039;funkcji celu&#039;&#039;&#039;, określonej także poprzez równanie liniowe. Nierówności są przy tym interpretowane jako ograniczenia jakie muszą spełniać zmienne występujące w funkcji celu.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Zagadnienie programowania liniowego ma postać standardową, jeśli w ograniczeniach występują wyłącznie równości (=), a wszystkie zmienne przyjmują wartości nie mniejsze niż zero. Zamiana nierówności na równania jest banalnie prosta (wystarczy dodać / odjąć dodatkową zmienną – szczegóły poniżej). Możemy więc poprzestać na rozwiązywaniu równań.&lt;br /&gt;
&lt;br /&gt;
Będziemy przy tym posługiwać się zapisem macierzowym (zobacz &amp;lt;nowiki&amp;gt;https://edu.pjwstk.edu.pl/wyklady/alg/scb/index35.html&amp;lt;/nowiki&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
Ograniczenia:&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
[x]&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
Funkcja celu:&lt;br /&gt;
&lt;br /&gt;
z = f(x) = &amp;lt;[c] * [x]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Gdzie &amp;lt;&amp;gt; oznacza iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
W języku Python macierz będzie listą wierszy (też reprezentowanych przez listy).&lt;br /&gt;
&lt;br /&gt;
Dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [-3,-4]&lt;br /&gt;
&lt;br /&gt;
def z(c,x): # Iloczyn skalarny&lt;br /&gt;
&lt;br /&gt;
return sum([c1*x1 for c1,x1 in zip(c,x)])&lt;br /&gt;
&lt;br /&gt;
Zdefiniujmy przykładową funkcję celu:&lt;br /&gt;
&lt;br /&gt;
z = 3*x1+4*x2 → max&lt;br /&gt;
&lt;br /&gt;
Wartości funkcji celu w poszczególnych wierzchołkach (zob. zamalowany obszar na rysunku) będą wynosić:&lt;br /&gt;
&lt;br /&gt;
x1=20, x2=60 (wyliczone powyżej): z=300&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=20: z=20*4=80&lt;br /&gt;
&lt;br /&gt;
x1=0, x2=50: z=50*4=200&lt;br /&gt;
&lt;br /&gt;
maksymalna wartość funkcji celu występuje więc w punkcie (20,60) i wynosi 300&lt;br /&gt;
&lt;br /&gt;
=== Metoda eliminacji Jordana-Gaussa ===&lt;br /&gt;
Metoda eliminacji Jordana-Gaussa polega na redukcji wszystkich poza jedną niewiadomą każdego wiersza. Operacje wykonujemy na „macierzy uzupełnionej”, w której ostatnia kolumna zawiera wartość równania (wyraz wolny). Przekształcanie polega na mnożeniu wiersza macierzy przez skalar oraz dodawaniu wierszy pomnożonych przez skalar. Takie ‘operacje elementarne’ oczywiście nie zmieniają wartości rozwiązania.&lt;br /&gt;
&lt;br /&gt;
Operacje elementarne:&lt;br /&gt;
&lt;br /&gt;
def mnoz_wiersz(S,wiersz,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz][i]=x*skalar&lt;br /&gt;
&lt;br /&gt;
def dodaj_wiersz(S,wiersz1,wiersz2,skalar):&lt;br /&gt;
&lt;br /&gt;
for i,x in enumerate(S[wiersz2]):&lt;br /&gt;
&lt;br /&gt;
S[wiersz1][i]=S[wiersz1][i]+x*skalar&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
S = [&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, - 10],&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
S=[ [0, 1.5, 90], [1, -0.5, -10]]&lt;br /&gt;
&lt;br /&gt;
Teraz eliminacja elementów &amp;lt;&amp;gt;0 w kolumnie 1:&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
Najpierw podzieliliśmy wiersz 0 przez drugi jego element (by uzyskać w tym elemencie 1), a następnie odjęliśmy od wiersza drugiego wiersz pierwszy pomnożony przez drugi jego element (by uzyskać w nim 0):&lt;br /&gt;
&lt;br /&gt;
S=[ [0.0, 1.0, 60.0], [1.0, 0.0, 20.0] ]&lt;br /&gt;
&lt;br /&gt;
Ostania kolumna zawiera rozwiązanie!&lt;br /&gt;
&lt;br /&gt;
== Postać standardowa problemu ==&lt;br /&gt;
Każde zagadnienie programowania liniowego daje się sprowadzić do postaci standardowej[[Algorytm Simplex#sdfootnote2sym|&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;]]: znaleźć minimum (lub maksimum) funkcji celu z, które równocześnie spełnia zadane ograniczenia (A*x=b).&lt;br /&gt;
&lt;br /&gt;
1. Gdy poszukujemy maksimum a nie minimum funkcji z:&lt;br /&gt;
&lt;br /&gt;
wektor c zastępujemy wektorem −c oraz otrzymaną minimalną wartość funkcji mnożymy przez −1.&lt;br /&gt;
&lt;br /&gt;
2. Nierówność ai1 * x1 + ai2 * x2 + . . . + ain * xn &amp;lt;= bi&lt;br /&gt;
&lt;br /&gt;
można sprowadzić do równania poprzez wprowadzenie dodatkowej zmiennej xn+1:&lt;br /&gt;
&lt;br /&gt;
ai1 * x1 + ai2 * x2 + . . . + ain * xn + xn+1 = bi&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku, gdy w miejsce znaku mniejszości&lt;br /&gt;
&lt;br /&gt;
mamy znak większości. Musimy wprowadzić tyle dodatkowych zmiennych, ile mamy nierówności!&lt;br /&gt;
&lt;br /&gt;
Zmienne te nazywamy „zmiennymi luzu”, albo „swobodnymi” (ile dzieli wynik od ekstremum).&lt;br /&gt;
&lt;br /&gt;
3. Gdy zmienne x nie spełniają ograniczenia (xi&amp;gt;0), korzystamy z faktu, że każda liczba rzeczywista może być przedstawiona jako różnica liczb nieujemnych. Wprowadzamy nowe zmienne xi’ i xi’’ i zamieniamy wystąpienia xi na różnicę xi’-xi’’.&lt;br /&gt;
&lt;br /&gt;
4. Gdy zmienna xi musi być większa od pewnej wartości di:&lt;br /&gt;
&lt;br /&gt;
xi ≥ di&lt;br /&gt;
&lt;br /&gt;
- wprowadzamy zmienną xi’, taką, że xi′ = xi − di&lt;br /&gt;
&lt;br /&gt;
Podobnie w przypadku mniejszości (w miejsce większości): xi′ = di − xi&lt;br /&gt;
&lt;br /&gt;
5. Dla ujednolicenia przyjmujemy, że mamy do czynienia wyłącznie z mniejszością nieostrą (&amp;lt;=). Gdy wśród warunków jest użyty znak większości – zamieniamy go na mniejszość mnożąc obie strony przez -1&lt;br /&gt;
&lt;br /&gt;
6. Gdy mamy warunek równości – zamieniamy go na dwa warunki nierówności nieostrej (dotyczy to także =0).&lt;br /&gt;
&lt;br /&gt;
Przedstawmy zagadnienie z wcześniej rozważanego przykładu w postaci wektorowej:&lt;br /&gt;
&lt;br /&gt;
(1) x1&amp;gt;=2*x2 – 100 == -x1+2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 &amp;lt;= 100&lt;br /&gt;
&lt;br /&gt;
(2) x1&amp;lt;=0.5*x2 – 10 == x1 - 0.5*x2 &amp;lt;= - 10 == 1*x1 - 0.5*x2 = - 10&lt;br /&gt;
&lt;br /&gt;
A*[x] = [b]&lt;br /&gt;
&lt;br /&gt;
z = &amp;lt;c * x&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [ [-1,2], [1,-0.5], ]&lt;br /&gt;
&lt;br /&gt;
b = [100, -10]&lt;br /&gt;
&lt;br /&gt;
c = [3,4]&lt;br /&gt;
&lt;br /&gt;
W postaci standardowej:&lt;br /&gt;
&lt;br /&gt;
(1) -1*x1 + 2*x2 &amp;lt;= 100 == -1*x1 + 2*x2 + 1 * x3 = 100&lt;br /&gt;
&lt;br /&gt;
(2) 1*x1 - 0.5*x2 = - 10 == 1*x1 - 0.5*x2 + 1 * x4 = - 10&lt;br /&gt;
&lt;br /&gt;
czyli:&lt;br /&gt;
&lt;br /&gt;
-1*x1 + 2*x2 + 1*x3 + 0*x4= 100&lt;br /&gt;
&lt;br /&gt;
1*x1 - 0.5*x2 + 0*x3 + 1*x4 = - 10&lt;br /&gt;
&lt;br /&gt;
x1&amp;gt;=0, x2&amp;gt;=0,x3&amp;gt;=0&amp;gt;,x4&amp;gt;=0&lt;br /&gt;
&lt;br /&gt;
z = x1+x2 →max&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0],&lt;br /&gt;
&lt;br /&gt;
[1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4]&lt;br /&gt;
&lt;br /&gt;
Możemy przejrzeć wszystkie wierzchołki i (jak poprzednio) znaleźć rozwiązanie dla (x1=20,x2=60,x3=0,x4=0)&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Podstawy&#039;&#039;&#039; ==&lt;br /&gt;
Aby zrozumieć algorytm Simplex, rozwiązujący zagadnienia programowania liniowego – musimy wprowadzić kilka prostych definicji i spostrzeżeń (lematów). &#039;&#039;&#039;Wiele z opisów i implementacji algorytmu simplex – jest trudnych do zrozumienia, gdyż brakuje takich prostych objaśnień. Albo też – wręcz przeciwnie – objaśnienia są obszerne i z wykorzystaniem bardziej ogólnych definicji matematycznych (formalnie wprowadzone zbiory wypukłe i ekstrema).&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(1). Podzbiór zdefiniowany przez ograniczenia nazywamy dopuszczalnym. Każdy element tego zbioru nazywa się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
(2). Rozwiązanie dopuszczalne x, dla którego funkcja celu f(x) osiąga minimum (maksimum) nazywamy rozwiązaniem optymalnym.&lt;br /&gt;
&lt;br /&gt;
(3). Ograniczenia definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”.&lt;br /&gt;
&lt;br /&gt;
(4). W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń (zapisanych w postaci równań). Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi.&lt;br /&gt;
&lt;br /&gt;
(5). Dwa wierzchołki są sąsiadami, jeśli różnią się wartością jednej zmiennej. Taka zmienna może służyć do poszukiwania lepszych rozwiązań (posuwając się od wierzchołka do jego sąsiada poprzez zmianę wartości tej zmiennej). Wtedy nazywamy ją „uwolnioną”.&lt;br /&gt;
&lt;br /&gt;
(6). Jeśli funkcja celu osiąga minimum (lub maksimum), to musi ona osiągać to ekstremum w wierzchołku wielościanu. Ponieważ funkcja celu jest zależnością liniową, mając dowolne rozwiązanie poza wierzchołkiem – możemy odpowiednio zwiększać lub zmniejszać wartość zmiennych, powodując zmianę wartości funkcji celu na bardziej zbliżoną do optymalnej. Takiej możliwości nie ma tylko w wierzchołku.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Bardziej ścisłe wprowadzenie tych pojęć: &amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Algorytm opisany przez tego samego autora: &#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1122&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Idea rozwiązania&#039;&#039;&#039; ==&lt;br /&gt;
Algorytm simplex w największym skrócie: zamiast przeglądać wszystkie wierzchołki wielościanu, wybierz jeden i posuwaj się wzdłuż krawędzi do sąsiadów – póki możesz poprawić w ten sposób wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Nierówności możemy zamienić na równania – odpowiednio dodając (&amp;lt;) lub odejmując (&amp;gt;) dodatkową („sztuczną”) zmienną. Taki zbiór równań jest liniowo niezależny (żadne z nich nie wynika z pozostałych). Na naszym przykładzie:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*4 + x2*2 - x3 = 250&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*3 + x2*6 - x4 = 300&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1*12 + x2*15 → max&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x1, x2, x3, x4 &amp;gt;= 0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
2. Ten układ równań ma trywialne rozwiązanie przy założeniu, że x1=x2=0. Otrzymamy dokładnie jedno rozwiązanie: x3=-250 i x4=-300. Zgodnie z definicją takie rozwiązanie będzie wierzchołkiem wielościanu wielowymiarowego zdefiniowanego przez równania liniowe ograniczeń. Zmienne niezerowe nazwiemy bazą, a ich zbiór – zbiorem bazowym.&lt;br /&gt;
&lt;br /&gt;
3. Algorytm Simplex polega na przeglądaniu sąsiednich wierzchołków wielościanu ograniczeń w poszukiwaniu rozwiązania lepszego (dającego lepszy wynik funkcji celu). Gdy taki znajdziemy – dokonujemy przesunięcia do następnego wierzchołka i znów przeszukujemy sąsiednie.&lt;br /&gt;
&lt;br /&gt;
Ten skrótowy opis zostanie uzupełniony i wyjaśniony poniżej.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Algorytm Simplex&#039;&#039;&#039; ==&lt;br /&gt;
Istnieje kilka wariantów algorytmu Simplex. W tym tekście opiszemy najczęściej spotykany – oparty o rozwiązania bazowe, z wykorzystaniem zmiennych luzu (swobodnych).&lt;br /&gt;
&lt;br /&gt;
Jeśli mamy:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A&#039;&#039;&#039; - macierz ograniczeń o wymiarach (&#039;&#039;&#039;m&#039;&#039;&#039;,&#039;&#039;&#039;n&#039;&#039;&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;b&#039;&#039;&#039; – wektor wyrazów wolnych o wymiarze &#039;&#039;&#039;m&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;c&#039;&#039;&#039; – wektor definiujący funkcję celu o wymiarze &#039;&#039;&#039;n&#039;&#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;x&#039;&#039;&#039; – wektor &#039;&#039;&#039;n&#039;&#039;&#039; zmiennych decyzyjnych (rozszerzony o zmienne swobodne/luzu), przyjmujących wartości nieujemne.&lt;br /&gt;
&lt;br /&gt;
Bazą nazywamy macierz (oznaczaną jako &#039;&#039;&#039;B&#039;&#039;&#039;) składającą się &#039;&#039;&#039;m&#039;&#039;&#039; liniowo niezależnych kolumn macierzy &#039;&#039;&#039;A&#039;&#039;&#039;. Kolumny wchodzące w skład B nazywamy kolumnami bazowymi (pozostałe kolumny macierzy &#039;&#039;&#039;A&#039;&#039;&#039; nazywa się kolumnami niebazowymi). Zmienne związane z kolumnami bazowymi nazywamy zmiennymi bazowymi zaś nazywamy pozostałe niebazowymi. Rozwiązanie bazowe uzyskujemy, ustawiając wartość 0 (zero) dla wszystkich zmiennych niebazowych.&lt;br /&gt;
&lt;br /&gt;
Jeżeli układ równań Ax&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt;=b&amp;lt;sup&amp;gt;T&amp;lt;/sup&amp;gt; posiada rozwiązania oraz (n&amp;gt;m), to posiada skończoną liczbę rozwiązań bazowych – jest ich co najwyżej:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;K&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ażdemu rozwiązaniu bazowemu odpowiada wierzchołek wielokąta ograniczeń&#039;&#039;&#039;. Dowód znajdziesz na stronie: &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;http://smurf.mimuw.edu.pl/node/1121&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Przeglądanie wierzchołków wielomianu sprowadza się więc do zmiany rozwiązania bazowego poprzez „wymianę” zmiennych bazowych. Jedna zmienna wchodzi do bazy, a inna z niej wychodzi. Taka wymiana następuje wyłącznie wtedy, gdy dzięki niej udaje się zwiększyć wartość funkcji celu.&lt;br /&gt;
&lt;br /&gt;
Pierwsze rozwiązanie bazowe możemy znaleźć dzięki wykorzystaniu „zmiennych swobodnych” (luzu). Zakładamy, że tylko one będą różne od zera. Ponieważ w każdym ograniczeniu mamy inną zmienną swobodną (odpowiedni współczynnik a[i]==1) – przy wyzerowaniu pozostałych zmiennych, przyjmą one odpowiednie wartości z &#039;&#039;&#039;b.&#039;&#039;&#039; W naszym przykładzie:&lt;br /&gt;
&lt;br /&gt;
A=[ [-1,2,1,0], [1,-0.5,0,1]]&lt;br /&gt;
&lt;br /&gt;
b=[100,-10]&lt;br /&gt;
&lt;br /&gt;
c=[3,4,0,0]&lt;br /&gt;
&lt;br /&gt;
Mamy zatem&lt;br /&gt;
&lt;br /&gt;
x1=x2=0&lt;br /&gt;
&lt;br /&gt;
x3 = 100&lt;br /&gt;
&lt;br /&gt;
x4=-10&lt;br /&gt;
&lt;br /&gt;
z=0&lt;br /&gt;
&lt;br /&gt;
Zauważmy, że dzięki wykorzystaniu zmiennych swobodnych, punkt zerowy w pierwotnym układzie współrzędnych (x1,x2) stał się rozwiązaniem dopuszczalnym.&lt;br /&gt;
&lt;br /&gt;
Jeśli początek układu współrzędnych jest rozwiązaniem dopuszczalnym, to jest także rozwiązaniem optymalnym wtedy i tylko wtedy, gdy wszystkie elementy [c] są ujemne (przy założeniu, że funkcja celu ma być maksymalizowana). Uzasadnienie jest proste: jeśli jakiś element [c] (c[i]) jest większy od zera, to możemy zwiększyć wartość funkcji celu, zwiększając odpowiednią zmienną x[i].&lt;br /&gt;
&lt;br /&gt;
Ponieważ algorytm z wykorzystaniem rozwiązania bazowego jest równoważny z algorytmem „geometrycznym” – ta reguła nadal obowiązuje. W przekształceniach dążymy do tego, by wszystkie elementy c były nieujemne.&lt;br /&gt;
&lt;br /&gt;
Do przekształceń wykorzystujemy metodę eliminacji Jordana-Gaussa. W tym celu tworzy się tablicę Simplex – dodając do &#039;&#039;&#039;A&#039;&#039;&#039; kolumnę &#039;&#039;&#039;b&#039;&#039;&#039; oraz wiersz &#039;&#039;&#039;c&#039;&#039;&#039; (uzupełniony zerem do rozmiaru n+1).&lt;br /&gt;
&lt;br /&gt;
Tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
A | b&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
c | 0&lt;br /&gt;
&lt;br /&gt;
W naszym przykładzie pierwsze rozwiązanie bazowe byłoby optymalne, gdyby lista &#039;&#039;&#039;c&#039;&#039;&#039; zawierała tylko ujemne elementy. Tak oczywiście nie jest (mamy [3,4]). Wybieramy kolumnę i o największej wartości dodatniej (max(&#039;&#039;&#039;c[i]&#039;&#039;&#039;) i wprowadzamy ją do bazy – eliminując współczynniki w tej kolumnie (sprowadzone do zera) – poza jednym – przy nowej zmiennej bazowej.&lt;br /&gt;
&lt;br /&gt;
W wyniku przekształcenia jedna ze zmiennych bazowych x[j] zostanie usunięta z bazy (współczynnik c[j] zostanie wyzerowany, a inna x[i] znajdzie się w bazie (współczynnik a[i] otrzyma wartość 1).&lt;br /&gt;
&lt;br /&gt;
Taką transformację możemy wykonać w następujący sposób:&lt;br /&gt;
&lt;br /&gt;
1) dzielimy wybrany wiersz &#039;&#039;&#039;w&#039;&#039;&#039; przez wartość komórki tego wiersza z wybranej kolumny (&#039;&#039;&#039;i)&#039;&#039;&#039; (A[w][i]) – w ten sposób współczynnik a[i] otrzyma wartość 1);&lt;br /&gt;
&lt;br /&gt;
2) odejmujemy ten wiersz od pozostałych po pomnożeniu przez wartość komórki wybranej kolumny zmienianego wiersza (dla wiersza &#039;&#039;&#039;u&#039;&#039;&#039; będzie to A[u][i]).&lt;br /&gt;
&lt;br /&gt;
Ten sposób przekształcenia gwarantuje, że wcześniej wybrane do bazy kolumny nie zostaną zaburzone – chyba, że zawierają 1 w wybranym aktualnie wierszu.&lt;br /&gt;
&lt;br /&gt;
Przekształcamy w ten sposób tablicę simplex tak długo, aż wszystkie elementy c[i] będą nie większe od zera, albo nie uda się znaleźć wierzchołka dającego wzrost funkcji celu (wtedy przyjmujemy, że zadanie nie ma rozwiązania).&lt;br /&gt;
&lt;br /&gt;
Na naszym przykładzie (ostatni wiersz zawiera funkcję celu):&lt;br /&gt;
&lt;br /&gt;
S=[&lt;br /&gt;
&lt;br /&gt;
[-1, 2, 1, 0, 100],&lt;br /&gt;
&lt;br /&gt;
[1, -0.5, 0, 1, - 10],&lt;br /&gt;
&lt;br /&gt;
[-3,-4,0,0,0]&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
Redukcję tabeli przedstawimy wykorzystując napisany powyżej program eliminacji Jordana-Gaussa:&lt;br /&gt;
&lt;br /&gt;
1. W kolumnie 0 mamy wartość już 1 w wierszu 1 (nie musimy wykonywać działania 1)). Pozostałe elementy redukujemy do zera dodając wiersz :&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
2. W kolumnie 1 sprowadzamy do 1 element wiersza 0, dzieląc go przez jego wartość (S[0][1]=1.5).&lt;br /&gt;
&lt;br /&gt;
Podobnie jak poprzednio odejmujemy wiersz zerowy od pozostałych, mnożąc go przez element eliminowany (z kolumny 1):&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
Wynik naszych działań:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ostatnia kolumna zawiera wynik – wartości zmiennych x oraz funkcji celu:&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.67, 0.67, 60.00&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.33, 1.33, 20.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, -3.67, -6.67, -300.00&lt;br /&gt;
&lt;br /&gt;
Trzeba jeszcze ustalić sposób wyboru wiersza i kolumny do wprowadzenia do bazy. Zgodnie z tak zwaną „regułą Blanda” (&amp;lt;nowiki&amp;gt;https://www.mimuw.edu.pl/~oskar/lecture_13.pdf&amp;lt;/nowiki&amp;gt;), można przyjąć, przy wyborze kolumny wybieramy pierwszą z lewej o dodatnim współczynniku c, a następnie wiersz, dla którego najmniejszy jest iloraz wyrazu wolnego (b[i]) przez element z wybranej kolumny (dla kolumny k będzie to najmniejsza spośród b[i]/a[k][i] (oczywiście pod warunkiem, że mianownik jest dodatni).&lt;br /&gt;
&lt;br /&gt;
Rozważmy inny przykład:&lt;br /&gt;
&lt;br /&gt;
2x1-x2&amp;lt;=4&lt;br /&gt;
&lt;br /&gt;
x1+2x2&amp;lt;=9&lt;br /&gt;
&lt;br /&gt;
-x1+x2&amp;lt;=3&lt;br /&gt;
&lt;br /&gt;
z=2x1+5x2→max&lt;br /&gt;
&lt;br /&gt;
r&lt;br /&gt;
&lt;br /&gt;
ysunek dzięki &amp;lt;nowiki&amp;gt;https://www.matemaks.pl/program-do-rysowania-wykresow-funkcji.html&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2],[-1,1]]&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2,5]&lt;br /&gt;
&lt;br /&gt;
S = [[2, -1,1,0,0,4], [1, 2,0,1,0,9],[-1,1,0,0,1,3],[2,5,0,0,0,0]]&lt;br /&gt;
&lt;br /&gt;
print(&#039;tablica Simplex:&#039;)&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 0 kolumna 0:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,0,1/S[0][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,1,0,-S[1][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,0,-S[2][0])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,0,-S[3][0])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 1 kolumna 1:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S,1,1/S[1][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,0,1,-S[0][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,2,1,-S[2][1])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S,3,1,-S[3][1])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
print(&#039;wybrany wiersz 2 kolumna 2:&#039;)&lt;br /&gt;
&lt;br /&gt;
mnoz_wiersz(S, 2, 1/S[2][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 0, 2, -S[0][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 1, 2, -S[1][2])&lt;br /&gt;
&lt;br /&gt;
dodaj_wiersz(S, 3, 2, -S[3][2])&lt;br /&gt;
&lt;br /&gt;
druk_tabeli(S)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie:&lt;br /&gt;
&lt;br /&gt;
tablica Simplex:&lt;br /&gt;
&lt;br /&gt;
2.00, -1.00, 1.00, 0.00, 0.00, 4.00&lt;br /&gt;
&lt;br /&gt;
1.00, 2.00, 0.00, 1.00, 0.00, 9.00&lt;br /&gt;
&lt;br /&gt;
-1.00, 1.00, 0.00, 0.00, 1.00, 3.00&lt;br /&gt;
&lt;br /&gt;
2.00, 5.00, 0.00, 0.00, 0.00, 0.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 0 kolumna 0:&lt;br /&gt;
&lt;br /&gt;
1.00, -0.50, 0.50, 0.00, 0.00, 2.00&lt;br /&gt;
&lt;br /&gt;
0.00, 2.50, -0.50, 1.00, 0.00, 7.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.50, 0.50, 0.00, 1.00, 5.00&lt;br /&gt;
&lt;br /&gt;
0.00, 6.00, -1.00, 0.00, 0.00, -4.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 1 kolumna 1:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.40, 0.20, 0.00, 3.40&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, -0.20, 0.40, 0.00, 2.80&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.60, -0.20, 1.00, 3.60&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.20, -2.40, 0.00, -20.80&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
wybrany wiersz 2 kolumna 2:&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
x1=1,x2=4&lt;br /&gt;
&lt;br /&gt;
z = 22&lt;br /&gt;
&lt;br /&gt;
Ten sam problem można rozwiązać przy pomocy arkusza Excel:&lt;br /&gt;
&lt;br /&gt;
== Implementacja ==&lt;br /&gt;
Istnieje wiele opisów algorytmu i jego implementacji. Na przykład zwięzła implementacja w Pythonie: &amp;lt;nowiki&amp;gt;https://github.com/j2kun/&amp;lt;/nowiki&amp;gt; opisana w tekście: &amp;lt;nowiki&amp;gt;https://jeremykun.com/2014/12/01/linear-programming-and-the-simplex-algorithm/&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
W jego analizie przyda się słowniczek:&lt;br /&gt;
&lt;br /&gt;
Zmienne decyzyjne - decision variables&lt;br /&gt;
&lt;br /&gt;
Funkcja celu - objective function&lt;br /&gt;
&lt;br /&gt;
Ograniczenia - constraints&lt;br /&gt;
&lt;br /&gt;
Zmienne agraniczeń - variable bounds&lt;br /&gt;
&lt;br /&gt;
zmienne swobodne (zmienna swobodna, zmienna luzu) - slack variables&lt;br /&gt;
&lt;br /&gt;
sąsiad – neighbor&lt;br /&gt;
&lt;br /&gt;
iloczyn skalarny - dot product&lt;br /&gt;
&lt;br /&gt;
analiza wrażliwości (sensitivity analysis)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie (solution)&lt;br /&gt;
&lt;br /&gt;
rozwiązanie wierzchołkowe (cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
dopuszczalne rozwiązanie wierzchołkowe (feasible cornerpoint solution)&lt;br /&gt;
&lt;br /&gt;
sąsiadujące rozwiązania wierzchołkowe (adjacent cornerpoint solutions)&lt;br /&gt;
&lt;br /&gt;
stopnie swobody (degrees of freedom, df)&lt;br /&gt;
&lt;br /&gt;
test minimalnej proporcji (minimum ratio test)&lt;br /&gt;
&lt;br /&gt;
Główna procedura simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
# Utwórz tabelę Simplex.&lt;br /&gt;
# Znajdź dodatni indeks ostatniego wiersza i zwiększ odpowiednią zmienną (dodając ją do bazy) na tyle, aby inna zmienna znalazła się w bazie zerowej (usuwając ją z bazy).&lt;br /&gt;
# Powtarzaj krok 2, aż ostatni wiersz będzie niedodatni.&lt;br /&gt;
# Wypisz ostatnią kolumnę.&lt;br /&gt;
&lt;br /&gt;
def simplex(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = initialTableau(c, A, b)&lt;br /&gt;
&lt;br /&gt;
while canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
pivot = findPivotIndex(tableau)&lt;br /&gt;
&lt;br /&gt;
pivotAbout(tableau, pivot)&lt;br /&gt;
&lt;br /&gt;
return tableau, objectiveValue(tableau)&lt;br /&gt;
&lt;br /&gt;
Funkcja  &amp;lt;code&amp;gt;initialTableau&amp;lt;/code&amp;gt; tylko tworzy tabelę Simplex. Dodaje do wierszy A odpowiedni wyraz wolny z b. W ostatnim wierszu wstawia wektor c uzupełniony zerem.&lt;br /&gt;
&lt;br /&gt;
def initialTableau(c, A, b):&lt;br /&gt;
&lt;br /&gt;
tableau = [row[:] + [x] for row, x in zip(A, b)]&lt;br /&gt;
&lt;br /&gt;
tableau.append([ci for ci in c] + [0])&lt;br /&gt;
&lt;br /&gt;
return tableau&lt;br /&gt;
&lt;br /&gt;
Funkcja &amp;lt;code&amp;gt;canImprove()&amp;lt;/code&amp;gt; sprawdza, czy w ostatnim wierszu znajduje się nieujemny wpis:&lt;br /&gt;
&lt;br /&gt;
def canImprove(tableau):&lt;br /&gt;
&lt;br /&gt;
lastRow = tableau[-1]&lt;br /&gt;
&lt;br /&gt;
return any(x &amp;gt; 0 for x in lastRow[:-1])&lt;br /&gt;
&lt;br /&gt;
Funkcja findPivotIndex() szuka dodatniego elementu w ostatnim wierszu (zawierającym c), a następnie wiersza w wybranej kolumnie o minimalnym ilorazie:&lt;br /&gt;
&lt;br /&gt;
def findPivotIndex(tableau):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór elementu ostatniego wiersza, dla którego x&amp;gt;0&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
column_choices = [(i,x) for (i,x) in enumerate(tableau[-1][:-1]) if x &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
column = min(column_choices, key=lambda a: a[1])[0]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie, czy rozwiązanie nie ograniczone (unbounded)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
if all(row[column] &amp;lt;= 0 for row in tableau):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is unbounded.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# sprawdzenie braku zdegenerowania: więcej niż jeden minimalny iloraz&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
quotients = [(i, r[-1] / r[column])&lt;br /&gt;
&lt;br /&gt;
for i,r in enumerate(tableau[:-1]) if r[column] &amp;gt; 0]&lt;br /&gt;
&lt;br /&gt;
if moreThanOneMin(quotients):&lt;br /&gt;
&lt;br /&gt;
raise Exception(&#039;Linear program is degenerate.&#039;)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# wybór indeksu wiersza o minimalnym ilorazie&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
row = min(quotients, key=lambda x: x[1])[0]&lt;br /&gt;
&lt;br /&gt;
return row, column&lt;br /&gt;
&lt;br /&gt;
Funkcja dla pierwszej tabeli zwraca parę (row=1, column=0).&lt;br /&gt;
&lt;br /&gt;
Następnie dokonywana jest zamiana – przy użyciu funkcji pivotAbout. Jej implementacja:&lt;br /&gt;
&lt;br /&gt;
def pivotAbout(tableau, pivot):&lt;br /&gt;
&lt;br /&gt;
i,j = pivot&lt;br /&gt;
&lt;br /&gt;
pivotDenom = tableau[i][j]&lt;br /&gt;
&lt;br /&gt;
tableau[i] = [x / pivotDenom for x in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
for k,row in enumerate(tableau):&lt;br /&gt;
&lt;br /&gt;
if k != i:&lt;br /&gt;
&lt;br /&gt;
pivotRowMultiple = [y * tableau[k][j] for y in tableau[i]]&lt;br /&gt;
&lt;br /&gt;
tableau[k] = [x - y for x,y in zip(tableau[k], pivotRowMultiple)]&lt;br /&gt;
&lt;br /&gt;
Główny program dla naszego przykładu:&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
b = [4, 9, 3]&lt;br /&gt;
&lt;br /&gt;
c = [2, 5]&lt;br /&gt;
&lt;br /&gt;
A = [[2, -1], [1, 2], [-1, 1]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;# add slack variables by hand&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A[0] += [1, 0, 0]&lt;br /&gt;
&lt;br /&gt;
A[1] += [0, 1, 0]&lt;br /&gt;
&lt;br /&gt;
A[2] += [0, 0, 1]&lt;br /&gt;
&lt;br /&gt;
c += [0, 0, 0]&lt;br /&gt;
&lt;br /&gt;
t, v = simplex(c, A, b)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wynik:&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;tabela simplex=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for w in t:&lt;br /&gt;
&lt;br /&gt;
print(&#039;, &#039;.join(&#039;{:0.2f}&#039;.format(x) for x in w))&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;wartość funkcji celu=&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(v)&lt;br /&gt;
&lt;br /&gt;
Wynik:&lt;br /&gt;
&lt;br /&gt;
tabela simplex=&lt;br /&gt;
&lt;br /&gt;
1.00, 0.00, 0.00, 0.33, -0.67, 1.00&lt;br /&gt;
&lt;br /&gt;
0.00, 1.00, 0.00, 0.33, 0.33, 4.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 1.00, -0.33, 1.67, 6.00&lt;br /&gt;
&lt;br /&gt;
0.00, 0.00, 0.00, -2.33, -0.33, -22.00&lt;br /&gt;
&lt;br /&gt;
wartość funkcji celu=&lt;br /&gt;
&lt;br /&gt;
22.0&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote1anc|1]]&amp;lt;nowiki&amp;gt;https://www.snopes.com/fact-check/the-unsolvable-math-problem/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Algorytm Simplex#sdfootnote2anc|2]]Justyna Kosakowska i Piotr Malicki, „Badania operacyjne - programowanie liniowe”&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Algorytmy&amp;diff=127</id>
		<title>Algorytmy</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Algorytmy&amp;diff=127"/>
		<updated>2022-09-25T06:49:36Z</updated>

		<summary type="html">&lt;p&gt;Admin: Utworzono nową stronę &amp;quot;* Algorytm Simplex&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[Algorytm Simplex]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=126</id>
		<title>Podstawy informatyki</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=126"/>
		<updated>2022-09-25T06:48:55Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;PODSTAWY INFORMATYKI&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Część I: Podstawowe pojęcia ==&lt;br /&gt;
* Moduł 1.1 [[Algorytm – program – system]]&lt;br /&gt;
* Moduł 1.2 [[Uczymy się myśleć abstrakcyjnie]]&lt;br /&gt;
* Moduł 1.3 [[Filozoficznie o programach komputerowych]] (dla humanistów i pasjonatów)&lt;br /&gt;
* Moduł 1.4 [[Procesor i język maszynowy - wprowadzenie]] (dla inżynierów i techników)&lt;br /&gt;
* Moduł 1.5 [[Logika i instrukcje warunkowe]]&lt;br /&gt;
&lt;br /&gt;
== Część II: Algorytmika ==&lt;br /&gt;
* Moduł 2.1 [[Programy a algorytmy]]&lt;br /&gt;
* Moduł 2.2 [[Implementacja algorytmów]]&lt;br /&gt;
* Moduł 2.3 [[Elementy językoznawstwa dla programistów]] (poziom zaawansowany)&lt;br /&gt;
* Moduł 2.4 [[Algorytmy]] (wybrane / najważniejsze algorytmy)&lt;br /&gt;
&lt;br /&gt;
== Część III: Podstawy programowania ==&lt;br /&gt;
* Moduł 3.1. [[Różnorodność struktur programów]]&lt;br /&gt;
&lt;br /&gt;
== Część IV: Matematyka obiektowa ==&lt;br /&gt;
* Moduł 4.1 [[Matematyka obiektowa]]&lt;br /&gt;
&lt;br /&gt;
== Ważne strony ==&lt;br /&gt;
* [//leanpub.com/pyprog leanpub.com/pyprog] - Podręcznik programowania w Pythonie&lt;br /&gt;
* [//elearning.otwartaedukacja.pl/ elearning.otwartaedukacja.pl] - &#039;&#039;&#039;E-learning&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Używane programy edukacyjne ==&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/bl/code/ otwartaedukacja.pl/programowanie/bl/code] - układanie programów z bloczków&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/schematy/ otwartaedukacja.pl/programowanie/schematy] - rysowanie schematów blokowych&lt;br /&gt;
-&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Matematyka_obiektowa&amp;diff=125</id>
		<title>Matematyka obiektowa</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Matematyka_obiektowa&amp;diff=125"/>
		<updated>2022-09-25T06:18:38Z</updated>

		<summary type="html">&lt;p&gt;Admin: Publikacja artykułu&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Często słyszymy, że podstawą informatyki jest matematyka. Tak – ale nie jest to taka matematyka, jaką męczą dzieci w szkole. W przeciwieństwie do matematyki, informatyka w całej swej historii dąży do jak najprostszego i zrozumiałego opisu tworzonych systemów. Nie ma też mowy o jakichkolwiek niedopowiedzeniach. Ma być jasno i precyzyjnie. Dlatego kreowany przez programistów świat wirtualny jest łatwiejszy do zrozumienia niż świat matematycznych abstrakcji.&lt;br /&gt;
&lt;br /&gt;
Może więc należałoby sytuację odwrócić, traktując informatykę jako klucz do zrozumienia matematyki?&lt;br /&gt;
&lt;br /&gt;
=== Czy matematyka jest trudna? ===&lt;br /&gt;
Niektóre teorie czy twierdzenia matematyczne są rzeczywiście bardzo trudne. Jednak na podstawowym poziomie matematyka powinna być bez większych problemów przyswajana przez każdego rozgarniętego człowieka. Dlaczego tak się nie dzieje? Jedną z przyczyn jest przyjęcie przez matematyków zasady „nieoglądowości” – czyli braku odwołań do pojęć jakich używamy w odniesieniu do postrzeganych rzeczy.&lt;br /&gt;
&lt;br /&gt;
Jeszcze w XVII wieku powszechnie uważano, że nasz ogląd świata jest źródłem pojęć z których budujemy sądy matematyczne1. Oczyszczanie matematyki z odniesień do rzeczywistości i naszych wyobrażeń wiązało się z dążeniem do precyzji i absolutnej pewności. Proces ten został domknięty przez Davida Hilberta2, który w celu wykazania niesprzeczności matematyki postulował jej aksjomatyzację – czyli przyjęcie, że każda teoria wynika logicznie z przyjętego zbioru aksjomatów3. Ostatecznie zwyciężył pogląd, że język matematyki jest całkowicie abstrakcyjny4. Nawet liczby naturalne definiuje się obecnie w oparciu o abstrakcyjną teorię mnogości.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ta sytuacja ma ogromne znaczenie w nauczaniu matematyki. Nauka matematyki to poznawanie świata abstrakcji, co stanowi poważną barierę dla wielu jej adeptów. Na dodatek archaiczna maniera matematyków każe im używać języka naszpikowanego trudnymi do zapamięta symbolami jednoliterowymi (kto dzisiaj zna alfabet grecki?).&lt;br /&gt;
&lt;br /&gt;
=== Matematyka z informatyką ===&lt;br /&gt;
Matematycy posługiwali się odniesieniami do rzeczywistego świata, które okazały się zbędne na pewnym etapie rozwoju tej nauki. Do zobrazowania tej sytuacji można przywołać za Wittgensteinem metaforę drabiny. Matematycy wspinali się po jej szczeblach (z których każdy był bardziej abstrakcyjny), aż na poziom całkowitej abstrakcji. Po odrzuceniu drabiny mamy czystą matematykę. Tylko dlaczego osobom studiującym matematykę odmawia się użycia tej „drabiny”?&lt;br /&gt;
&lt;br /&gt;
Jest to tym bardziej dziwne, że matematycy w swych publikacjach wcale nie są tak pryncypialni. Weźmy na przykład elementarny tekst na temat „rachunku zdań”: &amp;lt;nowiki&amp;gt;http://wazniak.mimuw.edu.pl/index.php?title=Logika_i_teoria_mnogo%C5%9Bci/Wyk%C5%82ad_2:_Rachunek_zda%C5%84&amp;lt;/nowiki&amp;gt;. Próżno w nim szukać na przykład definicji używanego pojęcia „zmienna zdaniowa”. Intuicyjnie rozumiemy, że chodzi o symbol reprezentujący zdanie.&lt;br /&gt;
&lt;br /&gt;
Takie podejście ma zasadniczą wadę: autor zakłada, że czytelnik potrafi trafnie uchwycić znaczenie wprowadzonych pojęć (intuicyjnie, lub poprzez studiowanie innych publikacji). To może być założeniem błędnym.&lt;br /&gt;
&lt;br /&gt;
Połączenie nauki matematyki i programowania sprawia natomiast, że możemy zakładać zrozumienie odwołań do pojęć z dziedziny informatyki. Takie powiązanie matematyki z informatyką nie wiąże się z zagrożeniem, któremu miało zapobiec „oczyszczenie” matematyki z „obrazowości”. Komputery są deterministyczne, a zasada ich działanie daje się opisać przy pomocy elementarnej logiki. Nie ma więc mowy o tym, by powyższy związek był źródłem błędów.&lt;br /&gt;
&lt;br /&gt;
=== Uniwersalność matematyki ===&lt;br /&gt;
Powyżej wspomniano o dwóch różnicach między informatyką i matematyką:&lt;br /&gt;
&lt;br /&gt;
1) silny związek informatyki ze światem rzeczywistym wobec dążenia matematyki do abstrakcji;&lt;br /&gt;
&lt;br /&gt;
2) język informatyki ma być możliwie najbardziej zrozumiały, czego nie oczekujemy od języka matematyki;&lt;br /&gt;
&lt;br /&gt;
Gdyby różnice między informatyką i matematyką sprowadzały się do takich „drobiazgów” – nie byłoby powodu traktować tych dziedzin jako odrębne (i pewnie z czasem nastąpiłoby „ujednolicenie”).&lt;br /&gt;
&lt;br /&gt;
Istnieją jednak różnice o wiele poważniejsze, które można uznać za fundamentalne.&lt;br /&gt;
&lt;br /&gt;
Porównajmy dwa objaśnienia algorytmu Simplex: matematyczne i informatyczne5. Jednym z kluczowych pojęć jest w tym algorytmie wierzchołek wielościanu wielowymiarowego.&lt;br /&gt;
&lt;br /&gt;
Matematyczna definicja wierzchołka (punktu ekstremalnego zbioru wypukłego)6:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Punkt e ∈ K jest punktem ekstremalnym zbioru wypukłego K, gdy równość&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;e = 𝜆𝐱 + (1 − 𝜆) y dla pewnych x,y ∈ K oraz 𝜆 ∈ [0,1] implikuje, że e = x lub e = y .&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
W tej definicji chodzi o to, że jeśli mamy jakiś odcinek (x,y) zawarty w zbiorze wypukłym, to wierzchołkiem może być jedynie jego początek lub koniec. Po tym objaśnieniu - chyba definicja staje się zrozumiała7. Tyle, że w kontekście algorytmu Simplex mało użyteczna.&lt;br /&gt;
&lt;br /&gt;
Porównajmy z definicją wierzchołka sformułowaną przez informatyka:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Ograniczenia [równania liniowe wielu zmiennych] definiują wielościan w przestrzeni n wymiarowej (gdzie n to ilość zmiennych). Wielościan ten nazywamy „wielościanem ograniczeń”. W wielościanie ograniczeń wierzchołek to jedyny punkt wspólny (rozwiązanie dopuszczalne) dla kilku (więcej niż 1) ograniczeń. Inaczej mówiąc wierzchołek to punkt wspólny dla kilku krawędzi. .&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Najważniejszą różnicą między tymi definicjami nie jest użycie jednoliterowych symboli.&lt;br /&gt;
&lt;br /&gt;
Definicja matematyczna w sposób dość typowy używa implikacji do zawężenia zbioru możliwości.&lt;br /&gt;
&lt;br /&gt;
Taka definicja jest bardziej uniwersalna, niż opis informatyka (‘jak to jest zrobione i co z tego wynika’). To wspaniale! Dzięki takiemu dążeniu do uniwersalności, wszystkie twierdzenia mogą znaleźć szersze zastosowanie! Tyle, że informatyka nie interesuje ogólne zastosowanie definicji, ale zastosowanie jej w objaśnieniu algorytmu który chce zaimplementować lub zastosować! Jego definicja zawiera własności wierzchołka, które po przyjęciu ogólniejszej definicji trzeba by dopiero udowodnić!&lt;br /&gt;
&lt;br /&gt;
Czy definicja informatyka jest mniej precyzyjna? Taki zarzut staje się bezprzedmiotowy, jeśli definicja zostanie wprost przełożona na działający poprawnie program. Świat komputera z takim programem jest lokalnym „uniwersum”, które możemy objaśniać poprzez zastosowania (świat realny) lub … matematykę! Informatyk może traktować matematykę tak jak elektronikę: są niezbędne, ale rzadko zachodzi potrzeba zgłębiania ich tajników.&lt;br /&gt;
&lt;br /&gt;
=== Matematyka obiektowa ===&lt;br /&gt;
Współczesny świat budują inżynierowie, dla których – jak się słusznie uważa – matematyka jest podstawą. W szczególności dotyczy to informatyków. Matematyka we współczesnej formie stanowi jedną z barier w kształceniu odpowiedniej ilości programistów. Z drugiej strony – świat kreowany przez programistów jest trudno dostępny dla przeciętnego użytkownika informatycznych produktów. Tu także może pomóc podniesienie ogólnego poziomu znajomości matematyki z uwzględnieniem jej związków z informatyką.&lt;br /&gt;
&lt;br /&gt;
Nadzieję na zmianę tej sytuacji daje podjęcie powszechnej edukacji w zakresie programowania. Niestety wygląda na to, że zmieniono ten z założenia szlachetny przedmiot w naukę programu Scratch. Ten absurd jest już tak ugruntowany, że nawet trudno liczyć na zmianę.&lt;br /&gt;
&lt;br /&gt;
Z powyższej refleksji zrodziła się idea stworzenia „matematyki obiektowej”.&lt;br /&gt;
&lt;br /&gt;
Dlaczego „matematyka obiektowa”? Po co tworzyć nowe terminy, skoro istnieje „matematyka dyskretna”? Termin „matematyka dyskretna” określa zakres (dziedzinę) matematyki związanej z informatyką8. Matematyka obiektowa wprowadza język i system pojęć pomocnych w opisaniu i zrozumieniu tej dziedziny wiedzy.&lt;br /&gt;
&lt;br /&gt;
Abstrakcyjna idea obiektów jest łatwą do zrozumienia (przez analogie ze światem realnych obiektów). Współczesne języki programowania w większości mają charakter obiektowy. Można więc w nich tworzyć obiekty, które objaśniają matematyczne pojęcia i twierdzenia.&lt;br /&gt;
&lt;br /&gt;
Obiekty matematyczne są opisywane poprzez definicje związków i działań w nich zachodzących. By zrozumieć ten opis, nierzadko trzeba zgłębić bardziej elementarne teorie i zapamiętać stosowane oznaczenia. Tymczasem obiekty w programowaniu są opisywane w sposób umożliwiający ich natychmiastowe użycie. Do ich zrozumienia często wystarczą przykłady użycia.&lt;br /&gt;
&lt;br /&gt;
Zmiana terminologii wiąże się więc ze zmianą podejścia: zastępujemy teorię (jak to jest zbudowane) przez praktykę (jak tego użyć). O ile w odniesieniu do elementarnych zagadnień takie podejście jest tylko jednym z możliwych9, to w przypadku zaawansowanych teorii pragmatyzm staje się często koniecznością (gdy chcemy z nich korzystać, ale nie mamy czasu na ich studiowanie).&lt;br /&gt;
&lt;br /&gt;
=== Semantyka matematyki (refleksja filozoficzna) ===&lt;br /&gt;
Podejście obiektowe może być skuteczne zwłaszcza w matematyce dyskretnej. Czy w ten sposób można opisać całą matematykę?&lt;br /&gt;
&lt;br /&gt;
Najpierw należałoby wyjaśnić – co znaczy „opisać”. Możemy na przykład zrobić zdjęcie dowolnego tekstu czy rysunku i po zeskanowaniu wgrać do komputera. Drugą skrajnością są systemy / programy komputerowe, w których zaimplementowano reguły matematycznej teorii. Interesujące jest jedynie pytanie o tą drugą możliwość. Czyli pytanie - czy można matematykę zredukować do informatyki? Całą matematykę? Odpowiedź na tak postawione pytanie wiąże się z semantyką matematyki.&lt;br /&gt;
&lt;br /&gt;
Jeśli język matematyki jest całkowicie abstrakcyjny, to znaczenie jego zdań możemy ustalić wyłącznie przez odwołanie się do innych zdań matematyki – w tym aksjomatów.&lt;br /&gt;
&lt;br /&gt;
Semantyka referencyjna z odwołaniem do rzeczywistości (np. liczba jako uogólnienie równolicznych zbiorów przedmiotów) groziłaby pozbawieniem matematyki absolutnej pewności.&lt;br /&gt;
&lt;br /&gt;
Takich problemów nie ma, gdy odwołujemy się do rzeczywistości wirtualnej – czyli tworów informatycznych, które dają się zredukować do zdań matematyki.&lt;br /&gt;
&lt;br /&gt;
Gdyby udałoby się zachować jednoznaczne przyporządkowanie konstrukcji matematycznych abstrakcjom (obiektom) informatycznym – można by takie przyporządkowanie uznać za semantykę (referencyjną) języka matematyki. Czy to wykonalne? Konieczne byłaby możliwość zapisania w pamięci komputera odpowiednika dowolnych obiektów matematycznych.&lt;br /&gt;
&lt;br /&gt;
W komputerze można zapisać dowolne obiekty. Jednak może być ich tylko skończona ilość. Nigdy nie będą to więc wszystkie możliwe konstrukcje matematyczne (wynika to z twierdzenia Goedla). Dlatego matematyka nigdy nie zostanie zredukowana do informatyki.&lt;br /&gt;
&lt;br /&gt;
Ten wynik ma ważne konsekwencje semantyczne, filozoficzne i technologiczne.&lt;br /&gt;
&lt;br /&gt;
1. Mamy tu wyjaśnienie dlaczego logicyzm10 nie jest możliwy.&lt;br /&gt;
&lt;br /&gt;
2. Możemy w systemie komputerowym zapisać symbol nieskończoności. Jednak ten symbol nie będzie się odnosił do niczego, co istnieje w systemie komputerowym. Nawet gdy stworzymy obiekty pozwalające na operowanie nieskończonością. Z punktu widzenia semantyki to tylko definiowanie nieznanego przez nieznane. Ściśle rzecz biorąc – w poszukiwaniu znaczenia symboli w komputerze możemy dojść do definicji maszyny iteracyjnej11, albo do „czegoś z zewnątrz”12.&lt;br /&gt;
&lt;br /&gt;
3. Konieczność odwołań do „czegoś z zewnątrz” (istnieje coś więcej) to mocny argument przeciw komputacjonizmowi13.&lt;br /&gt;
&lt;br /&gt;
=== Podsumowanie ===&lt;br /&gt;
Matematyka obiektowa absolutnie nie ma być „nową” matematyką, ale nowym jej przedstawieniem – łatwiejszym do przyswojenia. Łączy „oglądowość” z ideą abstrakcji, zastępując odniesienia do rzeczywistości, odniesieniami do świata wirtualnego, opisywanego w języku informatyki. Matematyka postrzegana jako teoretyczne objaśnienie elementów świata maszyn cyfrowych wydaje się łatwiejsza do zrozumienia niż matematyka jako czysto abstrakcyjny system.&lt;br /&gt;
&lt;br /&gt;
Dodatkowo, dzięki komputerom abstrakcyjne obiekty informatyki stają się częścią naszej rzeczywistości. Wzmacnia to efekt „oglądowości” (wyjaśniając pojęcia matematyczne można się odwoływać do komputerowych kreacji).&lt;br /&gt;
&lt;br /&gt;
Obiektowy język informatyki powinien ułatwić nauczanie matematyki - zwłaszcza gdy wzorem krajów skandynawskich zastosujemy kształcenie poprzez udział w zespołach rozwiązujących interdyscyplinarne problemy.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Jerzy Wawro, 2022&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Przypisy&lt;br /&gt;
&lt;br /&gt;
1Zob. Jerzy Dadaczyński „&#039;&#039;Filozofia matematyki Immanuela. Kanta jako punkt odniesienia filozofii matematyki stowarzyszonych z klasycznymi kierunkami badań podstaw matematyki&#039;&#039;” &amp;lt;nowiki&amp;gt;[https://bazhum.muzhp.pl/media/files/Slaskie_Studia_Historyczno_Teologiczne/Slaskie_Studia_Historyczno_Teologiczne-r1999-t32/Slaskie_Studia_Historyczno_Teologiczne-r1999-t32-s22-36/Slaskie_Studia_Historyczno_Teologiczne-r1999-t32-s22-36.pdf]&amp;lt;/nowiki&amp;gt;: &#039;&#039;Wymóg nieogladowości dowodów, zawarty we współczesnej metodologii matematyki, który zadomowił się tam ostatecznie od czasów Hilberta, wydaje się oczywisty i niepodważalny. Dziwne może nawet wydać się przypuszczenie, że kiedykolwiek można było wypowiedzieć twierdzenie przeciwne. Był jednak taki okres w dziejach metodologii matematyki − a precyzyjniej: w dziejach filozofii matematyki − kiedy twierdzono, że dowodząc tez matematycznych, nie tylko można, ale wręcz koniecznie trzeba odwoływać się do pewnych form oglądowości, do pewnego rodzaju przedstawień naocznych. Twórcą tego poglądu był Immanuel Kant&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
2https://encyklopedia.pwn.pl/haslo/Hilbert-David;3911678.html&lt;br /&gt;
&lt;br /&gt;
3Cel Hilberta (matematyka z wykazaną zupełnością i niesprzecznością) nie jest osiągalny.&lt;br /&gt;
&lt;br /&gt;
4Jak zauważa Jerzy Daczyński (dz.cyt.): „&#039;&#039;współczesne stanowisko można by za pomocą terminologii Kantowskiej oddać następująco: matematyka jest wiedzą czysto pojęciową, w żadnym dowodzie nie można się odwoływać do jakichkolwiek wyobrażeń (empirycznych czy apriorycznych)&#039;&#039;”. Czyli zdania matematyki nie są – jak uważał Kant – sądami syntetycznymi apriori, tylko sądami analitycznymi!&lt;br /&gt;
&lt;br /&gt;
5Marek Mika, „Teoretyczne podstawy programowania liniowego” (&amp;lt;nowiki&amp;gt;http://www.cs.put.poznan.pl/mmika/Teoretyczne%20podstawy%20programowania%20liniowego.pdf&amp;lt;/nowiki&amp;gt; ).&lt;br /&gt;
&lt;br /&gt;
6Definicja przytoczona przez Wikipedię pochodzi z John B. Conway: „&#039;&#039;A course in functional analysis&#039;&#039;”.&lt;br /&gt;
&lt;br /&gt;
7Wyjaśnienie wypukłości oraz przytoczonej definicji odcinka znajdziesz na blogu &amp;lt;nowiki&amp;gt;https://byc-matematykiem.pl/tajniki-interpolacji-czesc-1/&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
8Matematyka dyskretna to nauka o strukturach matematycznych zawierających skończoną liczbę elementów. [Ryan T. White, Archana Tikayat Ray „Practical Discrete Mathematics”]&lt;br /&gt;
&lt;br /&gt;
9Alternatywne podejście: „Need for Equipping Student Teachers with Language of Mathematics” „&#039;&#039;Znaczenie programu nauczania w budowaniu języka matematyki, który umożliwia uczącym się konstruowanie i przekazywanie wiedzy matematycznej, nie zostało docenione, mimo że od lat dyskutuje się o wyzwaniach pedagogicznych, przed którymi stają uczniowie w nauce matematyki. Nauka języka matematyki jest nie tylko cenna sama w sobie, ale także przydatna w zrozumieniu innych dziedzin wiedzy, zwłaszcza nauk ścisłych. Uważa się, że posługiwanie się narzędziami języka matematyki jest nawet pomocne w nauce języków potocznych, zwłaszcza w nauce gramatyki, rytmiki i wersyfikacji. Oczywiste jest, że rozumienie języka matematyki i jego specjalnych terminów tak płynnie, jak to możliwe, oprócz innych korzyści, uwalnia procesy poznawcze w uczącym się, aby móc podejmować bardziej przydatne czynności, w tym rozwiązywać problem. Dlatego ważne jest, aby programy kształcenia nauczycieli uwzględniały w nim elementy składowe lub elementy matematyki w taki sposób, aby struktura języka matematyki była zrozumiała dla uczniów. W artykule omówiono znaczenie języka matematyki, jego strukturę i znaczenie w kształceniu matematycznym. Sugeruje ponadto sposoby przekazywania nowicjuszom zrozumienia języka matematyki. Mając na uwadze znaczenie języka matematyki w nauczaniu uczenia się, w niniejszym opracowaniu rozważono również strategie, które można zastosować, aby wyposażyć przyszłych nauczycieli w umiejętności i kompetencje niezbędne do radzenia sobie z językiem matematyki”.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
10„W najprostszej postaci aksjomat nieskończoności powiada, że dla każdej liczby naturalnej istnieje jej następnik, zaś aksjomat wyboru postuluje, że dla każdej rodziny zbiorów parami rozłącznych istnieje jej selektor. Nie są to aksjomaty logiczne (postulują one istnienie jakichś obiektów, czego aksjomaty logiki nie robią)”. &amp;lt;nowiki&amp;gt;https://open.uj.edu.pl/mod/book/view.php?id=20&amp;amp;chapterid=112&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
11Maszyna iteracyjna to teoretyczny konstrukt Zdzisława Pawlaka. Można ją traktować jako alternatywę dla Maszyny Turinga. Składa się z pamięci (elementu o wielu stanach) i funkcji przejścia – wyliczającej na podstawie stanu pamięci w jakim stanie znajdzie się ona w chwili następnej.&lt;br /&gt;
&lt;br /&gt;
12Ten wynik jest zgodny z poglądami Cantora: &amp;lt;nowiki&amp;gt;https://bazhum.muzhp.pl/media/files/Humanistyka_i_Przyrodoznawstwo/Humanistyka_i_Przyrodoznawstwo-r2004-t10/Humanistyka_i_Przyrodoznawstwo-r2004-t10-s51-68/Humanistyka_i_Przyrodoznawstwo-r2004-t10-s51-68.pdf&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
13http://www.filozoficznie.pl/4/40_M_Milkowski_Analiza_tezy_komputacjonizmu.pdf&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Elementy_j%C4%99zykoznawstwa_dla_programist%C3%B3w&amp;diff=124</id>
		<title>Elementy językoznawstwa dla programistów</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Elementy_j%C4%99zykoznawstwa_dla_programist%C3%B3w&amp;diff=124"/>
		<updated>2022-09-25T06:00:35Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin przeniósł stronę Elementy językozawstwa dla programistów na Elementy językoznawstwa dla programistów, bez pozostawienia przekierowania pod starym tytułem: literówka w tytule&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{|&lt;br /&gt;
|-&lt;br /&gt;
| |Moduł: Elementy językozawstwa dla programistów &lt;br /&gt;
|-&lt;br /&gt;
| |Poziom: Zaawanowany&lt;br /&gt;
|-&lt;br /&gt;
| |Profil: Dla profesjonalistów&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Każda wypowiedź ma swoją strukturę, którą określamy terminem „[https://pl.wikipedia.org/wiki/Syntaktyka_(językoznawstwo syntaktyka]” lub składnia, oraz swoje znaczenie określane terminem „[https://pl.wikipedia.org/wiki/Semantyka_(językoznawstwo) semantyka]”. Obydwie te dziedziny są przedmiotem zainteresowania informatyki – ale ich znaczenie jest zupełnie różne. Semantyka to przedmiot badania sztucznej inteligencji (komunikacja w języku naturalnym, przetwarzanie wiedzy) oraz filozofii informatyki. Badania syntaktyki zostały natomiast wykorzystywane w rozwoju języków programowania.&lt;br /&gt;
&lt;br /&gt;
[[Plik:j_gr2.png]]&lt;br /&gt;
&lt;br /&gt;
Analizy językoznawców wykazały, że zdania dowolnego języka daje się opisać w postaci reguł budowania złożonych wypowiedzi z prostszych struktur. Proces generacji zdań nazywa się też procesem „wywodu”. &lt;br /&gt;
&lt;br /&gt;
Przykład:&lt;br /&gt;
&lt;br /&gt;
[[Plik:j_gr3.png]]&lt;br /&gt;
&lt;br /&gt;
Powstała struktura ma kształt odwróconego drzewa. Dlatego nazywa się ją „drzewem wywodu”.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Gramatyka struktur frazowych ==&lt;br /&gt;
Językoznawca [https://pl.wikipedia.org/wiki/Noam_Chomsky Noam Chomsky] stworzył teorię zwaną gramatyką generatywną (lub gramatyką struktur frazowych) opisującą ten proces generacji (dla zdań w formie podstawowej). Informatycy podążyli dalej w tym kierunku tworząc sztuczne języki i automaty je analizujące (translatory). Podstawą była formalizacja teorii gramatyk, którą w zarysie przedstawiono poniżej.&lt;br /&gt;
&lt;br /&gt;
Gramatyka składa się z: * zbioru symboli terminalnych T (symboli wchodzących w skład wygenerowanych zdań); &lt;br /&gt;
* zbioru symboli nieterminalnych N (zbiór symboli pomocniczych służących do przeprowadzenia generacji, oznacza się je często przez ujęcie w nawiasy ostre &amp;lt;...&amp;gt; &amp;lt;nowiki&amp;gt;= zob. &amp;lt;/nowiki&amp;gt;[https://pl.wikipedia.org/wiki/Notacja Notacja][https://pl.wikipedia.org/wiki/Notacja_BNF  BNF]); &lt;br /&gt;
* symbolu początkowego S (wyróżniony symbol nieterminalny od którego rozpoczyna się wywód); &lt;br /&gt;
* reguł wywodu pozwalających na zastępowanie symboli nieterminalnych przez ciągi symboli terminalnych i nieterminalnych aż do otrzymania samych symboli terminalnych; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;&#039;&#039;&#039;Przykład:&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dla zdania na powyższym obrazku można zaproponować gramatykę:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
T = { Jan, Zosia, trzyma, ma, czapka, pióro } &lt;br /&gt;
N = { &amp;lt;zdanie&amp;gt;, &amp;lt;fraza rzeczownika&amp;gt;, &amp;lt;fraza czasownika&amp;gt;, &amp;lt;rzeczownik&amp;gt;, &amp;lt;czasownik&amp;gt; } &lt;br /&gt;
S = &amp;lt;zdanie&amp;gt; &lt;br /&gt;
&lt;br /&gt;
reguły wywodu ( ::= oznacza operację zastępowania): &lt;br /&gt;
&lt;br /&gt;
(1) &amp;lt;zdanie&amp;gt; ::= &amp;lt;fraza rzeczownika&amp;gt;&amp;lt;fraza czasownika&amp;gt; &lt;br /&gt;
(2) &amp;lt;fraza rzeczownika&amp;gt; ::= &amp;lt;rzeczownik&amp;gt; &lt;br /&gt;
(3) &amp;lt;fraza czasownika&amp;gt; ::= &amp;lt;czasownik&amp;gt;&amp;lt;fraza rzeczownika&amp;gt; &lt;br /&gt;
(4) &amp;lt;rzeczownik&amp;gt; ::= Jan | Zosia | czapka | pióro (5) &amp;lt;czasownik&amp;gt; ::= trzyma | ma &lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Znak &#039;|&#039; oznacza alternatywę - np. można użyć reguły &#039;&#039;&amp;lt;czasownik&amp;gt; ::= trzyma&#039;&#039; lub &#039;&#039;&amp;lt;czasownik&amp;gt; ::= ma&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Wywód przykładowego zdania ( w nawiasach podano numery użytych reguł ): &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
S &#039;&#039;&#039;-(1)-&amp;gt; &#039;&#039;&#039;&amp;lt;fraza rzeczownika&amp;gt; &amp;lt;fraza czasownika&amp;gt; &#039;&#039;&#039;-(2)-&amp;gt; &#039;&#039;&#039;&amp;lt;rzeczownik&amp;gt;&amp;lt;fraza czasownika&amp;gt; &#039;&#039;&#039;-(4)-&amp;gt; &#039;&#039;&#039;Zosia &amp;lt;fraza czasownika&amp;gt; &#039;&#039;&#039;-(3)-&amp;gt;&#039;&#039;&#039; Zosia &amp;lt;czasownik&amp;gt; &amp;lt;fraza rzeczownika&amp;gt; &#039;&#039;&#039;-(5)-&amp;gt;&#039;&#039;&#039; Zosia ma &amp;lt;fraza rzeczownika&amp;gt; &#039;&#039;&#039;-(2)-&amp;gt;&#039;&#039;&#039; Zosia ma &amp;lt;rzeczownik&amp;gt; &#039;&#039;&#039;-(4)-&amp;gt; &#039;&#039;&#039;Zosia ma pióro &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Powyższy wywód można przedstawić w postaci drzewo wywodu, pokazanego na powyższym rysunku. Przy analizie drzewo wywodu nazywane jest też drzewem rozkładu (w jaki sposób zdanie rozkładamy na jego reprezentację). Drzewo to służy następnie wygenerowaniu kodu programu - wykonywanego przez komputer.&lt;br /&gt;
&lt;br /&gt;
Liście tego drzewa stanowią symbole terminalne. Każde poddrzewo drzewa wywodu nazywa się frazą. Ze względu na typ użytych reguł wywodu, gramatyki dzieli się na: &lt;br /&gt;
* &amp;lt;u&amp;gt;regularne&amp;lt;/u&amp;gt;: wszystkie reguły są w postaci A ::= aB, lub A ::= a, gdzie A, B - oznaczają symbole nieterminalne, a - symbol terminalny; &lt;br /&gt;
* &amp;lt;u&amp;gt;bezkontekstowe&amp;lt;/u&amp;gt;: daje się sprowadzić do zbioru takich reguł, że po lewej stronie każdej reguły wywodu znajduje się pojedynczy symbol nieterminalny (zob. [https://pl.wikipedia.org/wiki/Postać_normalna_Greibach postać normalna Greibach])&amp;lt;nowiki&amp;gt;; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* &amp;lt;u&amp;gt;kontekstowe&amp;lt;/u&amp;gt;: reguły wywodu mogą być dowolnej postaci; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mniej formalnie można powiedzieć, że gramatyka bezkontekstowa to taka, że przy analizie wypowiedzi można na podstawie wczytanych symboli dokładnie ustalić którą regułę wywodu należy zastosować. &lt;br /&gt;
&lt;br /&gt;
Zależnie od gramatyki jaka jest konieczna do wygenerowania zdań języka mówimy o językach regularnych, bezkontekstowych i kontekstowych. &lt;br /&gt;
&lt;br /&gt;
Gramatyki regularne opisują między innymi budowę poszczególnych elementów używanych w językach programowania komputerów (identyfikatory, liczby, słowa kluczowe). Instrukcje języków takich jak Pascal pochodzą z języków bezkontekstowych. W praktyce analiza języków programowania odbywa się dwustopniowo. Najpierw tzw. skaner wydziela z wejściowego łańcucha znaków &#039;tokeny&#039;, czyli wspomniane wcześniej proste elementy znaczeniowe. Później &#039;parser&#039; analizuje ciąg tokenów tworząc z nich instrukcje języka. Skaner jest zazwyczaj automatem implementującym gramatykę regularną.&lt;br /&gt;
&lt;br /&gt;
== Języki regularne. Automaty. ==&lt;br /&gt;
&lt;br /&gt;
Tokeny (liczby, napisy, słowa kluczowe), na które skaner dzieli przetwarzany ciąg znaków mają strukturę, którą można opisać gramatyką języków regularnych. Najbardziej naturalną metodą zapisywania konstrukcji języka regularnego są wyrażenia regularne. Użycie znaku * w tym wyrażeniu oznacza powtórzenie &amp;gt;=0 ilość razy poprzedzającego go symbolu.&lt;br /&gt;
&lt;br /&gt;
Przykład: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;margin:auto;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#e6e6e6;border:0.05;&amp;quot; | wyrażenie&amp;amp;nbsp;&lt;br /&gt;
| style=&amp;quot;background-color:#e6e6e6;border:0.05pt;&amp;quot; | przykłady użycia&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border:0.05pt;&amp;quot; | xy*z&amp;amp;nbsp;&lt;br /&gt;
| style=&amp;quot;border:0.05pt;;&amp;quot; | &amp;amp;nbsp;xyyz, xz, xyyyz&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border:0.05pt;&amp;quot; | (xy)*z*&amp;amp;nbsp;&lt;br /&gt;
| style=&amp;quot;border:0.05pt;&amp;quot; | xyxyzzzz, xyzzzz&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Analizę języków regularnych wygodnie jest opisywać (a niekiedy także implementować) jako działanie automatów skończenie-stanowych. Automat skończenie-stanowy to zbiór stanów połączonych ze sobą przy pomocy etykietowanych symbolami łuków (lub innych połączeń). Wyróżniany jest jeden stan jako stan początkowy i zbiór stanów końcowych. &lt;br /&gt;
&lt;br /&gt;
Zadaniem automatu jest analiza ciągu znaków. Jego działanie polega na przechodzeniu od stanu do stanu począwszy od stanu początkowego. Przejście jest możliwe, o ile analizowany symbol (znak) jest identyczny z definicją (etykietą) przejścia. Po przejściu pobierany jest do analizy następny symbol (znak). Jeśli po przetworzeniu całego ciągu znaków automat znajdzie się w stanie końcowym, ciąg należy do języka regularnego (jest akceptowalny przez automat), a stan końcowy wskazuje na to, co ciąg ten oznacza. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Przykład: &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Plik:j_gr1.png]]&lt;br /&gt;
&lt;br /&gt;
Automat akceptujący ciąg symboli: a, ab*, lub ab*c oznaczenia:* okrąg oznacza stan początkowy &lt;br /&gt;
* prostokąty z okrągłymi rogami (niebieskie) - oznaczają stany końcowe &lt;br /&gt;
* prostokąty(pomarańczowe) - pozostałe stany &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Uzupełnieniem tego niniejszego są programy z repozytorium [https://github.com/galicea/eduprog https://github.com/galicea/eduprog]. W podkatalogu lang można znaleźć program &#039;&#039;&#039;autogram&#039;&#039;&#039;, który tworzy automat na podstawie wyrażeń regularnych. Wywołanie dla powyższego przykładu: &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;autogram -a -i &amp;quot;a(&amp;amp;b&amp;amp;)@&#039;&#039;&#039;c&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W wyniku analizy otrzymujemy tabelkę przejść:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;margin:auto;&amp;quot;&lt;br /&gt;
| style=&amp;quot;background-color:#e6e6e6;border:0.05;&amp;quot; |     | a |  b | c&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:2pt;border:0.05;&amp;quot; | 1   |  2|  0|  0&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:2pt;border:0.05;&amp;quot;| 2   |  0|  2|  3&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;padding:2pt;border:0.05;&amp;quot;| 3   |  0|  0|  0&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
W wierszach są zawarte stany automatu, a w kolumnach symbole wyrażenia. Kolumny opisują do którego stanu automat przejdzie po wczytaniu symbolu. Na przykład w stanie 2 symbol &#039;&#039;&#039;b &#039;&#039;&#039;powoduje pozostanie w tym samym stanie, a symbol &#039;&#039;&#039;c - &#039;&#039;&#039;przejście do końcowego stanu 3 (gdzie już nic nie można przyjąć).&lt;br /&gt;
&lt;br /&gt;
== Gramatyki bezkontekstowe ==&lt;br /&gt;
&lt;br /&gt;
Aby utworzyć drzewo wywodu dla dowolnego zdania zbudowanego w oparciu o gramatykę należałoby po kolei próbować zastosować wszystkie produkcje (poddrzewa), wracając w razie niepowodzenia do wcześniejszego stadium analizy. Ten sposób analizy (analiza z powrotami) jest jednak bardzo nieefektywny. W praktyce na gramatyki bezkontekstowe nakłada się dodatkowe ograniczenia pozwalające jednoznacznie wskazać którą produkcję należy wybrać na podstawie: * dotychczasowego przebiegu analizy (stanu w którym znajduje się analizator (automat)); &lt;br /&gt;
* k symboli na wejściu (w praktyce prawie zawsze k=1); &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Analiza lewostronna (wywód lewostronny) polega na tym, że czytamy kolejne symbole i na tej podstawie decydujemy jaką regułę zastosować. Potrzebna do tego gramatyka jest określana mianem [https://pl.wikipedia.org/wiki/Parser_LL LL(1)] – dla podkreślenia, że chodzi o 1 symbol z lewej strony drzewa wywodu. Taką gramatykę zastosowano w języku Pascal. Drugą metodą analizy jest analiza prawostronna. Polega ona na tym, że wczytujemy kolejne symbole aż do chwili, gdy skompletujemy wszystkie symbole potrzebne do zastosowania reguły wywodu. Decyduje o tym zawsze ostatni wczytany symbol – czyli symbol z prawej strony drzewa wywodu. Stąd określenie [https://pl.wikipedia.org/wiki/Parser_LR LR(1)]. &lt;br /&gt;
&lt;br /&gt;
== Gramatyki LL(1) ==&lt;br /&gt;
&lt;br /&gt;
Gramatyka LL(1) ma tą własność, że każdą produkcję można zidentyfikować na podstawie pierwszego z lewej symbolu po prawej jej stronie. Gramatyki tego typu są najczęściej stosowane przy &#039;ręcznym&#039; konstruowaniu analizatora. Stosuje się przy tym analizę rekurencyjną. Polega ona na tym, że dla każdej produkcji tworzy się procedurę ją analizującą. Procedury te identyfikują i wywołują odpowiednie procedury dla zanalizowania podfrazy. Dokładny opis tej metody analizy można znaleźć w podręczniku N.Wirtha [2]. &lt;br /&gt;
&lt;br /&gt;
Poniżej prosty przykład kalkulatora wyrażeń w języku Python, który zawiera analizator LL(1). W przykładzie założono, że liczby są dodatnie jednocyfrowe, a dostępne działania to tylko mnożenie i dodawanie. Dzięki temu skaner (next_token) to tylko pobieranie kolejnego znaku (znak dolara oznacza koniec wejścia a wykrzyknik błąd). Proszę zauważyć, że wystarczy zawsze sprawdzić jaki jest kolejny token, by zdecydować o następnym kroku analizy. Ta stosunkowo prosta zasada sprawia, że analizatory LL(1) można zaimplementować ‘ręcznie’ - bez programów wspierających – takich jak [https://pl.wikipedia.org/wiki/Yacc Yacc] czy [https://www.gnu.org/software/bison/ Bison].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
class calculator():&lt;br /&gt;
  source=[]&lt;br /&gt;
  digits = (&#039;0&#039;,&#039;1&#039;,&#039;2&#039;,&#039;3&#039;,&#039;4&#039;,&#039;5&#039;,&#039;6&#039;,&#039;7&#039;,&#039;8&#039;,&#039;9&#039;)&lt;br /&gt;
  result=0&lt;br /&gt;
  token=&#039;!&#039;&lt;br /&gt;
&lt;br /&gt;
  def next_token(self):&lt;br /&gt;
    if len(self.source)==0:&lt;br /&gt;
      self.token=&#039;$&#039;&lt;br /&gt;
    else:&lt;br /&gt;
      self.token=self.source[0]&lt;br /&gt;
      del self.source[0]&lt;br /&gt;
&lt;br /&gt;
  def factor(self): # czynnik&lt;br /&gt;
    self.result=0&lt;br /&gt;
    if self.token==&#039;(&#039;:&lt;br /&gt;
      self.next_token()&lt;br /&gt;
      self.expr()&lt;br /&gt;
      if self.token != &#039;)&#039;:&lt;br /&gt;
        self.token=&#039;!&#039;&lt;br /&gt;
      else:&lt;br /&gt;
        self.next_token()&lt;br /&gt;
    elif self.token in self.digits:&lt;br /&gt;
      self.result=int(self.token)&lt;br /&gt;
      self.next_token()&lt;br /&gt;
&lt;br /&gt;
  def term(self): # skladnik&lt;br /&gt;
    self.factor()&lt;br /&gt;
    mem=self.result&lt;br /&gt;
    while self.token==&#039;*&#039;:&lt;br /&gt;
      self.next_token()&lt;br /&gt;
      self.factor()&lt;br /&gt;
      mem=mem*self.result&lt;br /&gt;
    self.result=mem&lt;br /&gt;
&lt;br /&gt;
  def expr(self):&lt;br /&gt;
    self.result=0&lt;br /&gt;
    self.term()&lt;br /&gt;
    mem=self.result&lt;br /&gt;
    while (self.token==&#039;+&#039;):&lt;br /&gt;
      self.next_token()&lt;br /&gt;
      self.term()&lt;br /&gt;
      mem=mem+self.result&lt;br /&gt;
    self.result=mem&lt;br /&gt;
&lt;br /&gt;
  def calc(self,expression):&lt;br /&gt;
    self.source=list(expression)&lt;br /&gt;
    self.next_token()&lt;br /&gt;
    self.expr()&lt;br /&gt;
    if self.token==&#039;$&#039;:&lt;br /&gt;
      return self.result&lt;br /&gt;
    else:&lt;br /&gt;
      return None&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Przykładowe użycie kalkulatora:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
c=calculator()&lt;br /&gt;
res=c.calc(&#039;4*(2+3)&#039;)&lt;br /&gt;
if res != None:&lt;br /&gt;
  print(res)&lt;br /&gt;
else:&lt;br /&gt;
  print(&#039;error&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Gramatyki LR(1) &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
W przeciwieństwie do poprzedniej, tą gramatykę stosuje się najczęściej przy użyciu generatorów przy pomocy których konstruuje się analizator. Pouczającym może być analiza takiego generatora. W repozytorium [https://github.com/galicea/eduprog https://github.com/galicea/eduprog], w podkatalogu lang znajduje się moduł u_makerl1 i program autogram wykorzystujący ten moduł generatora. Oprogramowanie jest napisane w języku Pascal (z polskimi komentarzami). Może więc być łatwiejsze w analizie (zwłaszcza, że poniżej podano szczegółowe objaśnienie algorytmu), niż rozbudowane generatory wspomniane wcześniej. &lt;br /&gt;
&lt;br /&gt;
=== Metoda analizy  ===&lt;br /&gt;
&lt;br /&gt;
Analizator jest automatem ze stosem. Oznacza to, że zawiera on pamięć w postaci stosu do której może dopisywać dane dotyczące aktualnego stanu (wkładanie na stos). Możliwe jest także odczytywanie danych w kolejności odwrotnej do tej w jakiej były zapisywane (zdejmowanie ze stosu). Automat pobiera kolejne symbole, wkłada je na stos i zmienia swój stan. Bieżący stan automatu jest zapisywany na stosie wraz z symbolem. Stan automatu opisuje całą zawartość stosu. Jeśli stan ten wskazuje, że na stosie jest pełna fraza - następuje redukcja. Polega ona na zdjęciu ze stosu symboli składających się na tą frazę i zastąpieniu ich symbolem nieterminalnym będący lewą stroną produkcji dającej taką frazę. &lt;br /&gt;
&lt;br /&gt;
Dzięki pamiętaniu stanu na stosie - po redukcji można ustalić nowy stan automatu. Stan zapisany na wierzchołku stosu opisuje bowiem całą jego zawartość i możemy ustalić jaki stan powstanie po dodaniu nowego symbolu. &lt;br /&gt;
&lt;br /&gt;
Analiza kończy się poprawnie, gdy pojawi się symbol sygnalizujący koniec danych, a na stosie znajduje się symbol początkowy gramatyki. &lt;br /&gt;
&lt;br /&gt;
Gramatyka dla takiej metody analizy musi spełniać jeden warunek: prawe części żadnych dwóch produkcji nie mogą być jednakowe (trzeba wiedzieć w oparciu o którą produkcję dokonać analizy). &lt;br /&gt;
&lt;br /&gt;
Ponieważ w trakcie analizy badamy zawsze jeden - ostatni z prawej symbol wywodu - metoda ta, oraz gramatyka noszą nazwę LR(1). &lt;br /&gt;
&lt;br /&gt;
=== Algorytm tworzenia automatu LR(1) ===&lt;br /&gt;
&lt;br /&gt;
1/ Ułożyć gramatykę LR(1) języka. Ponumerować wszystkie produkcje. &lt;br /&gt;
&lt;br /&gt;
2/ Spisać wszystkie możliwe stany automatu. Jeśli dowolną produkcję można przedstawić w postaci X::=PS, to P jest jednym z możliwych stanów automatu. &lt;br /&gt;
&lt;br /&gt;
3/ Utworzyć funkcję zmiany stanu stosu przy akceptacji tokenów. Rozróżniamy dwa rodzaje operacji: przesunięcie i redukcja. Przesunięcie polega na dodaniu tokenu na stos. Po przesunięciu pobierany jest następny token. Redukcja polega na zdjęciu ze stosu pełnej frazy.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PRZESUNIĘCIE:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
1) Jeśli istnieją stany stosu PQ i Qt, to dla tokenu t istnieje przejście od stanu PQ do stanu Qt; (oznacza to przejście do analizy podfrazy będącej bardziej z prawej strony).&lt;br /&gt;
&lt;br /&gt;
2) Jeśli nie zachodzi przypadek 1 - badamy zamiast t wszystkie symbole z których t można wyprowadzić lewostronnie. Oznacza to że jeśli istnieją stany PQ i z QR, oraz z R można wyprowadzić lewostronnie t, to dla tokenu t istnieje przejście od stanu PQ do stanu t;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;REDUKCJA: &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Dla każdego stanu stosu PQ szukamy najdłuższego łańcucha Q spełniającego warunki: - istnieje produkcja (reguła gramatyczna) r, dla której Q stanowi prawą stronę; - istnieje stan Pl(r), gdzie l(r) oznacza lewą stronę produkcji r; Redukcja r jest wykonywana w sytuacji, gdy przy stanie PQ pojawi się token, dl którego nie można dokonać przesunięcia.# Utworzyć funkcję przejścia do nowego stanu przy redukcji. Jeśli po dołączeniu do stanu ze szczytu stosu lewej strony produkcji r otrzymamy poprawny stan - jest to stan do którego następuje przejście automatu. Jeśli taki stan nie istnieje - następuje próba zanalizowania nowej frazy. Ustalany jest nowy stan opisujący lewą stronę użytej produkcji.&lt;br /&gt;
&lt;br /&gt;
4/ Zbudować automat działający wg. zasady:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
repeat &lt;br /&gt;
  PobierzNastępnySymbol; &lt;br /&gt;
  if symbol=znacznikKońcaDanych i na stosie znajduje się  symbol początkowy then &lt;br /&gt;
    koniec &lt;br /&gt;
  else if dla danego tokenu, oraz aktualnego stanu stosu &lt;br /&gt;
          istnieje przejście zgodne z funkcja przejścia (pkt. 3) then &lt;br /&gt;
    włóż symbol na stos z zaznaczeniem nowego stanu &lt;br /&gt;
  else if istnieje produkcja której prawa strona jest zawarta aktualnie na stosie then &lt;br /&gt;
    wykonaj redukcję, zmieniając stan na wskazany przez  funkcję przejścia zbudowaną w pkt. 4 &lt;br /&gt;
  else &lt;br /&gt;
    wystapił błąd &lt;br /&gt;
until błąd lub koniec;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Szczegółowy opis gramatyk LR(1) można znaleźć w pracy [1].&lt;br /&gt;
&lt;br /&gt;
== Przykład ==&lt;br /&gt;
&lt;br /&gt;
Programem autogram, który zawiera opisany powyżej generator stworzono automat analizujący proste wyrażenia arytmetyczne:&lt;br /&gt;
&lt;br /&gt;
gramatyka (plik gram.lr1):        &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
gramatyka (plik gram.lr1):        stany: &lt;br /&gt;
1: &amp;lt;Z&amp;gt; ::= &amp;lt;W&amp;gt;                 1 : &amp;lt;W&amp;gt; &lt;br /&gt;
2: &amp;lt;W&amp;gt; ::= &amp;lt;W&amp;gt; + &amp;lt;A&amp;gt;           2 : &amp;lt;W&amp;gt;+ &lt;br /&gt;
3: &amp;lt;W&amp;gt; ::= &amp;lt;W&amp;gt; - &amp;lt;A&amp;gt;           3 : &amp;lt;W&amp;gt;+&amp;lt;A&amp;gt; &lt;br /&gt;
4: &amp;lt;W&amp;gt; ::= &amp;lt;A&amp;gt;                 4 : &amp;lt;W&amp;gt;- &lt;br /&gt;
5: &amp;lt;A&amp;gt; ::= &amp;lt;A&amp;gt; * &amp;lt;A&amp;gt;           5 : &amp;lt;W&amp;gt;-&amp;lt;A&amp;gt; &lt;br /&gt;
6: &amp;lt;A&amp;gt; ::= &amp;lt;A&amp;gt; / &amp;lt;A&amp;gt;           6 : &amp;lt;A&amp;gt; &lt;br /&gt;
7: &amp;lt;A&amp;gt; ::= &amp;lt;B&amp;gt;                 7 : &amp;lt;A&amp;gt;* &lt;br /&gt;
8: &amp;lt;B&amp;gt; ::= + &amp;lt;C&amp;gt;               8 : &amp;lt;A&amp;gt;*&amp;lt;A&amp;gt; &lt;br /&gt;
9: &amp;lt;B&amp;gt; ::= - &amp;lt;C&amp;gt;               9 : &amp;lt;A&amp;gt;/ &lt;br /&gt;
10: &amp;lt;B&amp;gt; ::= &amp;lt;C&amp;gt;               10 : &amp;lt;A&amp;gt;/&amp;lt;A&amp;gt; &lt;br /&gt;
11: &amp;lt;C&amp;gt; ::= ( &amp;lt;W&amp;gt; )           11 : &amp;lt;B&amp;gt; &lt;br /&gt;
                              12 : &amp;lt;C&amp;gt; ::= NUM 12 : +&lt;br /&gt;
                              13 : +&amp;lt;C&amp;gt; &lt;br /&gt;
                              14 : - &lt;br /&gt;
                              15 : -&amp;lt;C&amp;gt; &lt;br /&gt;
                              16 : &amp;lt;C&amp;gt; &lt;br /&gt;
                              17 : ( &lt;br /&gt;
                              18 : (&amp;lt;W&amp;gt; &lt;br /&gt;
                              19 : (&amp;lt;W&amp;gt;) &lt;br /&gt;
                              20 : NUM &lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Fragmenty tablic sterujących działaniem automatu:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
analiza: &lt;br /&gt;
      |                 tokeny &lt;br /&gt;
stan: | +     -     *     /     (     NUM     EOIN &lt;br /&gt;
------+-------------------------------------------&lt;br /&gt;
0     | 12   14                 17     20 &lt;br /&gt;
1     |  2    4 &lt;br /&gt;
2     | 12   14                 17     20 &lt;br /&gt;
3     | -2   -2     7     9     -2     -2     -2 &lt;br /&gt;
&lt;br /&gt;
liczbami dodatnimi oznaczono nowe stany przy przesunięciu, a ujemnymi numery produkcji użytych do redukcji. &lt;br /&gt;
        EOI = znacznik końca danych &lt;br /&gt;
nowe stany po dokonaniu redukcji: &lt;br /&gt;
numer     | stan &lt;br /&gt;
produkcji | 1     2     3 ...... 16     17     18 &lt;br /&gt;
----------+--------------------------------------&lt;br /&gt;
2         | 1     1     1         1     18     1 &lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zauważ że generator tworzy pewną nadmiarowość. Wynik jego działania można poprawić usuwając dane dotyczące stanów przez które automat nie powinien przechodzić (na przykład w stanie 3 nie może pojawić się symbol &#039;(&#039;). Ten automat wykonuje działania tak długo jak to jest możliwe, zamiast zatrzymywać się przy pierwszej nieprawidłowości. &lt;br /&gt;
&lt;br /&gt;
Na podstawie tego automatu stworzono moduł kalkulatora KALK_LR1.PAS. Dla porównania analogiczny kalkulator zbudowano w oparciu o gramatykę LL(1): KALK_LL1.PAS&lt;br /&gt;
&lt;br /&gt;
== Bibliografia ==&lt;br /&gt;
&lt;br /&gt;
# W.M. Waite, G. Goos &#039;&#039;&amp;quot;Konstrukcja kompilatorów&amp;quot;&#039;&#039; &lt;br /&gt;
# N. Wirth &#039;&#039;&amp;quot;Algorytmy+struktury danych = programy&amp;quot;. &#039;&#039;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=123</id>
		<title>Podstawy informatyki</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=123"/>
		<updated>2022-09-25T05:58:01Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;PODSTAWY INFORMATYKI&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Część I: Podstawowe pojęcia ==&lt;br /&gt;
* Moduł 1.1 [[Algorytm – program – system]]&lt;br /&gt;
* Moduł 1.2 [[Uczymy się myśleć abstrakcyjnie]]&lt;br /&gt;
* Moduł 1.3 [[Filozoficznie o programach komputerowych]] (dla humanistów i pasjonatów)&lt;br /&gt;
* Moduł 1.4 [[Procesor i język maszynowy - wprowadzenie]] (dla inżynierów i techników)&lt;br /&gt;
* Moduł 1.5 [[Logika i instrukcje warunkowe]]&lt;br /&gt;
&lt;br /&gt;
== Część II: Algorytmika ==&lt;br /&gt;
* Moduł 2.1 [[Programy a algorytmy]]&lt;br /&gt;
* Moduł 2.2 [[Implementacja algorytmów]]&lt;br /&gt;
* Moduł 2.3 [[Elementy językoznawstwa dla programistów]] (poziom zaawansowany)&lt;br /&gt;
&lt;br /&gt;
== Część III: Podstawy programowania ==&lt;br /&gt;
* Moduł 3.1. [[Różnorodność struktur programów]]&lt;br /&gt;
&lt;br /&gt;
== Część IV: Matematyka obiektowa ==&lt;br /&gt;
* Moduł 4.1 [[Matematyka obiektowa]]&lt;br /&gt;
&lt;br /&gt;
== Ważne strony ==&lt;br /&gt;
* [//leanpub.com/pyprog leanpub.com/pyprog] - Podręcznik programowania w Pythonie&lt;br /&gt;
* [//elearning.otwartaedukacja.pl/ elearning.otwartaedukacja.pl] - &#039;&#039;&#039;E-learning&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Używane programy edukacyjne ==&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/bl/code/ otwartaedukacja.pl/programowanie/bl/code] - układanie programów z bloczków&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/schematy/ otwartaedukacja.pl/programowanie/schematy] - rysowanie schematów blokowych&lt;br /&gt;
-&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Strona_g%C5%82%C3%B3wna&amp;diff=122</id>
		<title>Strona główna</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Strona_g%C5%82%C3%B3wna&amp;diff=122"/>
		<updated>2022-09-25T05:52:14Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;INFORMATYKA&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. [[Podstawy informatyki]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
Do tworzenia stron wykorzystano projekt MediaWiki - który na pewno jest wszystkim znany z Wikipedii (zob. [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/pl MediaWiki FAQ]).&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Strona_g%C5%82%C3%B3wna&amp;diff=121</id>
		<title>Strona główna</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Strona_g%C5%82%C3%B3wna&amp;diff=121"/>
		<updated>2022-09-25T05:51:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Podstawy informatyki.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. [[Podstawy informatyki]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
Do tworzenia stron wykorzystano projekt MediaWiki - który na pewno jest wszystkim znany z Wikipedii (zob. [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/pl MediaWiki FAQ]).&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=120</id>
		<title>Podstawy informatyki</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=120"/>
		<updated>2022-09-25T05:51:14Z</updated>

		<summary type="html">&lt;p&gt;Admin: Admin przeniósł stronę Podstawy programowania na Podstawy informatyki, bez pozostawienia przekierowania pod starym tytułem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;PODSTAWY INFORMATYKI&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Część I: Podstawowe pojęcia ==&lt;br /&gt;
* Moduł 1.1 [[Algorytm – program – system]]&lt;br /&gt;
* Moduł 1.2 [[Uczymy się myśleć abstrakcyjnie]]&lt;br /&gt;
* Moduł 1.3 [[Filozoficznie o programach komputerowych]] (dla humanistów i pasjonatów)&lt;br /&gt;
* Moduł 1.4 [[Procesor i język maszynowy - wprowadzenie]] (dla inżynierów i techników)&lt;br /&gt;
* Moduł 1.5 [[Logika i instrukcje warunkowe]]&lt;br /&gt;
&lt;br /&gt;
== Część II: Algorytmy i języki programowania ==&lt;br /&gt;
* Moduł 2.1 [[Programy a algorytmy]]&lt;br /&gt;
* Moduł 2.2 [[Implementacja algorytmów]]&lt;br /&gt;
* Moduł 2.3 [[Elementy językozawstwa dla programistów]] (poziom zaawansowany)&lt;br /&gt;
&lt;br /&gt;
== Część III: Systematyka ==&lt;br /&gt;
* Moduł 3.1. [[Różnorodność struktur programów]]&lt;br /&gt;
&lt;br /&gt;
== Część IV: Projekty ==&lt;br /&gt;
* Moduł 4.1 [[Projekt &amp;quot;Ściąga&amp;quot;]] (poziom gimnazjum)&lt;br /&gt;
&lt;br /&gt;
== Ważne strony ==&lt;br /&gt;
* [//leanpub.com/pyprog leanpub.com/pyprog] - Podręcznik programowania w Pythonie&lt;br /&gt;
* [//python.otwartaedukacja.pl/ python.otwartaedukacja.pl] - przykłady z podręcznika&lt;br /&gt;
* [//bryk.otwartaedukacja.pl bryk.otwartaedukacja.pl] - program &amp;quot;ściąga&amp;quot;....&lt;br /&gt;
&lt;br /&gt;
* [//elearning.otwartaedukacja.pl/ elearning.otwartaedukacja.pl] - &#039;&#039;&#039;E-learning&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Używane programy edukacyjne ==&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/hanoi/ otwartaedukacja.pl/programowanie/hanoi/] - programowanie łamigłówki Wieże Hanoi&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/bl/code/ otwartaedukacja.pl/programowanie/bl/code] - układanie programów z bloczków&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/schematy/ otwartaedukacja.pl/programowanie/schematy] - rysowanie schematów blokowych&lt;br /&gt;
-&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=119</id>
		<title>Podstawy informatyki</title>
		<link rel="alternate" type="text/html" href="https://wiki.otwartaedukacja.pl/index.php?title=Podstawy_informatyki&amp;diff=119"/>
		<updated>2022-09-25T05:50:29Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;PODSTAWY INFORMATYKI&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Część I: Podstawowe pojęcia ==&lt;br /&gt;
* Moduł 1.1 [[Algorytm – program – system]]&lt;br /&gt;
* Moduł 1.2 [[Uczymy się myśleć abstrakcyjnie]]&lt;br /&gt;
* Moduł 1.3 [[Filozoficznie o programach komputerowych]] (dla humanistów i pasjonatów)&lt;br /&gt;
* Moduł 1.4 [[Procesor i język maszynowy - wprowadzenie]] (dla inżynierów i techników)&lt;br /&gt;
* Moduł 1.5 [[Logika i instrukcje warunkowe]]&lt;br /&gt;
&lt;br /&gt;
== Część II: Algorytmy i języki programowania ==&lt;br /&gt;
* Moduł 2.1 [[Programy a algorytmy]]&lt;br /&gt;
* Moduł 2.2 [[Implementacja algorytmów]]&lt;br /&gt;
* Moduł 2.3 [[Elementy językozawstwa dla programistów]] (poziom zaawansowany)&lt;br /&gt;
&lt;br /&gt;
== Część III: Systematyka ==&lt;br /&gt;
* Moduł 3.1. [[Różnorodność struktur programów]]&lt;br /&gt;
&lt;br /&gt;
== Część IV: Projekty ==&lt;br /&gt;
* Moduł 4.1 [[Projekt &amp;quot;Ściąga&amp;quot;]] (poziom gimnazjum)&lt;br /&gt;
&lt;br /&gt;
== Ważne strony ==&lt;br /&gt;
* [//leanpub.com/pyprog leanpub.com/pyprog] - Podręcznik programowania w Pythonie&lt;br /&gt;
* [//python.otwartaedukacja.pl/ python.otwartaedukacja.pl] - przykłady z podręcznika&lt;br /&gt;
* [//bryk.otwartaedukacja.pl bryk.otwartaedukacja.pl] - program &amp;quot;ściąga&amp;quot;....&lt;br /&gt;
&lt;br /&gt;
* [//elearning.otwartaedukacja.pl/ elearning.otwartaedukacja.pl] - &#039;&#039;&#039;E-learning&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Używane programy edukacyjne ==&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/hanoi/ otwartaedukacja.pl/programowanie/hanoi/] - programowanie łamigłówki Wieże Hanoi&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/bl/code/ otwartaedukacja.pl/programowanie/bl/code] - układanie programów z bloczków&lt;br /&gt;
* [//otwartaedukacja.pl/programowanie/schematy/ otwartaedukacja.pl/programowanie/schematy] - rysowanie schematów blokowych&lt;br /&gt;
-&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>