115 lines
4.2 KiB
Python
115 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Datenmodell für Elterndienstplaner
|
|
Enthält alle Daten und deren Laden sowie gemeinsame Type Aliases
|
|
"""
|
|
|
|
from datetime import date
|
|
from collections import defaultdict
|
|
from typing import Dict, List, Tuple, DefaultDict, Optional, TypeAlias
|
|
import pulp
|
|
|
|
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:
|
|
self.kuerzel: str = kuerzel
|
|
self.name: str = name
|
|
self.personen_anzahl: int = personen_anzahl
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.kuerzel} ({self.name}): {self.personen_anzahl} Person(en)"
|
|
|
|
def __repr__(self) -> str:
|
|
return f"Dienst('{self.kuerzel}', '{self.name}', {self.personen_anzahl})"
|
|
|
|
def braucht_mehrere_personen(self) -> bool:
|
|
"""Gibt True zurück, wenn mehr als eine Person benötigt wird"""
|
|
return self.personen_anzahl > 1
|
|
|
|
# Eltern: Ihnen koennen Dienste zugewiesen werden
|
|
Eltern: TypeAlias = str
|
|
|
|
# Verteilung von Diensten auf Eltern.
|
|
# - Zielsumme der Dienste ueber den Planungszeitraum
|
|
# - Kann nicht-ganzzahlig und negativ sein
|
|
Zielverteilung: TypeAlias = DefaultDict[Eltern, DefaultDict[Dienst, float]]
|
|
|
|
# Entscheidungsvariablen des Optimierungsproblems
|
|
# Variable: Eltern wird am Datum Dienst zugewiesen
|
|
Entscheidungsvariablen: TypeAlias = Dict[Tuple[Eltern, date, Dienst], pulp.LpVariable]
|
|
|
|
|
|
class ElterndienstplanerDaten:
|
|
"""Datenmodell für den Elterndienstplaner"""
|
|
|
|
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)
|
|
]
|
|
|
|
# Datenstrukturen
|
|
self.planungszeitraum: List[date] = []
|
|
self.eltern: List[Eltern] = []
|
|
self.benoetigte_dienste: Dict[date, List[Dienst]] = {}
|
|
self.verfügbarkeit: Dict[Tuple[Eltern, date], bool] = {}
|
|
self.präferenzen: Dict[Tuple[Eltern, date, Dienst], int] = {}
|
|
|
|
# dienstfaktoren[eltern][tag] = faktor.
|
|
# Wenn es eltern nicht gibt -> keyerror
|
|
# Wenn es tag nicht gibt -> default 0.0
|
|
self.dienstfaktoren: Dict[Eltern, DefaultDict[date, float]] = {}
|
|
self.historische_dienste: List[Tuple[date, Eltern, Dienst]] = []
|
|
|
|
def get_dienst(self, kuerzel: str) -> Optional[Dienst]:
|
|
"""Gibt das Dienst-Objekt für ein Kürzel zurück"""
|
|
for dienst in self.dienste:
|
|
if dienst.kuerzel == kuerzel:
|
|
return dienst
|
|
return None
|
|
|
|
def add_dienst(self, kuerzel: str, name: str, personen_anzahl: int = 1) -> Dienst:
|
|
"""Fügt einen neuen Dienst hinzu"""
|
|
dienst = Dienst(kuerzel, name, personen_anzahl)
|
|
self.dienste.append(dienst)
|
|
return dienst
|
|
|
|
def print_dienste_info(self) -> None:
|
|
"""Druckt Informationen über alle konfigurierten Dienste"""
|
|
print("Konfigurierte Dienste:")
|
|
for dienst in self.dienste:
|
|
print(f" {dienst}")
|
|
|
|
def lade_daten(
|
|
self,
|
|
eingabe_datei: str,
|
|
eltern_datei: str,
|
|
vorherige_datei: Optional[str] = None
|
|
) -> None:
|
|
"""Lädt alle benötigten CSV-Dateien
|
|
|
|
Args:
|
|
eingabe_datei: Pfad zur eingabe.csv mit Terminen und Präferenzen
|
|
eltern_datei: Pfad zur eltern.csv mit Dienstfaktoren
|
|
vorherige_datei: Optionaler Pfad zur vorherige-ausgaben.csv für Fairness-Constraints
|
|
"""
|
|
# Eingabe CSV: Termine, Präferenzen, Verfügbarkeit
|
|
self.eltern, self.planungszeitraum, self.benoetigte_dienste, self.verfügbarkeit, self.präferenzen = \
|
|
EingabeParser.parse_eingabe_csv(eingabe_datei, self.get_dienst)
|
|
|
|
# Eltern CSV: Dienstfaktoren
|
|
self.dienstfaktoren = EingabeParser.parse_eltern_csv(eltern_datei)
|
|
|
|
# Vorherige Ausgaben CSV (optional): Historische Dienste für Fairness
|
|
if vorherige_datei:
|
|
self.historische_dienste = \
|
|
EingabeParser.parse_vorherige_ausgaben_csv(vorherige_datei, self.eltern, self.dienste)
|