#!/usr/bin/env python3 # erzeuge_laufzeit_aufbau.py """ Erzeugt das Laufzeit-Diagramm zum Oekosystem-Kapitel: bilder_04/kap_oekosystem_laufzeit.svg Gestapelte Balken: Wie viel Zeit geht in den AUFBAU des Modells (Python) und wie viel ins LOESEN (C++)? Verglichen werden Variante A (ein Add() je Nebenbedingung) und Variante C (vektorisiert ueber NumPy) bei drei Problemgroessen. WARUM HIER NICHT GEMESSEN WIRD: Die Zeiten stehen bereits als abgedruckte Ausgabe im Kapitel. Ein Neumessen auf einer anderen Maschine ergaebe andere Werte - das Bild widerspraeche dann der Tabelle unmittelbar daneben. Die Konstanten unten sind aus genau dieser Ausgabe uebernommen; pruefe_anteile() rechnet die Prozentspalte grob nach und schlaegt an, wenn eine Abweichung groesser ist als die Rundung der abgedruckten Zeiten erklaeren kann. So ist das Uebertragen abgesichert, ohne die Messung zu wiederholen. Aufruf (aus dem Repository-Wurzelverzeichnis): python3 bilder_04/erzeuge_laufzeit_aufbau.py Benoetigt: numpy, matplotlib """ from __future__ import annotations import os import sys import numpy as np sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from stil_04 import FARBEN, neue_figur, speichere # noqa: E402 # (Groesse, Variablen, Aufbau A, Loesen A, Anteil A, Aufbau C, Loesen C, # Anteil C) - wortgleich aus der abgedruckten Ausgabe des Kapitels. MESSUNG = [ ("40 × 40", 1_600, 0.031, 0.005, 87, 0.001, 0.007, 14), ("120 × 120", 14_400, 0.287, 0.070, 80, 0.001, 0.047, 3), ("250 × 250", 62_500, 1.284, 0.569, 69, 0.003, 0.205, 1), ] # Wie weit die aus den gerundeten Zeiten nachgerechnete Prozentzahl von der # abgedruckten abweichen darf. Die Zeiten stehen mit drei Nachkommastellen im # Buch, die Prozentspalte wurde aber aus den UNGERUNDETEN Werten berechnet: # 0,001s / 0,008s ergibt nachgerechnet 12 %, abgedruckt sind 14 %. Das ist # kein Fehler, sondern die Folge der Rundung - bei einer Aufbauzeit von einer # Millisekunde schlaegt schon die vierte Stelle durch. Die Schranke faengt # trotzdem einen echten Uebertragungsfehler ab. TOLERANZ_PROZENTPUNKTE = 4 def pruefe_anteile() -> None: """Plausibilitaetspruefung der uebertragenen Prozentspalte.""" for name, _var, auf_a, los_a, pro_a, auf_c, los_c, pro_c in MESSUNG: for auf, los, pro, variante in ((auf_a, los_a, pro_a, "A"), (auf_c, los_c, pro_c, "C")): gerechnet = round(auf / (auf + los) * 100) if abs(gerechnet - pro) > TOLERANZ_PROZENTPUNKTE: raise SystemExit( f"Laufzeit-Diagramm: {name}, Variante {variante}: Aus " f"{auf}s Aufbau und {los}s Loesen folgen {gerechnet} % " f"Aufbauanteil, die Tabelle nennt {pro} %. Das ist mehr " f"als Rundung erklaert - Uebertragungsfehler?") def zeichne() -> None: figur, achse = neue_figur(breite=8.0, hoehe=4.4) # Zwei Balken je Groesse: oben Variante A, darunter Variante C. beschriftung, hoehen = [], [] aufbau, loesen = [], [] # Gezeichnet wird die ABGEDRUCKTE Prozentzahl - so zeigt das Bild genau # das, was in der Tabelle daneben steht. for name, variablen, _aa, _la, pro_a, _ac, _lc, pro_c in MESSUNG: for variante, anteil in (("A Schleife", pro_a), ("C vektorisiert", pro_c)): beschriftung.append(f"{name} {variante}") aufbau.append(float(anteil)) loesen.append(100.0 - anteil) hoehen.append(variablen) y = np.arange(len(beschriftung))[::-1].astype(float) # Luecke zwischen den Groessengruppen y = y + np.repeat(np.arange(len(MESSUNG))[::-1], 2) * 0.6 achse.barh(y, aufbau, height=0.62, color=FARBEN["fehler"], label="Aufbau in Python", zorder=3) achse.barh(y, loesen, height=0.62, left=aufbau, color=FARBEN["haupt"], label="Lösen in C++", zorder=3) for stelle, (anteil, name) in enumerate(zip(aufbau, beschriftung)): # Bei 1 % und 3 % ist der Balken schmaler als die Beschriftung - dann # steht sie rechts daneben, in der Farbe des Balkens. if anteil >= 10: achse.text(anteil / 2, y[stelle], f"{round(anteil)} %", ha="center", va="center", fontsize=8.5, color="white", fontweight="bold", zorder=4) else: achse.text(anteil + 1.5, y[stelle], f"{round(anteil)} %", ha="left", va="center", fontsize=8.5, color=FARBEN["fehler"], fontweight="bold", zorder=4) achse.text(101, y[stelle], name, va="center", fontsize=8.5, color=FARBEN["text"]) achse.set_yticks([]) achse.set_xlim(0, 100) achse.set_xlabel("Anteil an der Gesamtzeit in Prozent") achse.set_title("Wo die Zeit wirklich hingeht — dieselbe Aufgabe, zwei " "Arten sie aufzuschreiben", fontsize=10.5, color=FARBEN["text"]) achse.grid(axis="y", visible=False) achse.legend(fontsize=9, loc="lower center", bbox_to_anchor=(0.5, -0.28), ncol=2, frameon=False) speichere(figur, "kap_oekosystem_laufzeit") if __name__ == "__main__": pruefe_anteile() print("Prozentspalte stimmt mit den abgedruckten Zeiten überein.") zeichne()