123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- import { JavaObject, cast_java_lang_Object } from '../../../java/lang/JavaObject';
- import { JavaInteger, cast_java_lang_Integer } from '../../../java/lang/JavaInteger';
- import { AVLSet, cast_de_nrw_schule_svws_core_adt_set_AVLSet } from '../../../core/adt/set/AVLSet';
- import { Variable, cast_de_nrw_schule_svws_core_kursblockung_satsolver_Variable } from '../../../core/kursblockung/satsolver/Variable';
- 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 { LinkedCollection, cast_de_nrw_schule_svws_core_adt_collection_LinkedCollection } from '../../../core/adt/collection/LinkedCollection';
- import { Clause, cast_de_nrw_schule_svws_core_kursblockung_satsolver_Clause } from '../../../core/kursblockung/satsolver/Clause';
- import { JavaString, cast_java_lang_String } from '../../../java/lang/JavaString';
- import { Arrays, cast_java_util_Arrays } from '../../../java/util/Arrays';
- import { Heap, cast_de_nrw_schule_svws_core_kursblockung_satsolver_Heap } from '../../../core/kursblockung/satsolver/Heap';
- import { System, cast_java_lang_System } from '../../../java/lang/System';
- export class SatSolver3 extends SatSolverA {
- private static readonly MAX_LEARNED_CLAUSE_SIZE : number = 3;
- private heap : Heap;
- private vSize : number = 0;
- private vArrayPos : Array<Variable>;
- private vArrayNeg : Array<Variable>;
- private cSize : number = 0;
- private learnClauseMin : number = 0;
- /**
- * Konstruktor.
- */
- public constructor() {
- super();
- this.heap = new Heap();
- this.vSize = 0;
- this.cSize = 0;
- this.vArrayPos = Array(1).fill(null);
- this.vArrayNeg = Array(1).fill(null);
- }
- public isVarTrue(pVar : number) : boolean {
- let v : Variable = this.getVarOf(pVar);
- return v.index === -1;
- }
- public createNewVar() : number {
- this.vSize++;
- if (this.vSize >= this.vArrayPos.length) {
- let newSize : number = this.vSize * 2;
- this.vArrayPos = Arrays.copyOf(this.vArrayPos, newSize);
- this.vArrayNeg = Arrays.copyOf(this.vArrayNeg, newSize);
- }
- let vPos : Variable = new Variable(+this.vSize);
- let vNeg : Variable = new Variable(-this.vSize);
- vPos.negation = vNeg;
- vNeg.negation = vPos;
- this.vArrayPos[this.vSize] = vPos;
- this.vArrayNeg[this.vSize] = vNeg;
- this.heap.insert(vPos);
- this.heap.insert(vNeg);
- return this.vSize;
- }
- public addClause(pVars : Array<number>) : void {
- if (pVars.length === 0) {
- console.log(JSON.stringify("WARNUNG: Leere Klausel bei SatSolver.addClause(int[] pVars)!"));
- return;
- }
- let set : AVLSet<Number> = new AVLSet();
- for (let v of pVars) {
- if (set.contains(-v)) {
- return;
- }
- set.add(v);
- }
- let list : LinkedCollection<Number> = new LinkedCollection();
- while (!set.isEmpty()) {
- list.addLast(set.pollFirst());
- }
- while (list.size() > 3) {
- let x : number = list.removeFirst().valueOf();
- let y : number = list.removeFirst().valueOf();
- let z : number = this.createNewVar();
- list.addLast(z);
- this.addClause2(-x, z);
- this.addClause2(-y, z);
- this.addClause3(x, y, -z);
- }
- if (list.size() === 3) {
- this.addClause3(list.removeFirst().valueOf(), list.removeFirst().valueOf(), list.removeFirst().valueOf());
- }
- if (list.size() === 2) {
- this.addClause2(list.removeFirst().valueOf(), list.removeFirst().valueOf());
- }
- if (list.size() === 1) {
- this.addClause1(list.removeFirst().valueOf());
- }
- }
- /**
- * Fügt der Datenstruktur eine 1-CNF-Klausel hinzu.
- *
- * @param x Das 1. Literal (Variablennummer) der Klausel.
- */
- private addClause1(x : number) : void {
- let varX : Variable = this.getVarOf(x);
- if (varX.negation === null)
- throw new NullPointerException()
- this.heap.remove(varX);
- this.heap.remove(varX.negation);
- let c : Clause = new Clause(varX);
- this.cSize++;
- varX.clauses.addLast(c);
- varX.statSatFree[c.sat][c.free]++;
- this.heap.insert(varX);
- this.heap.insert(varX.negation);
- }
- /**
- * Fügt der Datenstruktur eine 2-CNF-Klausel hinzu.
- *
- * @param x Das 1. Literal (Variablennummer) der Klausel.
- * @param y Das 2. Literal (Variablennummer) der Klausel.
- */
- private addClause2(x : number, y : number) : void {
- let varX : Variable = this.getVarOf(x);
- let varY : Variable = this.getVarOf(y);
- if ((varX.negation === null) || (varY.negation === null))
- throw new NullPointerException()
- this.heap.remove(varX);
- this.heap.remove(varY);
- this.heap.remove(varX.negation);
- this.heap.remove(varY.negation);
- let c : Clause = new Clause(varX, varY);
- this.cSize++;
- varX.clauses.addLast(c);
- varX.statSatFree[c.sat][c.free]++;
- varX.neighbours.addLast(varY);
- varY.clauses.addLast(c);
- varY.statSatFree[c.sat][c.free]++;
- varY.neighbours.addLast(varX);
- this.heap.insert(varX);
- this.heap.insert(varY);
- this.heap.insert(varX.negation);
- this.heap.insert(varY.negation);
- }
- /**
- * Fügt der Datenstruktur eine 3-CNF-Klausel hinzu.
- *
- * @param x Das 1. Literal (Variablennummer) der Klausel.
- * @param y Das 2. Literal (Variablennummer) der Klausel.
- * @param z Das 3. Literal (Variablennummer) der Klausel.
- */
- private addClause3(x : number, y : number, z : number) : void {
- let varX : Variable = this.getVarOf(x);
- let varY : Variable = this.getVarOf(y);
- let varZ : Variable = this.getVarOf(z);
- if ((varX.negation === null) || (varY.negation === null) || (varZ.negation === null))
- throw new NullPointerException()
- this.heap.remove(varX);
- this.heap.remove(varY);
- this.heap.remove(varZ);
- this.heap.remove(varX.negation);
- this.heap.remove(varY.negation);
- this.heap.remove(varZ.negation);
- let c : Clause = new Clause(varX, varY, varZ);
- this.cSize++;
- varX.clauses.addLast(c);
- varX.statSatFree[c.sat][c.free]++;
- varX.neighbours.addLast(varY);
- varX.neighbours.addLast(varZ);
- varY.clauses.addLast(c);
- varY.statSatFree[c.sat][c.free]++;
- varY.neighbours.addLast(varX);
- varY.neighbours.addLast(varZ);
- varZ.clauses.addLast(c);
- varZ.statSatFree[c.sat][c.free]++;
- varZ.neighbours.addLast(varX);
- varZ.neighbours.addLast(varY);
- this.heap.insert(varX);
- this.heap.insert(varY);
- this.heap.insert(varZ);
- this.heap.insert(varX.negation);
- this.heap.insert(varY.negation);
- this.heap.insert(varZ.negation);
- }
- public getVarCount() : number {
- return this.vSize;
- }
- public getClauseCount() : number {
- return this.cSize;
- }
- public solve(pMaxTimeMillis : number) : number {
- let timeStart : number = System.currentTimeMillis();
- let backtrackV : Array<Variable | null> = Array(this.vSize).fill(null);
- let backtrackLearn : Array<Variable> = Array(SatSolver3.MAX_LEARNED_CLAUSE_SIZE).fill(null);
- let backtrackB : Array<boolean> = Array(this.vSize).fill(false);
- let index : number = 0;
- let max : number = 1;
- let countDown : number = 0;
- this.learnClauseMin = SatSolver3.MAX_LEARNED_CLAUSE_SIZE + 1;
- let maxIndex : number = 0;
- while ((index >= 0) && !this.heap.isEmpty()) {
- if (index > maxIndex) {
- maxIndex = index;
- }
- if (countDown === 0) {
- for (let i : number = index; i >= 0; i--){
- if (backtrackV[i] !== null) {
- this.unitpropagation_undo(cast_de_nrw_schule_svws_core_kursblockung_satsolver_Variable(backtrackV[i]));
- }
- backtrackV[i] = null;
- backtrackB[i] = false;
- }
- index = 0;
- if ((this.learnClauseMin >= 1) && (this.learnClauseMin <= SatSolver3.MAX_LEARNED_CLAUSE_SIZE)) {
- let clause : Array<number> = Array(this.learnClauseMin).fill(0);
- for (let i : number = 0; i < clause.length; i++){
- clause[i] = -backtrackLearn[i].nr;
- }
- this.addClause(clause);
- }
- let result : number = this.simplify();
- if (result !== SatSolverA.RESULT_UNKNOWN) {
- return result;
- }
- max = max + 1 + Math.trunc(max / 2);
- countDown = max;
- this.learnClauseMin = SatSolver3.MAX_LEARNED_CLAUSE_SIZE + 1;
- if (System.currentTimeMillis() - timeStart > pMaxTimeMillis) {
- return SatSolverA.RESULT_UNKNOWN;
- }
- continue;
- }
- countDown--;
- let varP : Variable | null = backtrackV[index];
- if ((varP !== null) && (backtrackB[index])) {
- this.unitpropagation_undo(varP);
- backtrackV[index] = null;
- backtrackB[index] = false;
- this.learnClause(backtrackV, backtrackLearn, index);
- index--;
- continue;
- }
- if (varP === null) {
- varP = this.heap.top();
- if (!varP.isUnsat()) {
- backtrackV[index] = varP;
- this.unitpropagation(varP);
- index++;
- continue;
- }
- } else {
- this.unitpropagation_undo(varP);
- }
- if (varP.negation === null)
- throw new NullPointerException()
- varP = varP.negation;
- if (varP.isUnsat()) {
- backtrackV[index] = null;
- this.learnClause(backtrackV, backtrackLearn, index);
- index--;
- continue;
- }
- backtrackV[index] = varP;
- backtrackB[index] = true;
- this.unitpropagation(varP);
- index++;
- continue;
- }
- return this.heap.isEmpty() ? SatSolverA.RESULT_SATISFIABLE : SatSolverA.RESULT_UNSATISFIABLE;
- }
- private learnClause(backtrackV : Array<Variable | null>, backtrackLearn : Array<Variable | null>, size : number) : void {
- if (size < 1) {
- return;
- }
- if (size >= this.learnClauseMin) {
- return;
- }
- this.learnClauseMin = size;
- for (let i : number = 0; i < size; i++){
- backtrackLearn[i] = backtrackV[i];
- }
- }
- private simplify() : number {
- let count1 : number = 0;
- let changed : boolean = true;
- while (changed) {
- changed = false;
- for (let nr : number = 1; nr <= this.vSize; nr++){
- let varP : Variable | null = this.vArrayPos[nr];
- if (varP.index < 0) {
- continue;
- }
- if (varP.statSatFree[0][0] > 0) {
- return SatSolverA.RESULT_UNSATISFIABLE;
- }
- if (varP.negation === null)
- throw new NullPointerException()
- if (varP.negation.statSatFree[0][0] > 0) {
- return SatSolverA.RESULT_UNSATISFIABLE;
- }
- if ((varP.statSatFree[0][1] > 0) && (varP.negation.statSatFree[0][1] > 0)) {
- return SatSolverA.RESULT_UNSATISFIABLE;
- }
- if (varP.statSatFree[0][1] > 0) {
- this.unitpropagation(varP);
- count1++;
- changed = true;
- continue;
- }
- if (varP.negation.statSatFree[0][1] > 0) {
- this.unitpropagation(varP.negation);
- count1++;
- changed = true;
- continue;
- }
- if (varP.getClauseOccurences() === 0) {
- this.unitpropagation(varP.negation);
- count1++;
- changed = true;
- continue;
- }
- if (varP.negation.getClauseOccurences() === 0) {
- this.unitpropagation(varP);
- count1++;
- changed = true;
- continue;
- }
- }
- }
- return SatSolverA.RESULT_UNKNOWN;
- }
- private static fill(index : number) : String | null {
- let s : String | null = "";
- for (let i : number = 0; i < index; i++){
- s = s.valueOf() + " ";
- }
- return s;
- }
- /**
- * Setzt die Variable {@code varP} auf TRUE und aktualisiert die gesamte Datenstruktur entsprechend.
- *
- * @param varP Die Variable, die auf TRUE gesetzt wird.
- */
- private unitpropagation(varP : Variable) : void {
- let varN : Variable | null = varP.negation;
- if (varN === null)
- throw new NullPointerException()
- this.heap.remove(varP);
- this.heap.remove(varN);
- varP.index = -1;
- varN.index = -2;
- this.unitpropagationHelper(varP.clauses, +1, -1);
- this.unitpropagationHelper(varN.clauses, +0, -1);
- }
- /**
- * Setzt die Variable {@code varP} von TRUE auf FREI und aktualisiert die gesamte Datenstruktur entsprechend.
- *
- * @param varP Die Variable, die von TRUE auf FREI gesetzt wird.
- */
- private unitpropagation_undo(varP : Variable) : void {
- let varN : Variable | null = varP.negation;
- if (varN === null)
- throw new NullPointerException()
- this.unitpropagationHelper(varP.clauses, -1, +1);
- this.unitpropagationHelper(varN.clauses, +0, +1);
- this.heap.insert(varP);
- this.heap.insert(varN);
- }
- /**
- * Eine Hilsmethode, die alle Klauseln der Liste aktualisiert.
- *
- * @param clauses Alle zu informmierenden Klausel.
- * @param pDeltaSat Die Veränderung der erfüllten Klauseln, relativ zum 1. Index im 2D-Array
- * {@link Variable#statSatFree}.
- * @param pDeltaFree Die Veränderung der freien Variablen, relativ zum 2. Index im 2D-Array
- * {@link Variable#statSatFree}.
- */
- private unitpropagationHelper(clauses : LinkedCollection<Clause>, pDeltaSat : number, pDeltaFree : number) : void {
- for (let c of clauses) {
- let sat1 : number = c.sat;
- let free1 : number = c.free;
- let sat2 : number = sat1 + pDeltaSat;
- let free2 : number = free1 + pDeltaFree;
- for (let v of c.variables) {
- v.statSatFree[sat1][free1]--;
- v.statSatFree[sat2][free2]++;
- this.heap.update(v);
- }
- c.sat = sat2;
- c.free = free2;
- }
- }
- /**
- * Liefert das zugehörige Variablenobjekt.
- *
- * @param pNr Der Variablennummer.
- *
- * @return Das zugehörige Variablenobjekt.
- */
- private getVarOf(pNr : number) : Variable {
- return (pNr > 0) ? this.vArrayPos[pNr] : this.vArrayNeg[-pNr];
- }
- isTranspiledInstanceOf(name : string): boolean {
- return ['de.nrw.schule.svws.core.kursblockung.satsolver.SatSolverA', 'de.nrw.schule.svws.core.kursblockung.satsolver.SatSolver3'].includes(name);
- }
- }
- export function cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolver3(obj : unknown) : SatSolver3 {
- return obj as SatSolver3;
- }
|