Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python" (Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch Version_03 (eingefroren) verwaltet und Version_04/ ignoriert. Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist. Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise, 325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren, 25 Notebooks, PDF mit 715 Seiten. Zusaetzlich in diesem Commit: * pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api, figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt unveraendert daneben bestehen. ortools steht in der Grundausstattung, highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der schlanken Installation gar nicht erst auftreten. * Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo steht in requirements.txt, wird aber von keinem Programm importiert, sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in [empfehlungen]). * NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen. * PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den tatsaechlichen aus erzeuge_titelseite.py korrigiert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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)
|