Loesungs-Dedup: getGruppenId/getPersonenId, keine doppelten Sitzordnungen
- getGruppenId (Gruppen-Ebene, personen-unabhaengig: welche Gruppen mit welcher Anzahl je Tisch) und getPersonenId (Personen-Ebene: alphabetische Namen je Tisch) an Sitzplatzverteilung; Basis-Methoden an Loesung. Gleiche Gruppen-Verteilung -> gleiche getGruppenId und damit gleiche Wertigkeit, egal welche Personen die geteilten Plaetze einnehmen. - Farm verwirft nach jeder Erzeugung/Mutation Loesungen mit schon gesehener getGruppenId, so dass dieselbe Sitzordnung nicht mehrfach gehalten und bewertet wird (defensiv: Klassen ohne getGruppenId bleiben unberuehrt, Tests unveraendert). - Web: Varianten-Vergleich ueber getGruppenId statt der person-basierten _Signatur; gruppenId und personenId zusaetzlich im Ergebnis-JSON. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ from random import *
|
||||
import ast
|
||||
import configparser, os
|
||||
import copy
|
||||
import hashlib
|
||||
import html
|
||||
import math
|
||||
from collections import defaultdict
|
||||
@@ -1114,6 +1115,44 @@ class Sitzplatzverteilung:
|
||||
return len( self.Gid_Tid[Gruppe.Id] ) - 1
|
||||
except KeyError:
|
||||
return 0
|
||||
def getGruppenId(self):
|
||||
"""eindeutige Id der Loesung auf GRUPPEN-Ebene (personen-unabhaengig).
|
||||
|
||||
Signatur: je Tisch, welche Gruppen mit wie vielen Mitgliedern dort
|
||||
sitzen. Zwei Loesungen mit identischer Gruppen-Verteilung bekommen
|
||||
dieselbe Id - egal welche konkreten Personen die geteilten Plaetze
|
||||
einnehmen (die Teilung einer 5er-Gruppe auf die Tische 3 und 4 ist
|
||||
dieselbe Sitzordnung, gleich welche Personen wohin kommen). Da die
|
||||
Bewertung (Strafliste) nur von den Gruppen-Anzahlen je Tisch, den
|
||||
Nachbarschaften und der Auslastung abhaengt, haben Loesungen mit
|
||||
gleicher getGruppenId auch dieselbe Wertigkeit. Diese Id dient dem
|
||||
Vergleich der Loesungen (Dedup), damit dieselbe Sitzordnung nicht
|
||||
mehrfach als eigene Loesung gehalten und bewertet wird."""
|
||||
Teile = []
|
||||
for T in sorted( self.Tische, key=lambda t: t.Id ):
|
||||
Zaehler = {}
|
||||
for P in T:
|
||||
try:
|
||||
Gid = self.Gruppen.GruppeVonPid( P.Id ).Id
|
||||
except KeyError:
|
||||
Gid = -1 # VIP / feste Platzierung (ohne GA-Gruppe)
|
||||
Zaehler[Gid] = Zaehler.get( Gid, 0 ) + 1
|
||||
Teile.append( (T.Id, tuple(sorted( Zaehler.items() ))) )
|
||||
return hashlib.sha1( repr(Teile).encode('utf-8') ).hexdigest()[:16]
|
||||
def getPersonenId(self):
|
||||
"""eindeutige Id der Loesung auf PERSONEN-Ebene.
|
||||
|
||||
Signatur: je Tisch die alphabetisch sortierten Personennamen.
|
||||
Identifiziert WIRKLICH identische Sitzbelegungen (dieselben Personen
|
||||
an denselben Tischen) - feiner als getGruppenId, das nur die Gruppen-
|
||||
Verteilung vergleicht."""
|
||||
Teile = []
|
||||
for T in sorted( self.Tische, key=lambda t: t.Id ):
|
||||
Namen = sorted(
|
||||
' '.join( s for s in (P._Titel, P._Vorname, P._Name) if s )
|
||||
for P in T )
|
||||
Teile.append( (T.Id, tuple(Namen)) )
|
||||
return hashlib.sha1( repr(Teile).encode('utf-8') ).hexdigest()[:16]
|
||||
def VIPsSetzen(self, VIPListe, VIPs, Tische ):
|
||||
"""setze die VIPs auf Ihre Plaetze"""
|
||||
#print " VIPsSetzen:"
|
||||
|
||||
+32
-1
@@ -61,6 +61,15 @@ class Loesung:
|
||||
print(" lade Loesung " + repr(self.Id))
|
||||
def speichern(self):
|
||||
print(" speichere Loesung " + repr(self.Id))
|
||||
def getGruppenId(self):
|
||||
"""Id fuer den Dedup-Vergleich (Basis: jede Loesung eigenstaendig).
|
||||
Unterklassen ueberladen dies mit einer inhaltlichen Signatur, so
|
||||
dass gleiche Loesungen dieselbe Id bekommen und nicht mehrfach
|
||||
gehalten werden."""
|
||||
return id(self)
|
||||
def getPersonenId(self):
|
||||
"""feinere Id fuer wirklich identische Loesungen (Basis: eigenstaendig)"""
|
||||
return id(self)
|
||||
def __repr__(self):
|
||||
return ' L '+ repr(self.Id)
|
||||
def __eq__(self,other):
|
||||
@@ -493,6 +502,9 @@ class Farm:
|
||||
self.Abstammung = Abstammung()
|
||||
self._AbsZaehler = 0 # vergibt fortlaufende Loesungs-Ids 1..N
|
||||
self._Generation = 0
|
||||
# schon gesehene Loesungs-Signaturen (getGruppenId), damit dieselbe
|
||||
# Sitzordnung nicht mehrfach gehalten und bewertet wird.
|
||||
self._GeseheneGruppenIds = set()
|
||||
if getattr(Zyklus, 'Modus', 'statisch') == 'adaptiv':
|
||||
self._LaufAdaptiv(Klasse, *Arguments, **keywords)
|
||||
else:
|
||||
@@ -580,10 +592,27 @@ class Farm:
|
||||
self._AbsZaehler = self._AbsZaehler + 1
|
||||
return self._AbsZaehler
|
||||
|
||||
def _LoesungIstNeu(self, L):
|
||||
"""Kontrolle nach jeder Erzeugung: True, wenn die Loesung eine bisher
|
||||
ungesehene Sitzordnung hat (Vergleich ueber getGruppenId, also auf
|
||||
Gruppen-Ebene) - und merkt sie dann vor. Duplikate (gleiche Sitz-
|
||||
ordnung) werden so nicht noch einmal gehalten und bewertet.
|
||||
Loesungen ohne getGruppenId gelten immer als neu (kein Dedup)."""
|
||||
Hole = getattr(L, 'getGruppenId', None)
|
||||
if Hole is None:
|
||||
return True
|
||||
Gid = Hole()
|
||||
if Gid in self._GeseheneGruppenIds:
|
||||
return False
|
||||
self._GeseheneGruppenIds.add(Gid)
|
||||
return True
|
||||
|
||||
def LoesungenErzeugen(self, N, Klasse, *Arguments, **keywords):
|
||||
""" Erzeuge Loesungen"""
|
||||
""" Erzeuge Loesungen (bereits gesehene Sitzordnungen werden verworfen)"""
|
||||
for i in range(N):
|
||||
L = Klasse( *Arguments, **keywords )
|
||||
if not self._LoesungIstNeu(L):
|
||||
continue # gleiche Sitzordnung schon vorhanden -> nicht behalten
|
||||
L._absid = self._NeueId() # Wurzel: kein Vorgaenger
|
||||
self.Abstammung.erfassen(
|
||||
L._absid, None, self._Generation, getattr(L, 'value', 0), 'e' )
|
||||
@@ -603,6 +632,8 @@ class Farm:
|
||||
for L in chain(self.Pool):
|
||||
O = deepcopy(L)
|
||||
Kind = O.mutieren()
|
||||
if not self._LoesungIstNeu(Kind):
|
||||
continue # gleiche Sitzordnung schon gesehen -> verwerfen
|
||||
# Kind bekommt eine neue fortlaufende Nummer; der Vorgaenger
|
||||
# (Eltern-Id) wird separat in der Abstammung gemerkt.
|
||||
ElternId = getattr(L, '_absid', None)
|
||||
|
||||
Reference in New Issue
Block a user