kleine Änderungen
This commit is contained in:
parent
0f9c815b86
commit
dc088fa214
47 changed files with 183868 additions and 573 deletions
|
|
@ -107,6 +107,72 @@ def untere_huelle(punkte):
|
|||
return huelle
|
||||
|
||||
|
||||
def tiefste_delle(front, huelle):
|
||||
"""Der unerreichbare Punkt mit dem groessten Abstand zur Huelle.
|
||||
|
||||
Liefert (Punkt, linke Huellenecke, rechte Huellenecke, Abstand). Genau an
|
||||
diesem Punkt ist die Luecke am besten zu sehen, und genau dort wird sie
|
||||
beschriftet - gesucht wird sie, nicht ausgewaehlt.
|
||||
|
||||
Gemessen wird SENKRECHT zur Huellenkante, nicht senkrecht nach oben. Der
|
||||
senkrechte Abstand ist der Abstand eines Punktes zu einer Geraden; der
|
||||
Abstand in y-Richtung haengt dagegen davon ab, welche Zielgroesse man auf
|
||||
die Hochachse legt - bei vertauschten Achsen faende er eine andere Delle."""
|
||||
unerreichbar = [p for p in front if p not in huelle]
|
||||
if not unerreichbar:
|
||||
return None
|
||||
bestes = None
|
||||
for punkt in unerreichbar:
|
||||
for links, rechts in zip(huelle, huelle[1:]):
|
||||
if not links[0] <= punkt[0] <= rechts[0]:
|
||||
continue
|
||||
if rechts[0] == links[0]:
|
||||
continue
|
||||
steigung = (rechts[1] - links[1]) / (rechts[0] - links[0])
|
||||
auf_huelle = links[1] + steigung * (punkt[0] - links[0])
|
||||
abstand = (punkt[1] - auf_huelle) / np.hypot(1.0, steigung)
|
||||
if bestes is None or abstand > bestes[3]:
|
||||
bestes = (punkt, links, rechts, abstand)
|
||||
return bestes
|
||||
|
||||
|
||||
def zeichne_luecke(achse, front, huelle) -> None:
|
||||
"""Warum die gewichtete Summe die Delle nicht erreicht - und was hilft.
|
||||
|
||||
Gezeichnet werden zwei Geraden derselben Steigung: die Tangente an die
|
||||
Huelle und die parallele Gerade durch den unerreichbaren Punkt. Eine
|
||||
gewichtete Summe minimiert genau diese Steigung; sie waehlt also immer die
|
||||
untere der beiden Geraden und damit nie den Punkt darueber. Der
|
||||
waagerechte Strich zeigt die Alternative: eine CO2-Schranke, unter der
|
||||
dieser Punkt der billigste ist - so ist die Front oben ueberhaupt
|
||||
entstanden."""
|
||||
delle = tiefste_delle(front, huelle)
|
||||
if delle is None:
|
||||
return
|
||||
punkt, links, rechts, _abstand = delle
|
||||
steigung = ((rechts[1] - links[1]) / (rechts[0] - links[0])
|
||||
if rechts[0] != links[0] else 0.0)
|
||||
|
||||
x = np.array(achse.get_xlim())
|
||||
achse.plot(x, links[1] + steigung * (x - links[0]), "-", color=INDIGO,
|
||||
linewidth=1.1, alpha=0.75, zorder=1)
|
||||
achse.plot(x, punkt[1] + steigung * (x - punkt[0]), ":", color=AMBER,
|
||||
linewidth=1.6, zorder=2)
|
||||
achse.annotate("dieselbe Steigung, eine Stufe höher —\n"
|
||||
"jede gewichtete Summe nimmt die untere",
|
||||
xy=(punkt[0], punkt[1]), xytext=(12, 26),
|
||||
textcoords="offset points", fontsize=7.5, color=AMBER,
|
||||
zorder=6)
|
||||
|
||||
achse.axhline(punkt[1], color="#059669", linestyle="--", linewidth=1.2,
|
||||
alpha=0.9, zorder=1)
|
||||
achse.annotate(f"ε-Constraint: CO₂ ≤ {punkt[1]:,} kg".replace(",", ".")
|
||||
+ "\nfindet genau diesen Punkt",
|
||||
xy=(x[0], punkt[1]), xytext=(6, -22),
|
||||
textcoords="offset points", fontsize=7.5, color="#059669",
|
||||
zorder=6)
|
||||
|
||||
|
||||
# --- Statische Fassung ------------------------------------------------------
|
||||
|
||||
def zeichne_statisch(front, huelle) -> None:
|
||||
|
|
@ -132,6 +198,9 @@ def zeichne_statisch(front, huelle) -> None:
|
|||
achse.set_xlabel("Transportkosten (EUR)")
|
||||
achse.set_ylabel("CO₂-Ausstoß (kg)")
|
||||
achse.set_title("Pareto-Front: Kosten gegen CO₂", fontsize=11)
|
||||
# Erst jetzt, damit die Geraden die endgueltigen Achsengrenzen benutzen.
|
||||
achse.autoscale(enable=False)
|
||||
zeichne_luecke(achse, front, huelle)
|
||||
achse.grid(linestyle=":", alpha=0.5)
|
||||
for rand in ("top", "right"):
|
||||
achse.spines[rand].set_visible(False)
|
||||
|
|
@ -203,5 +272,49 @@ if __name__ == "__main__":
|
|||
huelle = untere_huelle(front)
|
||||
print(f"Pareto-Punkte: {len(front)}, davon gestuetzt: {len(huelle)}, "
|
||||
f"unerreichbar: {len(front) - len(huelle)}")
|
||||
|
||||
# Die beiden Behauptungen des Luecken-Bildes nachrechnen, statt sie
|
||||
# hinzuschreiben.
|
||||
delle = tiefste_delle(front, huelle)
|
||||
if delle is not None:
|
||||
punkt, links, rechts, abstand = delle
|
||||
steigung = (rechts[1] - links[1]) / (rechts[0] - links[0])
|
||||
|
||||
def auf_tangente(x):
|
||||
return links[1] + steigung * (x - links[0])
|
||||
|
||||
# Eine Stuetzgerade der UNTEREN Huelle liegt unter allen Punkten und
|
||||
# beruehrt die beiden Ecken der Kante. Beides zusammen macht sie zur
|
||||
# Tangente; nur eines davon reicht nicht.
|
||||
for ecke in huelle:
|
||||
if ecke[1] < auf_tangente(ecke[0]) - 1e-6:
|
||||
raise SystemExit(
|
||||
f"Pareto-Luecke: Die Huellenecke {ecke} liegt UNTER der "
|
||||
f"gezeichneten Geraden - dann stuetzt sie die Huelle "
|
||||
f"nicht.")
|
||||
for ecke in (links, rechts):
|
||||
if abs(ecke[1] - auf_tangente(ecke[0])) > 1e-6:
|
||||
raise SystemExit(
|
||||
f"Pareto-Luecke: Die Gerade beruehrt die Huellenecke "
|
||||
f"{ecke} nicht - dann ist sie keine Tangente an diese "
|
||||
f"Kante.")
|
||||
if punkt[1] <= auf_tangente(punkt[0]) + 1e-6:
|
||||
raise SystemExit(
|
||||
f"Pareto-Luecke: {punkt} liegt nicht ueber der Tangente - "
|
||||
f"dann waere der Punkt von einer gewichteten Summe erreichbar.")
|
||||
gefunden = plane(KOSTEN, co2_grenze=punkt[1])
|
||||
if gefunden != punkt:
|
||||
raise SystemExit(
|
||||
f"Pareto-Luecke: Die Schranke CO2 <= {punkt[1]} liefert "
|
||||
f"{gefunden}, nicht {punkt}. Die Bildunterschrift zum "
|
||||
f"ε-Constraint waere falsch.")
|
||||
# Die Zahl getrennt formatieren: Ein .replace(",", ".") auf den ganzen
|
||||
# f-String erwischt auch das Komma im Tupel.
|
||||
abstand_text = f"{abstand:.1f}".replace(".", ",")
|
||||
print(f" tiefste Delle: {punkt}, Abstand zur Hülle "
|
||||
f"{abstand_text} (senkrecht)")
|
||||
print(f" Tangente stützt die Hülle, der Punkt liegt darüber")
|
||||
print(f" ε-Constraint CO₂ ≤ {punkt[1]} liefert genau diesen Punkt")
|
||||
|
||||
zeichne_statisch(front, huelle)
|
||||
zeichne_interaktiv(front, huelle)
|
||||
|
|
|
|||
Loading…
Reference in a new issue