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>
178 lines
9.6 KiB
Markdown
178 lines
9.6 KiB
Markdown
# 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)`).
|
|
|
|
```
|
|
Operations_Research_mit_Python_Version_04/ Quelle: 36 Kapiteldateien + Build-Skripte
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
|
|
* Überschriften: `# Kapitel: <Titel> {#kap:<label>}`, `## Titel {#sec:<label>}` — die Nummer
|
|
vergibt der Build (`resolve_numbering()`, `nummeriere_abschnitte()`).
|
|
* 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}`.
|
|
* 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
|
|
`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
|
|
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
|
|
|
|
Das Repository liegt oeffentlich auf <https://kitux.de/forgejo/dschlueter/operations_research>.
|
|
|
|
**`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.
|
|
|
|
---
|
|
|
|
## Sprache
|
|
|
|
Kommentare, Ausgaben und Fließtext sind durchgängig **Deutsch** — diesen Stil beibehalten.
|