mirror of
https://github.com/kuhyx/WUT_Computer_Science.git
synced 2026-11-10 23:07:09 +01:00
749 findings across six labs and two projects. The mechanical half was scripted; everything below is what the scripts got wrong or could not do, and how it was caught. Three regressions I introduced and then found by RUNNING the code, not by reading it: - Converting print() to logger.info() made the programs SILENT. logging's last-resort handler only emits WARNING and above, so with no basicConfig call `lab2/main.py -t 1 1` printed nothing at all. Fifteen files across the repo now configure logging where they log. - The same conversion dropped `end=""`. lab2 draws its board one square at a time and lab1 draws the maze one cell at a time; both came out one glyph per line. Those thirteen call sites are sys.stdout.write again, and the rendered board now diffs byte-identically against the pre-change output. - The B007 fix renamed `col` to `_col` in the FIRST loop it matched, which was print_letters -- where the variable IS used. That would have been a NameError on the first call. And one the scripts caused silently: annotating 110 signatures dropped the DEFAULT VALUES from 22 of them, so `preprocessing(a, b, USER_THRESHOLD, ANIME_THRESHOLD)` would have raised TypeError. Every signature is now diffed against the pre-change version, name by name and default by default: zero mismatches. Real defects the lint surfaced: - `alpha_beta` ended with an unreachable `return None` that violated its own return type. Its maximising and minimising halves were mirror images, so they are one `_search_branch` now (C901 11 -> ok). - `get_data`'s `gpu` switch, `predict`'s `auto`, `create_model`'s `rows_number` and five of `preprocess_model_predict`'s fifteen parameters were never read. Gone, with their call sites. - np.random.* -> Generator throughout (NPY002), `.values` -> `.to_numpy()`, `datetime.now()` with a tzinfo, `inplace=True` removed, `except:` given a type, `random.*` -> `SystemRandom` (S311). - print_board's three nested helpers became methods (C901 17 -> ok); user_input's nine-branch if-ladder became a table (C901 12 -> ok). Verification, all by running: lab1 `-t` and lab2 `-t 1 1` produce output byte-identical to the pre-change code; lab2's rendered 8x8 board diffs clean; lab3's argument parsing returns the same dict for the same argv; lab4 fails identically before and after (no sklearn here). Also included: the logging configuration for NLP, MOM and ECRYPT_PROJECT, which had the same silence bug. Repo-wide: 2,775 findings -> 1,883. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0172dj34FDpao6wsix8ZuCzE
169 lines
5.0 KiB
Python
Executable File
169 lines
5.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Bi-criteria distribution model for MOM project 3 (data set 1.6).
|
|
|
|
A PuLP transport problem over two factories, four warehouses and six
|
|
customers, minimising distribution cost while maximising customer
|
|
satisfaction. It is solved three ways: once on cost alone, then swept over
|
|
alpha in 0.0..1.0 to trace the efficient frontier, then at the five
|
|
weightings the report tabulates.
|
|
"""
|
|
|
|
import logging
|
|
import sys
|
|
|
|
import pulp
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logging.basicConfig(format="%(message)s", level=logging.INFO)
|
|
|
|
# alpha runs over 0.0, 0.1 ... 1.0, so eleven steps.
|
|
ALPHA_STEPS = 11
|
|
|
|
# Create a problem variable:
|
|
model = pulp.LpProblem("Optimal_Distribution", pulp.LpMinimize)
|
|
# Zdefiniowanie dostawcy (fabryki and magazyny)
|
|
fabryki = ["F1", "F2"]
|
|
magazyny = ["M1", "M2", "M3", "M4"]
|
|
dostawcy = fabryki + magazyny # Combining both lists
|
|
# Zdefiniowanie klientów
|
|
klienci = ["K1", "K2", "K3", "K4", "K5", "K6"]
|
|
koszt = {
|
|
"F1": {
|
|
"M1": 0.3,
|
|
"M2": 0.5,
|
|
"M3": 1.2,
|
|
"M4": 0.8,
|
|
"K1": 1.2,
|
|
"K2": 999,
|
|
"K3": 1.2,
|
|
"K4": 2.0,
|
|
"K5": 999,
|
|
"K6": 1.1,
|
|
},
|
|
"F2": {
|
|
"M1": 999,
|
|
"M2": 0.4,
|
|
"M3": 0.5,
|
|
"M4": 0.3,
|
|
"K1": 1.8,
|
|
"K2": 999,
|
|
"K3": 999,
|
|
"K4": 999,
|
|
"K5": 999,
|
|
"K6": 999,
|
|
},
|
|
"M1": {"K1": 999, "K2": 1.2, "K3": 0.2, "K4": 1.7, "K5": 999, "K6": 2.0},
|
|
"M2": {"K1": 1.4, "K2": 0.3, "K3": 1.8, "K4": 1.3, "K5": 0.5, "K6": 999},
|
|
"M3": {"K1": 999, "K2": 1.3, "K3": 2.0, "K4": 999, "K5": 0.3, "K6": 1.4},
|
|
"M4": {"K1": 999, "K2": 999, "K3": 0.4, "K4": 2.0, "K5": 0.5, "K6": 1.6},
|
|
}
|
|
P = pulp.LpVariable.dicts(
|
|
"P", [(i, j) for i in dostawcy for j in klienci], cat="Binary"
|
|
)
|
|
maksymalne_zamowienie = 60
|
|
poziom_satysfakcji = {
|
|
"K1": 50 / maksymalne_zamowienie,
|
|
"K2": 10 / maksymalne_zamowienie,
|
|
"K3": 40 / maksymalne_zamowienie,
|
|
"K4": 35 / maksymalne_zamowienie,
|
|
"K5": 60 / maksymalne_zamowienie,
|
|
"K6": 20 / maksymalne_zamowienie,
|
|
}
|
|
preferencja_klienta = {
|
|
"K1": ["F2"],
|
|
"K2": ["M1"],
|
|
"K3": ["M2", "M3"],
|
|
"K4": ["F1"],
|
|
"K5": [],
|
|
"K6": ["M3", "M4"],
|
|
}
|
|
suma_satysfakcji = pulp.lpSum(
|
|
[poziom_satysfakcji[j] * P[(i, j)] for i in dostawcy for j in klienci]
|
|
)
|
|
|
|
|
|
# Zmienne decyzyjne
|
|
x = pulp.LpVariable.dicts(
|
|
"x", [(i, j) for i in dostawcy for j in klienci], lowBound=0, cat="Integer"
|
|
)
|
|
y = pulp.LpVariable.dicts(
|
|
"y", [(i, k) for i in fabryki for k in magazyny], lowBound=0, cat="Integer"
|
|
)
|
|
# Funkcje Celu
|
|
koszt_dystrybucji = pulp.lpSum(
|
|
[koszt[i][j] * x[(i, j)] for i in dostawcy for j in klienci]
|
|
)
|
|
koszt_magazynowania = pulp.lpSum(
|
|
[koszt[i][k] * y[(i, k)] for i in fabryki for k in magazyny]
|
|
)
|
|
alpha = 0.5
|
|
beta = 0.5
|
|
model += alpha * (koszt_dystrybucji + koszt_magazynowania) - beta * suma_satysfakcji
|
|
mozliwosci_fabryki = {"F1": 150, "F2": 200}
|
|
pojemnosc_magazynu = {"M1": 70, "M2": 50, "M3": 100, "M4": 40}
|
|
zamowienia_klientow = {"K1": 50, "K2": 10, "K3": 40, "K4": 35, "K5": 60, "K6": 20}
|
|
for i in fabryki:
|
|
model += (
|
|
pulp.lpSum([x[(i, j)] for j in klienci] + [y[(i, k)] for k in magazyny])
|
|
<= mozliwosci_fabryki[i]
|
|
)
|
|
|
|
for k in magazyny:
|
|
model += pulp.lpSum([x[(k, j)] for j in klienci]) <= pojemnosc_magazynu[k]
|
|
|
|
for j in klienci:
|
|
model += pulp.lpSum([x[(i, j)] for i in dostawcy]) == zamowienia_klientow[j]
|
|
|
|
model.solve()
|
|
for v in model.variables():
|
|
logger.info("%s = %s", v.name, v.varValue)
|
|
|
|
koszt_wyniki = []
|
|
zadowolenie_wyniki = []
|
|
wyniki_funkcji = []
|
|
maksymalny_wynik = 0
|
|
for step in range(ALPHA_STEPS):
|
|
alpha = step / 10.0
|
|
beta = (ALPHA_STEPS - 1 - step + sys.float_info.epsilon) / 10.0
|
|
# Update objective function
|
|
model.objective = alpha * koszt_dystrybucji - beta * suma_satysfakcji
|
|
|
|
# Solve the model
|
|
model.solve()
|
|
logger.info("%s", alpha)
|
|
|
|
# Record the wyniki
|
|
calkowity_koszt = pulp.value(koszt_dystrybucji)
|
|
calkowite_zadowolenie = pulp.value(suma_satysfakcji)
|
|
wynik_funkcji = pulp.value(alpha * koszt_dystrybucji - beta * suma_satysfakcji)
|
|
koszt_wyniki.append(calkowity_koszt)
|
|
zadowolenie_wyniki.append(calkowite_zadowolenie)
|
|
maksymalny_wynik = max(maksymalny_wynik, wynik_funkcji)
|
|
wyniki_funkcji.append(wynik_funkcji)
|
|
|
|
logger.info("maksymalny_wynik %s %s", maksymalny_wynik, wyniki_funkcji)
|
|
|
|
# Pseudo-code, assuming model setup as previously discussed
|
|
scemariusze = [
|
|
(1.0, sys.float_info.epsilon),
|
|
(0.8, 0.2),
|
|
(0.5, 0.5),
|
|
(0.2, 0.8),
|
|
(sys.float_info.epsilon, 1.0),
|
|
]
|
|
wyniki = []
|
|
|
|
for alpha, beta in scemariusze:
|
|
model.objective = alpha * koszt_dystrybucji - beta * suma_satysfakcji
|
|
|
|
model.solve()
|
|
|
|
calkowity_koszt = pulp.value(koszt_dystrybucji)
|
|
calkowite_zadowolenie = pulp.value(suma_satysfakcji)
|
|
wyniki.append((alpha, beta, calkowity_koszt, calkowite_zadowolenie))
|
|
|
|
for idx, (alpha, beta, koszt, zadowolenie) in enumerate(wyniki):
|
|
logger.info("Krok %d:", idx + 1)
|
|
logger.info(" koszt: %s, zadowolenie: %s", alpha, beta)
|
|
logger.info(" Calkowity koszt: %s, zadowolenie klienta: %s\n", koszt, zadowolenie)
|