73 lines
3 KiB
Python
73 lines
3 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
|
||
|
|
# Solver_Wahl.py
|
||
|
|
"""
|
||
|
|
Kapitel Oekosystem: Entscheidungshilfe zur Solverwahl.
|
||
|
|
Beantwortet drei Fragen und empfiehlt Bibliothek + Backend.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from dataclasses import dataclass
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class Problem:
|
||
|
|
diskrete_entscheidungen: bool # Ja/Nein-Variablen, Zuordnungen, Reihenfolgen?
|
||
|
|
zielfunktion: str # "linear" | "quadratisch" | "konvex" | "beliebig"
|
||
|
|
routing: bool = False # Fahrzeuge, Depots, Zeitfenster?
|
||
|
|
groesse: str = "klein" # "klein" (<10^3 Var.) | "gross"
|
||
|
|
wiederholte_laeufe: bool = False
|
||
|
|
|
||
|
|
|
||
|
|
def empfehle(p: Problem) -> tuple[str, str, str]:
|
||
|
|
"""Gibt (Bibliothek, Backend, Begründung) zurück."""
|
||
|
|
if p.routing:
|
||
|
|
return ("ortools.constraint_solver (Routing)", "Routing Engine",
|
||
|
|
"Spezialisierte Heuristiken für VRP/TSP schlagen jedes selbstgebaute Modell.")
|
||
|
|
|
||
|
|
if p.diskrete_entscheidungen:
|
||
|
|
if p.zielfunktion in ("linear",) and not p.routing:
|
||
|
|
if p.groesse == "gross":
|
||
|
|
return ("highspy", "HiGHS Branch-and-Cut",
|
||
|
|
"MILP mit ökonomischer Struktur (Fixkosten, Kardinalität).")
|
||
|
|
return ("ortools.sat (CP-SAT)", "CP-SAT",
|
||
|
|
"Logische Regeln und Zuweisungen: CP-SAT propagiert sehr effizient.")
|
||
|
|
return ("ortools.sat (CP-SAT)", "CP-SAT",
|
||
|
|
"Diskrete Struktur dominiert; CP-SAT verarbeitet auch nichtlineare Logik.")
|
||
|
|
|
||
|
|
if p.zielfunktion == "linear":
|
||
|
|
if p.wiederholte_laeufe or p.groesse == "gross":
|
||
|
|
return ("highspy", "HiGHS Dual Simplex",
|
||
|
|
"Modell einmal aufbauen, Parameter ändern, wiederholt lösen.")
|
||
|
|
return ("scipy.optimize.linprog", "HiGHS",
|
||
|
|
"Kleinstes Setup, keine zusätzliche Abhängigkeit.")
|
||
|
|
|
||
|
|
if p.zielfunktion in ("quadratisch", "konvex"):
|
||
|
|
return ("cvxpy", "Clarabel / OSQP",
|
||
|
|
"Konvexität wird automatisch geprüft; Portfolio-Standard.")
|
||
|
|
|
||
|
|
return ("scipy.optimize.minimize", "SLSQP / trust-constr",
|
||
|
|
"Nicht konvex: nur lokales Optimum, Startpunkt variieren und vergleichen!")
|
||
|
|
|
||
|
|
|
||
|
|
BEISPIELE = {
|
||
|
|
"Vertretungsplan Schule": Problem(True, "linear", groesse="klein"),
|
||
|
|
"Produktionsplanung (LP)": Problem(False, "linear", groesse="klein"),
|
||
|
|
"Produktionsplanung, 50k Var.": Problem(False, "linear", groesse="gross"),
|
||
|
|
"Portfolio Markowitz": Problem(False, "quadratisch"),
|
||
|
|
"Portfolio mit max. 5 Titeln": Problem(True, "quadratisch"),
|
||
|
|
"Liefertouren mit Zeitfenstern": Problem(True, "linear", routing=True),
|
||
|
|
"Entropie-Allokation (NLP)": Problem(False, "beliebig"),
|
||
|
|
"Backtest, 60x neu optimieren": Problem(False, "konvex", wiederholte_laeufe=True),
|
||
|
|
}
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
print("=" * 92)
|
||
|
|
print(" SOLVER-EMPFEHLUNG")
|
||
|
|
print("=" * 92)
|
||
|
|
for name, p in BEISPIELE.items():
|
||
|
|
lib, backend, grund = empfehle(p)
|
||
|
|
print(f"\n{name}")
|
||
|
|
print(f" -> Bibliothek: {lib}")
|
||
|
|
print(f" Backend: {backend}")
|
||
|
|
print(f" Grund: {grund}")
|
||
|
|
print("\n" + "=" * 92)
|