Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
|
|
|
# CLAUDE.md
|
|
|
|
|
|
|
|
|
|
Kontext zum Repository *Optimierte Entscheidungsfindung mit Python*, Version 04.
|
|
|
|
|
|
|
|
|
|
## Vor jeder Arbeit zuerst lesen
|
|
|
|
|
|
|
|
|
|
* **`PLAN.md`** — das Ziel und der Weg dorthin: alle sechs Phasen, die Zielstruktur, der
|
|
|
|
|
Kapitel-Baukasten, die dreizehn verbindlichen Regeln, die Verifikationsschritte. Ändert
|
|
|
|
|
sich nur bei einem Kurswechsel.
|
|
|
|
|
* **`PROGRESS.md`** — der erreichte Stand: eine Checkliste zur Wiederaufnahme, die
|
|
|
|
|
Referenzwerte zum Gegenprüfen, was erledigt ist, welche Funde es unterwegs gab und **was
|
|
|
|
|
der konkret nächste Schritt ist**. Wird nach jedem Arbeitsschritt fortgeschrieben.
|
|
|
|
|
|
|
|
|
|
Ohne diese beiden Dateien fehlt der Kontext, um sinnvoll weiterzuarbeiten — die Kapiteltexte
|
|
|
|
|
allein verraten weder den Stand noch die Konventionen. Alle sechs Phasen sind abgeschlossen;
|
|
|
|
|
`PROGRESS.md` Abschnitt 7 nennt, was bewusst offen geblieben ist und warum.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Struktur
|
|
|
|
|
|
|
|
|
|
Dieses Verzeichnis ist die Wurzel; alle Skripte leiten ihre Pfade daraus ab
|
|
|
|
|
(`BASIS = dirname(dirname(__file__))` bzw. `dirname(HIER)`).
|
|
|
|
|
|
|
|
|
|
```
|
Glossar und Literatur trennen, Menue um Glossar und ZIP-Download ergaenzen
94_Anhang_Glossar_und_Literatur.md enthielt zwei verschiedene Nachschlagewerke
in einer Datei. Jetzt sind es zwei Anhaenge: E = Glossar (92 Eintraege),
F = Literaturverzeichnis (6 Kategorien). Aus 5 Anhaengen werden 6, aus 36
Kapiteldateien 37.
Die Teilung war billig: Die Datei trug bereits zwei eigenstaendige
Ueberschriften mit nichts als einem --- dazwischen, und im ganzen Buch gab es
genau einen {ref:anhang:glossar-literatur} - die Weiter-mit-Zeile im
Spickzettel. Geprueft: keine Inhaltszeile verloren, alle 92 Glossareintraege
auf der neuen Seite, Indexmarken unveraendert bei 328.
Das Seitenleisten-Menue bekommt zwei Eintraege:
Beispielprogramme
Notebooks
Download Notebooks als ZIP <- neu, eingerueckt
Glossar <- neu
Stichwortverzeichnis
Gesamtdokument (eine Seite)
Download als PDF
Der ZIP-Link benutzt dieselbe Konstante wie baue_notebooks_seite() beim
Schreiben des Archivs, damit Link und Datei nicht auseinanderlaufen. Das
Glossar erscheint absichtlich doppelt: hier als Abkuerzung neben dem
Stichwortverzeichnis, und unten in der Gruppe "Anhaenge", weil es ein Anhang
ist.
Die verwaiste anhang-glossar-literatur.html von Hand entfernt - der Build
raeumt alte Seiten nicht ab.
Nebenbefund, in PROGRESS.md festgehalten: OR_HTML_04/assets/site.css ist eine
von Hand gepflegte Quelle, die im als "generiert" beschriebenen Verzeichnis
liegt. Der Build schreibt sie nie. Dasselbe gilt fuer site.js, icons.svg,
highlight.css und plotly.min.js.
--check: 5 Teile, 23 Kapitel, 6 Anhaenge, 296 Abschnitte, 825 Querverweise,
328 Indexmarken, 37 Dateien, 28.544 Zeilen, 305 Hauptueberschriften, keine
Warnung. PDF unveraendert 759 Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:48:57 +02:00
|
|
|
Operations_Research_mit_Python_Version_04/ Quelle: 37 Kapiteldateien + Build-Skripte
|
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
|
|
|
bilder_04/ Quelle: Diagramme + erzeuge_*.py-Generatoren
|
|
|
|
|
Operations_Research_mit_Python_Version_04.md generiert: Gesamtdokument
|
|
|
|
|
Operations_Research_mit_Python_Version_04.pdf generiert: PDF (xelatex)
|
|
|
|
|
OR_HTML_04/ generiert: Mehrseiten-Website
|
|
|
|
|
Operations_Research_mit_Python_Version_04_Programme/ generiert: Beispielprogramme
|
|
|
|
|
Notebooks_04/ generiert: ein .ipynb je Kapitel
|
|
|
|
|
Kritik_und_Verbesserungsvorschlaege/ Quelle: Rezension, Verbesserungsvorschläge,
|
|
|
|
|
NEUER_TITEL.md (Vorlage des Titelblatts)
|
|
|
|
|
pyproject.toml Quelle: Abhängigkeiten in Gruppen
|
Veroeffentlichung: Lizenzen, README, Colab-Entscheidung, JupyterLab im Image
Sechs Dinge, alle fuer das jetzt oeffentliche Repository.
LIZENZEN. LICENSE traegt die MIT-Lizenz fuer den Programmcode (alle .py,
Notebooks, Dockerfile, pyproject.toml), LICENSE-TEXT.md die CC BY-SA 4.0 fuer
Buchtext, PDF, Website und Diagramme. Beide Dateien nennen ausdruecklich, was
sie abdecken und was nicht - ein Codeblock im Buchtext bleibt Programmcode und
steht unter MIT. Vorher hatte das Repository gar keine Lizenz, womit
standardmaessig "alle Rechte vorbehalten" galt und niemand die 76 Programme
haette weiterverwenden duerfen.
COLAB. COLAB_BASIS_URL steht jetzt auf "". Der Platzhalter zeigte auf GitHub,
das Repository liegt auf einer eigenen Forgejo-Instanz - und Colab oeffnet
Notebooks NUR aus GitHub, Google Drive oder einem Upload. Die URL-Form
colab.research.google.com/github/... ist fest auf GitHub verdrahtet; eine
selbstgehostete Adresse dort einzusetzen ergaebe keinen Link zum eigenen
Server, sondern einen toten GitHub-Link. Der Kommentar im Quelltext ging von
GitHub aus und war damit selbst irrefuehrend; er ist ersetzt.
Verloren geht nichts: Die 25 Notebooks liegen neben der Website und bekommen
einen echten Download-Link, jetzt mit dem Hinweis, was man damit tut -
"herunterladen und in Jupyter oeffnen, in Colab hochladen oder mit dem
Kurs-Image starten".
JUPYTERLAB IM KURS-IMAGE. Neue pyproject-Gruppe [notebook] mit jupyterlab,
die Notebooks werden ins Image kopiert, und ein kleiner Startbefehl macht
beide Betriebsarten ohne --entrypoint moeglich: ohne Argument JupyterLab, mit
Argument ein einzelnes Programm. Gebaut und geprueft - Rucksack.py laeuft,
JupyterLab antwortet mit HTTP 200 und zeigt alle 25 Notebooks. Image 1,31 ->
1,46 GB. Es laeuft ohne Token, deshalb im README die Portfreigabe an
127.0.0.1 gebunden.
README KOMPLETT NEU. Es war die Bau-Anleitung eines privaten Verzeichnisses
und ist jetzt die Visitenkarte eines oeffentlichen Repositorys: was das Buch
ist, wo man es liest, drei Wege die Beispiele auszufuehren (Container,
schlanke Installation, alles auf einmal), was hier liegt, wie man baut, die
Colab-Frage, die Lizenzen und wie man mitwirkt. Alle relativen Links
geprueft: 0 tot.
.gitattributes. Ohne die Datei entschied core.autocrlf des jeweiligen
Rechners, was beim Klonen passiert - ein Windows-Leser bekam CRLF-Rauschen in
jedem Diff. Jetzt: im Repository immer LF, im Arbeitsverzeichnis passend zum
System, Binaerdateien ausdruecklich ausgenommen. Der Bestand war bereits
sauber (git add --renormalize aendert null Dateien). Zusaetzlich sind die
erzeugten Verzeichnisse als linguist-generated markiert, sonst zaehlt die
Sprachstatistik das Repository als HTML-Projekt.
PROGRESS.md: Remote-Repository als erledigt markiert, der Colab-Befund
festgehalten. CLAUDE.md um Veroeffentlichung, Lizenzen und die neuen Dateien
ergaenzt.
Geprueft: --check ohne Fehler, 0 tote README-Links, 76 Programme unveraendert,
33 pytest-Tests, pyproject baut mit acht Gruppen, PDF 759 Seiten (eine
weniger - die Colab-Zeile entfaellt in 25 Kapiteln).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 14:54:04 +02:00
|
|
|
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
|
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
|
|
|
pandoc-defaults-basis.yaml, pandoc/, pandoc-defaults-buch.yaml PDF-Konfiguration
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Nur die als **Quelle** markierten Verzeichnisse werden von Hand bearbeitet.
|
|
|
|
|
|
|
|
|
|
Dieses Verzeichnis ist seit dem 08.09.2026 ein **eigenes Git-Repository** (`main`). Das
|
|
|
|
|
übergeordnete `OR_mit_Python/` ist nur noch das Archiv der Historie bis zur Trennung und
|
|
|
|
|
verwaltet aktiv allein `Version_03`; es trägt `Version_04/` in seiner `.gitignore`. Commits
|
|
|
|
|
gehören ab jetzt hierher.
|
|
|
|
|
|
|
|
|
|
## Build
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
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
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`--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
|
|
|
|
|
`Handrechnung\n12.1` über zwei Zeilen, an dem jede zeilenweise Suche vorbeiläuft.
|
|
|
|
|
|
|
|
|
|
`build_version_04.py` fasst nicht notwendige harte Zeilenumbrüche innerhalb von Absätzen
|
|
|
|
|
zusammen (`reflow_markdown()`) — viele Markdown-Renderer stellen einen einzelnen Umbruch
|
|
|
|
|
sonst fälschlich als sichtbaren Umbruch dar.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Die wichtigsten Konventionen
|
|
|
|
|
|
|
|
|
|
**Keine abgeleiteten Zahlen im Quelltext.** Das ist die Regel, an der dieses Projekt am
|
Sechster und siebter Fund: die letzten handgeschriebenen Nummern
Der Loesungsanhang trug 98 Marken der Bauart "**9.2 — Ansatz waehlen.**",
saemtlich aus Version 03, wo Unsicherheit Kapitel 9 war. Heute ist es
Kapitel 12, und die Aufgabe wird korrekt als "Aufgabe 12.2" gesetzt.
Das war keine Schoenheitsfrage: "Aufgabe 9.2" existiert wirklich - sie
gehoert zum Kapitel Metaheuristiken ("Zuggroesse und Temperatur"). Wer die
Loesung zu 9.2 nachschlug, landete beim falschen Thema. Beide bisherigen
Pruefungen liefen vorbei: Vor der Zahl steht kein Schluesselwort, und es ist
keine Tabellenzelle.
Zwei Messungen machten die Reparatur billig. In allen 15 nummerierten
Abschnitten gab es exakt so viele Loesungen wie Aufgaben, lueckenlos 1..n -
nur der Kapitelteil war falsch. Und die acht in Phase 3 ergaenzten Kapitel
machten es laengst richtig (**Titel.** ohne Nummer); der Anhang wurde also
nicht auf etwas Neues umgestellt, sondern auf das, was seine neueren Teile
schon taten.
nummeriere_marken() vergibt die Marken jetzt selbst. Der Praefix kommt NICHT
aus "# Anhang A:" - der Anhang ist eine Ueberschrift, seine Abschnitte
gehoeren aber zu 23 verschiedenen Kapiteln. Er kommt aus
{#sec:loesungen-X} -> {#kap:X}; diese Zuordnung gilt geprueft fuer alle 23.
Im Quelltext steht "**{loesung} — Titel.**".
Siebter Fund unterwegs: neun Verweise auf Denkfehler-Nummern. Saetze wie
"siehe Denkfehler 8.1" standen in alter Zaehlung - "8" war in Version 03 das
QP/NLP-Kapitel, heute ist es Graphen. Eine blosse Umnummerierung haette sie
stillschweigend woanders hin zeigen lassen; das Ziel wurde deshalb fuer jeden
einzelnen aus dem Zusammenhang bestimmt und auf {ref:sec:<kapitel>-denkfehler}
umgestellt. Einer steckte in einem Programm-Docstring und bekam nach Regel 12
den Kapitelnamen statt eines Verweises.
Eine bewusste Abweichung vom Plan: Der Denkfehler bekommt GAR KEINE Nummer.
Es gibt je Kapitel genau einen, die zweite Stelle waere immer .1, und er
steht ohnehin unter einer nummerierten Ueberschrift. Eine Nummer, die nie
variiert, holte nur die Fragilitaet zurueck, die hier beseitigt wird. Auch
das folgt den acht neuen Kapiteln, die ihren Denkfehler schon vorher nur mit
dem Titel des Raetsels ankuendigen.
--check bewacht jetzt alle Familien (Denkfehler N.M, Micro-Quiz N, **N.M —
im Anhang) und zaehlt zusaetzlich ab, dass jeder Loesungsabschnitt so viele
{loesung}-Marken hat wie sein Kapitel Aufgaben - das faengt eine vergessene
oder doppelte Loesung, was keine Textsuche leisten kann. Gegengetestet mit
vier kuenstlichen Fehlern auf einmal: alle vier gemeldet, nach dem Rueckbau
null.
Gegenprobe der Umstellung: Gesamtdokument vorher gesichert, nachher
verglichen. 168 geaenderte Zeilen, restlos einer Familie zuzuordnen - 118
Loesungsmarken (138 gesamt minus 20, die in den Kapiteln 1 bis 3 zufaellig
schon stimmten), 15 Anhang-Ueberschriften, 15 Kapitel-Callouts, 12
Micro-Quiz, 7 Zeilen mit Verweisen, 1 Docstring. Keine verschobene oder
inhaltlich veraenderte Zeile.
Ergebnis: 138 Aufgaben, 138 Loesungen, keine ohne Gegenstueck. Micro-Quiz
tragen die echten Kapitelnummern. 293 Abschnitte, 720 Querverweise, 327
Indexmarken, PDF unveraendert 725 Seiten, 33 pytest-Tests, 67 netzfreie
Programme fehlerfrei (die vier yfinance-Programme scheiterten am Rate-Limit
des Anbieters, nicht an dieser Aenderung).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 09:52:41 +02:00
|
|
|
häufigsten gescheitert ist — **sieben** 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).
|
|
|
|
|
Seit dem letzten Fund trägt **keine** Marke mehr eine handgeschriebene Nummer, und `--check`
|
|
|
|
|
bewacht jede Familie. Konkret:
|
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
|
|
|
|
|
|
|
|
* Überschriften: `# Kapitel: <Titel> {#kap:<label>}`, `## Titel {#sec:<label>}` — die Nummer
|
|
|
|
|
vergibt der Build (`resolve_numbering()`, `nummeriere_abschnitte()`).
|
Sechster und siebter Fund: die letzten handgeschriebenen Nummern
Der Loesungsanhang trug 98 Marken der Bauart "**9.2 — Ansatz waehlen.**",
saemtlich aus Version 03, wo Unsicherheit Kapitel 9 war. Heute ist es
Kapitel 12, und die Aufgabe wird korrekt als "Aufgabe 12.2" gesetzt.
Das war keine Schoenheitsfrage: "Aufgabe 9.2" existiert wirklich - sie
gehoert zum Kapitel Metaheuristiken ("Zuggroesse und Temperatur"). Wer die
Loesung zu 9.2 nachschlug, landete beim falschen Thema. Beide bisherigen
Pruefungen liefen vorbei: Vor der Zahl steht kein Schluesselwort, und es ist
keine Tabellenzelle.
Zwei Messungen machten die Reparatur billig. In allen 15 nummerierten
Abschnitten gab es exakt so viele Loesungen wie Aufgaben, lueckenlos 1..n -
nur der Kapitelteil war falsch. Und die acht in Phase 3 ergaenzten Kapitel
machten es laengst richtig (**Titel.** ohne Nummer); der Anhang wurde also
nicht auf etwas Neues umgestellt, sondern auf das, was seine neueren Teile
schon taten.
nummeriere_marken() vergibt die Marken jetzt selbst. Der Praefix kommt NICHT
aus "# Anhang A:" - der Anhang ist eine Ueberschrift, seine Abschnitte
gehoeren aber zu 23 verschiedenen Kapiteln. Er kommt aus
{#sec:loesungen-X} -> {#kap:X}; diese Zuordnung gilt geprueft fuer alle 23.
Im Quelltext steht "**{loesung} — Titel.**".
Siebter Fund unterwegs: neun Verweise auf Denkfehler-Nummern. Saetze wie
"siehe Denkfehler 8.1" standen in alter Zaehlung - "8" war in Version 03 das
QP/NLP-Kapitel, heute ist es Graphen. Eine blosse Umnummerierung haette sie
stillschweigend woanders hin zeigen lassen; das Ziel wurde deshalb fuer jeden
einzelnen aus dem Zusammenhang bestimmt und auf {ref:sec:<kapitel>-denkfehler}
umgestellt. Einer steckte in einem Programm-Docstring und bekam nach Regel 12
den Kapitelnamen statt eines Verweises.
Eine bewusste Abweichung vom Plan: Der Denkfehler bekommt GAR KEINE Nummer.
Es gibt je Kapitel genau einen, die zweite Stelle waere immer .1, und er
steht ohnehin unter einer nummerierten Ueberschrift. Eine Nummer, die nie
variiert, holte nur die Fragilitaet zurueck, die hier beseitigt wird. Auch
das folgt den acht neuen Kapiteln, die ihren Denkfehler schon vorher nur mit
dem Titel des Raetsels ankuendigen.
--check bewacht jetzt alle Familien (Denkfehler N.M, Micro-Quiz N, **N.M —
im Anhang) und zaehlt zusaetzlich ab, dass jeder Loesungsabschnitt so viele
{loesung}-Marken hat wie sein Kapitel Aufgaben - das faengt eine vergessene
oder doppelte Loesung, was keine Textsuche leisten kann. Gegengetestet mit
vier kuenstlichen Fehlern auf einmal: alle vier gemeldet, nach dem Rueckbau
null.
Gegenprobe der Umstellung: Gesamtdokument vorher gesichert, nachher
verglichen. 168 geaenderte Zeilen, restlos einer Familie zuzuordnen - 118
Loesungsmarken (138 gesamt minus 20, die in den Kapiteln 1 bis 3 zufaellig
schon stimmten), 15 Anhang-Ueberschriften, 15 Kapitel-Callouts, 12
Micro-Quiz, 7 Zeilen mit Verweisen, 1 Docstring. Keine verschobene oder
inhaltlich veraenderte Zeile.
Ergebnis: 138 Aufgaben, 138 Loesungen, keine ohne Gegenstueck. Micro-Quiz
tragen die echten Kapitelnummern. 293 Abschnitte, 720 Querverweise, 327
Indexmarken, PDF unveraendert 725 Seiten, 33 pytest-Tests, 67 netzfreie
Programme fehlerfrei (die vier yfinance-Programme scheiterten am Rate-Limit
des Anbieters, nicht an dieser Aenderung).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 09:52:41 +02:00
|
|
|
* Aufgaben, Handrechnungen, Abbildungen, Micro-Quiz: `**Aufgabe ⭐ — Titel.**`,
|
|
|
|
|
`> **✏️ Handrechnung: Titel**`, ``,
|
|
|
|
|
`> **❓ Micro-Quiz: Titel**` — Nummern von `nummeriere_marken()`.
|
|
|
|
|
* **Lösungen in Anhang A: `**{loesung} — Titel.**`** Der Präfix kommt nicht aus
|
|
|
|
|
`# Anhang A:`, sondern aus dem Kapitel des umgebenden `{#sec:loesungen-<X>}`-Abschnitts —
|
|
|
|
|
die Zuordnung `sec:loesungen-<X>` ↔ `kap:<X>` gilt für alle 23. `--check` zählt zusätzlich
|
|
|
|
|
ab, dass es je Kapitel so viele Lösungen wie Aufgaben gibt.
|
|
|
|
|
* **Der Denkfehler bekommt bewusst gar keine Nummer.** Es gibt je Kapitel genau einen, unter
|
|
|
|
|
einer bereits nummerierten Überschrift. Verwiesen wird auf
|
|
|
|
|
`{ref:sec:<kapitel>-denkfehler}`.
|
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
|
|
|
* Im Fließtext `{ref:<label>}`, nie eine Literalzahl.
|
|
|
|
|
* In Code-Kommentaren und Docstrings der Kapitel**name** („Kapitel Metaheuristiken:"), nie
|
|
|
|
|
die Nummer. Auch nicht im Dateinamen.
|
|
|
|
|
|
|
|
|
|
**Querverweise für die Website** laufen über `baue_seiten_registry()` /
|
|
|
|
|
`resolve_numbering_seite()`, nicht über `resolve_numbering()` — nur dort entsteht aus einem
|
|
|
|
|
seitenübergreifenden Verweis `andere-seite.html#anker`.
|
|
|
|
|
|
|
|
|
|
**Stichwortregister:** `{idx:Begriff}` bzw. `{idx:Oberbegriff!Unterbegriff}`. Vor einem neuen
|
|
|
|
|
Begriff prüfen, ob er schon existiert:
|
|
|
|
|
`grep -ohE '\{idx:[^}]+\}' Operations_Research_mit_Python_Version_04/*.md | sort -u` — sonst
|
|
|
|
|
entstehen zwei Registereinträge für dasselbe Konzept. `texindy` sortiert mit dem deutschen
|
|
|
|
|
`din5007`-Modul (Umlaute wie im Telefonbuch); das generische `-L german` bricht ab.
|
|
|
|
|
|
|
|
|
|
**Programme sind ein Artefakt, keine zweite Quelle.** Änderungen gehören in den
|
|
|
|
|
Kapitel-Codeblock, danach `extract_programme_04.py`. Ein Codeblock gilt als vollständiges
|
|
|
|
|
Programm, wenn er mit `#!/usr/bin/env python3`, einer Leerzeile und `# Name.py` beginnt.
|
|
|
|
|
Auch das `README.md` im Programme-Verzeichnis wird erzeugt — aus der Vorlage
|
|
|
|
|
`README_Programme.md`; `requirements.txt` ist die einzige dort von Hand gepflegte Datei.
|
|
|
|
|
|
|
|
|
|
**`or_kern.py` ist der gemeinsame Unterbau** aller Programme (Domänenmodell, `SolverStatus`,
|
|
|
|
|
`Loesung`-DTO, Abnahmeprüfung). Abgedruckt im Kapitel Praxisfallen.
|
|
|
|
|
|
|
|
|
|
**`ortools` und `highspy` lassen sich nicht im selben Prozess importieren** (beide bringen
|
|
|
|
|
eine eigene HiGHS-Kopie mit). Deshalb lädt `or_kern.py` Solverbibliotheken erst in der
|
|
|
|
|
aufrufenden Funktion, und Programme, die beide brauchen, starten getrennte Prozesse (Muster:
|
|
|
|
|
`Ein_System_Vier_Ansaetze.py`, `Solverwechsel_CPSAT_HiGHS.py`). `cvxpy` zieht ein
|
|
|
|
|
installiertes `highspy` bei der Solver-Erkennung selbst mit hinein — der Konflikt entsteht
|
|
|
|
|
also auch indirekt.
|
|
|
|
|
|
|
|
|
|
**Neue Kapiteldatei** ⇒ in die `DATEIEN`-Liste in `build_version_04.py`.
|
|
|
|
|
**Neues Programm** ⇒ drei Stellen: Kapitelkopf („Programme:"), Vorwort
|
|
|
|
|
(„Verzeichnis der Beispielprogramme"), bei neuer Abhängigkeit `requirements.txt` **und**
|
|
|
|
|
`pyproject.toml` (dort in die passende Gruppe, nicht pauschal in die Grundausstattung).
|
|
|
|
|
|
|
|
|
|
Die vollständigen **dreizehn Regeln** stehen in `PLAN.md` Abschnitt 9 — darunter, dass jede
|
|
|
|
|
abgedruckte Ausgabe aus einem echten Lauf stammt und dass `PROGRESS.md` in denselben Commit
|
|
|
|
|
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
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
Die übrigen 14 sind schematisch (Kästen, Pfeile, beschriftete Formeln) und bekommen bewusst
|
|
|
|
|
keinen Generator — dort kann nichts driften. Das Kriterium steht in `PROGRESS.md`
|
|
|
|
|
Abschnitt 6c.
|
|
|
|
|
|
|
|
|
|
Konventionen der Generatoren: `plt.rcParams["svg.hashsalt"] = "or-mit-python-v04"` und
|
Aufgeraeumt: 33 PNG-Zweitfassungen, Bau-Ueberbleibsel, Ausgabepfade
Drei Aufraeumarbeiten - und zwei Funde, die dabei auffielen.
1. DIE PNG-ZWEITFASSUNGEN SIND WEG. Jedes Diagramm lag doppelt vor, als SVG
und als PNG, und kein einziges src=/href= in der Website zeigte je auf ein
PNG. Der Build kopierte sie trotzdem mit: 3,3 MB im Repository plus 3,3 MB,
die bei jeder Veroeffentlichung auf den Webserver gingen. Die 15 Generatoren
schreiben jetzt nur noch SVG, die Docstrings sind mitgezogen. Vor dem
Loeschen geprueft: Jedes PNG hatte sein gleichnamiges SVG, alle 33 waren
versioniert.
FUND 1: erzeuge_kap06_gantt.py folgte als einziger Generator nicht der
Konvention - weder svg.hashsalt noch metadata={"Date": None}. Sein SVG trug
einen echten Zeitstempel und bei jedem Lauf andere clip-path-IDs, war also
nie byteidentisch reproduzierbar, obwohl CLAUDE.md genau das fuer alle
Generatoren festhaelt. Aufgefallen nur, weil nach der PNG-Umstellung 32 von
33 SVGs bitgleich blieben und eines nicht. Jetzt byteidentisch ueber zwei
Laeufe.
FUND 2: spiegle_bilder() legte leere Verzeichnisse auf dem Webserver an. Der
Dateifilter arbeitete korrekt, aber os.walk durchlief auch __pycache__/, und
os.makedirs() erzeugte es am Ziel. Die Verzeichnisliste wird jetzt vorher
gefiltert. Gegengetestet.
2. BAU-UEBERBLEIBSEL entfernt (alle ignoriert und neu erzeugbar):
svg-inkscape/, build_v04.log, .pytest_cache/, Programme/output/, vier
__pycache__/ und die Excel-Mappen. Arbeitsbaum 36 -> 33 MB, danach null
ignorierte Ueberbleibsel.
3. Excel_Bruecke.py SCHREIBT NEBEN DAS SKRIPT statt ins
Arbeitsverzeichnis. Es benutzte blanke relative Namen; wer es aus der
Repository-Wurzel startete, verstreute dort produktionsmix.xlsx und
produktionsmix_ergebnis.xlsx. Jetzt wie die vier anderen schreibenden
Programme ueber os.path.dirname(os.path.abspath(__file__)). Nachgemessen:
Lauf aus der Wurzel legt dort null Dateien ab.
Ausserdem git gc: 653 lose Objekte gepackt, .git von 71 MB auf 28 MB -
reines Repacken, kein Inhalt beruehrt.
Geprueft: alle 33 im Buch referenzierten SVGs vorhanden, in Quelle und
Website; 16 Generatoren fehlerfrei; keine fehlenden Bilder im LaTeX-Lauf;
33 pytest-Tests; PDF unveraendert 760 Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 14:22:26 +02:00
|
|
|
`metadata={"Date": None}` für byteidentische Läufe — **beides, sonst trägt das SVG einen
|
|
|
|
|
Zeitstempel und wechselnde `clip-path`-IDs**. Geschrieben wird **nur SVG**; PNG-Zweitfassungen
|
|
|
|
|
gab es einmal, sie wurden nirgends referenziert; stammt die Instanz aus einem
|
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
|
|
|
Zufallsstrom, wird die Ziehungsreihenfolge des Buchprogramms nachgespielt.
|
|
|
|
|
|
|
|
|
|
## Plotly-Figuren
|
|
|
|
|
|
|
|
|
|
`{plotly:name}` bindet `bilder_04/plotly/<name>.html` in die Kapitelseite ein. Das Fragment
|
|
|
|
|
wird als Rohblock ` ```{=html} ` ausgegeben — **nicht** als blankes HTML: Plotlys Fragment ist
|
|
|
|
|
eine einzige lange Zeile mit eingebetteten Leerzeichenketten, aus der Pandoc sonst einen
|
|
|
|
|
Codeblock macht. Genau daran waren alle vier Figuren kaputt, bis es die Schlussabnahme fand.
|
|
|
|
|
Im PDF steht stattdessen ein Hinweis auf die Website.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
Veroeffentlichung: Lizenzen, README, Colab-Entscheidung, JupyterLab im Image
Sechs Dinge, alle fuer das jetzt oeffentliche Repository.
LIZENZEN. LICENSE traegt die MIT-Lizenz fuer den Programmcode (alle .py,
Notebooks, Dockerfile, pyproject.toml), LICENSE-TEXT.md die CC BY-SA 4.0 fuer
Buchtext, PDF, Website und Diagramme. Beide Dateien nennen ausdruecklich, was
sie abdecken und was nicht - ein Codeblock im Buchtext bleibt Programmcode und
steht unter MIT. Vorher hatte das Repository gar keine Lizenz, womit
standardmaessig "alle Rechte vorbehalten" galt und niemand die 76 Programme
haette weiterverwenden duerfen.
COLAB. COLAB_BASIS_URL steht jetzt auf "". Der Platzhalter zeigte auf GitHub,
das Repository liegt auf einer eigenen Forgejo-Instanz - und Colab oeffnet
Notebooks NUR aus GitHub, Google Drive oder einem Upload. Die URL-Form
colab.research.google.com/github/... ist fest auf GitHub verdrahtet; eine
selbstgehostete Adresse dort einzusetzen ergaebe keinen Link zum eigenen
Server, sondern einen toten GitHub-Link. Der Kommentar im Quelltext ging von
GitHub aus und war damit selbst irrefuehrend; er ist ersetzt.
Verloren geht nichts: Die 25 Notebooks liegen neben der Website und bekommen
einen echten Download-Link, jetzt mit dem Hinweis, was man damit tut -
"herunterladen und in Jupyter oeffnen, in Colab hochladen oder mit dem
Kurs-Image starten".
JUPYTERLAB IM KURS-IMAGE. Neue pyproject-Gruppe [notebook] mit jupyterlab,
die Notebooks werden ins Image kopiert, und ein kleiner Startbefehl macht
beide Betriebsarten ohne --entrypoint moeglich: ohne Argument JupyterLab, mit
Argument ein einzelnes Programm. Gebaut und geprueft - Rucksack.py laeuft,
JupyterLab antwortet mit HTTP 200 und zeigt alle 25 Notebooks. Image 1,31 ->
1,46 GB. Es laeuft ohne Token, deshalb im README die Portfreigabe an
127.0.0.1 gebunden.
README KOMPLETT NEU. Es war die Bau-Anleitung eines privaten Verzeichnisses
und ist jetzt die Visitenkarte eines oeffentlichen Repositorys: was das Buch
ist, wo man es liest, drei Wege die Beispiele auszufuehren (Container,
schlanke Installation, alles auf einmal), was hier liegt, wie man baut, die
Colab-Frage, die Lizenzen und wie man mitwirkt. Alle relativen Links
geprueft: 0 tot.
.gitattributes. Ohne die Datei entschied core.autocrlf des jeweiligen
Rechners, was beim Klonen passiert - ein Windows-Leser bekam CRLF-Rauschen in
jedem Diff. Jetzt: im Repository immer LF, im Arbeitsverzeichnis passend zum
System, Binaerdateien ausdruecklich ausgenommen. Der Bestand war bereits
sauber (git add --renormalize aendert null Dateien). Zusaetzlich sind die
erzeugten Verzeichnisse als linguist-generated markiert, sonst zaehlt die
Sprachstatistik das Repository als HTML-Projekt.
PROGRESS.md: Remote-Repository als erledigt markiert, der Colab-Befund
festgehalten. CLAUDE.md um Veroeffentlichung, Lizenzen und die neuen Dateien
ergaenzt.
Geprueft: --check ohne Fehler, 0 tote README-Links, 76 Programme unveraendert,
33 pytest-Tests, pyproject baut mit acht Gruppen, PDF 759 Seiten (eine
weniger - die Colab-Zeile entfaellt in 25 Kapiteln).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 14:54:04 +02:00
|
|
|
## Veroeffentlichung
|
|
|
|
|
|
Website-Adresse eintragen - und ein Fund beim Nachsehen
https://jamulix.de/OR/ steht jetzt im README (Kopfzeile und Lesen-Tabelle,
mit Direktlinks auf PDF, Gesamtdokument und Notebooks), in der
Namensnennungs-Vorlage von LICENSE-TEXT.md, in CLAUDE.md und in PROGRESS.md.
Beim Eintragen habe ich die Adresse geprueft: Landing-Page, Kapitelseiten,
Diagramme, Notebooks, Suchindex, KaTeX und PDF antworten alle mit HTTP 200,
und die fuenf neuen Synthese-Seiten sind da.
DABEI DER FUND: Die veroeffentlichte Fassung ist einen Bau alt. lp.html
enthaelt noch einen toten Colab-Link, die neue Notebook-Formulierung
("herunterladen und in Jupyter oeffnen...") fehlt, und das PDF dort ist
3.820.135 statt 3.816.207 Bytes gross. Der Stand liegt zwischen Phase 8.1
(die Synthese-Seiten sind schon oben) und der Colab-Umstellung.
OR_HTML_04/ muss also neu kopiert werden.
Damit das nicht wieder unbemerkt auseinanderlaeuft, steht in CLAUDE.md
jetzt, wie man es prueft: ein curl auf lp.html darf 0 Colab-Treffer ergeben,
und die Groesse des dort liegenden PDF muss zur lokalen Datei passen.
Nebenbei die Seitenzahl auf 759 nachgezogen - sie war seit dem Wegfall der
Colab-Zeile in 25 Kapiteln um eine Seite kleiner, im README stand noch 760.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:00:28 +02:00
|
|
|
Das Buch steht online auf <https://jamulix.de/OR/>, das Repository oeffentlich auf
|
|
|
|
|
<https://kitux.de/forgejo/dschlueter/operations_research>.
|
|
|
|
|
|
Notebook-Uebersichtsseite - das fehlende Gegenstueck zu programme.html
Der 403 auf /OR/Notebooks_04/ hatte eine andere Ursache als vermutet: Beim
Eintragen der Website-Adresse ins README hatte ich in der Lesen-Tabelle das
VERZEICHNIS verlinkt. Keine Seite der Website tut das - die Kapitelseiten
zeigen direkt auf Notebooks_04/<name>.ipynb, und das funktioniert. Der
Webserver verweigert Directory-Listing, zu Recht.
Die Frage "gibt es so etwas nicht schon?" war aber berechtigt und hat die
eigentliche Luecke sichtbar gemacht: baue_programme_seite() erzeugt seit
jeher programme.html, eine gestaltete Uebersicht der 76 Programme. Fuer die
25 Notebooks gab es kein Gegenstueck - sie wurden ausgeliefert, aber keine
Seite listete sie.
Neu ist baue_notebooks_seite(), nach demselben Muster und mit denselben
Bausteinen: die Zuordnung Seite -> Notebook kommt fertig aus
baue_notebooks(), Rahmen und Navigation aus baue_seiten_schablone() und
baue_sidebar_html(). Gruppiert nach Vorspann, Kapiteln und Anhaengen; der
einleitende Absatz nennt die drei Wege, ein Notebook auszufuehren.
Dazu ein ZIP mit allen 25 Notebooks (208 KB), byteidentisch ueber zwei
Laeufe. Ein ZIP speichert je Eintrag die Aenderungszeit; ohne festen Wert
entstuende bei jedem Bau eine andere Datei, und da OR_HTML_04/ versioniert
ist, wuechse das Repository bei jedem Lauf. Die Eintraege werden deshalb
sortiert und mit ZipInfo(date_time=(1980,1,1,0,0,0)) geschrieben - dieselbe
Sorgfalt wie svg.hashsalt bei den Diagrammen.
Gegen kuenftige 403 schreiben spiegle_notebooks() und baue_programme_seite()
je eine dreizeilige index.html mit meta refresh in ihr Downloadverzeichnis.
Das behebt zugleich denselben latenten Fall bei programme/.
Ein eigener Fehler, zum zweiten Mal derselbe: Das .replace(",", ".") fuer
deutsche Tausenderpunkte hing am Ende eines mehrzeiligen f-Strings - und in
Python bindet die Methode an die GESAMTE zusammengesetzte Zeichenkette. Aus
"Drei Wege, sie auszufuehren" wurde "Drei Wege. sie auszufuehren". Exakt der
Fehler, vor dem ich in erzeuge_wirkung.py selbst einen Kommentar hinterlassen
hatte. Die Zahl wird jetzt getrennt formatiert.
Geprueft: 25 gelistete Notebooks, 0 tote Links auf der Seite, ZIP mit 25
Eintraegen und identischen Zeitstempeln, Seitenleisteneintrag auf allen 40
Seiten mit Seitenleiste, --check fehlerfrei, PDF unveraendert 759 Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:20:06 +02:00
|
|
|
Die Website hat vier Übersichtsseiten: `index.html` (Landing), `programme.html`,
|
|
|
|
|
`notebooks.html` und `stichwortverzeichnis.html`. Die beiden Downloadverzeichnisse
|
|
|
|
|
`programme/` und `Notebooks_04/` bekommen je eine `index.html`, die auf ihre Übersicht
|
|
|
|
|
weiterleitet — sonst antwortet der Webserver mit 403, weil Directory-Listing abgeschaltet
|
|
|
|
|
ist.
|
|
|
|
|
|
Website-Adresse eintragen - und ein Fund beim Nachsehen
https://jamulix.de/OR/ steht jetzt im README (Kopfzeile und Lesen-Tabelle,
mit Direktlinks auf PDF, Gesamtdokument und Notebooks), in der
Namensnennungs-Vorlage von LICENSE-TEXT.md, in CLAUDE.md und in PROGRESS.md.
Beim Eintragen habe ich die Adresse geprueft: Landing-Page, Kapitelseiten,
Diagramme, Notebooks, Suchindex, KaTeX und PDF antworten alle mit HTTP 200,
und die fuenf neuen Synthese-Seiten sind da.
DABEI DER FUND: Die veroeffentlichte Fassung ist einen Bau alt. lp.html
enthaelt noch einen toten Colab-Link, die neue Notebook-Formulierung
("herunterladen und in Jupyter oeffnen...") fehlt, und das PDF dort ist
3.820.135 statt 3.816.207 Bytes gross. Der Stand liegt zwischen Phase 8.1
(die Synthese-Seiten sind schon oben) und der Colab-Umstellung.
OR_HTML_04/ muss also neu kopiert werden.
Damit das nicht wieder unbemerkt auseinanderlaeuft, steht in CLAUDE.md
jetzt, wie man es prueft: ein curl auf lp.html darf 0 Colab-Treffer ergeben,
und die Groesse des dort liegenden PDF muss zur lokalen Datei passen.
Nebenbei die Seitenzahl auf 759 nachgezogen - sie war seit dem Wegfall der
Colab-Zeile in 25 Kapiteln um eine Seite kleiner, im README stand noch 760.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:00:28 +02:00
|
|
|
**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.
|
Veroeffentlichung: Lizenzen, README, Colab-Entscheidung, JupyterLab im Image
Sechs Dinge, alle fuer das jetzt oeffentliche Repository.
LIZENZEN. LICENSE traegt die MIT-Lizenz fuer den Programmcode (alle .py,
Notebooks, Dockerfile, pyproject.toml), LICENSE-TEXT.md die CC BY-SA 4.0 fuer
Buchtext, PDF, Website und Diagramme. Beide Dateien nennen ausdruecklich, was
sie abdecken und was nicht - ein Codeblock im Buchtext bleibt Programmcode und
steht unter MIT. Vorher hatte das Repository gar keine Lizenz, womit
standardmaessig "alle Rechte vorbehalten" galt und niemand die 76 Programme
haette weiterverwenden duerfen.
COLAB. COLAB_BASIS_URL steht jetzt auf "". Der Platzhalter zeigte auf GitHub,
das Repository liegt auf einer eigenen Forgejo-Instanz - und Colab oeffnet
Notebooks NUR aus GitHub, Google Drive oder einem Upload. Die URL-Form
colab.research.google.com/github/... ist fest auf GitHub verdrahtet; eine
selbstgehostete Adresse dort einzusetzen ergaebe keinen Link zum eigenen
Server, sondern einen toten GitHub-Link. Der Kommentar im Quelltext ging von
GitHub aus und war damit selbst irrefuehrend; er ist ersetzt.
Verloren geht nichts: Die 25 Notebooks liegen neben der Website und bekommen
einen echten Download-Link, jetzt mit dem Hinweis, was man damit tut -
"herunterladen und in Jupyter oeffnen, in Colab hochladen oder mit dem
Kurs-Image starten".
JUPYTERLAB IM KURS-IMAGE. Neue pyproject-Gruppe [notebook] mit jupyterlab,
die Notebooks werden ins Image kopiert, und ein kleiner Startbefehl macht
beide Betriebsarten ohne --entrypoint moeglich: ohne Argument JupyterLab, mit
Argument ein einzelnes Programm. Gebaut und geprueft - Rucksack.py laeuft,
JupyterLab antwortet mit HTTP 200 und zeigt alle 25 Notebooks. Image 1,31 ->
1,46 GB. Es laeuft ohne Token, deshalb im README die Portfreigabe an
127.0.0.1 gebunden.
README KOMPLETT NEU. Es war die Bau-Anleitung eines privaten Verzeichnisses
und ist jetzt die Visitenkarte eines oeffentlichen Repositorys: was das Buch
ist, wo man es liest, drei Wege die Beispiele auszufuehren (Container,
schlanke Installation, alles auf einmal), was hier liegt, wie man baut, die
Colab-Frage, die Lizenzen und wie man mitwirkt. Alle relativen Links
geprueft: 0 tot.
.gitattributes. Ohne die Datei entschied core.autocrlf des jeweiligen
Rechners, was beim Klonen passiert - ein Windows-Leser bekam CRLF-Rauschen in
jedem Diff. Jetzt: im Repository immer LF, im Arbeitsverzeichnis passend zum
System, Binaerdateien ausdruecklich ausgenommen. Der Bestand war bereits
sauber (git add --renormalize aendert null Dateien). Zusaetzlich sind die
erzeugten Verzeichnisse als linguist-generated markiert, sonst zaehlt die
Sprachstatistik das Repository als HTML-Projekt.
PROGRESS.md: Remote-Repository als erledigt markiert, der Colab-Befund
festgehalten. CLAUDE.md um Veroeffentlichung, Lizenzen und die neuen Dateien
ergaenzt.
Geprueft: --check ohne Fehler, 0 tote README-Links, 76 Programme unveraendert,
33 pytest-Tests, pyproject baut mit acht Gruppen, PDF 759 Seiten (eine
weniger - die Colab-Zeile entfaellt in 25 Kapiteln).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 14:54:04 +02:00
|
|
|
|
|
|
|
|
**`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
|
|
|
|
|
verdrahtet und kann eine selbstgehostete Git-Instanz nicht lesen. Statt eines toten Knopfes
|
|
|
|
|
bekommt jedes Kapitel einen Download-Link auf sein Notebook. Wer spaeter nach GitHub
|
|
|
|
|
spiegelt, traegt dort **einen** Wert ein.
|
|
|
|
|
|
|
|
|
|
Wer ohne eigene Installation rechnen will, nimmt das Kurs-Image:
|
|
|
|
|
`docker run --rm -p 127.0.0.1:8888:8888 or-mit-python` startet JupyterLab mit allen
|
|
|
|
|
25 Notebooks. Ohne Portfreigabe und mit einem Programmnamen als Argument fuehrt dasselbe
|
|
|
|
|
Image ein einzelnes Programm aus.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
|
|
|
## Sprache
|
|
|
|
|
|
|
|
|
|
Kommentare, Ausgaben und Fließtext sind durchgängig **Deutsch** — diesen Stil beibehalten.
|