refactoring: lokale fairness
This commit is contained in:
parent
03d1c362f1
commit
9588e75ee0
@ -252,7 +252,7 @@ class Elterndienstplaner:
|
||||
return faktor
|
||||
return 0
|
||||
|
||||
def berechne_faire_zielverteilung(self) -> DefaultDict[str, DefaultDict[Dienst, float]]:
|
||||
def berechne_faire_zielverteilung_global(self) -> DefaultDict[str, DefaultDict[Dienst, float]]:
|
||||
"""Berechnet die faire Zielanzahl von Diensten pro Eltern-Dienst-Kombination
|
||||
basierend auf tatsächlich geleisteten historischen Diensten und deren fairer Umverteilung"""
|
||||
|
||||
@ -356,6 +356,55 @@ class Elterndienstplaner:
|
||||
|
||||
return ziel_dienste
|
||||
|
||||
def berechne_faire_zielverteilung_lokal(self) -> DefaultDict[str, DefaultDict[Dienst, float]]:
|
||||
"""Berechnet die lokale faire Zielanzahl von Diensten pro Eltern-Dienst-Kombination
|
||||
basierend auf Dienstfaktoren und benötigten Diensten im aktuellen Planungsmonat"""
|
||||
|
||||
ziel_dienste_lokal: DefaultDict[str, DefaultDict[Dienst, float]] = \
|
||||
defaultdict(lambda: defaultdict(float))
|
||||
|
||||
print("\nBerechne lokale faire Zielverteilung für aktuellen Monat...")
|
||||
|
||||
# Gesamtdienstfaktor für aktuellen Monat berechnen
|
||||
gesamt_dienstfaktor_monat = sum(
|
||||
sum(self.dienstfaktoren.get(e, {}).get(tag, 0) for tag in self.tage)
|
||||
for e in self.eltern
|
||||
)
|
||||
|
||||
if gesamt_dienstfaktor_monat == 0:
|
||||
print(" WARNUNG: Gesamtdienstfaktor ist 0, keine lokale Zielverteilung möglich")
|
||||
return ziel_dienste_lokal
|
||||
|
||||
# Für jeden Dienst die lokale faire Verteilung berechnen
|
||||
for dienst in self.dienste:
|
||||
# Anzahl benötigter Dienste im aktuellen Monat
|
||||
benoetigte_dienste_monat = sum(
|
||||
1 for tag in self.tage
|
||||
if dienst in self.benoetigte_dienste.get(tag, [])
|
||||
)
|
||||
# Multipliziere mit Anzahl benötigter Personen pro Dienst
|
||||
benoetigte_dienste_monat *= dienst.personen_anzahl
|
||||
|
||||
if benoetigte_dienste_monat > 0:
|
||||
print(f" {dienst.kuerzel}: {benoetigte_dienste_monat} Dienste benötigt")
|
||||
|
||||
for eltern in self.eltern:
|
||||
# Dienstfaktor für diesen Elternteil im aktuellen Monat
|
||||
monatlicher_dienstfaktor = sum(
|
||||
self.dienstfaktoren.get(eltern, {}).get(tag, 0) for tag in self.tage
|
||||
)
|
||||
|
||||
if monatlicher_dienstfaktor > 0:
|
||||
anteil = monatlicher_dienstfaktor / gesamt_dienstfaktor_monat
|
||||
faire_zuteilung = anteil * benoetigte_dienste_monat
|
||||
ziel_dienste_lokal[eltern][dienst] = faire_zuteilung
|
||||
|
||||
if faire_zuteilung > 0.1: # Debug nur für relevante Werte
|
||||
print(f" {eltern}: Faktor={monatlicher_dienstfaktor:.1f} "
|
||||
f"-> {faire_zuteilung:.2f} Dienste")
|
||||
|
||||
return ziel_dienste_lokal
|
||||
|
||||
def erstelle_optimierungsmodell(self) -> Tuple[pulp.LpProblem, Dict[Tuple[str, date, Dienst], pulp.LpVariable]]:
|
||||
"""Erstellt das PuLP Optimierungsmodell"""
|
||||
print("Erstelle Optimierungsmodell...")
|
||||
@ -442,8 +491,9 @@ class Elterndienstplaner:
|
||||
# FAIRNESS-CONSTRAINTS UND ZIELFUNKTION
|
||||
objective_terms = []
|
||||
|
||||
# Berechne faire Zielverteilung
|
||||
ziel_dienste = self.berechne_faire_zielverteilung()
|
||||
# Berechne faire Zielverteilungen (global und lokal)
|
||||
ziel_dienste_global = self.berechne_faire_zielverteilung_global()
|
||||
ziel_dienste_lokal = self.berechne_faire_zielverteilung_lokal()
|
||||
|
||||
# Hilfsvariablen für Fairness-Abweichungen
|
||||
fairness_abweichung_lokal = {} # F2
|
||||
@ -459,12 +509,6 @@ class Elterndienstplaner:
|
||||
# F1: Globale Fairness & F2: Lokale Fairness
|
||||
for eltern in self.eltern:
|
||||
for dienst in self.dienste:
|
||||
# Dienstfaktor für aktuellen Monat
|
||||
monatlicher_dienstfaktor = sum(
|
||||
self.dienstfaktoren.get(eltern, {}).get(tag, 0) for tag in self.tage
|
||||
)
|
||||
|
||||
if monatlicher_dienstfaktor > 0:
|
||||
# Tatsächliche Dienste im aktuellen Monat
|
||||
tatsaechliche_dienste_monat = pulp.lpSum(
|
||||
x[eltern, tag, dienst]
|
||||
@ -473,41 +517,26 @@ class Elterndienstplaner:
|
||||
)
|
||||
|
||||
# F2: Lokale Fairness - nur aktueller Monat
|
||||
benoetigte_dienste_monat = sum(
|
||||
1 for tag in self.tage
|
||||
if dienst in self.benoetigte_dienste.get(tag, [])
|
||||
)
|
||||
# Multipliziere mit Anzahl benötigter Personen pro Dienst
|
||||
benoetigte_dienste_monat *= dienst.personen_anzahl
|
||||
|
||||
gesamt_dienstfaktor_monat = sum(
|
||||
sum(self.dienstfaktoren.get(e, {}).get(tag, 0) for tag in self.tage)
|
||||
for e in self.eltern
|
||||
)
|
||||
|
||||
if gesamt_dienstfaktor_monat > 0 and benoetigte_dienste_monat > 0:
|
||||
erwartete_dienste_lokal = (
|
||||
monatlicher_dienstfaktor / gesamt_dienstfaktor_monat
|
||||
) * benoetigte_dienste_monat
|
||||
|
||||
# F2: Lokale Fairness-Constraints
|
||||
prob += (tatsaechliche_dienste_monat - erwartete_dienste_lokal <=
|
||||
ziel_lokal = ziel_dienste_lokal[eltern][dienst]
|
||||
if ziel_lokal > 0:
|
||||
# Lokale Fairness-Constraints
|
||||
prob += (tatsaechliche_dienste_monat - ziel_lokal <=
|
||||
fairness_abweichung_lokal[eltern, dienst])
|
||||
prob += (erwartete_dienste_lokal - tatsaechliche_dienste_monat <=
|
||||
prob += (ziel_lokal - tatsaechliche_dienste_monat <=
|
||||
fairness_abweichung_lokal[eltern, dienst])
|
||||
|
||||
# F1: Globale Fairness - basierend auf berechneter Zielverteilung
|
||||
ziel_gesamt = ziel_dienste[eltern][dienst]
|
||||
ziel_global = ziel_dienste_global[eltern][dienst]
|
||||
vorherige_dienste = self.vorherige_dienste[eltern][dienst]
|
||||
|
||||
if ziel_gesamt > 0:
|
||||
if ziel_global > 0:
|
||||
# Tatsächliche Dienste global (Vergangenheit + geplant)
|
||||
total_dienste_inkl_vergangenheit = tatsaechliche_dienste_monat + vorherige_dienste
|
||||
|
||||
# F1: Globale Fairness-Constraints
|
||||
prob += (total_dienste_inkl_vergangenheit - ziel_gesamt <=
|
||||
# Globale Fairness-Constraints
|
||||
prob += (total_dienste_inkl_vergangenheit - ziel_global <=
|
||||
fairness_abweichung_global[eltern, dienst])
|
||||
prob += (ziel_gesamt - total_dienste_inkl_vergangenheit <=
|
||||
prob += (ziel_global - total_dienste_inkl_vergangenheit <=
|
||||
fairness_abweichung_global[eltern, dienst])
|
||||
|
||||
# Gewichtung: Jahresanfang F1 stärker, Jahresende F2 stärker
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user