Dienstaufwand und paralleles Rechnen
This commit is contained in:
parent
9f7d3c6d4a
commit
f7b1267c98
@ -15,16 +15,17 @@ from csv_io import EingabeParser
|
||||
class Dienst:
|
||||
"""Repräsentiert einen Diensttyp mit allen seinen Eigenschaften"""
|
||||
|
||||
def __init__(self, kuerzel: str, name: str, personen_anzahl: int = 1) -> None:
|
||||
def __init__(self, kuerzel: str, name: str, personen_anzahl: int = 1, aufwand: int = 1) -> None:
|
||||
self.kuerzel: str = kuerzel
|
||||
self.name: str = name
|
||||
self.personen_anzahl: int = personen_anzahl
|
||||
self.aufwand: int = aufwand
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.kuerzel} ({self.name}): {self.personen_anzahl} Person(en)"
|
||||
return f"{self.kuerzel} ({self.name}): {self.personen_anzahl} Person(en), Aufwand={self.aufwand}"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Dienst('{self.kuerzel}', '{self.name}', {self.personen_anzahl})"
|
||||
return f"Dienst('{self.kuerzel}', '{self.name}', {self.personen_anzahl}, {self.aufwand})"
|
||||
|
||||
def braucht_mehrere_personen(self) -> bool:
|
||||
"""Gibt True zurück, wenn mehr als eine Person benötigt wird"""
|
||||
@ -49,11 +50,11 @@ class ElterndienstplanerDaten:
|
||||
def __init__(self) -> None:
|
||||
# Dienste als Liste definieren
|
||||
self.dienste: List[Dienst] = [
|
||||
Dienst('F', 'Frühstücksdienst', 1),
|
||||
Dienst('P', 'Putznotdienst', 1),
|
||||
Dienst('E', 'Essensausgabenotdienst', 1),
|
||||
Dienst('K', 'Kochen', 1),
|
||||
Dienst('A', 'Elternabend', 2)
|
||||
Dienst('F', 'Frühstücksdienst', 1, aufwand=3),
|
||||
Dienst('P', 'Putznotdienst', 1, aufwand=1),
|
||||
Dienst('E', 'Essensausgabenotdienst', 1, aufwand=1),
|
||||
Dienst('K', 'Kochen', 1, aufwand=3),
|
||||
Dienst('A', 'Elternabend', 2, aufwand=2)
|
||||
]
|
||||
|
||||
# Datenstrukturen
|
||||
|
||||
@ -8,6 +8,7 @@ Datum: Dezember 2025
|
||||
|
||||
import sys
|
||||
import pulp
|
||||
import multiprocessing
|
||||
from datetime import timedelta, date
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List, Tuple, DefaultDict, Optional
|
||||
@ -355,14 +356,16 @@ class Elterndienstplaner:
|
||||
lowBound=0)
|
||||
|
||||
|
||||
# Zähle tatsächliche Dienste gewichtet mit dem Aufwand des Dienstes
|
||||
tatsaechliche_dienste_gesamt = pulp.lpSum(
|
||||
x[eltern, tag, dienst]
|
||||
dienst.aufwand * x[eltern, tag, dienst]
|
||||
for tag in self.daten.planungszeitraum
|
||||
for dienst in self.daten.dienste
|
||||
if (eltern, tag, dienst) in x
|
||||
)
|
||||
|
||||
ziel_gesamt = sum(ziel_dienste[eltern][dienst] for dienst in self.daten.dienste)
|
||||
# Zielgesamt ebenfalls mit Dienst-Aufwand gewichtet
|
||||
ziel_gesamt = sum(ziel_dienste[eltern][dienst] * dienst.aufwand for dienst in self.daten.dienste)
|
||||
|
||||
prob += (tatsaechliche_dienste_gesamt - ziel_gesamt <=
|
||||
fairness_abweichung_gesamt[eltern])
|
||||
@ -393,21 +396,23 @@ class Elterndienstplaner:
|
||||
|
||||
for eltern in self.daten.eltern:
|
||||
for dienst in self.daten.dienste:
|
||||
objective_terms.append(gewicht_f1 * fairness_abweichung_global[eltern, dienst])
|
||||
objective_terms.append(gewicht_f2 * fairness_abweichung_lokal[eltern, dienst])
|
||||
# Skaliere diensttyp-spezifische Fairness mit dem Aufwand des Dienstes
|
||||
objective_terms.append(gewicht_f1 * fairness_abweichung_global[eltern, dienst] * dienst.aufwand)
|
||||
objective_terms.append(gewicht_f2 * fairness_abweichung_lokal[eltern, dienst] * dienst.aufwand)
|
||||
|
||||
# Gesamt-Fairness (bereits dienstabhängig in den Constraints) — keine zusätzliche Mean-Skalierung mehr
|
||||
objective_terms.append(gewicht_f3_global * fairness_abweichung_gesamt_global[eltern])
|
||||
objective_terms.append(gewicht_f4_lokal * fairness_abweichung_gesamt_lokal[eltern])
|
||||
|
||||
# P1: Bevorzugte Dienste
|
||||
# P1: Bevorzugte Dienste (stärker für aufwändigere Dienste)
|
||||
for (eltern, tag, dienst), praef in self.daten.praeferenzen.items():
|
||||
if (eltern, tag, dienst) in x and praef == 1:
|
||||
objective_terms.append(-5 * x[eltern, tag, dienst])
|
||||
objective_terms.append(-10 * dienst.aufwand * x[eltern, tag, dienst])
|
||||
|
||||
# P2: Abgelehnte Dienste
|
||||
# P2: Abgelehnte Dienste (stärker für aufwändigere Dienste)
|
||||
for (eltern, tag, dienst), praef in self.daten.praeferenzen.items():
|
||||
if (eltern, tag, dienst) in x and praef == -1:
|
||||
objective_terms.append(25 * x[eltern, tag, dienst])
|
||||
objective_terms.append(20 * dienst.aufwand * x[eltern, tag, dienst])
|
||||
|
||||
if objective_terms:
|
||||
prob += pulp.lpSum(objective_terms)
|
||||
@ -480,13 +485,15 @@ class Elterndienstplaner:
|
||||
|
||||
solver = None
|
||||
try:
|
||||
print("Versuche CBC Solver...")
|
||||
solver = pulp.PULP_CBC_CMD(msg=0, timeLimit=60)
|
||||
except:
|
||||
cpu_count = multiprocessing.cpu_count()
|
||||
threads = max(1, cpu_count - 1)
|
||||
print(f"Versuche CBC Solver mit {threads} Threads...")
|
||||
solver = pulp.PULP_CBC_CMD(msg=0, timeLimit=20, threads=threads)
|
||||
except Exception:
|
||||
try:
|
||||
print("Versuche GLPK Solver...")
|
||||
solver = pulp.GLPK_CMD(msg=0)
|
||||
except:
|
||||
except Exception:
|
||||
print("Kein spezifizierter Solver verfügbar, verwende Standard.")
|
||||
solver = None
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user