Dokumentation nachgezogen - und dabei den neunten Fund gemacht
Der Leser-Wegweiser Operations_Research_mit_Python_Version_04/README.md, die Datei, die Leser als erstes oeffnen, beschrieb noch die Struktur der Version 03: * 12 der 15 Kapitelnummern falsch. "20_Lineare_Programmierung.md | 4" - es ist Kapitel 5. Bei den Finanzkapiteln lag die Abweichung bei sieben: README 11, tatsaechlich 18. * 8 der 23 Kapitel fehlten ganz (Metaheuristiken, Spaltengenerierung, Mehrziel, Predict-then-Optimize, Testing und drei weitere). * 93_Anhang_Spickzettel.md fehlte in der Anhangtabelle; der Bauabschnitt nannte dreimal build_version_03.py statt _04 und beschrieb --html als "Single-Page-HTML", obwohl es laengst eine mehrseitige Website erzeugt. Dieselbe Regel wie acht Mal zuvor, dieselbe Behandlung: Die Tabelle wird erzeugt, nicht korrigiert. schreibe_kapiteltabelle() ersetzt den Block zwischen den KAPITELTABELLE-Marken aus der Struktur, die baue_seiten_registry() ohnehin ermittelt - derselben Quelle, aus der die Nummern im Buch stammen. --check meldet einen veralteten Block und bricht ab. Gegenprobe: alle 37 Dateien aus DATEIEN stehen in der Uebersicht. Weiter nachgezogen: * CLAUDE.md kannte veroeffentliche_04.py nicht und nannte .env.beispiel nicht. Der Abschnitt "Veroeffentlichung" beschrieb noch das Kopieren von Hand samt curl-Kontrolle - das erledigt jetzt das Skript. * Fundzahl der Nummern-Regel: CLAUDE.md sagte sieben, README acht, PROGRESS dokumentiert einen "Achter Fund". Jetzt ueberall neun. * Diagrammzahl: CLAUDE.md zaehlt 32 Kapiteldiagramme, README 33 - der Unterschied ist titelseite.svg. Das steht jetzt dabei. Nebenbei am Upload-Skript: rsync bekommt --checksum. Der Bau schreibt alle 42 Seiten bei jedem Lauf neu, auch ohne inhaltliche Aenderung; nach Zeitstempel und Groesse waeren das jedes Mal rund 19 MB sinnlose Uebertragung. Gemessen nach einem Neubau ohne Aenderung: 0 statt 151 Dateien. Website unveraendert - kein Upload noetig, der Probelauf meldet 0 zu uebertragen und 0 zu loeschen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e3ff5846f6
commit
3d85488d7c
6 changed files with 212 additions and 42 deletions
39
CLAUDE.md
39
CLAUDE.md
|
|
@ -39,6 +39,8 @@ pyproject.toml Quelle: Abhängigkeiten in Gruppe
|
|||
Dockerfile, .dockerignore Quelle: Kurs-Image (Programme + JupyterLab)
|
||||
LICENSE, LICENSE-TEXT.md MIT fuer Code, CC BY-SA 4.0 fuer den Text
|
||||
.gitattributes LF im Repository, egal auf welchem System
|
||||
.env.beispiel Vorlage; die echte .env (Ziel des Uploads)
|
||||
ist bewusst NICHT im Repository
|
||||
pandoc-defaults-basis.yaml, pandoc/, pandoc-defaults-buch.yaml PDF-Konfiguration
|
||||
```
|
||||
|
||||
|
|
@ -60,8 +62,17 @@ cd Version_04
|
|||
python3 Operations_Research_mit_Python_Version_04/build_version_04.py --check # nur prüfen
|
||||
python3 Operations_Research_mit_Python_Version_04/build_version_04.py --pdf --html
|
||||
python3 Operations_Research_mit_Python_Version_04/extract_programme_04.py
|
||||
python3 Operations_Research_mit_Python_Version_04/veroeffentliche_04.py # hochladen
|
||||
```
|
||||
|
||||
`veroeffentliche_04.py` lädt `OR_HTML_04/` per `rsync --delete` nach <https://jamulix.de/OR/>
|
||||
— **nicht** per `scp`, denn das überschreibt nur und löscht nie; eine aus dem Buch entfernte
|
||||
Seite bliebe sonst dauerhaft online. Vorher prüft es, ob eine Quelldatei neuer ist als die
|
||||
gebaute Website (die Website hing einmal wochenlang einen Bau zurück, ohne dass es auffiel),
|
||||
hinterher ruft es vierzehn Adressen per HTTP ab. Bei mehr als 30 Löschungen bricht es ab —
|
||||
die Liste ist dann anzusehen, bevor `--loeschgrenze N` sie freigibt. Ziel in `.env`
|
||||
(nicht im Repository, Vorlage `.env.beispiel`); Anmeldung per SSH-Schlüssel, kein Passwort.
|
||||
|
||||
`--check` prüft mehr als die Struktur: fehlende Codezäune, Links auf nicht existierende
|
||||
Dateien und **harte Kapitel-/Abschnitts-/Aufgabennummern im Quelltext**. Es meldet Datei und
|
||||
Zeile. Der Suchausdruck erlaubt beliebigen Zwischenraum — der letzte gefundene Fall war ein
|
||||
|
|
@ -76,9 +87,10 @@ sonst fälschlich als sichtbaren Umbruch dar.
|
|||
## Die wichtigsten Konventionen
|
||||
|
||||
**Keine abgeleiteten Zahlen im Quelltext.** Das ist die Regel, an der dieses Projekt am
|
||||
häufigsten gescheitert ist — **sieben** Mal an verschiedenen Stellen verletzt gefunden
|
||||
häufigsten gescheitert ist — **neun** Mal an verschiedenen Stellen verletzt gefunden
|
||||
(Anhang A, 66 Programm-Docstrings, die Übersichtstabellen der Anhänge, `CLAUDE.md` selbst,
|
||||
eine Tabellenzelle, die 98 Lösungsmarken des Anhangs, neun Denkfehler-Verweise).
|
||||
eine Tabellenzelle, die 98 Lösungsmarken des Anhangs, neun Denkfehler-Verweise, sieben
|
||||
„Übung N.N"-Verweise in alter Zählung, zuletzt die Dateiübersicht des Leser-Wegweisers).
|
||||
Seit dem letzten Fund trägt **keine** Marke mehr eine handgeschriebene Nummer, und `--check`
|
||||
bewacht jede Familie. Konkret:
|
||||
|
||||
|
|
@ -95,6 +107,11 @@ bewacht jede Familie. Konkret:
|
|||
einer bereits nummerierten Überschrift. Verwiesen wird auf
|
||||
`{ref:sec:<kapitel>-denkfehler}`.
|
||||
* Im Fließtext `{ref:<label>}`, nie eine Literalzahl.
|
||||
* **Die Dateiübersicht in `Operations_Research_mit_Python_Version_04/README.md`** steht
|
||||
zwischen `<!-- KAPITELTABELLE:ANFANG -->` und `<!-- KAPITELTABELLE:ENDE -->` und wird von
|
||||
`schreibe_kapiteltabelle()` aus derselben Struktur erzeugt wie die Nummern im Buch. Nicht
|
||||
von Hand bearbeiten — `--check` meldet einen veralteten Block, ein Lauf ohne `--check`
|
||||
zieht ihn nach.
|
||||
* In Code-Kommentaren und Docstrings der Kapitel**name** („Kapitel Metaheuristiken:"), nie
|
||||
die Nummer. Auch nicht im Dateinamen.
|
||||
|
||||
|
|
@ -137,8 +154,10 @@ gehört wie die Arbeit, die sie beschreibt.
|
|||
|
||||
## Diagramme
|
||||
|
||||
`bilder_04/erzeuge_*.py` erzeugen 18 der 32 SVGs, jeweils **aus derselben Instanz wie das
|
||||
zugehörige Buchprogramm**. Das ist kein Selbstzweck: Von zehn nachgebauten Bildern förderten
|
||||
`bilder_04/erzeuge_*.py` erzeugen 18 der 32 Kapiteldiagramme, jeweils **aus derselben
|
||||
Instanz wie das zugehörige Buchprogramm**. (Das 33. SVG im Verzeichnis ist `titelseite.svg`,
|
||||
die der Build bei jedem Lauf selbst schreibt — deshalb nennt `README.md` 33 und diese Datei
|
||||
32.) Das ist kein Selbstzweck: Von zehn nachgebauten Bildern förderten
|
||||
sieben einen Fehler zutage — dreimal ein Modell, das im Buch gar nicht vorkommt, einmal
|
||||
widersprüchliche Zahlen zwischen Bild und Text, einmal ein gekipptes Vorzeichen. Wer ein
|
||||
Diagramm anfasst, vergleicht es zuerst mit dem Modell des Kapitels.
|
||||
|
|
@ -174,10 +193,14 @@ Die Website hat vier Übersichtsseiten: `index.html` (Landing), `programme.html`
|
|||
weiterleitet — sonst antwortet der Webserver mit 403, weil Directory-Listing abgeschaltet
|
||||
ist.
|
||||
|
||||
**Nach jedem `--pdf --html` muss `OR_HTML_04/` neu auf den Webserver kopiert werden** — sonst
|
||||
laeuft die veroeffentlichte Fassung dem Repository hinterher. Woran man das merkt: Ein
|
||||
`curl -s https://jamulix.de/OR/lp.html | grep -c colab.research` muss **0** ergeben, und die
|
||||
Groesse des dort liegenden PDF muss zur lokalen Datei passen.
|
||||
**Nach jedem `--pdf --html` gehoert `veroeffentliche_04.py` hinterher** — sonst laeuft die
|
||||
veroeffentlichte Fassung dem Repository hinterher, und genau das ist einmal wochenlang
|
||||
unbemerkt geblieben. Von Hand muss dabei nichts mehr geprueft werden: Das Skript weigert
|
||||
sich, einen veralteten Bau hochzuladen, und ruft anschliessend vierzehn Adressen ab.
|
||||
|
||||
Der erste Lauf am 08.09.2026 uebertrug 213 Dateien und loeschte 35 — 33 verwaiste PNGs, ein
|
||||
leeres `__pycache__/` und die geteilte Anhangseite. Alle 35 haette ein `scp`-Upload stehen
|
||||
gelassen.
|
||||
|
||||
**`COLAB_BASIS_URL` ist bewusst leer.** Colab oeffnet Notebooks nur aus GitHub, Google Drive
|
||||
oder einem Upload; die URL-Form `colab.research.google.com/github/...` ist fest auf GitHub
|
||||
|
|
|
|||
|
|
@ -29,63 +29,81 @@ arbeiten, üben und eigene Anwendungen bauen können.**
|
|||
Der Text ist auf mehrere Dateien verteilt, damit er handhabbar bleibt. Die Nummern-Präfixe
|
||||
legen die Lesereihenfolge fest.
|
||||
|
||||
<!-- KAPITELTABELLE:ANFANG - erzeugt von build_version_04.py -->
|
||||
|
||||
### Vorspann
|
||||
|
||||
| Datei | Inhalt |
|
||||
| --- | --- |
|
||||
| [`00_Vorwort_und_Lesehilfe.md`](00_Vorwort_und_Lesehilfe.md) | Vorwort, Lernpfade, Verzeichnis der Beispielprogramme, Setup, wie die Lernelemente funktionieren |
|
||||
| [`01_Notation_und_Abkuerzungen.md`](01_Notation_und_Abkuerzungen.md) | Alle Symbole und Abkürzungen, ausgeschrieben und erklärt |
|
||||
| [`00_Vorwort_und_Lesehilfe.md`](00_Vorwort_und_Lesehilfe.md) | Vorwort & Lesehilfe |
|
||||
| [`01_Notation_und_Abkuerzungen.md`](01_Notation_und_Abkuerzungen.md) | Notation & Abkürzungen |
|
||||
|
||||
### Teil I — Grundlagen
|
||||
### Teil I: Grundlagen des Operations Research
|
||||
|
||||
| Datei | Kapitel |
|
||||
| --- | --- |
|
||||
| [`10_Einfuehrung_OR.md`](10_Einfuehrung_OR.md) | 1 — Einführung in Operations Research |
|
||||
| [`11_Mathematisches_Fundament.md`](11_Mathematisches_Fundament.md) | 2 — Vektoren, Matrizen, Konvexität |
|
||||
| [`12_Python_Oekosystem.md`](12_Python_Oekosystem.md) | 3 — Das Python-Ökosystem für OR |
|
||||
| [`10_Einfuehrung_OR.md`](10_Einfuehrung_OR.md) | Kapitel 1 — Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung |
|
||||
| [`11_Mathematisches_Fundament.md`](11_Mathematisches_Fundament.md) | Kapitel 2 — Das mathematische Fundament — Vektoren, Matrizen, Konvexität |
|
||||
| [`12_Python_Oekosystem.md`](12_Python_Oekosystem.md) | Kapitel 3 — Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten |
|
||||
| [`13_Vom_Wunsch_zum_Modell.md`](13_Vom_Wunsch_zum_Modell.md) | Kapitel 4 — Vom Management-Wunsch zum Modell |
|
||||
| [`19_Synthese_Grundlagen.md`](19_Synthese_Grundlagen.md) | Synthese Teil I |
|
||||
|
||||
### Teil II — Deterministische Kernverfahren
|
||||
### Teil II: Die Kernverfahren der deterministischen Optimierung
|
||||
|
||||
| Datei | Kapitel |
|
||||
| --- | --- |
|
||||
| [`20_Lineare_Programmierung.md`](20_Lineare_Programmierung.md) | 4 — Lineare Programmierung, Simplex, Dualität |
|
||||
| [`21_MILP.md`](21_MILP.md) | 5 — Gemischt-ganzzahlige Optimierung |
|
||||
| [`22_CP_SAT.md`](22_CP_SAT.md) | 6 — Constraint Programming mit CP-SAT |
|
||||
| [`23_Graphen_Fluesse_Touren.md`](23_Graphen_Fluesse_Touren.md) | 7 — Graphen, Flüsse, Tourenplanung |
|
||||
| [`20_Lineare_Programmierung.md`](20_Lineare_Programmierung.md) | Kapitel 5 — Lineare Programmierung — Simplex, Dualität und Schattenpreise |
|
||||
| [`21_MILP.md`](21_MILP.md) | Kapitel 6 — Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound |
|
||||
| [`22_CP_SAT.md`](22_CP_SAT.md) | Kapitel 7 — Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung |
|
||||
| [`23_Graphen_Fluesse_Touren.md`](23_Graphen_Fluesse_Touren.md) | Kapitel 8 — Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP |
|
||||
| [`24_Metaheuristiken.md`](24_Metaheuristiken.md) | Kapitel 9 — Metaheuristiken — wenn der exakte Solver aussteigt |
|
||||
| [`25_Spaltengenerierung.md`](25_Spaltengenerierung.md) | Kapitel 10 — Spaltengenerierung — das Modell umbauen statt die Lösung raten |
|
||||
| [`29_Synthese_Kernverfahren.md`](29_Synthese_Kernverfahren.md) | Synthese Teil II |
|
||||
|
||||
### Teil III — Nichtlinearität, Unsicherheit, Dynamik
|
||||
### Teil III: Nichtlinearität, Unsicherheit und mehrperiodige Dynamik
|
||||
|
||||
| Datei | Kapitel |
|
||||
| --- | --- |
|
||||
| [`30_QP_und_NLP.md`](30_QP_und_NLP.md) | 8 — Quadratische und nichtlineare Optimierung, KKT |
|
||||
| [`31_Unsicherheit.md`](31_Unsicherheit.md) | 9 — Monte-Carlo, stochastische und robuste Optimierung |
|
||||
| [`32_Dynamische_Programmierung.md`](32_Dynamische_Programmierung.md) | 10 — Dynamische Programmierung, Bellman |
|
||||
| [`30_QP_und_NLP.md`](30_QP_und_NLP.md) | Kapitel 11 — Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität |
|
||||
| [`31_Unsicherheit.md`](31_Unsicherheit.md) | Kapitel 12 — Optimierung unter Unsicherheit — Monte-Carlo, Stochastik, Robustheit |
|
||||
| [`32_Dynamische_Programmierung.md`](32_Dynamische_Programmierung.md) | Kapitel 13 — Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution |
|
||||
| [`33_Mehrziel_und_Pareto.md`](33_Mehrziel_und_Pareto.md) | Kapitel 14 — Mehrere Ziele — Pareto-Fronten statt Gewichte |
|
||||
| [`34_Predict_then_Optimize.md`](34_Predict_then_Optimize.md) | Kapitel 15 — Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung |
|
||||
| [`39_Synthese_Nichtlinear.md`](39_Synthese_Nichtlinear.md) | Synthese Teil III |
|
||||
|
||||
### Teil IV — Operations Research an den Finanzmärkten
|
||||
### Teil IV: Anwendungen — Energiewirtschaft und Finanzmärkte
|
||||
|
||||
| Datei | Kapitel |
|
||||
| --- | --- |
|
||||
| [`40_Finanzdaten.md`](40_Finanzdaten.md) | 11 — Finanzdaten, Kovarianz, Shrinkage |
|
||||
| [`41_Markowitz.md`](41_Markowitz.md) | 12 — Markowitz-Portfoliotheorie |
|
||||
| [`42_CVaR.md`](42_CVaR.md) | 13 — Tail-Risiko, CVaR, Transaktionskosten |
|
||||
| [`43_Handelsmaschine.md`](43_Handelsmaschine.md) | 14 — Die vollständige Handelsmaschine |
|
||||
| [`35_Strukturbruecke.md`](35_Strukturbruecke.md) | Kapitel 16 — Die Strukturbrücke — dieselbe Mathematik, zwei Welten |
|
||||
| [`36_Supply_Chain_Energie.md`](36_Supply_Chain_Energie.md) | Kapitel 17 — Supply-Chain und Energieeinsatz unter Unsicherheit |
|
||||
| [`40_Finanzdaten.md`](40_Finanzdaten.md) | Kapitel 18 — Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage |
|
||||
| [`41_Markowitz.md`](41_Markowitz.md) | Kapitel 19 — Die moderne Portfoliotheorie nach Markowitz |
|
||||
| [`42_CVaR.md`](42_CVaR.md) | Kapitel 20 — Tail-Risiko, CVaR und Transaktionskosten |
|
||||
| [`43_Handelsmaschine.md`](43_Handelsmaschine.md) | Kapitel 21 — Die vollständige quantitative Handelsmaschine |
|
||||
| [`49_Synthese_Anwendungen.md`](49_Synthese_Anwendungen.md) | Synthese Teil IV |
|
||||
|
||||
### Teil V — Praxis
|
||||
### Teil V: Praxis
|
||||
|
||||
| Datei | Kapitel |
|
||||
| --- | --- |
|
||||
| [`50_Praxis.md`](50_Praxis.md) | 15 — Praxisfallen und produktiver Einsatz |
|
||||
| [`59_Projektwerkstatt.md`](59_Projektwerkstatt.md) | Projektwerkstatt: 8 eigene Anwendungen |
|
||||
| [`50_Praxis.md`](50_Praxis.md) | Kapitel 22 — Praxisfallen und der Weg zum produktiven Einsatz |
|
||||
| [`51_Testing_und_Deployment.md`](51_Testing_und_Deployment.md) | Kapitel 23 — Testen, Messen, Ausliefern |
|
||||
| [`52_Synthese_Praxis.md`](52_Synthese_Praxis.md) | Synthese Teil V |
|
||||
| [`59_Projektwerkstatt.md`](59_Projektwerkstatt.md) | Projektwerkstatt |
|
||||
|
||||
### Anhang
|
||||
|
||||
| Datei | Inhalt |
|
||||
| --- | --- |
|
||||
| [`90_Anhang_Loesungen.md`](90_Anhang_Loesungen.md) | Lösungen zu **allen** Übungsaufgaben und Selbsttests |
|
||||
| [`91_Anhang_Modellierungsmuster.md`](91_Anhang_Modellierungsmuster.md) | Musterkatalog: 24 wiederkehrende Modellierungstricks |
|
||||
| [`92_Anhang_Fehlerdiagnose.md`](92_Anhang_Fehlerdiagnose.md) | Diagnose-Handbuch für Solver-Probleme |
|
||||
| [`94_Anhang_Glossar.md`](94_Anhang_Glossar.md) | Glossar der Fachbegriffe |
|
||||
| [`95_Anhang_Literatur.md`](95_Anhang_Literatur.md) | Literaturverzeichnis |
|
||||
| [`90_Anhang_Loesungen.md`](90_Anhang_Loesungen.md) | Anhang A — Lösungen zu allen Übungsaufgaben |
|
||||
| [`91_Anhang_Modellierungsmuster.md`](91_Anhang_Modellierungsmuster.md) | Anhang B — Katalog der Modellierungsmuster |
|
||||
| [`92_Anhang_Fehlerdiagnose.md`](92_Anhang_Fehlerdiagnose.md) | Anhang C — Fehlerdiagnose-Handbuch |
|
||||
| [`93_Anhang_Spickzettel.md`](93_Anhang_Spickzettel.md) | Anhang D — Spickzettel der Solver |
|
||||
| [`94_Anhang_Glossar.md`](94_Anhang_Glossar.md) | Anhang E — Glossar |
|
||||
| [`95_Anhang_Literatur.md`](95_Anhang_Literatur.md) | Anhang F — Literaturverzeichnis |
|
||||
|
||||
<!-- KAPITELTABELLE:ENDE -->
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -95,7 +113,7 @@ Wer lieber ein einziges Dokument möchte (z. B. zum Drucken oder für die PDF-Er
|
|||
baut es aus den Einzeldateien:
|
||||
|
||||
```bash
|
||||
cd OR_mit_Python/Version_04 # Wurzel der Version 04
|
||||
cd Version_04 # das Wurzelverzeichnis des Repositorys
|
||||
python3 Operations_Research_mit_Python_Version_04/build_version_04.py
|
||||
```
|
||||
|
||||
|
|
@ -105,11 +123,15 @@ Inhaltsverzeichnis-Platzhalter und entfernten unnötigen Zeilenumbrüchen innerh
|
|||
Absätzen. Optionen:
|
||||
|
||||
```bash
|
||||
python3 .../build_version_03.py --pdf # zusätzlich PDF über pandoc + xelatex
|
||||
python3 .../build_version_03.py --html # zusätzlich Single-Page-HTML
|
||||
python3 .../build_version_03.py --check # nur Konsistenzprüfung, schreibt nichts
|
||||
python3 .../build_version_04.py --pdf # zusätzlich PDF über pandoc + xelatex
|
||||
python3 .../build_version_04.py --html # zusätzlich die Website OR_HTML_04/
|
||||
python3 .../build_version_04.py --check # nur Konsistenzprüfung, schreibt nichts
|
||||
```
|
||||
|
||||
`--html` erzeugt die **mehrseitige** Website mit Suche, Stichwortverzeichnis und
|
||||
Notebook-Downloads; das Gesamtdokument auf einer Seite liegt darin als
|
||||
`gesamtdokument.html`.
|
||||
|
||||
---
|
||||
|
||||
## Empfohlene Reihenfolge für Kursteilnehmer
|
||||
|
|
|
|||
|
|
@ -2443,6 +2443,86 @@ def baue_stichwortverzeichnis(html_verz: str, struktur: list[dict],
|
|||
print(f"Stichwortverzeichnis erzeugt: {len(namen)} Hauptbegriffe.")
|
||||
|
||||
|
||||
# Der Leser-Wegweiser Operations_Research_mit_Python_Version_04/README.md fuehrt
|
||||
# alle Quelldateien mit ihrer Kapitelnummer auf. Diese Tabelle stand von Hand
|
||||
# darin - und war der NEUNTE Fall der Regel "keine abgeleiteten Zahlen im
|
||||
# Quelltext": 12 der 15 Nummern zeigten noch die Zaehlung der Version 03, und
|
||||
# 8 der 23 Kapitel fehlten ganz. Jetzt erzeugt der Bau den Block zwischen den
|
||||
# beiden Marken; --check meldet, wenn er veraltet ist.
|
||||
README_MARKE_ANFANG = "<!-- KAPITELTABELLE:ANFANG - erzeugt von build_version_04.py -->"
|
||||
README_MARKE_ENDE = "<!-- KAPITELTABELLE:ENDE -->"
|
||||
|
||||
LESER_README = os.path.join(HIER, "README.md")
|
||||
|
||||
|
||||
def baue_kapiteltabelle(struktur: list[dict]) -> str:
|
||||
"""Baut die Dateiuebersicht des Leser-Wegweisers aus der Struktur, die
|
||||
baue_seiten_registry() ohnehin ermittelt - dieselbe Quelle, aus der auch
|
||||
die Nummern im Buch stammen. Damit koennen die beiden nicht auseinander-
|
||||
laufen."""
|
||||
zeilen = [README_MARKE_ANFANG, ""]
|
||||
|
||||
def tabelle(eintraege: list[dict], spalte: str) -> None:
|
||||
zeilen.append(f"| Datei | {spalte} |")
|
||||
zeilen.append("| --- | --- |")
|
||||
for e in eintraege:
|
||||
was = f'{e["nummer"]} — {e["titel"]}' if e["nummer"] else e["titel"]
|
||||
zeilen.append(f'| [`{e["datei"]}`]({e["datei"]}) | {was} |')
|
||||
zeilen.append("")
|
||||
|
||||
vorspann = [e for e in struktur if e["teil"] is None and e["typ"] == "sonder"]
|
||||
if vorspann:
|
||||
zeilen.append("### Vorspann")
|
||||
zeilen.append("")
|
||||
tabelle(vorspann, "Inhalt")
|
||||
|
||||
gesehen: list[str] = []
|
||||
for e in struktur:
|
||||
if e["teil"] and e["teil"] not in gesehen:
|
||||
gesehen.append(e["teil"])
|
||||
for teil in gesehen:
|
||||
zeilen.append(f"### {teil}")
|
||||
zeilen.append("")
|
||||
tabelle([e for e in struktur if e["teil"] == teil], "Kapitel")
|
||||
|
||||
anhaenge = [e for e in struktur if e["typ"] == "anhang"]
|
||||
if anhaenge:
|
||||
zeilen.append("### Anhang")
|
||||
zeilen.append("")
|
||||
tabelle(anhaenge, "Inhalt")
|
||||
|
||||
zeilen.append(README_MARKE_ENDE)
|
||||
return "\n".join(zeilen)
|
||||
|
||||
|
||||
def schreibe_kapiteltabelle(struktur: list[dict], nur_pruefen: bool) -> list[str]:
|
||||
"""Ersetzt den markierten Block im Leser-Wegweiser. Liefert bei --check
|
||||
eine nicht leere Liste, wenn er veraltet ist."""
|
||||
if not os.path.exists(LESER_README):
|
||||
return []
|
||||
with open(LESER_README, encoding="utf-8") as f:
|
||||
inhalt = f.read()
|
||||
if README_MARKE_ANFANG not in inhalt or README_MARKE_ENDE not in inhalt:
|
||||
print(f"FEHLER: {os.path.basename(LESER_README)} hat keine "
|
||||
f"KAPITELTABELLE-Marken - die Dateiuebersicht kann nicht "
|
||||
f"erzeugt werden.")
|
||||
return ["README-Marken"]
|
||||
vorher, rest = inhalt.split(README_MARKE_ANFANG, 1)
|
||||
_, nachher = rest.split(README_MARKE_ENDE, 1)
|
||||
neu = vorher + baue_kapiteltabelle(struktur) + nachher
|
||||
if neu == inhalt:
|
||||
return []
|
||||
if nur_pruefen:
|
||||
print(f"FEHLER: Die Dateiuebersicht in "
|
||||
f"{os.path.basename(LESER_README)} ist veraltet - ein Lauf ohne "
|
||||
f"--check zieht sie nach.")
|
||||
return ["README-Kapiteltabelle"]
|
||||
with open(LESER_README, "w", encoding="utf-8") as f:
|
||||
f.write(neu)
|
||||
print(f"Dateiuebersicht im Leser-Wegweiser nachgezogen.")
|
||||
return []
|
||||
|
||||
|
||||
def erzeuge_suchindex(html_verz: str, suchindex: list[dict]) -> None:
|
||||
# .js mit globaler Variable statt .json + fetch() - siehe Kommentar in
|
||||
# baue_programme_seite() (fetch() auf lokale Dateien scheitert unter
|
||||
|
|
@ -2511,6 +2591,13 @@ def main() -> int:
|
|||
print(f"Geprueft: {len(DATEIEN)} Dateien, {zeilen:,} Zeilen, "
|
||||
f"{zeichen/1024:.0f} KB, {kapitel} Hauptueberschriften.")
|
||||
|
||||
# Die Dateiuebersicht des Leser-Wegweisers stammt aus derselben Struktur
|
||||
# wie die Nummern im Buch. Bei --check wird nur gemeldet, dass sie veraltet
|
||||
# ist; geschrieben wird sie im normalen Lauf.
|
||||
_, _, _, struktur_fuer_readme, _ = baue_seiten_registry()
|
||||
if schreibe_kapiteltabelle(struktur_fuer_readme, nur_pruefen=argumente.check):
|
||||
return 1
|
||||
|
||||
if argumente.check:
|
||||
print("Nur Pruefung - es wurde nichts geschrieben.")
|
||||
return 0
|
||||
|
|
|
|||
|
|
@ -192,7 +192,13 @@ def rsync_befehl(env: dict[str, str], probelauf: bool) -> list[str]:
|
|||
# ohnehin nicht setzen, -a erzeugte dafuer nur Warnungen. --chmod sorgt
|
||||
# dafuer, dass der Webserver alles lesen kann, unabhaengig von der lokalen
|
||||
# umask.
|
||||
befehl = ["rsync", "-rltz", "--delete", "--chmod=D755,F644",
|
||||
# --checksum: vergleiche INHALTE, nicht Groesse und Zeitstempel. Der Bau
|
||||
# schreibt alle 42 Seiten bei jedem Lauf neu, auch wenn sich nichts
|
||||
# geaendert hat - nach der Vorgabe waeren das jedes Mal rund 19 MB
|
||||
# sinnlose Uebertragung. Mit --checksum meldet der Probelauf genau die
|
||||
# Dateien, deren Inhalt sich wirklich unterscheidet. Das Lesen der 23 MB
|
||||
# auf beiden Seiten faellt dagegen nicht ins Gewicht.
|
||||
befehl = ["rsync", "-rltz", "--checksum", "--delete", "--chmod=D755,F644",
|
||||
"--skip-compress=pdf/zip/woff2/png/jpg/svg",
|
||||
"--itemize-changes",
|
||||
"-e", ssh_optionen(env)]
|
||||
|
|
|
|||
32
PROGRESS.md
32
PROGRESS.md
|
|
@ -2158,6 +2158,38 @@ Damit ist der seit dem Colab-Umbau offene Punkt erledigt: Online steht kein tote
|
|||
Colab-Link mehr, `Notebooks_04/` liefert statt 403 eine Übersichtsseite, und das PDF
|
||||
entspricht byte-genau dem gebauten.
|
||||
|
||||
### 🐛 Neunter Fund: die Dateiübersicht des Leser-Wegweisers
|
||||
|
||||
Beim Durchgehen der Dokumentation zeigte sich, dass
|
||||
`Operations_Research_mit_Python_Version_04/README.md` — die Datei, die **Leser** als erstes
|
||||
öffnen — noch die Struktur der Version 03 beschrieb:
|
||||
|
||||
* **12 der 15 Kapitelnummern waren falsch.** „20_Lineare_Programmierung.md | 4" — es ist
|
||||
Kapitel 5. Bei den Finanzkapiteln lag die Abweichung bei sieben: README 11, tatsächlich 18.
|
||||
* **8 der 23 Kapitel fehlten ganz** (unter anderem Metaheuristiken, Spaltengenerierung,
|
||||
Mehrziel, Predict-then-Optimize, Testing).
|
||||
* Auch `93_Anhang_Spickzettel.md` fehlte in der Anhangtabelle, und der Bauabschnitt nannte
|
||||
dreimal `build_version_03.py` statt `_04`, dazu „Single-Page-HTML" für einen Schalter, der
|
||||
längst eine mehrseitige Website erzeugt.
|
||||
|
||||
Dieselbe Regel, dieselbe Ursache: eine abgeleitete Zahl von Hand geschrieben. Deshalb dieselbe
|
||||
Behandlung — **die Tabelle wird jetzt erzeugt**, nicht korrigiert. `schreibe_kapiteltabelle()`
|
||||
ersetzt den Block zwischen `<!-- KAPITELTABELLE:ANFANG -->` und `<!-- KAPITELTABELLE:ENDE -->`
|
||||
aus der Struktur, die `baue_seiten_registry()` ohnehin ermittelt — derselben Quelle, aus der
|
||||
die Nummern im Buch stammen. Auseinanderlaufen können die beiden damit nicht mehr.
|
||||
|
||||
`--check` meldet einen veralteten Block und bricht ab; ein Lauf ohne `--check` zieht ihn nach.
|
||||
Gegenprobe: Alle **37** Dateien aus `DATEIEN` stehen in der erzeugten Übersicht, mit 23
|
||||
Kapiteln, 5 Teil-Synthesen und 6 Anhängen.
|
||||
|
||||
**Das Muster ist inzwischen belastbar:** Neun Funde, neun Prüfungen. Keiner davon wurde durch
|
||||
Nachdenken gefunden — jeder durch einen Vergleich der Behauptung mit der Messung.
|
||||
|
||||
**Nebenbei am Upload-Skript:** `rsync` bekommt jetzt `--checksum`. Der Bau schreibt alle 42
|
||||
Seiten bei jedem Lauf neu, auch wenn sich nichts geändert hat; nach Zeitstempel und Größe
|
||||
hätte das jedes Mal rund 19 MB sinnlose Übertragung bedeutet. Gemessen nach einem Neubau
|
||||
ohne inhaltliche Änderung: **0 statt 151 Dateien**.
|
||||
|
||||
---
|
||||
|
||||
## 8. Commit-Historie des V04-Strangs
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ python3 bilder_04/erzeuge_kondition.py
|
|||
`--check` prüft mehr als die Struktur: fehlende Codezäune, tote Dateilinks, eine gebrochene
|
||||
Lesekette, Lösungsabschnitte mit falscher Aufgabenzahl — und **jede von Hand geschriebene
|
||||
Nummer**, die der Build selbst vergeben müsste. Diese Regel ist die in diesem Projekt am
|
||||
häufigsten verletzte; acht Fälle wurden nachträglich gefunden, und jeder hat eine eigene
|
||||
häufigsten verletzte; neun Fälle wurden nachträglich gefunden, und jeder hat eine eigene
|
||||
Prüfung hinterlassen.
|
||||
|
||||
### Externe Werkzeuge
|
||||
|
|
|
|||
Loading…
Reference in a new issue