123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- 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<KursblockungDynKurs>;
- private readonly schuelerAlle : Array<KursblockungDynSchueler>;
- 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<KursblockungDynKurs, Array<number> | null> = new HashMap();
- for (let kurs of this.kurseAlle) {
- let schienen : Array<number> = 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<KursblockungDynSchueler, HashMap<KursblockungDynFachart, Number>> = new HashMap();
- let mapSchuelerIstInKurs : HashMap<KursblockungDynSchueler, HashMap<KursblockungDynKurs, Number>> = new HashMap();
- let listNichtwahlen : LinkedCollection<Number> = 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<KursblockungDynFachart, Number> | 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<KursblockungDynKurs, Number> | null = mapSchuelerIstInKurs.get(schueler);
- if (mapIstInKurs === null)
- throw new NullPointerException()
- mapIstInKurs.put(kurs, varKurs);
- }
- }
- }
- for (let kurs of this.kurseAlle) {
- let list : LinkedCollection<Number> = new LinkedCollection();
- let schienen : Array<number> | 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<Number> = new LinkedCollection();
- for (let kurs of fachart.gibKurse()) {
- let mapIstInKurs : HashMap<KursblockungDynKurs, Number> | 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<KursblockungDynKurs, Number> | 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<number> | null = mapKursSchiene.get(kurs1);
- let schienenKurs2 : Array<number> | 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<Number> = new LinkedCollection();
- for (let s : number = 0; s < nSchienen; s++){
- let schienenKurs : Array<number> | 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;
- }
|