#!/usr/bin/env python3

# Fluch_des_Durchschnitts.py
"""
Kapitel Unsicherheit: Der Fluch des Durchschnitts (die Handrechnung dazu) als Scan ueber alle
moeglichen Kapazitaeten - zeigt, dass das Optimum nicht beim Mittelwert liegt.
"""

import numpy as np

SZENARIEN = np.array([100, 250, 500])
WAHRSCHEINLICHKEITEN = np.array([0.5, 0.3, 0.2])
PREIS_VORAB = 40.0
PREIS_ZUKAUF = 120.0
PREIS_VERWALTUNG = 5.0

ERWARTUNGSWERT = float(SZENARIEN @ WAHRSCHEINLICHKEITEN)


def erwartete_kosten(x):
    kosten = np.where(
        SZENARIEN >= x,
        PREIS_VORAB * x + PREIS_ZUKAUF * (SZENARIEN - x),
        PREIS_VORAB * x + PREIS_VERWALTUNG * (x - SZENARIEN),
    )
    return float(kosten @ WAHRSCHEINLICHKEITEN)


if __name__ == "__main__":
    print("=" * 70)
    print("  DER FLUCH DES DURCHSCHNITTS")
    print("=" * 70)
    print(f"Erwarteter Bedarf (Mittelwert): {ERWARTUNGSWERT:.1f}")
    print(f"Kosten bei naiver Planung x={ERWARTUNGSWERT:.0f}: "
          f"{erwartete_kosten(ERWARTUNGSWERT):,.2f} EUR\n")

    x_werte = np.arange(0, 501, 1)
    kosten_werte = np.array([erwartete_kosten(x) for x in x_werte])
    x_optimal = x_werte[np.argmin(kosten_werte)]
    kosten_optimal = kosten_werte.min()

    print(f"Optimales x (durch Scan gefunden): {x_optimal}")
    print(f"Kosten beim Optimum:                {kosten_optimal:,.2f} EUR")
    print(f"Ersparnis gegenueber naiver Planung: "
          f"{erwartete_kosten(ERWARTUNGSWERT) - kosten_optimal:,.2f} EUR\n")

    print("Kosten fuer ausgewaehlte x zum Vergleich:")
    for x in [100, 225, 250, 300, 500]:
        markierung = "  <- Mittelwert" if x == 225 else ("  <- Optimum" if x == 250 else "")
        print(f"  x={x:4d}: {erwartete_kosten(x):>12,.2f} EUR{markierung}")

    print("\nDas Optimum liegt exakt auf einem Szenariowert (250 = 'Volatil'),")
    print("nicht beim Mittelwert 225 - typisch fuer asymmetrische Kostenfunktionen.")
