operations_research/OR_HTML_04/programme/Solver_Wahl.py
dschlueter b7af2f1d9a Version 04 als eigenes Repository
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>
2026-09-08 01:20:09 +02:00

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)