#!/usr/bin/env python3 # erzeuge_solverwahl_diagramme.py """ Erzeugt die beiden Entscheidungs-Flussdiagramme "Welches Werkzeug passt zu meinem Problem?" fuer die Auftakte von Teil II und Teil III: bilder_04/teil2_solverwahl.svg / .png deterministische Verfahren bilder_04/teil3_solverwahl.svg / .png Nichtlinearitaet und Unsicherheit Beide entstehen mit Graphviz. Die Farben folgen der Buchpalette (Indigo, Cyan, Violett, Gruen, Amber), die Kastenform codiert die Rolle: Raute = Frage, abgerundeter Kasten = Empfehlung. Aufruf (aus dem Repository-Wurzelverzeichnis): python3 bilder_04/erzeuge_solverwahl_diagramme.py Benoetigt: graphviz (Python-Paket) und das Kommandozeilenwerkzeug 'dot' """ from __future__ import annotations import os import graphviz BASIS = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BILDER = os.path.join(BASIS, "bilder_04") INDIGO, CYAN, VIOLETT, GRUEN, AMBER = ( "#4338ca", "#0891b2", "#7c3aed", "#059669", "#b45309") TINT = {INDIGO: "#eef2ff", CYAN: "#ecfeff", VIOLETT: "#f5f3ff", GRUEN: "#ecfdf5", AMBER: "#fffbeb"} def neuer_graph(titel: str) -> graphviz.Digraph: punkt = graphviz.Digraph(format="svg") punkt.attr(rankdir="TB", splines="polyline", nodesep="0.35", ranksep="0.45", fontname="DejaVu Sans", label=titel, labelloc="t", fontsize="13", bgcolor="transparent") punkt.attr("node", fontname="DejaVu Sans", fontsize="10") punkt.attr("edge", fontname="DejaVu Sans", fontsize="9", color="#5c6380") return punkt def frage(punkt: graphviz.Digraph, name: str, text: str, farbe: str = INDIGO) -> None: punkt.node(name, text, shape="diamond", style="filled", fillcolor=TINT[farbe], color=farbe, penwidth="1.6", margin="0.08,0.02") def empfehlung(punkt: graphviz.Digraph, name: str, text: str, farbe: str) -> None: punkt.node(name, text, shape="box", style="filled,rounded", fillcolor=TINT[farbe], color=farbe, penwidth="2.0", margin="0.16,0.09") def schreibe(punkt: graphviz.Digraph, name: str) -> None: os.makedirs(BILDER, exist_ok=True) for endung in ("svg", "png"): punkt.format = endung pfad = punkt.render(os.path.join(BILDER, name), cleanup=True) print(f"geschrieben: {pfad}") # --- Teil II: deterministische Optimierung ---------------------------------- def teil2() -> None: punkt = neuer_graph("Welches Werkzeug passt zu meinem Problem? (Teil II)") frage(punkt, "f1", "Fahrzeuge, Depots,\nZeitfenster?") frage(punkt, "f2", "Ja/Nein-Entscheidungen,\nZuordnungen, Reihenfolgen?") frage(punkt, "f3", "Zielfunktion und alle\nNebenbedingungen linear?") frage(punkt, "f4", "Logische Regeln\n(wenn-dann, entweder-oder)\noder Zeitplanung?") frage(punkt, "f5", "Nur Fluss oder\nZuordnung im Netzwerk?") empfehlung(punkt, "routing", "OR-Tools Routing\n(Kapitel Graphen)", AMBER) empfehlung(punkt, "cpsat", "CP-SAT\n(Kapitel CP-SAT)", VIOLETT) empfehlung(punkt, "milp", "MILP: HiGHS / CP-SAT\n(Kapitel MILP)", CYAN) empfehlung(punkt, "netz", "Spezialalgorithmus:\nMin-Cost-Flow,\nUngarische Methode", GRUEN) empfehlung(punkt, "lp", "LP: scipy.linprog\noder highspy\n(Kapitel LP)", INDIGO) empfehlung(punkt, "teil3", "weiter in Teil III", AMBER) punkt.edge("f1", "routing", "ja") punkt.edge("f1", "f2", "nein") punkt.edge("f2", "f4", "ja") punkt.edge("f2", "f3", "nein") punkt.edge("f4", "cpsat", "ja") punkt.edge("f4", "milp", "nein\n(Fixkosten,\nKardinalität)") punkt.edge("f3", "f5", "ja") punkt.edge("f3", "teil3", "nein") punkt.edge("f5", "netz", "ja") punkt.edge("f5", "lp", "nein") schreibe(punkt, "teil2_solverwahl") # --- Teil III: Nichtlinearitaet, Unsicherheit, Dynamik ---------------------- def teil3() -> None: punkt = neuer_graph("Welches Werkzeug passt zu meinem Problem? (Teil III)") frage(punkt, "g1", "Sind die Daten sicher\nbekannt?") frage(punkt, "g2", "Entscheidung fällt in\nmehreren Stufen\nüber die Zeit?") frage(punkt, "g3", "Wahrscheinlichkeiten\nbekannt?") frage(punkt, "g4", "Zielfunktion konvex?\n(Quadrate, Normen,\nlog/exp konvex kombiniert)") frage(punkt, "g5", "Quadratisch mit\nlinearen Nebenbedingungen?") empfehlung(punkt, "dp", "Dynamische Programmierung\n(Bellman)", AMBER) empfehlung(punkt, "stoch", "Zweistufige stochastische\nOptimierung, Szenarien", VIOLETT) empfehlung(punkt, "robust", "Robuste Optimierung\n(Worst Case)", VIOLETT) empfehlung(punkt, "qp", "QP über CVXPY\n(OSQP, Clarabel)", CYAN) empfehlung(punkt, "konvex", "CVXPY\n— prüft Konvexität selbst", GRUEN) empfehlung(punkt, "nichtkonvex", "scipy.optimize.minimize\nmit mehreren Startpunkten\n— nur lokales Optimum!", AMBER) punkt.edge("g1", "g4", "ja") punkt.edge("g1", "g2", "nein") punkt.edge("g2", "dp", "ja") punkt.edge("g2", "g3", "nein") punkt.edge("g3", "stoch", "ja") punkt.edge("g3", "robust", "nein,\nnur Bandbreiten") punkt.edge("g4", "g5", "ja") punkt.edge("g4", "nichtkonvex", "nein") punkt.edge("g5", "qp", "ja") punkt.edge("g5", "konvex", "nein") schreibe(punkt, "teil3_solverwahl") if __name__ == "__main__": teil2() teil3()