Różnice między wybraną wersją a wersją aktualną.
Poprzednia rewizja po obu stronachPoprzednia wersjaNowa wersja | Poprzednia wersja | ||
notatki:programowanie_liniowe [2025/05/16 18:25] – [Rozwiązanie w Pythonie (biblioteka `PuLP`)] administrator | notatki:programowanie_liniowe [2025/05/16 19:26] (aktualna) – administrator | ||
---|---|---|---|
Linia 193: | Linia 193: | ||
* Rajstopy grube: **4,00 zł / para**. | * Rajstopy grube: **4,00 zł / para**. | ||
- | \==== Zmienna decyzyjna ==== | + | ==== Zmienna decyzyjna ==== |
Niech: | Niech: | ||
Linia 659: | Linia 659: | ||
+ | ====== Przykład Minimalizacyjny Ogrzewanie pomieszczeń ====== | ||
+ | Do ogrzania dwóch pomieszczeń o początkowej temperaturze 0°C można używać dwóch źródeł ciepła: węgla i koksu. Każde z tych paliw wpływa inaczej na temperaturę w pomieszczeniach, | ||
+ | |||
+ | ===== Dane wejściowe ===== | ||
+ | Początkowa temperatura w obu pomieszczeniach: | ||
+ | Minimalne wymagane temperatury: | ||
+ | * Pomieszczenie 1: co najmniej 180°C | ||
+ | * Pomieszczenie 2: co najmniej 200°C | ||
+ | fekt spalania: | ||
+ | **1 kg węgla**: | ||
+ | * Pomieszczenie 1: +30°C | ||
+ | * Pomieszczenie 2: +20°C | ||
+ | **1 kg koksu**: | ||
+ | * Pomieszczenie 1: +10°C | ||
+ | * Pomieszczenie 2: +20°C | ||
+ | Koszty: | ||
+ | * 1 tona węgla: 500 zł → 1 kg = 0,50 zł | ||
+ | * 1 tona koksu: 300 zł → 1 kg = 0,30 zł | ||
+ | |||
+ | ===== Zmienne decyzyjne ===== | ||
+ | * $ x $ – liczba **kg węgla** do spalenia | ||
+ | * $ y $ – liczba **kg koksu** do spalenia | ||
+ | |||
+ | ===== Funkcja celu ===== | ||
+ | Minimalizacja łącznego kosztu ogrzewania: | ||
+ | $$ | ||
+ | \min Z = 0.50x + 0.30y | ||
+ | $$ | ||
+ | |||
+ | ===== Ograniczenia ===== | ||
+ | Temperatury muszą być osiągnięte lub przekroczone: | ||
+ | |||
+ | * Dla pierwszego pomieszczenia: | ||
+ | $$ | ||
+ | 30x + 10y \geq 180 | ||
+ | $$ | ||
+ | |||
+ | * Dla drugiego pomieszczenia: | ||
+ | $$ | ||
+ | 20x + 20y \geq 200 | ||
+ | $$ | ||
+ | |||
+ | * Dodatkowo, nie możemy spalać ujemnych ilości paliwa: | ||
+ | $$ | ||
+ | x \geq 0,\quad y \geq 0 | ||
+ | $$ | ||
+ | |||
+ | ===== Cel ===== | ||
+ | Wyznaczyć minimalne ilości węgla $ x $ i koksu $ y $, które pozwolą uzyskać wymaganą temperaturę w obu pomieszczeniach przy **najniższym koszcie ogrzewania**. | ||
+ | |||
+ | ===== Rozwiązanie ===== | ||
+ | Rozwiązanie można uzyskać za pomocą: | ||
+ | * arkusza kalkulacyjnego (Excel: dodając Solver), | ||
+ | * programowania liniowego w Pythonie (np. z użyciem biblioteki PuLP), | ||
+ | * metody graficznej (jeśli szukamy wizualnego zrozumienia dla 2 zmiennych). | ||
+ | |||
+ | ==== Rozwiązanie w Pythonie (biblioteka `PuLP`) ==== | ||
+ | |||
+ | Python oferuje bibliotekę `PuLP`, która umożliwia tworzenie i rozwiązywanie problemów programowania liniowego. | ||
+ | |||
+ | === Przykładowy kod: === | ||
+ | |||
+ | <code python> | ||
+ | from pulp import LpProblem, LpVariable, LpMinimize, LpStatus, value | ||
+ | |||
+ | # Tworzenie modelu | ||
+ | model = LpProblem(" | ||
+ | |||
+ | # Zmienne decyzyjne: kg węgla (x), kg koksu (y) | ||
+ | x = LpVariable(" | ||
+ | y = LpVariable(" | ||
+ | |||
+ | # Funkcja celu: minimalizacja kosztów | ||
+ | model += 0.50 * x + 0.30 * y, " | ||
+ | |||
+ | # Ograniczenia temperatury | ||
+ | model += 30 * x + 10 * y >= 180, " | ||
+ | model += 20 * x + 20 * y >= 200, " | ||
+ | |||
+ | # Rozwiązanie | ||
+ | model.solve() | ||
+ | |||
+ | # Wyniki | ||
+ | print(" | ||
+ | print(" | ||
+ | print(" | ||
+ | print(" | ||
+ | |||
+ | |||
+ | </ | ||
+ | |||
+ | === Wynik: === | ||
+ | < | ||
+ | Status: Optimal | ||
+ | Węgiel (kg): 4.0 | ||
+ | Koks (kg): 6.0 | ||
+ | Minimalny koszt (zł): 3.8 | ||
+ | </ | ||
+ | |||
+ | ====== Problem transportowy - Transport mieszanki soli i piasku ====== | ||
+ | |||
+ | Miasto musi w okresie zimowym dostarczyć mieszankę soli i piasku z dwóch składnic do czterech dzielnic. Celem jest ustalenie takiego planu transportu, który **zaspokoi zapotrzebowanie wszystkich dzielnic** przy **najniższym możliwym koszcie transportu**. | ||
+ | |||
+ | ===== Dane wejściowe ===== | ||
+ | * Miasto dysponuje **dwiema składnicami** materiału. | ||
+ | * Materiał musi być rozwieziony do **czterech dzielnic**. | ||
+ | * Każda dzielnica ma określone **zapotrzebowanie na mieszankę (w tonach)**. | ||
+ | * Każda składnica ma ograniczoną **maksymalną ilość materiału, jaką może dostarczyć**. | ||
+ | * Koszty transportu (w zł/t) różnią się w zależności od trasy (składnica–dzielnica). | ||
+ | |||
+ | ==== Tabela kosztów transportu i zapotrzebowań ==== | ||
+ | |||
+ | ^ Dzielnica ^ Składnica 1 (zł/t) ^ Składnica 2 (zł/t) ^ Zapotrzebowanie (t) ^ | ||
+ | | 1 | 2.00 | 4.00 | 300 | | ||
+ | | 2 | 3.00 | 3.50 | 450 | | ||
+ | | 3 | 1.50 | 2.50 | 500 | | ||
+ | | 4 | 2.50 | 3.00 | 350 | | ||
+ | |||
+ | ==== Pojemności składnic ==== | ||
+ | |||
+ | * Składnica 1: **900 ton** | ||
+ | * Składnica 2: **750 ton** | ||
+ | |||
+ | ===== Zmienne decyzyjne ===== | ||
+ | Niech: | ||
+ | $x_{ij}$ – ilość ton mieszanki przetransportowanej ze składnicy $i$ do dzielnicy $j$, | ||
+ | gdzie $i \in \{1, 2\}$ i $j \in \{1, 2, 3, 4\}$. | ||
+ | |||
+ | ===== Funkcja celu ===== | ||
+ | Minimalizacja całkowitego kosztu transportu: | ||
+ | |||
+ | $$ | ||
+ | Z = \min \sum_{i=1}^{2} \sum_{j=1}^{4} c_{ij} \cdot x_{ij} | ||
+ | $$ | ||
+ | |||
+ | Gdzie $c_{ij}$ to koszt transportu 1 tony ze składnicy $i$ do dzielnicy $j$. | ||
+ | |||
+ | ===== Ograniczenia ===== | ||
+ | **Pojemności składnic: | ||
+ | |||
+ | $$ | ||
+ | x_{11} + x_{12} + x_{13} + x_{14} \leq 900 \\ | ||
+ | x_{21} + x_{22} + x_{23} + x_{24} \leq 750 | ||
+ | $$ | ||
+ | |||
+ | **Zapotrzebowanie dzielnic:** | ||
+ | |||
+ | $$ | ||
+ | x_{11} + x_{21} = 300 \\ | ||
+ | x_{12} + x_{22} = 450 \\ | ||
+ | x_{13} + x_{23} = 500 \\ | ||
+ | x_{14} + x_{24} = 350 | ||
+ | $$ | ||
+ | |||
+ | **Nieujemność zmiennych: | ||
+ | |||
+ | $$ | ||
+ | x_{ij} \geq 0 \quad \text{dla każdego } i, j | ||
+ | $$ | ||
+ | |||
+ | ===== Cel ===== | ||
+ | Wyznaczyć optymalne wartości $x_{ij}$, aby **całkowity koszt transportu był jak najmniejszy**, | ||
+ | |||
+ | ===== Uwagi ===== | ||
+ | To klasyczny przykład tzw. **problemu transportowego** w programowaniu liniowym. Rozwiązanie można znaleźć m.in. za pomocą: | ||
+ | * metody potencjałów (ręcznie lub w arkuszu kalkulacyjnym), | ||
+ | * programowania liniowego w Pythonie (np. `PuLP`, `scipy.optimize`), | ||
+ | * narzędzi takich jak Excel Solver. | ||
+ | |||
+ | ==== Rozwiązanie w Pythonie (biblioteka `PuLP`) ==== | ||
+ | |||
+ | Python oferuje bibliotekę `PuLP`, która umożliwia tworzenie i rozwiązywanie problemów programowania liniowego. | ||
+ | |||
+ | === Przykładowy kod: === | ||
+ | |||
+ | <code python> | ||
+ | import pulp | ||
+ | |||
+ | # Tworzymy problem minimalizacji kosztów | ||
+ | problem = pulp.LpProblem(" | ||
+ | |||
+ | # Składnice i dzielnice | ||
+ | skladnice = [1, 2] | ||
+ | dzielnice = [1, 2, 3, 4] | ||
+ | |||
+ | # Koszty transportu c_ij (słownik) | ||
+ | koszty = { | ||
+ | (1, 1): 2.00, (1, 2): 3.00, (1, 3): 1.50, (1, 4): 2.50, | ||
+ | (2, 1): 4.00, (2, 2): 3.50, (2, 3): 2.50, (2, 4): 3.00 | ||
+ | } | ||
+ | |||
+ | # Zapotrzebowania dzielnic | ||
+ | zapotrzebowanie = {1: 300, 2: 450, 3: 500, 4: 350} | ||
+ | |||
+ | # Pojemności składnic | ||
+ | pojemnosc = {1: 900, 2: 750} | ||
+ | |||
+ | # Zmienne decyzyjne x_ij: ilość materiału z i-tej składnicy do j-tej dzielnicy | ||
+ | x = pulp.LpVariable.dicts(" | ||
+ | lowBound=0, cat=' | ||
+ | |||
+ | # Funkcja celu: minimalizacja kosztu transportu | ||
+ | problem += pulp.lpSum(koszty[i, | ||
+ | |||
+ | # Ograniczenia pojemności składnic | ||
+ | for i in skladnice: | ||
+ | problem += pulp.lpSum(x[i, | ||
+ | |||
+ | # Ograniczenia zapotrzebowania dzielnic | ||
+ | for j in dzielnice: | ||
+ | problem += pulp.lpSum(x[i, | ||
+ | |||
+ | # Rozwiązanie problemu | ||
+ | problem.solve() | ||
+ | |||
+ | # Wyniki | ||
+ | print(" | ||
+ | print(" | ||
+ | |||
+ | for i in skladnice: | ||
+ | for j in dzielnice: | ||
+ | print(f" | ||
+ | |||
+ | </ | ||
+ | === Wynik === | ||
+ | |||
+ | < | ||
+ | Status: Optimal | ||
+ | Minimalny koszt transportu: 3925.0 zł | ||
+ | x(1,1) = 300.0 t | ||
+ | x(1,2) = 0.0 t | ||
+ | x(1,3) = 500.0 t | ||
+ | x(1,4) = 100.0 t | ||
+ | x(2,1) = 0.0 t | ||
+ | x(2,2) = 450.0 t | ||
+ | x(2,3) = 0.0 t | ||
+ | x(2,4) = 250.0 t | ||
+ | </ | ||
+ | ====== Transport truskawek ====== | ||
+ | |||
+ | W sezonie letnim truskawki zbierane przez plantatorów muszą być dostarczone do punktów skupu. Każdy z plantatorów dysponuje określoną ilością truskawek (w tonach), a każdy punkt skupu ma sprecyzowane zapotrzebowanie. Celem jest tak zaplanować transport, aby **pokryć zapotrzebowanie punktów skupu przy minimalnych kosztach transportu**. | ||
+ | |||
+ | ===== Dane wejściowe ===== | ||
+ | |||
+ | **Dostępność truskawek u plantatorów: | ||
+ | * Plantator I: 12 tony | ||
+ | * Plantator II: 30 ton | ||
+ | * Plantator III: 6 ton | ||
+ | |||
+ | **Zapotrzebowanie punktów skupu:** | ||
+ | * Punkt A: 18 ton | ||
+ | * Punkt B: 12 ton | ||
+ | * Punkt C: 18 ton | ||
+ | |||
+ | ==== Tabela kosztów transportu (w zł za 1 tonę) ==== | ||
+ | |||
+ | ^ Plantator ↓ / Punkt → ^ A ^ B ^ C ^ | ||
+ | | I | 80 | 160 | 160 | | ||
+ | | II |240 | 320 | 80 | | ||
+ | | III | 32 | 160 | 32 | | ||
+ | |||
+ | ===== Zmienne decyzyjne ===== | ||
+ | Niech: | ||
+ | * $x_{ij}$ – ilość ton truskawek transportowana od plantatora $i$ do punktu skupu $j$ | ||
+ | gdzie $i \in \{1,2,3\}$ (plantatorzy) i $j \in \{A,B,C\}$ (punkty skupu) | ||
+ | |||
+ | ===== Funkcja celu ===== | ||
+ | Minimalizacja całkowitego kosztu transportu: | ||
+ | |||
+ | $$ | ||
+ | Z = \min \sum_{i=1}^{3} \sum_{j \in \{A,B,C\}} c_{ij} \cdot x_{ij} | ||
+ | $$ | ||
+ | |||
+ | Gdzie $c_{ij}$ to koszt transportu 1 tony z plantatora $i$ do punktu skupu $j$. | ||
+ | |||
+ | ===== Ograniczenia ===== | ||
+ | |||
+ | **Dostępność u plantatorów: | ||
+ | $$ | ||
+ | x_{1A} + x_{1B} + x_{1C} \leq 24 \\ | ||
+ | x_{2A} + x_{2B} + x_{2C} \leq 30 \\ | ||
+ | x_{3A} + x_{3B} + x_{3C} \leq 6 | ||
+ | $$ | ||
+ | |||
+ | **Zapotrzebowanie punktów skupu:** | ||
+ | $$ | ||
+ | x_{1A} + x_{2A} + x_{3A} = 18 \\ | ||
+ | x_{1B} + x_{2B} + x_{3B} = 12 \\ | ||
+ | x_{1C} + x_{2C} + x_{3C} = 18 | ||
+ | $$ | ||
+ | |||
+ | **Nieujemność zmiennych: | ||
+ | $$ | ||
+ | x_{ij} \geq 0 \quad \text{dla każdego } i,j | ||
+ | $$ | ||
+ | |||
+ | ===== Cel ===== | ||
+ | Wyznaczyć optymalne wartości zmiennych $x_{ij}$, aby: | ||
+ | * Całkowity koszt transportu był **najniższy** | ||
+ | * Spełnione zostały ograniczenia dostępności i zapotrzebowania | ||
+ | |||
+ | ===== Uwagi ===== | ||
+ | To klasyczny **problem transportowy** możliwy do rozwiązania z użyciem: | ||
+ | * **Python + PuLP** | ||
+ | * **Excel Solver** | ||
+ | * **Metody północno-zachodniego narożnika + metoda potencjałów** (dla zadań ręcznych) | ||
+ | === Kod === | ||
+ | <code python> | ||
+ | from pulp import LpProblem, LpVariable, LpMinimize, LpStatus, lpSum, value | ||
+ | |||
+ | # Model | ||
+ | model = LpProblem(" | ||
+ | |||
+ | # Plantatorzy i punkty skupu | ||
+ | plantatorzy = [' | ||
+ | punkty_skupu = [' | ||
+ | |||
+ | # Koszty transportu (zł/t) | ||
+ | koszty = { | ||
+ | (' | ||
+ | (' | ||
+ | (' | ||
+ | } | ||
+ | |||
+ | # Ilość dostępnych truskawek (t) | ||
+ | dostawy = {' | ||
+ | |||
+ | # Zapotrzebowanie punktów skupu (t) | ||
+ | zapotrzebowanie = {' | ||
+ | |||
+ | # Zmienne decyzyjne | ||
+ | x = { | ||
+ | (p, s): LpVariable(f" | ||
+ | for p in plantatorzy for s in punkty_skupu | ||
+ | } | ||
+ | |||
+ | # Funkcja celu: minimalizacja kosztów transportu | ||
+ | model += lpSum(koszty[p, | ||
+ | |||
+ | # Ograniczenia dostępności plantatorów | ||
+ | for p in plantatorzy: | ||
+ | model += lpSum(x[p, s] for s in punkty_skupu) <= dostawy[p], f" | ||
+ | |||
+ | # Ograniczenia zapotrzebowania punktów skupu | ||
+ | for s in punkty_skupu: | ||
+ | model += lpSum(x[p, s] for p in plantatorzy) == zapotrzebowanie[s], | ||
+ | |||
+ | # Rozwiązanie | ||
+ | model.solve() | ||
+ | |||
+ | # Wyniki | ||
+ | print(" | ||
+ | print(" | ||
+ | print(" | ||
+ | for p in plantatorzy: | ||
+ | for s in punkty_skupu: | ||
+ | print(f" | ||
+ | </ | ||
+ | === Wynik: === | ||
+ | < | ||
+ | Status: Optimal | ||
+ | Minimalny koszt transportu (zł): 6432.0 | ||
+ | |||
+ | Wielkości dostaw (t): | ||
+ | P1 -> A: 0.0 t | ||
+ | P1 -> B: 12.0 t | ||
+ | P1 -> C: 0.0 t | ||
+ | P2 -> A: 12.0 t | ||
+ | P2 -> B: 0.0 t | ||
+ | P2 -> C: 18.0 t | ||
+ | P3 -> A: 6.0 t | ||
+ | P3 -> B: 0.0 t | ||
+ | P3 -> C: 0.0 t | ||
+ | </ |