Adaptiver GA-Zyklus, Pool-Groessen-Panel, Konfig direkt aus cfg-Dateien

Zyklus/Farm:
- neuer adaptiver Modus: grosse Startpopulation, die je Generation
  schrumpft (Start/Schrumpfung/MinPopulation) und bei Konvergenz stoppt
  (Geduld Generationen ohne Verbesserung >= Schwelle, max MaxGenerationen)
- Zyklus.laden erkennt adaptives Profil am Feld 'Start' (Modus adaptiv),
  sonst klassisch (Abfolge/Anzahl); Farm._LaufStatisch/_LaufAdaptiv
- neue Trunkierungs-Selektion Farm.PopulationBegrenzen
- [Adaptiv]-Profil in zyklus.cfg (dokumentiert)

Entwicklungsgrafik:
- zweites Panel unter dem Verlauf zeigt die Anzahl erzeugter
  Verteilungen im Pool je Schritt (gemeinsame Zeitachse)

Konfiguration:
- platz.cfg entfernt; zyklus.cfg/strafen.cfg werden direkt aus
  $PLATZ_CFG geladen
- neuer Schalter --zyklus-art (Default Adaptiv) waehlt das GA-Profil
- web/main.py analog: direktes Laden, Profil via PLATZ_ZYKLUSART

Doku (README.md, CLAUDE.md) und Tests entsprechend aktualisiert;
Beispiele mit dem Adaptiv-Default neu berechnet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Michael Stangl
2026-07-11 14:31:59 +02:00
parent 4f87895303
commit 644f61ef6b
23 changed files with 1909 additions and 1607 deletions
+24 -14
View File
@@ -70,18 +70,27 @@ the same layout:
- Output (written back into the same `--indir` directory): `TischePersonen.txt` (table →
seated people) and `PersonenTische.csv` (person → table, sorted).
`cfg/platz.cfg` (still located via `$PLATZ_CFG`, independent of `--indir`) only selects the
GA cycle/penalty config:
- `cfg/zyklus.cfg` — defines the GA run schedule ("Zyklus"): a sequence of actions
(`e`=erzeugen/create, `s`=selektieren/select-best, `S`=random-select, `m`=mutieren/mutate,
`j`=behalten/keep parents, `z`=neue Generation/advance generation) each with a count.
The GA cycle and penalty scheme are read directly from `$PLATZ_CFG/zyklus.cfg` and
`$PLATZ_CFG/strafen.cfg` (independent of `--indir`). There is no `platz.cfg` indirection any
more — it was removed; `zyklus.cfg`/`strafen.cfg` are loaded straight from `$PLATZ_CFG`, and
the GA profile is chosen by the `--zyklus-art <name>` switch (default `Adaptiv`).
- `cfg/zyklus.cfg` — defines the GA profiles. Two flavours: **static** profiles (`Easy`,
`Simple`) give an explicit sequence of actions (`e`=erzeugen/create, `s`=selektieren/
select-best, `S`=random-select, `m`=mutieren/mutate, `j`=behalten/keep parents, `z`=neue
Generation/advance generation) each with a count (`Abfolge`/`Anzahl`). The **adaptive**
profile (`Adaptiv`, the default) is recognised by a `Start` field and has no fixed action
list: `Zyklus.Modus` becomes `'adaptiv'` and `Farm._LaufAdaptiv()` runs a generation loop
with a shrinking population (`Start`, `Schrumpfung`, `MinPopulation`) and a convergence
stop (`Geduld` generations without an improvement of at least `Schwelle`, capped by
`MaxGenerationen`). Static profiles run via `Farm._LaufStatisch()`.
- `cfg/strafen.cfg` — the penalty ("Strafpunkte") table: cost of splitting a group across
tables (by group size and number of splits), cost of a lone person, and per-table
under-utilization penalties.
tables (by group size and number of splits), cost of a lone person, per-table
under-utilization penalties, and (optional `[Abstand]` section) a penalty for the spatial
distance between split-off parts of a group.
`tische.ini`/`bestellung.json`/`TischePersonen.txt`/`PersonenTische.csv` are fixed filenames
resolved as `os.path.join(indir, ...)` in `platz.py` — they are no longer configured in
`platz.cfg`.
resolved as `os.path.join(indir, ...)` in `platz.py`.
Pass `--tosvg` to additionally write `<indir>/Sitzplatzverteilung.svg` via
`Sitzplatzverteilung.alsSVG()` (see below).
@@ -139,11 +148,12 @@ Domain-agnostic and reusable in principle:
`XMLConfig` did not; `CSVConfig` (the web CSV adapter) returns the same 5-tuple.
### Data flow through `platz.py` (`__main__`)
1. Parse `--indir` (required) from the command line via `optparse`.
2. Read `platz.cfg` to locate `zyklus.cfg`/`strafen.cfg` (env-var expansion via
`os.path.expandvars`).
3. Load `Zyklus` (GA schedule), `Strafliste` (penalties), `Tische` (table layout, from
`<indir>/tische.ini`).
1. Parse `--indir` (required) and `--zyklus-art` (default `Adaptiv`) from the command line
via `optparse`.
2. Resolve `zyklus.cfg`/`strafen.cfg` directly as `os.path.join($PLATZ_CFG, ...)`.
3. Load `Zyklus` (GA profile named by `--zyklus-art`), `Strafliste` (penalties), `Tische`
(table layout, from `<indir>/tische.ini`).
4. Load `<indir>/bestellung.json` via `JSONConfig` → people, groups, VIP group, VIP seat
map, group names.
5. Build a `Farm(Zyklus, Sitzplatzverteilung, Tische=..., Gruppen=..., Strafen=...,