import { JavaObject, cast_java_lang_Object } from '../../java/lang/JavaObject'; import { KursblockungDynFachart, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynFachart } from '../../core/kursblockung/KursblockungDynFachart'; import { SatSolver3, cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolver3 } from '../../core/kursblockung/satsolver/SatSolver3'; import { HashMap, cast_java_util_HashMap } from '../../java/util/HashMap'; import { SatSolverWrapper, cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolverWrapper } from '../../core/kursblockung/satsolver/SatSolverWrapper'; import { LinkedCollection, cast_de_nrw_schule_svws_core_adt_collection_LinkedCollection } from '../../core/adt/collection/LinkedCollection'; import { KursblockungDynKurs, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynKurs } from '../../core/kursblockung/KursblockungDynKurs'; import { Logger, cast_de_nrw_schule_svws_logger_Logger } from '../../logger/Logger'; import { System, cast_java_lang_System } from '../../java/lang/System'; import { JavaInteger, cast_java_lang_Integer } from '../../java/lang/JavaInteger'; import { SatSolverA, cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolverA } from '../../core/kursblockung/satsolver/SatSolverA'; import { NullPointerException, cast_java_lang_NullPointerException } from '../../java/lang/NullPointerException'; import { KursblockungDynDaten, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynDaten } from '../../core/kursblockung/KursblockungDynDaten'; import { KursblockungAlgorithmusK, cast_de_nrw_schule_svws_core_kursblockung_KursblockungAlgorithmusK } from '../../core/kursblockung/KursblockungAlgorithmusK'; import { KursblockungDynSchueler, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler } from '../../core/kursblockung/KursblockungDynSchueler'; export class KursblockungAlgorithmusKSatSolver extends KursblockungAlgorithmusK { private readonly kurseAlle : Array; private readonly schuelerAlle : Array; private maxNichtWaehler : number = 0; /** * Im Konstruktor kann die Klasse die jeweiligen Datenstrukturen aufbauen. Kurse * dürfen in diese Methode noch nicht auf Schienen verteilt werden. * * @param logger Logger für Benutzerhinweise, Warnungen und Fehler. * @param dynDat Die dynamischen Blockungsdaten. */ public constructor(logger : Logger, dynDat : KursblockungDynDaten) { super(logger, dynDat); this.kurseAlle = dynDat.gibKurseAlle(); this.schuelerAlle = this.dynDaten.gibSchuelerArray(false); this.maxNichtWaehler = 10; } public berechne(pMaxTimeMillis : number) : void { if (this.dynDaten.gibKurseDieFreiSindAnzahl() === 0) { return; } let timeStart : number = System.currentTimeMillis(); this.dynDaten.aktionSchuelerAusAllenKursenEntfernen(); this.dynDaten.aktionKurseFreieZufaelligVerteilen(); this.dynDaten.aktionZustandSpeichernK(); let difNichtWaehler : number = 1; while (System.currentTimeMillis() - timeStart < pMaxTimeMillis) { let result : number = this.berechneSchritt(pMaxTimeMillis); if (result === SatSolverA.RESULT_UNKNOWN) { return; } if (result === SatSolverA.RESULT_SATISFIABLE) { this.maxNichtWaehler = Math.max(this.maxNichtWaehler - difNichtWaehler, 0); continue; } this.maxNichtWaehler++; difNichtWaehler = 0; } } /** * Erzeugt eine Formel in konjuntiver Normalform (CNF) und übergibt sie dem * SAT-Solver. Der Solver versucht die Formel innerhalb des Zeitlimits zu lösen. * Falls er es nicht schafft, dann wurde zuvor eine zufällige Kursverteilung * definiert. # * * @param pMaxTimeMillis Die maximale Blockungszeit in Millisekunde. * * @return Liefert eines der drei möglichen Ergebnisse * {@link SatSolverA#RESULT_SATISFIABLE oder SatSolverI#RESULT_UNKNOWN * oder SatSolverI#RESULT_UNSATISFIABLE. } */ public berechneSchritt(pMaxTimeMillis : number) : number { let ssw : SatSolverWrapper = new SatSolverWrapper(new SatSolver3()); let nSchienen : number = this.dynDaten.gibSchienenAnzahl(); let mapKursSchiene : HashMap | null> = new HashMap(); for (let kurs of this.kurseAlle) { let schienen : Array = Array(nSchienen).fill(0); for (let s : number = 0; s < nSchienen; s++){ schienen[s] = kurs.gibIstSchieneFixiert(s) ? ssw.getVarTRUE() : kurs.gibIstSchieneGesperrt(s) ? ssw.getVarFALSE() : ssw.createNewVar(); } mapKursSchiene.put(kurs, schienen); } let mapSchuelerFachartNichtwahl : HashMap> = new HashMap(); let mapSchuelerIstInKurs : HashMap> = new HashMap(); let listNichtwahlen : LinkedCollection = new LinkedCollection(); for (let schueler of this.schuelerAlle) { mapSchuelerFachartNichtwahl.put(schueler, new HashMap()); mapSchuelerIstInKurs.put(schueler, new HashMap()); for (let fachart of schueler.gibFacharten()) { let varNichtwahlen : number = ssw.createNewVar(); let mapFachartNichtwahl : HashMap | null = mapSchuelerFachartNichtwahl.get(schueler); if (mapFachartNichtwahl === null) throw new NullPointerException() mapFachartNichtwahl.put(fachart, varNichtwahlen); listNichtwahlen.add(varNichtwahlen); for (let kurs of fachart.gibKurse()) { let varKurs : number = ssw.createNewVar(); let mapIstInKurs : HashMap | null = mapSchuelerIstInKurs.get(schueler); if (mapIstInKurs === null) throw new NullPointerException() mapIstInKurs.put(kurs, varKurs); } } } for (let kurs of this.kurseAlle) { let list : LinkedCollection = new LinkedCollection(); let schienen : Array | null = mapKursSchiene.get(kurs); if (schienen === null) throw new NullPointerException() for (let s : number = 0; s < nSchienen; s++){ list.add(schienen[s]); } let amount : number = kurs.gibSchienenAnzahl(); ssw.c_exactly_GENERIC(list, amount); } for (let schueler of this.schuelerAlle) { for (let fachart of schueler.gibFacharten()) { let list : LinkedCollection = new LinkedCollection(); for (let kurs of fachart.gibKurse()) { let mapIstInKurs : HashMap | null = mapSchuelerIstInKurs.get(schueler); if (mapIstInKurs === null) throw new NullPointerException() let varKurs : Number | null = mapIstInKurs.get(kurs); if (varKurs === null) throw new NullPointerException() list.add(varKurs); } ssw.c_exactly_GENERIC(list, 1); } } for (let schueler of this.schuelerAlle) { let mapIstInKurs : HashMap | null = mapSchuelerIstInKurs.get(schueler); if (mapIstInKurs === null) throw new NullPointerException() for (let fachart1 of schueler.gibFacharten()) { for (let fachart2 of schueler.gibFacharten()) { if (fachart1.gibNr() < fachart2.gibNr()) { for (let kurs1 of fachart1.gibKurse()) { for (let kurs2 of fachart2.gibKurse()) { let var1 : Number | null = mapIstInKurs.get(kurs1); let var2 : Number | null = mapIstInKurs.get(kurs2); if ((var1 === null) || (var2 === null)) throw new NullPointerException() let x : number = ssw.c_new_var_AND(var1.valueOf(), var2.valueOf()); for (let s : number = 0; s < nSchienen; s++){ let schienenKurs1 : Array | null = mapKursSchiene.get(kurs1); let schienenKurs2 : Array | null = mapKursSchiene.get(kurs2); if ((schienenKurs1 === null) || (schienenKurs2 === null)) throw new NullPointerException() let var3 : number = schienenKurs1[s]; let var4 : number = schienenKurs2[s]; ssw.c_3(-x, -var3, -var4); } } } } } } } console.log(JSON.stringify("V=" + ssw.getVarCount() + ", C=" + ssw.getClauseCount())); let satresult : number = ssw.solve(pMaxTimeMillis); if (satresult !== SatSolverA.RESULT_SATISFIABLE) { return satresult; } this.dynDaten.aktionSchuelerAusAllenKursenEntfernen(); for (let kurs of this.kurseAlle) { let schienen : LinkedCollection = new LinkedCollection(); for (let s : number = 0; s < nSchienen; s++){ let schienenKurs : Array | null = mapKursSchiene.get(kurs); if (schienenKurs === null) throw new NullPointerException() if (ssw.isVarTrue(schienenKurs[s])) { schienen.add(s); } } kurs.aktionVerteileAufSchienen(schienen); } return satresult; } isTranspiledInstanceOf(name : string): boolean { return ['de.nrw.schule.svws.core.kursblockung.KursblockungAlgorithmusKSatSolver', 'de.nrw.schule.svws.core.kursblockung.KursblockungAlgorithmusK'].includes(name); } } export function cast_de_nrw_schule_svws_core_kursblockung_KursblockungAlgorithmusKSatSolver(obj : unknown) : KursblockungAlgorithmusKSatSolver { return obj as KursblockungAlgorithmusKSatSolver; }