KursblockungAlgorithmusKSatSolver.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import { JavaObject, cast_java_lang_Object } from '../../java/lang/JavaObject';
  2. import { KursblockungDynFachart, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynFachart } from '../../core/kursblockung/KursblockungDynFachart';
  3. import { SatSolver3, cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolver3 } from '../../core/kursblockung/satsolver/SatSolver3';
  4. import { HashMap, cast_java_util_HashMap } from '../../java/util/HashMap';
  5. import { SatSolverWrapper, cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolverWrapper } from '../../core/kursblockung/satsolver/SatSolverWrapper';
  6. import { LinkedCollection, cast_de_nrw_schule_svws_core_adt_collection_LinkedCollection } from '../../core/adt/collection/LinkedCollection';
  7. import { KursblockungDynKurs, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynKurs } from '../../core/kursblockung/KursblockungDynKurs';
  8. import { Logger, cast_de_nrw_schule_svws_logger_Logger } from '../../logger/Logger';
  9. import { System, cast_java_lang_System } from '../../java/lang/System';
  10. import { JavaInteger, cast_java_lang_Integer } from '../../java/lang/JavaInteger';
  11. import { SatSolverA, cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolverA } from '../../core/kursblockung/satsolver/SatSolverA';
  12. import { NullPointerException, cast_java_lang_NullPointerException } from '../../java/lang/NullPointerException';
  13. import { KursblockungDynDaten, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynDaten } from '../../core/kursblockung/KursblockungDynDaten';
  14. import { KursblockungAlgorithmusK, cast_de_nrw_schule_svws_core_kursblockung_KursblockungAlgorithmusK } from '../../core/kursblockung/KursblockungAlgorithmusK';
  15. import { KursblockungDynSchueler, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler } from '../../core/kursblockung/KursblockungDynSchueler';
  16. export class KursblockungAlgorithmusKSatSolver extends KursblockungAlgorithmusK {
  17. private readonly kurseAlle : Array<KursblockungDynKurs>;
  18. private readonly schuelerAlle : Array<KursblockungDynSchueler>;
  19. private maxNichtWaehler : number = 0;
  20. /**
  21. * Im Konstruktor kann die Klasse die jeweiligen Datenstrukturen aufbauen. Kurse
  22. * dürfen in diese Methode noch nicht auf Schienen verteilt werden.
  23. *
  24. * @param logger Logger für Benutzerhinweise, Warnungen und Fehler.
  25. * @param dynDat Die dynamischen Blockungsdaten.
  26. */
  27. public constructor(logger : Logger, dynDat : KursblockungDynDaten) {
  28. super(logger, dynDat);
  29. this.kurseAlle = dynDat.gibKurseAlle();
  30. this.schuelerAlle = this.dynDaten.gibSchuelerArray(false);
  31. this.maxNichtWaehler = 10;
  32. }
  33. public berechne(pMaxTimeMillis : number) : void {
  34. if (this.dynDaten.gibKurseDieFreiSindAnzahl() === 0) {
  35. return;
  36. }
  37. let timeStart : number = System.currentTimeMillis();
  38. this.dynDaten.aktionSchuelerAusAllenKursenEntfernen();
  39. this.dynDaten.aktionKurseFreieZufaelligVerteilen();
  40. this.dynDaten.aktionZustandSpeichernK();
  41. let difNichtWaehler : number = 1;
  42. while (System.currentTimeMillis() - timeStart < pMaxTimeMillis) {
  43. let result : number = this.berechneSchritt(pMaxTimeMillis);
  44. if (result === SatSolverA.RESULT_UNKNOWN) {
  45. return;
  46. }
  47. if (result === SatSolverA.RESULT_SATISFIABLE) {
  48. this.maxNichtWaehler = Math.max(this.maxNichtWaehler - difNichtWaehler, 0);
  49. continue;
  50. }
  51. this.maxNichtWaehler++;
  52. difNichtWaehler = 0;
  53. }
  54. }
  55. /**
  56. * Erzeugt eine Formel in konjuntiver Normalform (CNF) und übergibt sie dem
  57. * SAT-Solver. Der Solver versucht die Formel innerhalb des Zeitlimits zu lösen.
  58. * Falls er es nicht schafft, dann wurde zuvor eine zufällige Kursverteilung
  59. * definiert. #
  60. *
  61. * @param pMaxTimeMillis Die maximale Blockungszeit in Millisekunde.
  62. *
  63. * @return Liefert eines der drei möglichen Ergebnisse
  64. * {@link SatSolverA#RESULT_SATISFIABLE oder SatSolverI#RESULT_UNKNOWN
  65. * oder SatSolverI#RESULT_UNSATISFIABLE. }
  66. */
  67. public berechneSchritt(pMaxTimeMillis : number) : number {
  68. let ssw : SatSolverWrapper = new SatSolverWrapper(new SatSolver3());
  69. let nSchienen : number = this.dynDaten.gibSchienenAnzahl();
  70. let mapKursSchiene : HashMap<KursblockungDynKurs, Array<number> | null> = new HashMap();
  71. for (let kurs of this.kurseAlle) {
  72. let schienen : Array<number> = Array(nSchienen).fill(0);
  73. for (let s : number = 0; s < nSchienen; s++){
  74. schienen[s] = kurs.gibIstSchieneFixiert(s) ? ssw.getVarTRUE() : kurs.gibIstSchieneGesperrt(s) ? ssw.getVarFALSE() : ssw.createNewVar();
  75. }
  76. mapKursSchiene.put(kurs, schienen);
  77. }
  78. let mapSchuelerFachartNichtwahl : HashMap<KursblockungDynSchueler, HashMap<KursblockungDynFachart, Number>> = new HashMap();
  79. let mapSchuelerIstInKurs : HashMap<KursblockungDynSchueler, HashMap<KursblockungDynKurs, Number>> = new HashMap();
  80. let listNichtwahlen : LinkedCollection<Number> = new LinkedCollection();
  81. for (let schueler of this.schuelerAlle) {
  82. mapSchuelerFachartNichtwahl.put(schueler, new HashMap());
  83. mapSchuelerIstInKurs.put(schueler, new HashMap());
  84. for (let fachart of schueler.gibFacharten()) {
  85. let varNichtwahlen : number = ssw.createNewVar();
  86. let mapFachartNichtwahl : HashMap<KursblockungDynFachart, Number> | null = mapSchuelerFachartNichtwahl.get(schueler);
  87. if (mapFachartNichtwahl === null)
  88. throw new NullPointerException()
  89. mapFachartNichtwahl.put(fachart, varNichtwahlen);
  90. listNichtwahlen.add(varNichtwahlen);
  91. for (let kurs of fachart.gibKurse()) {
  92. let varKurs : number = ssw.createNewVar();
  93. let mapIstInKurs : HashMap<KursblockungDynKurs, Number> | null = mapSchuelerIstInKurs.get(schueler);
  94. if (mapIstInKurs === null)
  95. throw new NullPointerException()
  96. mapIstInKurs.put(kurs, varKurs);
  97. }
  98. }
  99. }
  100. for (let kurs of this.kurseAlle) {
  101. let list : LinkedCollection<Number> = new LinkedCollection();
  102. let schienen : Array<number> | null = mapKursSchiene.get(kurs);
  103. if (schienen === null)
  104. throw new NullPointerException()
  105. for (let s : number = 0; s < nSchienen; s++){
  106. list.add(schienen[s]);
  107. }
  108. let amount : number = kurs.gibSchienenAnzahl();
  109. ssw.c_exactly_GENERIC(list, amount);
  110. }
  111. for (let schueler of this.schuelerAlle) {
  112. for (let fachart of schueler.gibFacharten()) {
  113. let list : LinkedCollection<Number> = new LinkedCollection();
  114. for (let kurs of fachart.gibKurse()) {
  115. let mapIstInKurs : HashMap<KursblockungDynKurs, Number> | null = mapSchuelerIstInKurs.get(schueler);
  116. if (mapIstInKurs === null)
  117. throw new NullPointerException()
  118. let varKurs : Number | null = mapIstInKurs.get(kurs);
  119. if (varKurs === null)
  120. throw new NullPointerException()
  121. list.add(varKurs);
  122. }
  123. ssw.c_exactly_GENERIC(list, 1);
  124. }
  125. }
  126. for (let schueler of this.schuelerAlle) {
  127. let mapIstInKurs : HashMap<KursblockungDynKurs, Number> | null = mapSchuelerIstInKurs.get(schueler);
  128. if (mapIstInKurs === null)
  129. throw new NullPointerException()
  130. for (let fachart1 of schueler.gibFacharten()) {
  131. for (let fachart2 of schueler.gibFacharten()) {
  132. if (fachart1.gibNr() < fachart2.gibNr()) {
  133. for (let kurs1 of fachart1.gibKurse()) {
  134. for (let kurs2 of fachart2.gibKurse()) {
  135. let var1 : Number | null = mapIstInKurs.get(kurs1);
  136. let var2 : Number | null = mapIstInKurs.get(kurs2);
  137. if ((var1 === null) || (var2 === null))
  138. throw new NullPointerException()
  139. let x : number = ssw.c_new_var_AND(var1.valueOf(), var2.valueOf());
  140. for (let s : number = 0; s < nSchienen; s++){
  141. let schienenKurs1 : Array<number> | null = mapKursSchiene.get(kurs1);
  142. let schienenKurs2 : Array<number> | null = mapKursSchiene.get(kurs2);
  143. if ((schienenKurs1 === null) || (schienenKurs2 === null))
  144. throw new NullPointerException()
  145. let var3 : number = schienenKurs1[s];
  146. let var4 : number = schienenKurs2[s];
  147. ssw.c_3(-x, -var3, -var4);
  148. }
  149. }
  150. }
  151. }
  152. }
  153. }
  154. }
  155. console.log(JSON.stringify("V=" + ssw.getVarCount() + ", C=" + ssw.getClauseCount()));
  156. let satresult : number = ssw.solve(pMaxTimeMillis);
  157. if (satresult !== SatSolverA.RESULT_SATISFIABLE) {
  158. return satresult;
  159. }
  160. this.dynDaten.aktionSchuelerAusAllenKursenEntfernen();
  161. for (let kurs of this.kurseAlle) {
  162. let schienen : LinkedCollection<Number> = new LinkedCollection();
  163. for (let s : number = 0; s < nSchienen; s++){
  164. let schienenKurs : Array<number> | null = mapKursSchiene.get(kurs);
  165. if (schienenKurs === null)
  166. throw new NullPointerException()
  167. if (ssw.isVarTrue(schienenKurs[s])) {
  168. schienen.add(s);
  169. }
  170. }
  171. kurs.aktionVerteileAufSchienen(schienen);
  172. }
  173. return satresult;
  174. }
  175. isTranspiledInstanceOf(name : string): boolean {
  176. return ['de.nrw.schule.svws.core.kursblockung.KursblockungAlgorithmusKSatSolver', 'de.nrw.schule.svws.core.kursblockung.KursblockungAlgorithmusK'].includes(name);
  177. }
  178. }
  179. export function cast_de_nrw_schule_svws_core_kursblockung_KursblockungAlgorithmusKSatSolver(obj : unknown) : KursblockungAlgorithmusKSatSolver {
  180. return obj as KursblockungAlgorithmusKSatSolver;
  181. }