import { JavaObject, cast_java_lang_Object } from '../../../java/lang/JavaObject'; 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 { LinkedCollection, cast_de_nrw_schule_svws_core_adt_collection_LinkedCollection } from '../../../core/adt/collection/LinkedCollection'; import { JavaIterator, cast_java_util_Iterator } from '../../../java/util/JavaIterator'; import { System, cast_java_lang_System } from '../../../java/lang/System'; export class SatSolverWrapper extends SatSolverA { private readonly _solver : SatSolverA; private readonly varFALSE : number; private readonly varTRUE : number; /** * Erstellt eine Ebene über dem {@link SatSolverA}, um verschiedene Bedingungen/Constraints als Klauseln zu * codieren. * * @param solver Der Solver, der intern verwendet wird. */ public constructor(solver : SatSolverA) { super(); this._solver = solver; this.varTRUE = this._solver.createNewVar(); this.varFALSE = -this.varTRUE; this.c_1(this.varTRUE); } public createNewVar() : number { return this._solver.createNewVar(); } public addClause(pVars : Array) : void { this._solver.addClause(pVars); } public isVarTrue(pVar : number) : boolean { return this._solver.isVarTrue(pVar); } public solve(maxTimeMillis : number) : number { return this._solver.solve(maxTimeMillis); } public getVarCount() : number { return this._solver.getVarCount(); } public getClauseCount() : number { return this._solver.getClauseCount(); } /** * Liefert ein Array der Länge n mit neu erzeugten Variablennummern. * * @param n Die Länge des Arrays. * * @return Ein Array der Länge n mit neu erzeugten Variablennummern. */ public createNewVars(n : number) : Array { let temp : Array | null = Array(n).fill(0); for (let i : number = 0; i < temp.length; i++){ temp[i] = this._solver.createNewVar(); } return temp; } /** * Liefert eine Variable, die zuvor auf FALSE forciert wurde. * * @return Eine Variable, die zuvor auf FALSE forciert wurde. */ public getVarFALSE() : number { return this.varFALSE; } /** * Liefert eine Variable, die zuvor auf TRUE forciert wurde. * * @return Eine Variable, die zuvor auf TRUE forciert wurde. */ public getVarTRUE() : number { return this.varTRUE; } /** * Fügt eine Klausel der Größe 1 hinzu. Forciert damit die übergebene Variable auf TRUE. * * @param x Die Variable wird auf TRUE gesetzt. */ public c_1(x : number) : void { this._solver.addClause([x]); } /** * Fügt eine Klausel der Größe 2 hinzu. Forciert damit, dass mindestens eine der beiden Variablen TRUE ist, * letzlich @code{x + y >= 1}. * * @param x Die Variable x der Klausel (x OR y). * @param y Die Variable y der Klausel (x OR y). */ public c_2(x : number, y : number) : void { this._solver.addClause([x, y]); } /** * Fügt eine Klausel der Größe 3 hinzu. Forciert damit, dass mindestens eine der drei Variablen TRUE ist, * letzlich @code{x + y + z >= 1}. * * @param x Die Variable x der Klausel (x OR y OR z). * @param y Die Variable y der Klausel (x OR y OR z). * @param z Die Variable z der Klausel (x OR y OR z). */ public c_3(x : number, y : number, z : number) : void { this._solver.addClause([x, y, z]); } /** * Forciert, dass nicht beide Variablen TRUE sind, letzlich @code{x + y ≤ 1}. * * @param x Die Variable x der Klausel (-x OR -y). * @param y Die Variable y der Klausel (-x OR -y). */ public c_not_both(x : number, y : number) : void { this.c_2(-x, -y); } /** * Liefert die Variable z für die {@code z = x AND y} gilt. * * @param x Variable der obigen Gleichung. * @param y Variable der obigen Gleichung. * * @return Die Variable z für die {@code z = x AND y} gilt. */ public c_new_var_AND(x : number, y : number) : number { let c : number = this._solver.createNewVar(); this.c_2(x, -c); this.c_2(y, -c); this.c_3(-x, -y, c); return c; } /** * Forciert, dass genau {@code amount} Variablen des Arrays den Wert TRUE haben. * * @param pArray Das Variablenarray. * @param amount Die Anzahl an TRUEs in der Variablenliste. */ public c_exactly_GENERIC(pArray : Array, amount : number) : void; /** * Forciert, dass genau {@code amount} Variablen der Variablenliste den Wert TRUE haben. * * @param list Die Variablenliste. * @param amount Die Anzahl an TRUEs in der Variablenliste. */ public c_exactly_GENERIC(list : LinkedCollection, amount : number) : void; /** * Implementation for method overloads of 'c_exactly_GENERIC' */ public c_exactly_GENERIC(__param0 : Array | LinkedCollection, __param1 : number) : void { if (((typeof __param0 !== "undefined") && Array.isArray(__param0)) && ((typeof __param1 !== "undefined") && typeof __param1 === "number")) { let pArray : Array = __param0; let amount : number = __param1 as number; this.c_exactly_GENERIC(SatSolverWrapper.toList(pArray), amount); } else if (((typeof __param0 !== "undefined") && ((__param0 instanceof JavaObject) && (__param0.isTranspiledInstanceOf('de.nrw.schule.svws.core.adt.collection.LinkedCollection'))) || (__param0 === null)) && ((typeof __param1 !== "undefined") && typeof __param1 === "number")) { let list : LinkedCollection = cast_de_nrw_schule_svws_core_adt_collection_LinkedCollection(__param0); let amount : number = __param1 as number; list = new LinkedCollection(list); if (amount > list.size()) { console.log(JSON.stringify("FEHLER: c_exactly_GENERIC --> amount > list.size()")); } if (amount === 0) { for (let x of list) { this.c_1(-x); } return; } if (amount === list.size()) { for (let x of list) { this.c_1(+x); } return; } if (amount === 1) { if (list.size() === 1) { this.c_1(list.getFirst().valueOf()); return; } if (list.size() === 2) { this.c_unequal(list.getFirst().valueOf(), list.getLast().valueOf()); return; } this.c_exactly_one(list); return; } this.c_exactly_NETWORK(list, amount); } else throw new Error('invalid method overload'); } /** * Forciert, dass höchstens {@code maximum} Variablen der Variablenliste den Wert TRUE haben. * * @param list Die Variablenliste. * @param maximum Die maximale Anzahl an TRUEs in der Variablenliste. */ public c_at_most_GENERIC(list : LinkedCollection, maximum : number) : void { list = new LinkedCollection(list); if (maximum >= list.size()) { return; } if (maximum === 0) { for (let x of list) { this.c_1(-x); } return; } if (maximum === 1) { this.c_at_most_one_tree(list); return; } this.c_at_most_NETWORK(list, maximum); } /** * Forciert, dass genau eine Variable der Liste TRUE ist. Falls die Liste leer ist, führt das zur direkten * Unlösbarkeit der Formel. * * @param list Genau eine der Variablen der Liste muss TRUE sein. */ private c_exactly_one(list : LinkedCollection) : void { this.c_1(this.c_at_most_one_tree(list)); } /** * Forciert, dass {@code z = x OR y} gilt. * * @param x Variable der obigen Gleichung. * @param y Variable der obigen Gleichung. * @param z Variable der obigen Gleichung. */ private c_z_equals_x_or_y(x : number, y : number, z : number) : void { this.c_2(-x, z); this.c_2(-y, z); this.c_3(x, y, -z); } /** * Liefert die Variable z für die {@code z = x OR y} gilt. * * @param x Variable der obigen Gleichung. * @param y Variable der obigen Gleichung. * * @return Die Variable z für die {@code z = x OR y} gilt. */ private c_new_var_OR(x : number, y : number) : number { let z : number = this._solver.createNewVar(); this.c_2(-x, z); this.c_2(-y, z); this.c_3(x, y, -z); return z; } /** * Forciert, dass in der Liste maximal eine Variable TRUE ist. Die Ergebnisvariable ist eine OR-Verknüpfung * aller Variablen der Liste. * * @param list Forciert, dass maximal eine Variable der Liste TRUE ist. * * @return Die Ergebnisvariable ist eine OR-Verknüpfung aller Variablen der Liste. */ private c_at_most_one_tree(list : LinkedCollection) : number { list = new LinkedCollection(list); if (list.isEmpty()) { list.add(this.varFALSE); } while (list.size() >= 2) { let a : number = list.removeFirst().valueOf(); let b : number = list.removeFirst().valueOf(); let c : number = this._solver.createNewVar(); this.c_not_both(a, b); this.c_z_equals_x_or_y(a, b, c); list.add(c); } return list.removeFirst().valueOf(); } private c_exactly_NETWORK(list : LinkedCollection, amount : number) : void { this.c_bitonic_sort(list); let i : number = 0; let iter : JavaIterator = list.iterator(); while (iter.hasNext()) { let value : Number = iter.next(); if (i < amount) { this.c_1(+value.valueOf()); } else { this.c_1(-value.valueOf()); } i++; } } private c_at_most_NETWORK(list : LinkedCollection, maximum : number) : void { this.c_bitonic_sort(list); let i : number = 0; let iter : JavaIterator = list.iterator(); while (iter.hasNext()) { let value : Number = iter.next(); if (i < maximum) i++; else this.c_1(-value.valueOf()); } } private c_bitonic_sort(list : LinkedCollection) : void { this.c_fill_False_until_power_two(list); this.c_bitonic_sort_power_two(list); } private c_fill_False_until_power_two(list : LinkedCollection) : void { let size : number = 1; while (size < list.size()) { size *= 2; } while (list.size() < size) { list.addLast(this.varFALSE); } } private c_bitonic_sort_power_two(list : LinkedCollection) : void { for (let window : number = 2; window <= list.size(); window *= 2){ this.c_bitonic_sort_spiral(list, window); for (let difference : number = Math.trunc(window / 2); difference >= 2; difference /= 2){ this.c_bitonic_sort_difference(list, difference); } } } private c_bitonic_sort_spiral(list : LinkedCollection, size : number) : void { for (let i : number = 0; i < list.size(); i += size){ for (let i1 : number = i, i2 : number = i + size - 1; i1 < i2; i1++, i2--){ this.c_bitonic_comparator(list, i1, i2); } } } private c_bitonic_sort_difference(list : LinkedCollection, size : number) : void { let half : number = Math.trunc(size / 2); for (let i : number = 0; i < list.size(); i += size){ for (let j : number = 0; j < half; j++){ this.c_bitonic_comparator(list, i + j, i + j + half); } } } private c_bitonic_comparator(result : LinkedCollection, i1 : number, i2 : number) : void { if (i1 >= i2) { console.log(JSON.stringify("c_bitonic_comparator: " + i1 + "," + i2 + " <-- ERROR!!!")); } let a : number = result.get(i1).valueOf(); let b : number = result.get(i2).valueOf(); result.set(i1, this.c_new_var_OR(a, b)); result.set(i2, this.c_new_var_AND(a, b)); } private static toList(pArray : Array) : LinkedCollection { let list : LinkedCollection = new LinkedCollection(); for (let x of pArray) { list.addLast(x); } return list; } c_unequal(x : number, y : number) : void { this.c_equal(x, -y); } c_equal(x : number, y : number) : void { this.c_2(-x, +y); this.c_2(+x, -y); } isTranspiledInstanceOf(name : string): boolean { return ['de.nrw.schule.svws.core.kursblockung.satsolver.SatSolverA', 'de.nrw.schule.svws.core.kursblockung.satsolver.SatSolverWrapper'].includes(name); } } export function cast_de_nrw_schule_svws_core_kursblockung_satsolver_SatSolverWrapper(obj : unknown) : SatSolverWrapper { return obj as SatSolverWrapper; }