#!/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)