From 4ea2644bc2ab542efe61649e1cd263ebc62c1e70 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Thu, 1 Dec 2022 11:02:50 +0100 Subject: [PATCH 01/44] Next development version 2.5.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 46a1fb80..66b1acb9 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.4.1 + 2.5.0-SNAPSHOT bundle LogicNG From 5cdab69e166bb7366bf4b3c66dacdae47cf48cb1 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Tue, 31 Jan 2023 17:36:32 +0100 Subject: [PATCH 02/44] fixed SATSolver#add: Ensure all variables are added to the internal solver --- CHANGELOG.md | 6 ++++ pom.xml | 2 +- .../java/org/logicng/solvers/MiniSat.java | 14 +++++++- .../cardinalityconstraints/CCALKTest.java | 4 +-- .../cardinalityconstraints/CCAMKTest.java | 6 ++-- .../ModelEnumerationFunctionTest.java | 32 ++++++++++++++++++- .../java/org/logicng/solvers/sat/SATTest.java | 31 +++++++++++++++--- .../transformations/cnf/BDDCNFTest.java | 4 +-- .../transformations/dnf/BDDDNFTest.java | 4 +-- 9 files changed, 86 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e9b85fa..df47d769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.4.2] - 2023-xx-xx + +### Fixed + +- Fixed edge case in method `add(Formula formula, Proposition proposition)` in `MiniSat`. If a formula is added to the SAT solver, it can happen that a variable is not added to the solver because it was removed during the CNF transformation. A `model()` call or model enumeration will not produce models containing this variable since it was not added to the solver. The fix ensures that all variables of the original formula are added to the solver and thus, a found model includes the variable. + ## [2.4.1] - 2022-12-01 ### Changed diff --git a/pom.xml b/pom.xml index 66b1acb9..da4fb766 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.5.0-SNAPSHOT + 2.4.2-SNAPSHOT bundle LogicNG diff --git a/src/main/java/org/logicng/solvers/MiniSat.java b/src/main/java/org/logicng/solvers/MiniSat.java index 5b4e8f00..4428b014 100644 --- a/src/main/java/org/logicng/solvers/MiniSat.java +++ b/src/main/java/org/logicng/solvers/MiniSat.java @@ -67,7 +67,7 @@ /** * Wrapper for the MiniSAT-style SAT solvers. - * @version 2.4.0 + * @version 2.4.2 * @since 1.0 */ public class MiniSat extends SATSolver { @@ -241,6 +241,18 @@ public void add(final Formula formula, final Proposition proposition) { } else { addFormulaAsCNF(formula, proposition); } + addAllOriginalVariables(formula); + } + + /** + * Adds all variables of the given formula to the solver if not already present. + * This method can be used to ensure that the internal solver knows the given variables. + * @param originalFormula the original formula + */ + private void addAllOriginalVariables(final Formula originalFormula) { + for (final Variable var : originalFormula.variables()) { + getOrAddIndex(var); + } } protected void addFormulaAsCNF(final Formula formula, final Proposition proposition) { diff --git a/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java b/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java index 6270f631..fdebac98 100644 --- a/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java +++ b/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java @@ -46,7 +46,7 @@ /** * Unit tests for the at-least-k configs. - * @version 2.0.0 + * @version 2.4.2 * @since 1.0 */ public class CCALKTest implements LogicNGTest { @@ -66,7 +66,7 @@ public void testALK() { int counter = 0; for (final CCConfig config : this.configs) { f.putConfiguration(config); - testCC(10, 0, 1, f); + testCC(10, 0, 1024, f); testCC(10, 1, 1023, f); testCC(10, 2, 1013, f); testCC(10, 3, 968, f); diff --git a/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java b/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java index 984dba52..611f0e67 100644 --- a/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java +++ b/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java @@ -43,7 +43,7 @@ /** * Unit tests for the at-most-k encoders. - * @version 2.0.0 + * @version 2.4.2 * @since 1.0 */ public class CCAMKTest implements LogicNGTest { @@ -73,8 +73,8 @@ public void testAMK() { testCC(10, 7, 968, f, false); testCC(10, 8, 1013, f, false); testCC(10, 9, 1023, f, false); - testCC(10, 10, 1, f, false); - testCC(10, 15, 1, f, false); + testCC(10, 10, 1024, f, false); + testCC(10, 15, 1024, f, false); assertThat(f.newCCVariable().name()).endsWith("_" + counter++); } } diff --git a/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java b/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java index 0e3aa04b..73fa7237 100644 --- a/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java +++ b/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java @@ -1,19 +1,24 @@ package org.logicng.solvers.functions; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.util.FormulaHelper.variables; import org.junit.jupiter.api.Test; import org.logicng.datastructures.Assignment; +import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; +import org.logicng.formulas.FormulaFactoryConfig; +import org.logicng.formulas.Variable; import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; +import org.logicng.solvers.sat.MiniSatConfig; import java.util.List; /** * Units tests for {@link ModelEnumerationFunction}. - * @version 2.3.0 + * @version 2.4.2 * @since 2.3.0 */ public class ModelEnumerationFunctionTest { @@ -47,4 +52,29 @@ public void testFastEvaluable() throws ParserException { models = solver.execute(ModelEnumerationFunction.builder().fastEvaluable(true).build()); assertThat(models).extracting(Assignment::fastEvaluable).containsOnly(true); } + + @Test + public void testVariableRemovedBySimplificationOccursInModels() throws ParserException { + final FormulaFactory f = new FormulaFactory(FormulaFactoryConfig.builder().simplifyComplementaryOperands(true).build()); + final SATSolver solver = MiniSat.miniSat(this.f, MiniSatConfig.builder().cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()); + final Variable a = f.variable("A"); + final Variable b = f.variable("B"); + final Formula formula = this.f.parse("A & B => A"); + solver.add(formula); // during NNF conversion, used by the PG transformation, the formula simplifies to verum when added to the solver + final List models = solver.execute(ModelEnumerationFunction.builder().variables(formula.variables()).build()); + assertThat(models).hasSize(4); + for (final Assignment model : models) { + assertThat(variables(model.literals())).containsExactlyInAnyOrder(a, b); + } + } + + @Test + public void testUnknownVariableNotOccurringInModel() { + final SATSolver solver = MiniSat.miniSat(this.f); + final Variable a = this.f.variable("A"); + solver.add(a); + final List models = solver.execute(ModelEnumerationFunction.builder().variables(this.f.variables("A", "X")).build()); + assertThat(models).hasSize(1); + assertThat(models.get(0).literals()).containsExactly(a); + } } diff --git a/src/test/java/org/logicng/solvers/sat/SATTest.java b/src/test/java/org/logicng/solvers/sat/SATTest.java index d2949650..079e96fa 100644 --- a/src/test/java/org/logicng/solvers/sat/SATTest.java +++ b/src/test/java/org/logicng/solvers/sat/SATTest.java @@ -33,6 +33,7 @@ import static org.logicng.datastructures.Tristate.UNDEF; import static org.logicng.solvers.sat.MiniSatConfig.ClauseMinimization.BASIC; import static org.logicng.solvers.sat.MiniSatConfig.ClauseMinimization.NONE; +import static org.logicng.util.FormulaHelper.variables; import org.junit.jupiter.api.Test; import org.logicng.LogicNGTest; @@ -43,6 +44,7 @@ import org.logicng.formulas.CType; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; +import org.logicng.formulas.FormulaFactoryConfig; import org.logicng.formulas.Literal; import org.logicng.formulas.Variable; import org.logicng.handlers.ModelEnumerationHandler; @@ -61,7 +63,6 @@ import org.logicng.solvers.functions.ModelEnumerationFunction; import org.logicng.solvers.functions.UpZeroLiteralsFunction; import org.logicng.testutils.PigeonHoleGenerator; -import org.logicng.util.FormulaHelper; import java.io.BufferedReader; import java.io.File; @@ -81,7 +82,7 @@ /** * Unit tests for the SAT solvers. - * @version 1.6 + * @version 2.4.1 * @since 1.0 */ public class SATTest extends TestWithExampleFormulas implements LogicNGTest { @@ -296,6 +297,28 @@ public void testPartialModel() { } } + @Test + public void testVariableRemovedBySimplificationOccursInModel() throws ParserException { + final FormulaFactory f = new FormulaFactory(FormulaFactoryConfig.builder().simplifyComplementaryOperands(true).build()); + final SATSolver solver = MiniSat.miniSat(f, MiniSatConfig.builder().cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()); + final Variable a = f.variable("A"); + final Variable b = f.variable("B"); + final Formula formula = this.f.parse("A & B => A"); + solver.add(formula); // during NNF conversion, used by the PG transformation, the formula simplifies to verum when added to the solver + assertThat(solver.sat()).isEqualTo(Tristate.TRUE); + assertThat(solver.knownVariables()).containsExactlyInAnyOrder(a, b); + assertThat(variables(solver.model().literals())).containsExactlyInAnyOrder(a, b); + } + + @Test + public void testUnknownVariableNotOccurringInModel() { + final SATSolver solver = MiniSat.miniSat(this.f); + final Variable a = this.f.variable("A"); + solver.add(a); + assertThat(solver.sat()).isEqualTo(Tristate.TRUE); + assertThat(solver.model(this.f.variables("A", "X")).literals()).containsExactly(a); + } + @Test public void testModelEnumerationHandler() { for (final SATSolver s : this.solvers) { @@ -341,7 +364,6 @@ public boolean foundModel(final Assignment assignment) { } @Test - @SuppressWarnings("deprecation") public void testWithRelaxation() throws ParserException { final PropositionalParser parser = new PropositionalParser(this.f); final Formula one = parser.parse("a & b & (c | ~d)"); @@ -822,7 +844,6 @@ public void testKnownVariables() throws ParserException { } @Test - @SuppressWarnings("deprecation") public void testAddWithoutUnknown() throws ParserException { final PropositionalParser parser = new PropositionalParser(this.f); final Formula phi = parser.parse("x1 & (~x2 | x3) & (x4 | ~x5)"); @@ -1086,7 +1107,7 @@ public void testDimacsFilesWithSelectionOrder() throws IOException { if (fileName.endsWith(".cnf")) { readCNF(solver, file); final List selectionOrder = new ArrayList<>(); - for (final Variable var : FormulaHelper.variables(solver.execute(FormulaOnSolverFunction.get()))) { + for (final Variable var : variables(solver.execute(FormulaOnSolverFunction.get()))) { if (selectionOrder.size() < 10) { selectionOrder.add(var.negate()); } diff --git a/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java b/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java index 1ff65372..f0768f33 100644 --- a/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java +++ b/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java @@ -42,7 +42,7 @@ /** * Unit Tests for {@link BDDCNFTransformation}. - * @version 2.3.0 + * @version 2.4.2 * @since 1.4.0 */ public class BDDCNFTest extends TestWithExampleFormulas { @@ -160,7 +160,7 @@ public void testNot() throws ParserException { @Test public void testCC() throws ParserException { final PseudoBooleanParser p = new PseudoBooleanParser(this.f); - final Formula f1 = p.parse("a <=> (1 * b <= 1)"); + final Formula f1 = p.parse("a <=> (1 * b <= 0)"); final Formula f2 = p.parse("~(1 * b <= 1)"); final Formula f3 = p.parse("(1 * b + 1 * c + 1 * d <= 1)"); final Formula f4 = p.parse("~(1 * b + 1 * c + 1 * d <= 1)"); diff --git a/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java b/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java index 9ce2cff8..581b528f 100644 --- a/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java +++ b/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java @@ -43,7 +43,7 @@ /** * Unit Tests for {@link BDDDNFTransformation}. - * @version 2.3.0 + * @version 2.4.2 * @since 2.3.0 */ public class BDDDNFTest extends TestWithExampleFormulas { @@ -162,7 +162,7 @@ public void testNot() throws ParserException { @Test public void testCC() throws ParserException { final PseudoBooleanParser p = new PseudoBooleanParser(this.f); - final Formula f1 = p.parse("a <=> (1 * b <= 1)"); + final Formula f1 = p.parse("a <=> (1 * b <= 0)"); final Formula f2 = p.parse("~(1 * b <= 1)"); final Formula f3 = p.parse("(1 * b + 1 * c + 1 * d <= 1)"); final Formula f4 = p.parse("~(1 * b + 1 * c + 1 * d <= 1)"); From 6cb1643a0d1848c1f8b3ce760aac1b34c4492541 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Mon, 6 Feb 2023 09:45:42 +0100 Subject: [PATCH 03/44] added side effect note in SATSolver for assumption solving --- CHANGELOG.md | 4 ++++ .../java/org/logicng/solvers/SATSolver.java | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df47d769..163dd220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [2.4.2] - 2023-xx-xx +### Changed + +- Added side effect note in `SATSolver` for the four assumption solving methods. + ### Fixed - Fixed edge case in method `add(Formula formula, Proposition proposition)` in `MiniSat`. If a formula is added to the SAT solver, it can happen that a variable is not added to the solver because it was removed during the CNF transformation. A `model()` call or model enumeration will not produce models containing this variable since it was not added to the solver. The fix ensures that all variables of the original formula are added to the solver and thus, a found model includes the variable. diff --git a/src/main/java/org/logicng/solvers/SATSolver.java b/src/main/java/org/logicng/solvers/SATSolver.java index 5cd7c6d4..d3cd4348 100644 --- a/src/main/java/org/logicng/solvers/SATSolver.java +++ b/src/main/java/org/logicng/solvers/SATSolver.java @@ -234,6 +234,12 @@ public Tristate sat() { /** * Returns {@code Tristate.TRUE} if the current formula in the solver and a given literal are satisfiable, * {@code Tristate.FALSE} if it is unsatisfiable, or {@code UNDEF} if the solving process was aborted. + *

+ * Side effect: Solving with assumptions adds the assumption literals as known variables to the solver if not already known. + * This change lasts beyond the assumption solving call and can have unintended results for subsequent solver calls. + * For example, a subsequent model enumeration call will produce models containing the now known variables. + * A reliable workaround for this side effect is to save the state of the solver with {@link #saveState()} + * and load the state of the solver after the assumption call(s) with {@link #loadState(SolverState)}. * @param literal the assumed literal * @return the satisfiability of the formula in the solver */ @@ -246,6 +252,12 @@ public Tristate sat(final Literal literal) { * are satisfiable, {@code Tristate.FALSE} if it is unsatisfiable, or {@code UNDEF} if the solving process was aborted. * The assumptions can be seen as an additional conjunction of literals. * Note: Use ordered collections to ensure determinism in the solving process and thus in the resulting model or conflict. + *

+ * Side effect: Solving with assumptions adds the assumption literals as known variables to the solver if not already known. + * This change lasts beyond the assumption solving call and can have unintended results for subsequent solver calls. + * For example, a subsequent model enumeration call will produce models containing the now known variables. + * A reliable workaround for this side effect is to save the state of the solver with {@link #saveState()} + * and load the state of the solver after the assumption call(s) with {@link #loadState(SolverState)}. * @param assumptions a collection of literals * @return the satisfiability of the formula in the solver */ @@ -256,6 +268,12 @@ public Tristate sat(final Collection assumptions) { /** * Returns {@code Tristate.TRUE} if the current formula in the solver and a given literal are satisfiable, * {@code Tristate.FALSE} if it is unsatisfiable, or {@code UNDEF} if the solving process was aborted. + *

+ * Side effect: Solving with assumptions adds the assumption literals as known variables to the solver if not already known. + * This change lasts beyond the assumption solving call and can have unintended results for subsequent solver calls. + * For example, a subsequent model enumeration call will produce models containing the now known variables. + * A reliable workaround for this side effect is to save the state of the solver with {@link #saveState()} + * and load the state of the solver after the assumption call(s) with {@link #loadState(SolverState)}. * @param handler the SAT handler * @param literal the assumed literal * @return the satisfiability of the formula in the solver @@ -267,6 +285,12 @@ public Tristate sat(final Collection assumptions) { * are satisfiable, {@code Tristate.FALSE} if it is unsatisfiable, or {@code UNDEF} if the solving process was aborted. * The assumptions can be seen as an additional conjunction of literals. * Note: Use ordered collections to ensure determinism in the solving process and thus in the resulting model or conflict. + *

+ * Side effect: Solving with assumptions adds the assumption literals as known variables to the solver if not already known. + * This change lasts beyond the assumption solving call and can have unintended results for subsequent solver calls. + * For example, a subsequent model enumeration call will produce models containing the now known variables. + * A reliable workaround for this side effect is to save the state of the solver with {@link #saveState()} + * and load the state of the solver after the assumption call(s) with {@link #loadState(SolverState)}. * @param handler the SAT handler * @param assumptions a collection of literals * @return the satisfiability of the formula in the solver From 068d647dc6a92305835ba31d46106a076f3a3e89 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Tue, 29 Aug 2023 22:58:14 +0200 Subject: [PATCH 04/44] ubtrees data structure now supports empty sets --- CHANGELOG.md | 3 +- .../datastructures/ubtrees/UBTree.java | 38 ++++- .../datastructures/ubtrees/UBTreeTest.java | 157 +++++++++++++++++- 3 files changed, 189 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 163dd220..afd81fd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,11 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [2.4.2] - 2023-xx-xx +## [2.5.0] - 2023-xx-xx ### Changed +- UBTree data structure now supports empty sets. - Added side effect note in `SATSolver` for the four assumption solving methods. ### Fixed diff --git a/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java b/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java index b9c347ef..ecb761a4 100644 --- a/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java +++ b/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java @@ -41,17 +41,19 @@ * A data structure for storing sets with efficient sub- and superset queries. * C.f. `A New Method to Index and Query Sets`, Hoffmann and Koehler, 1999 * @param the type of the elements (must be comparable) - * @version 2.0.0 + * @version 2.5.0 * @since 1.5.0 */ public final class UBTree> { private final SortedMap> rootNodes; + private SortedSet rootSet; /** * Constructs an empty UBTree. */ public UBTree() { this.rootNodes = new TreeMap<>(); + this.rootSet = null; } /** @@ -69,7 +71,9 @@ public void addSet(final SortedSet set) { } nodes = node.children(); } - if (node != null) { + if (node == null) { + this.rootSet = set; + } else { node.setEndSet(set); } } @@ -80,10 +84,15 @@ public void addSet(final SortedSet set) { * @return the first subset which is found for the given set or {@code null} if there is none */ public SortedSet firstSubset(final SortedSet set) { - if (this.rootNodes.isEmpty() || set == null || set.isEmpty()) { + final boolean emptyTree = this.rootSet == null && this.rootNodes.isEmpty(); + if (emptyTree || set == null) { return null; } - return firstSubset(set, this.rootNodes); + if (this.rootSet == null) { + return set.isEmpty() ? null : firstSubset(set, this.rootNodes); + } else { + return this.rootSet; + } } /** @@ -93,6 +102,9 @@ public SortedSet firstSubset(final SortedSet set) { */ public Set> allSubsets(final SortedSet set) { final Set> subsets = new LinkedHashSet<>(); + if (this.rootSet != null) { + subsets.add(this.rootSet); + } allSubsets(set, this.rootNodes, subsets); return subsets; } @@ -103,6 +115,9 @@ public Set> allSubsets(final SortedSet set) { * @return all supersets of the given set */ public Set> allSupersets(final SortedSet set) { + if (set.isEmpty()) { + return allSets(); + } final Set> supersets = new LinkedHashSet<>(); allSupersets(set, this.rootNodes, supersets); return supersets; @@ -113,9 +128,11 @@ public Set> allSupersets(final SortedSet set) { * @return all sets in this UBTree */ public Set> allSets() { - final List> allEndOfPathNodes = getAllEndOfPathNodes(this.rootNodes); final Set> allSets = new LinkedHashSet<>(); - for (final UBNode endOfPathNode : allEndOfPathNodes) { + if (this.rootSet != null) { + allSets.add(this.rootSet); + } + for (final UBNode endOfPathNode : getAllEndOfPathNodes(this.rootNodes)) { allSets.add(endOfPathNode.set()); } return allSets; @@ -129,6 +146,15 @@ SortedMap> rootNodes() { return this.rootNodes; } + /** + * Returns the set of the root. If the root is a terminal node, it holds an empty set. + * In this case this method returns this set, otherwise it returns {@code null}. + * @return the set of the root node if it is a terminal node, {@code null} otherwise + */ + SortedSet rootSet() { + return this.rootSet; + } + private SortedSet firstSubset(final SortedSet set, final SortedMap> forest) { final Set> nodes = getAllNodesContainingElements(set, forest); SortedSet foundSubset = null; diff --git a/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java b/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java index 3bb02d6e..e3d54366 100644 --- a/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java +++ b/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java @@ -38,16 +38,24 @@ /** * Unit tests for {@link UBTree}. - * @version 2.0.0 + * @version 2.5.0 * @since 1.5.0 */ public class UBTreeTest { + @Test + public void testEmtpyUBTree() { + final UBTree tree = new UBTree<>(); + assertThat(tree.rootNodes()).isEmpty(); + assertThat(tree.rootSet()).isNull(); + } + @Test public void testEmptySet() { final UBTree tree = new UBTree<>(); tree.addSet(new TreeSet<>()); assertThat(tree.rootNodes()).isEmpty(); + assertThat(tree.rootSet()).isEmpty(); } @Test @@ -65,6 +73,7 @@ public void testSingleSet() { assertThat(tree.rootNodes().get("A").children().get("B").children().get("C").isEndOfPath()).isTrue(); assertThat(tree.rootNodes().get("A").children().get("B").children().get("C").set()).isEqualTo(set("A", "B", "C")); assertThat(tree.rootNodes().get("A").children().get("B").children().get("C").children()).isEmpty(); + assertThat(tree.rootSet()).isNull(); } @Test @@ -76,6 +85,7 @@ public void testExampleFromPaper() { tree.addSet(set("e2", "e3")); assertThat(tree.rootNodes()).hasSize(2); assertThat(tree.rootNodes().keySet()).containsExactly("e0", "e2"); + assertThat(tree.rootSet()).isNull(); // root nodes final UBNode e0 = tree.rootNodes().get("e0"); @@ -122,6 +132,7 @@ public void testContainsSubset() { tree.addSet(e013); tree.addSet(e012); tree.addSet(e23); + assertThat(tree.firstSubset(set())).isNull(); assertThat(tree.firstSubset(set("e0"))).isNull(); assertThat(tree.firstSubset(set("e1"))).isNull(); assertThat(tree.firstSubset(set("e2"))).isNull(); @@ -154,6 +165,52 @@ public void testContainsSubset() { assertThat(tree.firstSubset(set("e0", "e1", "e2", "e3", "e4"))).isIn(e0123, e013, e012, e23); } + @Test + public void testContainsSubsetWithEmtpySet() { + final UBTree tree = new UBTree<>(); + final SortedSet e0123 = set("e0", "e1", "e2", "e3"); + final SortedSet e013 = set("e0", "e1", "e3"); + final SortedSet e012 = set("e0", "e1", "e2"); + final SortedSet e23 = set("e2", "e3"); + final SortedSet empty = set(); + tree.addSet(e0123); + tree.addSet(e013); + tree.addSet(e012); + tree.addSet(e23); + tree.addSet(empty); + assertThat(tree.firstSubset(set())).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e2"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e2"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1", "e2"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1", "e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e2", "e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1", "e2"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1", "e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e2", "e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1", "e2", "e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1", "e2", "e3"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e2", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e3", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e2", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e3", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1", "e2", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1", "e3", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e2", "e3", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1", "e2", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1", "e3", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e2", "e3", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e1", "e2", "e3", "e4"))).isEqualTo(empty); + assertThat(tree.firstSubset(set("e0", "e1", "e2", "e3", "e4"))).isEqualTo(empty); + } + @Test public void testAllSubsets() { final UBTree tree = new UBTree<>(); @@ -165,6 +222,7 @@ public void testAllSubsets() { tree.addSet(e013); tree.addSet(e012); tree.addSet(e23); + assertThat(tree.allSubsets(set())).isEmpty(); assertThat(tree.allSubsets(set("e0"))).isEmpty(); assertThat(tree.allSubsets(set("e1"))).isEmpty(); assertThat(tree.allSubsets(set("e2"))).isEmpty(); @@ -197,6 +255,52 @@ public void testAllSubsets() { assertThat(tree.allSubsets(set("e0", "e1", "e2", "e3", "e4"))).containsExactlyInAnyOrder(e0123, e013, e012, e23); } + @Test + public void testAllSubsetsWithEmptySet() { + final UBTree tree = new UBTree<>(); + final SortedSet e0123 = set("e0", "e1", "e2", "e3"); + final SortedSet e013 = set("e0", "e1", "e3"); + final SortedSet e012 = set("e0", "e1", "e2"); + final SortedSet e23 = set("e2", "e3"); + final SortedSet empty = set(); + tree.addSet(e0123); + tree.addSet(e013); + tree.addSet(e012); + tree.addSet(e23); + tree.addSet(empty); + assertThat(tree.allSubsets(set())).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e0"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e1"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e2"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e3"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e0", "e1"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e0", "e2"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e0", "e3"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e1", "e2"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e1", "e3"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e2", "e3"))).containsExactlyInAnyOrder(empty, e23); + assertThat(tree.allSubsets(set("e0", "e1", "e2"))).containsExactlyInAnyOrder(empty, e012); + assertThat(tree.allSubsets(set("e0", "e1", "e3"))).containsExactlyInAnyOrder(empty, e013); + assertThat(tree.allSubsets(set("e0", "e2", "e3"))).containsExactlyInAnyOrder(empty, e23); + assertThat(tree.allSubsets(set("e1", "e2", "e3"))).containsExactlyInAnyOrder(empty, e23); + assertThat(tree.allSubsets(set("e0", "e1", "e2", "e3"))).containsExactlyInAnyOrder(empty, e0123, e013, e012, e23); + assertThat(tree.allSubsets(set("e0", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e1", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e2", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e3", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e0", "e1", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e0", "e2", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e0", "e3", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e1", "e2", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e1", "e3", "e4"))).containsExactlyInAnyOrder(empty); + assertThat(tree.allSubsets(set("e2", "e3", "e4"))).containsExactlyInAnyOrder(empty, e23); + assertThat(tree.allSubsets(set("e0", "e1", "e2", "e4"))).containsExactlyInAnyOrder(empty, e012); + assertThat(tree.allSubsets(set("e0", "e1", "e3", "e4"))).containsExactlyInAnyOrder(empty, e013); + assertThat(tree.allSubsets(set("e0", "e2", "e3", "e4"))).containsExactlyInAnyOrder(empty, e23); + assertThat(tree.allSubsets(set("e1", "e2", "e3", "e4"))).containsExactlyInAnyOrder(empty, e23); + assertThat(tree.allSubsets(set("e0", "e1", "e2", "e3", "e4"))).containsExactlyInAnyOrder(empty, e0123, e013, e012, e23); + } + @Test public void testAllSupersets() { final UBTree tree = new UBTree<>(); @@ -208,6 +312,52 @@ public void testAllSupersets() { tree.addSet(e013); tree.addSet(e012); tree.addSet(e23); + assertThat(tree.allSupersets(set())).containsExactlyInAnyOrder(e0123, e013, e012, e23); + assertThat(tree.allSupersets(set("e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0"))).containsExactlyInAnyOrder(e0123, e012, e013); + assertThat(tree.allSupersets(set("e1"))).containsExactlyInAnyOrder(e0123, e012, e013); + assertThat(tree.allSupersets(set("e2"))).containsExactlyInAnyOrder(e0123, e012, e23); + assertThat(tree.allSupersets(set("e3"))).containsExactlyInAnyOrder(e0123, e013, e23); + assertThat(tree.allSupersets(set("e0", "e1"))).containsExactlyInAnyOrder(e0123, e012, e013); + assertThat(tree.allSupersets(set("e0", "e2"))).containsExactlyInAnyOrder(e0123, e012); + assertThat(tree.allSupersets(set("e0", "e3"))).containsExactlyInAnyOrder(e0123, e013); + assertThat(tree.allSupersets(set("e1", "e2"))).containsExactlyInAnyOrder(e0123, e012); + assertThat(tree.allSupersets(set("e1", "e3"))).containsExactlyInAnyOrder(e0123, e013); + assertThat(tree.allSupersets(set("e2", "e3"))).containsExactlyInAnyOrder(e0123, e23); + assertThat(tree.allSupersets(set("e0", "e1", "e2"))).containsExactlyInAnyOrder(e0123, e012); + assertThat(tree.allSupersets(set("e0", "e2", "e3"))).containsExactlyInAnyOrder(e0123); + assertThat(tree.allSupersets(set("e0", "e1", "e2", "e3"))).containsExactlyInAnyOrder(e0123); + assertThat(tree.allSupersets(set("e0", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e1", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e2", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e3", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0", "e1", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0", "e2", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0", "e3", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e1", "e2", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e1", "e3", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e2", "e3", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0", "e1", "e2", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0", "e1", "e3", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0", "e2", "e3", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e1", "e2", "e3", "e4"))).isEmpty(); + assertThat(tree.allSupersets(set("e0", "e1", "e2", "e3", "e4"))).isEmpty(); + } + + @Test + public void testAllSupersetsWithEmptySet() { + final UBTree tree = new UBTree<>(); + final SortedSet e0123 = set("e0", "e1", "e2", "e3"); + final SortedSet e013 = set("e0", "e1", "e3"); + final SortedSet e012 = set("e0", "e1", "e2"); + final SortedSet e23 = set("e2", "e3"); + final SortedSet empty = set(); + tree.addSet(e0123); + tree.addSet(e013); + tree.addSet(e012); + tree.addSet(e23); + tree.addSet(empty); + assertThat(tree.allSupersets(set())).containsExactlyInAnyOrder(e0123, e013, e012, e23, empty); assertThat(tree.allSupersets(set("e4"))).isEmpty(); assertThat(tree.allSupersets(set("e0"))).containsExactlyInAnyOrder(e0123, e012, e013); assertThat(tree.allSupersets(set("e1"))).containsExactlyInAnyOrder(e0123, e012, e013); @@ -246,6 +396,7 @@ public void testAllSets() { final SortedSet e013 = set("e0", "e1", "e3"); final SortedSet e012 = set("e0", "e1", "e2"); final SortedSet e23 = set("e2", "e3"); + final SortedSet empty = set(); tree.addSet(e0123); assertThat(tree.allSets()).containsExactlyInAnyOrder(e0123); tree.addSet(e013); @@ -254,9 +405,11 @@ public void testAllSets() { assertThat(tree.allSets()).containsExactlyInAnyOrder(e0123, e013, e012); tree.addSet(e23); assertThat(tree.allSets()).containsExactlyInAnyOrder(e0123, e013, e012, e23); + tree.addSet(empty); + assertThat(tree.allSets()).containsExactlyInAnyOrder(e0123, e013, e012, e23, empty); } - private SortedSet set(final String... elements) { + private static SortedSet set(final String... elements) { return new TreeSet<>(Arrays.asList(elements)); } } From 2399dc798abda0528582d179dbfbb131b8e57c68 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Tue, 29 Aug 2023 23:01:27 +0200 Subject: [PATCH 05/44] remove unused parameter from UBTree#getAllNodesContainingElementsLessThan --- src/main/java/org/logicng/datastructures/ubtrees/UBTree.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java b/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java index ecb761a4..a65edadf 100644 --- a/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java +++ b/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java @@ -185,7 +185,7 @@ private void allSubsets(final SortedSet set, final SortedMap> fo } private void allSupersets(final SortedSet set, final SortedMap> forest, final Set> supersets) { - final Set> nodes = getAllNodesContainingElementsLessThan(set, forest, set.first()); + final Set> nodes = getAllNodesContainingElementsLessThan(forest, set.first()); for (final UBNode node : nodes) { allSupersets(set, node.children(), supersets); } @@ -219,7 +219,7 @@ private Set> getAllNodesContainingElements(final SortedSet set, fin return nodes; } - private Set> getAllNodesContainingElementsLessThan(final SortedSet set, final SortedMap> forest, final T element) { + private Set> getAllNodesContainingElementsLessThan(final SortedMap> forest, final T element) { final Set> nodes = new LinkedHashSet<>(); for (final UBNode node : forest.values()) { if (node != null && node.element().compareTo(element) < 0) { From 7c8c8d11528b74f116853bb8b6b32433e734cba3 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Wed, 30 Aug 2023 00:05:16 +0200 Subject: [PATCH 06/44] new public method UBTree#generateSubsumedUBTree to generate a subsumed UBTree --- CHANGELOG.md | 4 ++ .../datastructures/ubtrees/UBTree.java | 24 +++++++++++ .../logicng/transformations/Subsumption.java | 43 +++++++++---------- .../transformations/cnf/CNFSubsumption.java | 16 ++----- .../transformations/dnf/DNFSubsumption.java | 16 ++----- .../datastructures/ubtrees/UBTreeTest.java | 19 +++++++- 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afd81fd1..21fa545b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [2.5.0] - 2023-xx-xx +### Added + +- Class `UBTree` offers new method `generateSubsumedUBTree` to directly generate a subsumed UBTree for the given sets. + ### Changed - UBTree data structure now supports empty sets. diff --git a/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java b/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java index a65edadf..39e23b1e 100644 --- a/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java +++ b/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java @@ -29,8 +29,10 @@ package org.logicng.datastructures.ubtrees; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; @@ -56,6 +58,28 @@ public UBTree() { this.rootSet = null; } + /** + * Generates a subsumed UBTree from the given sets. + * @param sets the sets + * @param the type of the elements (must be comparable) + * @return the subsumed UBTree + */ + public static > UBTree generateSubsumedUBTree(final Collection> sets) { + final SortedMap>> sizes = new TreeMap<>(); + for (final Collection set : sets) { + sizes.computeIfAbsent(set.size(), k -> new ArrayList<>()).add(new TreeSet<>(set)); + } + final UBTree ubTree = new UBTree<>(); + for (final Map.Entry>> entry : sizes.entrySet()) { + for (final SortedSet set : entry.getValue()) { + if (ubTree.firstSubset(set) == null) { + ubTree.addSet(set); + } + } + } + return ubTree; + } + /** * Adds a set of comparable objects to this UBTree. * @param set the set of comparable objects diff --git a/src/main/java/org/logicng/transformations/Subsumption.java b/src/main/java/org/logicng/transformations/Subsumption.java index f7fb6896..faba0203 100644 --- a/src/main/java/org/logicng/transformations/Subsumption.java +++ b/src/main/java/org/logicng/transformations/Subsumption.java @@ -30,41 +30,40 @@ import org.logicng.datastructures.ubtrees.UBTree; import org.logicng.formulas.Formula; +import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Literal; +import org.logicng.formulas.NAryOperator; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.SortedMap; import java.util.SortedSet; -import java.util.TreeMap; /** * A superclass for subsumptions (CNF or DNF). - * @version 2.0.0 + * @version 2.5.0 * @since 1.5.0 */ public abstract class Subsumption { - /** - * Generates a UBTree from the formulas operands (clauses in CNF, minterms in DNF) - * where all subsumed operands are already deleted. - * @param formula the formula (must be an n-ary operator and CNF or DNF) - * @return the UBTree with the operands and deleted subsumed operands - */ - protected static UBTree generateSubsumedUBTree(final Formula formula) { - final SortedMap>> mapping = new TreeMap<>(); - for (final Formula term : formula) { - mapping.computeIfAbsent(term.literals().size(), k -> new ArrayList<>()).add(term.literals()); + protected static Formula compute(final NAryOperator nary, final boolean cnf) { + final List> terms = getTerms(nary); + final UBTree ubTree = UBTree.generateSubsumedUBTree(terms); + return toNormalForm(ubTree, cnf, nary.factory()); + } + + private static List> getTerms(final NAryOperator nary) { + final List> terms = new ArrayList<>(); + for (final Formula term : nary) { + terms.add(term.literals()); } - final UBTree ubTree = new UBTree<>(); - for (final Map.Entry>> entry : mapping.entrySet()) { - for (final SortedSet set : entry.getValue()) { - if (ubTree.firstSubset(set) == null) { - ubTree.addSet(set); - } - } + return terms; + } + + private static Formula toNormalForm(final UBTree ubTree, final boolean cnf, final FormulaFactory f) { + final List terms = new ArrayList<>(); + for (final SortedSet term : ubTree.allSets()) { + terms.add(cnf ? f.or(term) : f.and(term)); } - return ubTree; + return cnf ? f.cnf(terms) : f.or(terms); } } diff --git a/src/main/java/org/logicng/transformations/cnf/CNFSubsumption.java b/src/main/java/org/logicng/transformations/cnf/CNFSubsumption.java index f84e0f19..f02eaa80 100644 --- a/src/main/java/org/logicng/transformations/cnf/CNFSubsumption.java +++ b/src/main/java/org/logicng/transformations/cnf/CNFSubsumption.java @@ -28,23 +28,18 @@ package org.logicng.transformations.cnf; -import org.logicng.datastructures.ubtrees.UBTree; +import org.logicng.formulas.And; import org.logicng.formulas.FType; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaTransformation; -import org.logicng.formulas.Literal; import org.logicng.transformations.Subsumption; -import java.util.ArrayList; -import java.util.List; -import java.util.SortedSet; - /** * This transformation performs subsumption on a given CNF and returns a new CNF. * I.e. performs as many subsumptions as possible. A subsumption in a CNF means, * that e.g. a clause {@code A | B | C} is subsumed by another clause {@code A | B} * and can therefore be deleted for an equivalent CNF. - * @version 2.3.0 + * @version 2.5.0 * @since 1.5.0 */ public final class CNFSubsumption extends Subsumption implements FormulaTransformation { @@ -77,11 +72,6 @@ public Formula apply(final Formula formula, final boolean cache) { return formula; } assert formula.type() == FType.AND; - final UBTree ubTree = generateSubsumedUBTree(formula); - final List clauses = new ArrayList<>(); - for (final SortedSet literals : ubTree.allSets()) { - clauses.add(formula.factory().clause(literals)); - } - return formula.factory().cnf(clauses); + return compute((And) formula, true); } } diff --git a/src/main/java/org/logicng/transformations/dnf/DNFSubsumption.java b/src/main/java/org/logicng/transformations/dnf/DNFSubsumption.java index 1061438c..1f82653f 100644 --- a/src/main/java/org/logicng/transformations/dnf/DNFSubsumption.java +++ b/src/main/java/org/logicng/transformations/dnf/DNFSubsumption.java @@ -28,23 +28,18 @@ package org.logicng.transformations.dnf; -import org.logicng.datastructures.ubtrees.UBTree; import org.logicng.formulas.FType; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaTransformation; -import org.logicng.formulas.Literal; +import org.logicng.formulas.Or; import org.logicng.transformations.Subsumption; -import java.util.ArrayList; -import java.util.List; -import java.util.SortedSet; - /** * This transformation performs subsumption on a given DNF and returns a new DNF. * I.e. performs as many subsumptions as possible. A subsumption in a DNF means, * that e.g. a minterm {@code A & B & C} is subsumed by another minterm {@code A & B} * and can therefore be deleted for an equivalent DNF. - * @version 2.3.0 + * @version 2.5.0 * @since 1.5.0 */ public final class DNFSubsumption extends Subsumption implements FormulaTransformation { @@ -76,11 +71,6 @@ public Formula apply(final Formula formula, final boolean cache) { return formula; } assert formula.type() == FType.OR; - final UBTree ubTree = generateSubsumedUBTree(formula); - final List minterms = new ArrayList<>(); - for (final SortedSet literals : ubTree.allSets()) { - minterms.add(formula.factory().and(literals)); - } - return formula.factory().or(minterms); + return compute((Or) formula, false); } } diff --git a/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java b/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java index e3d54366..9540af75 100644 --- a/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java +++ b/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java @@ -28,11 +28,13 @@ package org.logicng.datastructures.ubtrees; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; -import java.util.Arrays; import java.util.SortedSet; import java.util.TreeSet; @@ -43,6 +45,19 @@ */ public class UBTreeTest { + @Test + public void testGenerateSubsumedUBTree() { + final SortedSet e0123 = set("e0", "e1", "e2", "e3"); + final SortedSet e013 = set("e0", "e1", "e3"); + final SortedSet e012 = set("e0", "e1", "e2"); + final SortedSet e23 = set("e2", "e3"); + final SortedSet empty = set(); + assertThat(UBTree.generateSubsumedUBTree(emptyList()).allSets()).isEmpty(); + assertThat(UBTree.generateSubsumedUBTree(singletonList(e0123)).allSets()).containsExactlyInAnyOrder(e0123); + assertThat(UBTree.generateSubsumedUBTree(asList(e0123, e013, e012, e23)).allSets()).containsExactlyInAnyOrder(e013, e012, e23); + assertThat(UBTree.generateSubsumedUBTree(asList(e0123, e013, e012, e23, empty)).allSets()).containsExactlyInAnyOrder(empty); + } + @Test public void testEmtpyUBTree() { final UBTree tree = new UBTree<>(); @@ -410,6 +425,6 @@ public void testAllSets() { } private static SortedSet set(final String... elements) { - return new TreeSet<>(Arrays.asList(elements)); + return new TreeSet<>(asList(elements)); } } From 37807bcadb744536ae045c454516d77e9600f7da Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Mon, 29 Jan 2024 14:49:34 +0100 Subject: [PATCH 07/44] remove mattermost workflow --- .github/workflows/mattermost.yml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .github/workflows/mattermost.yml diff --git a/.github/workflows/mattermost.yml b/.github/workflows/mattermost.yml deleted file mode 100644 index 8afa3d29..00000000 --- a/.github/workflows/mattermost.yml +++ /dev/null @@ -1,13 +0,0 @@ -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Create the Mattermost Message - run: | - echo "{\"text\":\"New Commit or PR on GitHub\", \"username\":\"GitHub\"}" > mattermost.json - - uses: mattermost/action-mattermost-notify@master - env: - MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }} From 7e36dced899de6ddab3a373d15abf5ecfc9bb2e9 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Sat, 3 Feb 2024 10:37:00 +0100 Subject: [PATCH 08/44] Prepare 2.5.0 release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index da4fb766..66b1acb9 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.4.2-SNAPSHOT + 2.5.0-SNAPSHOT bundle LogicNG From a90abda56e46a9dede60e6c75d0820fa6d873233 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Sat, 3 Feb 2024 13:02:28 +0100 Subject: [PATCH 09/44] Necessary adjustements for formula and solver serializiation --- .../logicng/collections/LNGBooleanVector.java | 5 +++ .../org/logicng/collections/LNGIntVector.java | 5 +++ .../logicng/collections/LNGLongVector.java | 5 +++ .../java/org/logicng/solvers/MiniSat.java | 38 ++++++++++++++-- .../datastructures/LNGBoundedIntQueue.java | 34 ++++++++++++++ .../datastructures/LNGBoundedLongQueue.java | 34 ++++++++++++++ .../solvers/datastructures/LNGHeap.java | 14 ++++++ .../solvers/datastructures/MSClause.java | 19 ++++++++ .../solvers/datastructures/MSVariable.java | 10 +++++ .../org/logicng/solvers/sat/GlucoseSyrup.java | 35 +++++++-------- .../org/logicng/solvers/sat/MiniCard.java | 44 +++++++++---------- .../logicng/solvers/sat/MiniSat2Solver.java | 34 +++++++------- .../solvers/sat/MiniSatStyleSolver.java | 19 ++++---- .../logicng/solvers/sat/GlucoseSyrupTest.java | 2 - .../org/logicng/solvers/sat/MiniCardTest.java | 2 - 15 files changed, 227 insertions(+), 73 deletions(-) diff --git a/src/main/java/org/logicng/collections/LNGBooleanVector.java b/src/main/java/org/logicng/collections/LNGBooleanVector.java index 363715d1..cca8786b 100644 --- a/src/main/java/org/logicng/collections/LNGBooleanVector.java +++ b/src/main/java/org/logicng/collections/LNGBooleanVector.java @@ -88,6 +88,11 @@ public LNGBooleanVector(final boolean... elems) { this.size = elems.length; } + LNGBooleanVector(final boolean[] elements, final int size) { + this.elements = elements; + this.size = size; + } + /** * Returns whether the vector is empty or not. * @return {@code true} if the vector is empty, {@code false} otherwise diff --git a/src/main/java/org/logicng/collections/LNGIntVector.java b/src/main/java/org/logicng/collections/LNGIntVector.java index f2eac46f..c732168b 100644 --- a/src/main/java/org/logicng/collections/LNGIntVector.java +++ b/src/main/java/org/logicng/collections/LNGIntVector.java @@ -88,6 +88,11 @@ public LNGIntVector(final int... elems) { this.size = elems.length; } + LNGIntVector(final int[] elements, final int size) { + this.elements = elements; + this.size = size; + } + /** * Returns whether the vector is empty or not. * @return {@code true} if the vector is empty, {@code false} otherwise diff --git a/src/main/java/org/logicng/collections/LNGLongVector.java b/src/main/java/org/logicng/collections/LNGLongVector.java index 42ba48dd..738bf030 100644 --- a/src/main/java/org/logicng/collections/LNGLongVector.java +++ b/src/main/java/org/logicng/collections/LNGLongVector.java @@ -88,6 +88,11 @@ public LNGLongVector(final long... elems) { this.size = elems.length; } + LNGLongVector(final long[] elements, final int size) { + this.elements = elements; + this.size = size; + } + /** * Returns whether the vector is empty or not. * @return {@code true} if the vector is empty, {@code false} otherwise diff --git a/src/main/java/org/logicng/solvers/MiniSat.java b/src/main/java/org/logicng/solvers/MiniSat.java index 4428b014..797dffe5 100644 --- a/src/main/java/org/logicng/solvers/MiniSat.java +++ b/src/main/java/org/logicng/solvers/MiniSat.java @@ -75,10 +75,10 @@ public class MiniSat extends SATSolver { public enum SolverStyle {MINISAT, GLUCOSE, MINICARD} protected final MiniSatConfig config; - protected final MiniSatStyleSolver solver; - protected final CCEncoder ccEncoder; - protected final SolverStyle style; - protected final LNGIntVector validStates; + protected MiniSatStyleSolver solver; + protected CCEncoder ccEncoder; + protected SolverStyle style; + protected LNGIntVector validStates; protected final boolean initialPhase; protected final boolean incremental; protected int nextStateId; @@ -122,6 +122,36 @@ protected MiniSat(final FormulaFactory f, final SolverStyle solverStyle, final M this.fullPgTransformation = new PlaistedGreenbaumTransformationSolver(false, this.underlyingSolver(), this.initialPhase); } + /** + * Constructs a new MiniSat solver with a given underlying solver core. This + * method is primarily used for serialization purposes and should not be + * required in any other application use case. + * @param f the formula factory + * @param underlyingSolver the underlying solver core + */ + public MiniSat(final FormulaFactory f, final MiniSatStyleSolver underlyingSolver) { + super(f); + this.config = underlyingSolver.getConfig(); + if (underlyingSolver instanceof MiniSat2Solver) { + this.style = SolverStyle.MINISAT; + } else if (underlyingSolver instanceof MiniCard) { + this.style = SolverStyle.MINICARD; + } else if (underlyingSolver instanceof GlucoseSyrup) { + this.style = SolverStyle.GLUCOSE; + } else { + throw new IllegalArgumentException("Unknown solver type: " + underlyingSolver.getClass()); + } + this.initialPhase = underlyingSolver.getConfig().initialPhase(); + this.solver = underlyingSolver; + this.result = UNDEF; + this.incremental = underlyingSolver.getConfig().incremental(); + this.validStates = new LNGIntVector(); + this.nextStateId = 0; + this.ccEncoder = new CCEncoder(f); + this.pgTransformation = new PlaistedGreenbaumTransformationSolver(true, underlyingSolver, this.initialPhase); + this.fullPgTransformation = new PlaistedGreenbaumTransformationSolver(false, underlyingSolver, this.initialPhase); + } + /** * Returns a new MiniSat solver with the MiniSat configuration from the formula factory. * @param f the formula factory diff --git a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java index 80db3aee..e9988e6b 100644 --- a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java +++ b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java @@ -104,6 +104,16 @@ public LNGBoundedIntQueue() { this.queueSize = 0; } + LNGBoundedIntQueue(final LNGIntVector elems, final int first, final int last, final long sumOfQueue, + final int maxSize, final int queueSize) { + this.elems = elems; + this.first = first; + this.last = last; + this.sumOfQueue = sumOfQueue; + this.maxSize = maxSize; + this.queueSize = queueSize; + } + /** * Initializes the size of this queue. * @param size the size @@ -154,6 +164,30 @@ private void growTo(final int size) { this.last = 0; } + LNGIntVector getElems() { + return this.elems; + } + + int getFirst() { + return this.first; + } + + int getLast() { + return this.last; + } + + long getSumOfQueue() { + return this.sumOfQueue; + } + + int getMaxSize() { + return this.maxSize; + } + + int getQueueSize() { + return this.queueSize; + } + @Override public String toString() { return String.format("LNGBoundedIntQueue{first=%d, last=%d, sumOfQueue=%d, maxSize=%d, queueSize=%d, elems=%s}", diff --git a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java index b091d5ce..753ccd30 100644 --- a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java +++ b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java @@ -104,6 +104,16 @@ public LNGBoundedLongQueue() { this.queueSize = 0; } + LNGBoundedLongQueue(final LNGLongVector elems, final int first, final int last, final long sumOfQueue, + final int maxSize, final int queueSize) { + this.elems = elems; + this.first = first; + this.last = last; + this.sumOfQueue = sumOfQueue; + this.maxSize = maxSize; + this.queueSize = queueSize; + } + /** * Initializes the size of this queue. * @param size the size @@ -172,6 +182,30 @@ public void fastClear() { this.sumOfQueue = 0; } + LNGLongVector getElems() { + return this.elems; + } + + int getFirst() { + return this.first; + } + + int getLast() { + return this.last; + } + + long getSumOfQueue() { + return this.sumOfQueue; + } + + int getMaxSize() { + return this.maxSize; + } + + int getQueueSize() { + return this.queueSize; + } + @Override public String toString() { return String.format("LNGBoundedLongQueue{first=%d, last=%d, sumOfQueue=%d, maxSize=%d, queueSize=%d, elems=%s}", diff --git a/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java b/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java index 40074a3b..5b1db19f 100644 --- a/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java +++ b/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java @@ -69,6 +69,12 @@ public LNGHeap(final MiniSatStyleSolver solver) { this.indices = new LNGIntVector(1000); } + LNGHeap(final MiniSatStyleSolver s, final LNGIntVector heap, final LNGIntVector indices) { + this.s = s; + this.heap = heap; + this.indices = indices; + } + /** * Returns the left position on the heap for a given position. * @param pos the position @@ -252,6 +258,14 @@ private void percolateDown(final int pos) { this.indices.set(y, p); } + LNGIntVector getHeap() { + return this.heap; + } + + LNGIntVector getIndices() { + return this.indices; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("LNGHeap{"); diff --git a/src/main/java/org/logicng/solvers/datastructures/MSClause.java b/src/main/java/org/logicng/solvers/datastructures/MSClause.java index 1f0d71f3..1feb20bc 100644 --- a/src/main/java/org/logicng/solvers/datastructures/MSClause.java +++ b/src/main/java/org/logicng/solvers/datastructures/MSClause.java @@ -123,6 +123,21 @@ public MSClause(final LNGIntVector ps, final boolean learnt, final boolean isAtM this.atMostWatchers = -1; } + MSClause(final LNGIntVector data, final boolean learnt, final boolean isAtMost, final double activity, + final int szWithoutSelectors, final boolean seen, final long lbd, final boolean canBeDel, + final boolean oneWatched, final int atMostWatchers) { + this.data = data; + this.learnt = learnt; + this.isAtMost = isAtMost; + this.activity = activity; + this.szWithoutSelectors = szWithoutSelectors; + this.seen = seen; + this.lbd = lbd; + this.canBeDel = canBeDel; + this.oneWatched = oneWatched; + this.atMostWatchers = atMostWatchers; + } + /** * Returns the size (number of literals) of this clause. * @return the size @@ -301,6 +316,10 @@ public int cardinality() { return this.data.size() - this.atMostWatchers + 1; } + LNGIntVector getData() { + return this.data; + } + @Override public int hashCode() { return this.data.hashCode(); diff --git a/src/main/java/org/logicng/solvers/datastructures/MSVariable.java b/src/main/java/org/logicng/solvers/datastructures/MSVariable.java index 926d8011..f7545b0b 100644 --- a/src/main/java/org/logicng/solvers/datastructures/MSVariable.java +++ b/src/main/java/org/logicng/solvers/datastructures/MSVariable.java @@ -74,6 +74,16 @@ public MSVariable(final boolean polarity) { this.decision = false; } + MSVariable(final Tristate assignment, final int level, final MSClause reason, final double activity, + final boolean polarity, final boolean decision) { + this.assignment = assignment; + this.level = level; + this.reason = reason; + this.activity = activity; + this.polarity = polarity; + this.decision = decision; + } + /** * Sets the decision level of this variable. * @param level the decision level diff --git a/src/main/java/org/logicng/solvers/sat/GlucoseSyrup.java b/src/main/java/org/logicng/solvers/sat/GlucoseSyrup.java index 84276b6b..8ba2b44a 100644 --- a/src/main/java/org/logicng/solvers/sat/GlucoseSyrup.java +++ b/src/main/java/org/logicng/solvers/sat/GlucoseSyrup.java @@ -516,14 +516,14 @@ protected MSClause propagate() { } @Override - protected boolean litRedundant(final int p, final int abstractLevels) { - this.analyzeStack.clear(); - this.analyzeStack.push(p); - final int top = this.analyzeToClear.size(); - while (this.analyzeStack.size() > 0) { - assert v(this.analyzeStack.back()).reason() != null; - final MSClause c = v(this.analyzeStack.back()).reason(); - this.analyzeStack.pop(); + protected boolean litRedundant(final int p, final int abstractLevels, final LNGIntVector analyzeToClear) { + final LNGIntVector analyzeStack = new LNGIntVector(); + analyzeStack.push(p); + final int top = analyzeToClear.size(); + while (analyzeStack.size() > 0) { + assert v(analyzeStack.back()).reason() != null; + final MSClause c = v(analyzeStack.back()).reason(); + analyzeStack.pop(); if (c.size() == 2 && value(c.get(0)) == Tristate.FALSE) { assert value(c.get(1)) == Tristate.TRUE; final int tmp = c.get(0); @@ -535,13 +535,13 @@ protected boolean litRedundant(final int p, final int abstractLevels) { if (!this.seen.get(var(q)) && v(q).level() > 0) { if (v(q).reason() != null && (abstractLevel(var(q)) & abstractLevels) != 0) { this.seen.set(var(q), true); - this.analyzeStack.push(q); - this.analyzeToClear.push(q); + analyzeStack.push(q); + analyzeToClear.push(q); } else { - for (int j = top; j < this.analyzeToClear.size(); j++) { - this.seen.set(var(this.analyzeToClear.get(j)), false); + for (int j = top; j < analyzeToClear.size(); j++) { + this.seen.set(var(analyzeToClear.get(j)), false); } - this.analyzeToClear.removeElements(this.analyzeToClear.size() - top); + analyzeToClear.removeElements(analyzeToClear.size() - top); return false; } } @@ -985,14 +985,14 @@ protected void simplifyClause(final LNGIntVector outLearnt, final LNGIntVector s for (i = 0; i < selectors.size(); i++) { outLearnt.push(selectors.get(i)); } - this.analyzeToClear = new LNGIntVector(outLearnt); + final LNGIntVector analyzeToClear = new LNGIntVector(outLearnt); if (this.ccminMode == MiniSatConfig.ClauseMinimization.DEEP) { int abstractLevel = 0; for (i = 1; i < outLearnt.size(); i++) { abstractLevel |= abstractLevel(var(outLearnt.get(i))); } for (i = j = 1; i < outLearnt.size(); i++) { - if (v(outLearnt.get(i)).reason() == null || !litRedundant(outLearnt.get(i), abstractLevel)) { + if (v(outLearnt.get(i)).reason() == null || !litRedundant(outLearnt.get(i), abstractLevel, analyzeToClear)) { outLearnt.set(j++, outLearnt.get(i)); } } @@ -1052,8 +1052,8 @@ protected void simplifyClause(final LNGIntVector outLearnt, final LNGIntVector s } this.lastDecisionLevel.clear(); } - for (int m = 0; m < this.analyzeToClear.size(); m++) { - this.seen.set(var(this.analyzeToClear.get(m)), false); + for (int m = 0; m < analyzeToClear.size(); m++) { + this.seen.set(var(analyzeToClear.get(m)), false); } for (int m = 0; m < selectors.size(); m++) { this.seen.set(var(selectors.get(m)), false); @@ -1073,4 +1073,3 @@ protected boolean isRotatable(final int lit) { return true; } } - diff --git a/src/main/java/org/logicng/solvers/sat/MiniCard.java b/src/main/java/org/logicng/solvers/sat/MiniCard.java index 09df3ab4..4e09f3f9 100644 --- a/src/main/java/org/logicng/solvers/sat/MiniCard.java +++ b/src/main/java/org/logicng/solvers/sat/MiniCard.java @@ -392,14 +392,14 @@ protected MSClause propagate() { } @Override - protected boolean litRedundant(final int p, final int abstractLevels) { - this.analyzeStack.clear(); - this.analyzeStack.push(p); - final int top = this.analyzeToClear.size(); - while (this.analyzeStack.size() > 0) { - assert v(this.analyzeStack.back()).reason() != null; - final MSClause c = v(this.analyzeStack.back()).reason(); - this.analyzeStack.pop(); + protected boolean litRedundant(final int p, final int abstractLevels, final LNGIntVector analyzeToClear) { + final LNGIntVector analyzeStack = new LNGIntVector(); + analyzeStack.push(p); + final int top = analyzeToClear.size(); + while (analyzeStack.size() > 0) { + assert v(analyzeStack.back()).reason() != null; + final MSClause c = v(analyzeStack.back()).reason(); + analyzeStack.pop(); if (c.isAtMost()) { for (int i = 0; i < c.size(); i++) { if (value(c.get(i)) != Tristate.TRUE) { @@ -409,13 +409,13 @@ protected boolean litRedundant(final int p, final int abstractLevels) { if (!this.seen.get(var(q)) && v(q).level() > 0) { if (v(q).reason() != null && (abstractLevel(var(q)) & abstractLevels) != 0) { this.seen.set(var(q), true); - this.analyzeStack.push(q); - this.analyzeToClear.push(q); + analyzeStack.push(q); + analyzeToClear.push(q); } else { - for (int j = top; j < this.analyzeToClear.size(); j++) { - this.seen.set(var(this.analyzeToClear.get(j)), false); + for (int j = top; j < analyzeToClear.size(); j++) { + this.seen.set(var(analyzeToClear.get(j)), false); } - this.analyzeToClear.removeElements(this.analyzeToClear.size() - top); + analyzeToClear.removeElements(analyzeToClear.size() - top); return false; } } @@ -426,13 +426,13 @@ protected boolean litRedundant(final int p, final int abstractLevels) { if (!this.seen.get(var(q)) && v(q).level() > 0) { if (v(q).reason() != null && (abstractLevel(var(q)) & abstractLevels) != 0) { this.seen.set(var(q), true); - this.analyzeStack.push(q); - this.analyzeToClear.push(q); + analyzeStack.push(q); + analyzeToClear.push(q); } else { - for (int j = top; j < this.analyzeToClear.size(); j++) { - this.seen.set(var(this.analyzeToClear.get(j)), false); + for (int j = top; j < analyzeToClear.size(); j++) { + this.seen.set(var(analyzeToClear.get(j)), false); } - this.analyzeToClear.removeElements(this.analyzeToClear.size() - top); + analyzeToClear.removeElements(analyzeToClear.size() - top); return false; } } @@ -808,14 +808,14 @@ protected void analyze(final MSClause conflictClause, final LNGIntVector outLear protected void simplifyClause(final LNGIntVector outLearnt) { int i; int j; - this.analyzeToClear = new LNGIntVector(outLearnt); + final LNGIntVector analyzeToClear = new LNGIntVector(outLearnt); if (this.ccminMode == MiniSatConfig.ClauseMinimization.DEEP) { int abstractLevel = 0; for (i = 1; i < outLearnt.size(); i++) { abstractLevel |= abstractLevel(var(outLearnt.get(i))); } for (i = j = 1; i < outLearnt.size(); i++) { - if (v(outLearnt.get(i)).reason() == null || !litRedundant(outLearnt.get(i), abstractLevel)) { + if (v(outLearnt.get(i)).reason() == null || !litRedundant(outLearnt.get(i), abstractLevel, analyzeToClear)) { outLearnt.set(j++, outLearnt.get(i)); } } @@ -850,8 +850,8 @@ protected void simplifyClause(final LNGIntVector outLearnt) { outLearnt.set(1, p); this.analyzeBtLevel = v(p).level(); } - for (int l = 0; l < this.analyzeToClear.size(); l++) { - this.seen.set(var(this.analyzeToClear.get(l)), false); + for (int l = 0; l < analyzeToClear.size(); l++) { + this.seen.set(var(analyzeToClear.get(l)), false); } } diff --git a/src/main/java/org/logicng/solvers/sat/MiniSat2Solver.java b/src/main/java/org/logicng/solvers/sat/MiniSat2Solver.java index 95e64afc..f042cc23 100644 --- a/src/main/java/org/logicng/solvers/sat/MiniSat2Solver.java +++ b/src/main/java/org/logicng/solvers/sat/MiniSat2Solver.java @@ -416,26 +416,26 @@ protected MSClause propagate() { } @Override - protected boolean litRedundant(final int p, final int abstractLevels) { - this.analyzeStack.clear(); - this.analyzeStack.push(p); - final int top = this.analyzeToClear.size(); - while (this.analyzeStack.size() > 0) { - assert v(this.analyzeStack.back()).reason() != null; - final MSClause c = v(this.analyzeStack.back()).reason(); - this.analyzeStack.pop(); + protected boolean litRedundant(final int p, final int abstractLevels, final LNGIntVector analyzeToClear) { + final LNGIntVector analyzeStack = new LNGIntVector(); + analyzeStack.push(p); + final int top = analyzeToClear.size(); + while (analyzeStack.size() > 0) { + assert v(analyzeStack.back()).reason() != null; + final MSClause c = v(analyzeStack.back()).reason(); + analyzeStack.pop(); for (int i = 1; i < c.size(); i++) { final int q = c.get(i); if (!this.seen.get(var(q)) && v(q).level() > 0) { if (v(q).reason() != null && (abstractLevel(var(q)) & abstractLevels) != 0) { this.seen.set(var(q), true); - this.analyzeStack.push(q); - this.analyzeToClear.push(q); + analyzeStack.push(q); + analyzeToClear.push(q); } else { - for (int j = top; j < this.analyzeToClear.size(); j++) { - this.seen.set(var(this.analyzeToClear.get(j)), false); + for (int j = top; j < analyzeToClear.size(); j++) { + this.seen.set(var(analyzeToClear.get(j)), false); } - this.analyzeToClear.removeElements(this.analyzeToClear.size() - top); + analyzeToClear.removeElements(analyzeToClear.size() - top); return false; } } @@ -684,14 +684,14 @@ protected void analyze(final MSClause conflictClause, final LNGIntVector outLear protected void simplifyClause(final LNGIntVector outLearnt) { int i; int j; - this.analyzeToClear = new LNGIntVector(outLearnt); + final LNGIntVector analyzeToClear = new LNGIntVector(outLearnt); if (this.ccminMode == MiniSatConfig.ClauseMinimization.DEEP) { int abstractLevel = 0; for (i = 1; i < outLearnt.size(); i++) { abstractLevel |= abstractLevel(var(outLearnt.get(i))); } for (i = j = 1; i < outLearnt.size(); i++) { - if (v(outLearnt.get(i)).reason() == null || !litRedundant(outLearnt.get(i), abstractLevel)) { + if (v(outLearnt.get(i)).reason() == null || !litRedundant(outLearnt.get(i), abstractLevel, analyzeToClear)) { outLearnt.set(j++, outLearnt.get(i)); } } @@ -726,8 +726,8 @@ protected void simplifyClause(final LNGIntVector outLearnt) { outLearnt.set(1, p); this.analyzeBtLevel = v(p).level(); } - for (int l = 0; l < this.analyzeToClear.size(); l++) { - this.seen.set(var(this.analyzeToClear.get(l)), false); + for (int l = 0; l < analyzeToClear.size(); l++) { + this.seen.set(var(analyzeToClear.get(l)), false); } } diff --git a/src/main/java/org/logicng/solvers/sat/MiniSatStyleSolver.java b/src/main/java/org/logicng/solvers/sat/MiniSatStyleSolver.java index ec967348..c65bd45e 100644 --- a/src/main/java/org/logicng/solvers/sat/MiniSatStyleSolver.java +++ b/src/main/java/org/logicng/solvers/sat/MiniSatStyleSolver.java @@ -85,7 +85,7 @@ public abstract class MiniSatStyleSolver { public static final int LIT_UNDEF = -1; // external solver configuration - protected final MiniSatConfig config; + protected MiniSatConfig config; // internal solver state protected boolean ok; @@ -101,8 +101,6 @@ public abstract class MiniSatStyleSolver { protected LNGIntVector conflict; protected LNGIntVector assumptions; protected LNGBooleanVector seen; - protected LNGIntVector analyzeStack; - protected LNGIntVector analyzeToClear; protected int analyzeBtLevel; protected double claInc; protected int simpDBAssigns; @@ -244,8 +242,6 @@ protected void initialize() { this.conflict = new LNGIntVector(); this.assumptions = new LNGIntVector(); this.seen = new LNGBooleanVector(); - this.analyzeStack = new LNGIntVector(); - this.analyzeToClear = new LNGIntVector(); this.analyzeBtLevel = 0; this.claInc = 1; this.simpDBAssigns = -1; @@ -633,9 +629,10 @@ protected void claBumpActivity(final MSClause c) { * Returns {@code true} if a given literal is redundant in the current conflict analysis, {@code false} otherwise. * @param p the literal * @param abstractLevels an abstraction of levels + * @param analyzeToClear the clear analysis vector * @return {@code true} if a given literal is redundant in the current conflict analysis */ - protected abstract boolean litRedundant(int p, int abstractLevels); + protected abstract boolean litRedundant(int p, int abstractLevels, LNGIntVector analyzeToClear); /** * Analysis the final conflict if there were assumptions. @@ -743,8 +740,6 @@ public String toString() { sb.append("conflict ").append(this.conflict).append(System.lineSeparator()); sb.append("assumptions ").append(this.assumptions).append(System.lineSeparator()); sb.append("#seen ").append(this.seen.size()).append(System.lineSeparator()); - sb.append("#stack ").append(this.analyzeStack.size()).append(System.lineSeparator()); - sb.append("#toclear ").append(this.analyzeToClear.size()).append(System.lineSeparator()); sb.append("claInc ").append(this.claInc).append(System.lineSeparator()); sb.append("simpDBAssigns ").append(this.simpDBAssigns).append(System.lineSeparator()); @@ -1122,4 +1117,12 @@ public void setSelectionOrder(final List selectionOrder) { public void resetSelectionOrder() { this.selectionOrder.clear(); } + + /** + * Returns the solver config. + * @return the solver config + */ + public MiniSatConfig getConfig() { + return this.config; + } } diff --git a/src/test/java/org/logicng/solvers/sat/GlucoseSyrupTest.java b/src/test/java/org/logicng/solvers/sat/GlucoseSyrupTest.java index abf904cf..c0f76995 100644 --- a/src/test/java/org/logicng/solvers/sat/GlucoseSyrupTest.java +++ b/src/test/java/org/logicng/solvers/sat/GlucoseSyrupTest.java @@ -78,8 +78,6 @@ public void testToString() { "conflict []%n" + "assumptions []%n" + "#seen 4%n" + - "#stack 0%n" + - "#toclear 0%n" + "claInc 1.0%n" + "simpDBAssigns -1%n" + "simpDBProps 0%n" + diff --git a/src/test/java/org/logicng/solvers/sat/MiniCardTest.java b/src/test/java/org/logicng/solvers/sat/MiniCardTest.java index 23bfa5f7..026b80f6 100644 --- a/src/test/java/org/logicng/solvers/sat/MiniCardTest.java +++ b/src/test/java/org/logicng/solvers/sat/MiniCardTest.java @@ -136,8 +136,6 @@ public void testToString() { "conflict []%n" + "assumptions []%n" + "#seen 4%n" + - "#stack 0%n" + - "#toclear 0%n" + "claInc 1.0%n" + "simpDBAssigns -1%n" + "simpDBProps 0%n" + From 5eb5ef246df40afcc30bfed0f005071e6983c98f Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Sun, 4 Feb 2024 20:43:35 +0100 Subject: [PATCH 10/44] Equals/Hashcode for DNNF data structure --- .../dnnf/datastructures/Dnnf.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java b/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java index 4a2dea46..1b2f964b 100644 --- a/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java +++ b/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java @@ -32,11 +32,12 @@ import org.logicng.formulas.Variable; import org.logicng.knowledgecompilation.dnnf.functions.DnnfFunction; +import java.util.Objects; import java.util.SortedSet; /** * A DNNF - Decomposable Negation Normal Form. - * @version 2.0.0 + * @version 2.5.0 * @since 2.0.0 */ public final class Dnnf { @@ -79,4 +80,21 @@ public Formula formula() { public SortedSet getOriginalVariables() { return this.originalVariables; } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final Dnnf dnnf = (Dnnf) o; + return Objects.equals(this.originalVariables, dnnf.originalVariables) && Objects.equals(this.formula, dnnf.formula); + } + + @Override + public int hashCode() { + return Objects.hash(this.originalVariables, this.formula); + } } From d058151e2f202c01df3a425a90805ee2f3378814 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Mon, 5 Feb 2024 23:52:45 +0100 Subject: [PATCH 11/44] added (unsafe) methods term/dnf to the FormulaFactory --- CHANGELOG.md | 3 +- .../org/logicng/formulas/FormulaFactory.java | 144 +++++++++++++++++- .../java/org/logicng/formulas/AndTest.java | 19 ++- .../java/org/logicng/formulas/OrTest.java | 25 ++- 4 files changed, 187 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21fa545b..9b6fa80a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,11 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [2.5.0] - 2023-xx-xx +## [2.5.0] - 2024-xx-xx ### Added +- Added unsafe methods `term` and `dnf` to the `FormulaFactory` to create a term (conjunction of literals) or a DNF (c.f. with method `FormulaFactory#clause` and `FormulaFactory#cnf`). Both methods do not perform reduction operations and therefore are faster. Only use these methods if you are sure the input is free of complementary and redundant operands. - Class `UBTree` offers new method `generateSubsumedUBTree` to directly generate a subsumed UBTree for the given sets. ### Changed diff --git a/src/main/java/org/logicng/formulas/FormulaFactory.java b/src/main/java/org/logicng/formulas/FormulaFactory.java index 664df73c..58e77ab5 100644 --- a/src/main/java/org/logicng/formulas/FormulaFactory.java +++ b/src/main/java/org/logicng/formulas/FormulaFactory.java @@ -80,7 +80,7 @@ *

* A formula factory is NOT thread-safe. If you generate formulas from more than one thread you either need to synchronize the formula factory * yourself or you use a formula factory for each single thread. - * @version 2.4.0 + * @version 2.5.0 * @since 1.0 */ public class FormulaFactory { @@ -802,6 +802,84 @@ private Formula constructOr(final LinkedHashSet operandsIn) { return or; } + /** + * Creates a new DNF from an array of terms (conjunctions of literals). + *

+ * ATTENTION: it is assumed that the operands are really terms - this is not checked for performance reasons. + * Also, no reduction of operands is performed - this method should only be used if you are sure that the DNF is free + * of redundant terms. + * @param terms the array of terms + * @return a new DNF + */ + public Formula dnf(final Formula... terms) { + final LinkedHashSet ops = new LinkedHashSet<>(terms.length); + Collections.addAll(ops, terms); + return this.constructDNF(ops); + } + + /** + * Creates a new DNF from a collection of terms (conjunctions of literals). + *

+ * ATTENTION: it is assumed that the operands are really terms - this is not checked for performance reasons. + * Also, no reduction of operands is performed - this method should only be used if you are sure that the DNF is free + * of redundant terms. + * @param terms the collection of terms + * @return a new DNF + */ + public Formula dnf(final Collection terms) { + final LinkedHashSet ops = new LinkedHashSet<>(terms); + return this.constructDNF(ops); + } + + /** + * Creates a new DNF. + * @param termsIn the terms + * @return a new DNF + */ + private Formula constructDNF(final LinkedHashSet termsIn) { + final LinkedHashSet terms = importOrPanic(termsIn); + if (terms.isEmpty()) { + return this.falsum(); + } + if (terms.size() == 1) { + return terms.iterator().next(); + } + Map, Or> opOrMap = this.orsN; + switch (terms.size()) { + case 2: + opOrMap = this.ors2; + break; + case 3: + opOrMap = this.ors3; + break; + case 4: + opOrMap = this.ors4; + break; + default: + break; + } + Or tempOr = opOrMap.get(terms); + if (tempOr != null) { + return tempOr; + } + tempOr = new Or(terms, this); + setCnfCaches(tempOr, isCnf(termsIn)); + opOrMap.put(terms, tempOr); + return tempOr; + } + + private static boolean isCnf(final LinkedHashSet terms) { + if (terms.size() <= 1) { + return true; + } + for (final Formula term : terms) { + if (term.type() != LITERAL) { + return false; + } + } + return true; + } + /** * Creates a new clause from an array of literals. *

@@ -866,6 +944,70 @@ private Formula constructClause(final LinkedHashSet literalsIn) { return tempOr; } + /** + * Creates a new term from an array of literals. + *

+ * ATTENTION: No reduction of operands is performed - this method should only be used if you are sure that the term + * is free of redundant or contradicting literals. + * @param literals the collection of literals + * @return a new term + */ + public Formula term(final Literal... literals) { + final LinkedHashSet ops = new LinkedHashSet<>(literals.length); + Collections.addAll(ops, literals); + return this.constructTerm(ops); + } + + /** + * Creates a new term from a collection of literals. + *

+ * ATTENTION: No reduction of operands is performed - this method should only be used if you are sure that the term + * is free of contradicting literals. + * @param literals the collection of literals + * @return a new term + */ + public Formula term(final Collection literals) { + final LinkedHashSet ops = new LinkedHashSet<>(literals); + return this.constructTerm(ops); + } + + /** + * Creates a new term. + * @param literalsIn the literals + * @return a new term + */ + private Formula constructTerm(final LinkedHashSet literalsIn) { + final LinkedHashSet literals = importOrPanic(literalsIn); + if (literals.isEmpty()) { + return this.verum(); + } + if (literals.size() == 1) { + return literals.iterator().next(); + } + Map, And> opAndMap = this.andsN; + switch (literals.size()) { + case 2: + opAndMap = this.ands2; + break; + case 3: + opAndMap = this.ands3; + break; + case 4: + opAndMap = this.ands4; + break; + default: + break; + } + And tempAnd = opAndMap.get(literals); + if (tempAnd != null) { + return tempAnd; + } + tempAnd = new And(literals, this); + setCnfCaches(tempAnd, true); + opAndMap.put(literals, tempAnd); + return tempAnd; + } + private void setCnfCaches(final Formula formula, final boolean isCNF) { if (isCNF) { setPredicateCacheEntry(formula, IS_CNF, true); diff --git a/src/test/java/org/logicng/formulas/AndTest.java b/src/test/java/org/logicng/formulas/AndTest.java index f92742f1..0bc2d126 100644 --- a/src/test/java/org/logicng/formulas/AndTest.java +++ b/src/test/java/org/logicng/formulas/AndTest.java @@ -28,6 +28,8 @@ package org.logicng.formulas; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -44,7 +46,7 @@ /** * Unit Tests for the class {@link And}. - * @version 2.3.0 + * @version 2.5.0 * @since 1.0 */ public class AndTest extends TestWithExampleFormulas { @@ -74,7 +76,16 @@ public void testCreator() { assertThat(this.f.and(lits)).isEqualTo(this.AND1); assertThat(this.f.and(this.A, this.B, this.X, this.FALSE)).isEqualTo(this.FALSE); assertThat(this.f.and(this.f.and(this.A, this.B), this.f.and(this.X, this.Y))).isEqualTo(this.f.and(this.A, this.B, this.X, this.Y)); + assertThat(this.f.cnf(emptyList())).isEqualTo(this.f.verum()); + assertThat(this.f.cnf(singletonList(this.f.falsum()))).isEqualTo(this.f.falsum()); + assertThat(this.f.cnf(singletonList(this.f.verum()))).isEqualTo(this.f.verum()); assertThat(this.f.cnf(this.f.clause(this.X, this.Y), this.f.and(this.f.or(this.f.and(this.NX, this.NX), this.NY), this.f.or(this.f.and(this.NX, this.TRUE), this.NY)))).isEqualTo(this.AND3); + assertThat(this.f.term()).isEqualTo(this.f.verum()); + assertThat(this.f.term(this.A)).isEqualTo(this.A); + assertThat(this.f.term(this.A, this.NB)).isEqualTo(this.f.and(this.A, this.NB)); + assertThat(this.f.term(emptyList())).isEqualTo(this.f.verum()); + assertThat(this.f.term(singletonList(this.A))).isEqualTo(this.A); + assertThat(this.f.term(Arrays.asList(this.A, this.NB))).isEqualTo(this.f.and(this.A, this.NB)); assertThat(this.f.naryOperator(FType.AND, this.A, this.B, this.A, this.B, this.A)).isEqualTo(this.AND1); assertThat(this.f.naryOperator(FType.AND, Arrays.asList(this.A, this.B, this.A, this.B, this.A))).isEqualTo(this.AND1); } @@ -223,6 +234,9 @@ public void testIsDNF() { assertThat(this.AND1.isDNF()).isTrue(); assertThat(this.AND2.isDNF()).isTrue(); assertThat(this.AND3.isDNF()).isFalse(); + assertThat(this.f.term().isDNF()).isTrue(); + assertThat(this.f.term(this.A).isDNF()).isTrue(); + assertThat(this.f.term(this.A, this.NB).isDNF()).isTrue(); } @Test @@ -230,5 +244,8 @@ public void testIsCNF() { assertThat(this.AND1.isCNF()).isTrue(); assertThat(this.AND2.isCNF()).isTrue(); assertThat(this.AND3.isCNF()).isTrue(); + assertThat(this.f.term().isCNF()).isTrue(); + assertThat(this.f.term(this.A).isCNF()).isTrue(); + assertThat(this.f.term(this.A, this.NB).isCNF()).isTrue(); } } diff --git a/src/test/java/org/logicng/formulas/OrTest.java b/src/test/java/org/logicng/formulas/OrTest.java index 5eec20a0..35cdce7a 100644 --- a/src/test/java/org/logicng/formulas/OrTest.java +++ b/src/test/java/org/logicng/formulas/OrTest.java @@ -28,6 +28,8 @@ package org.logicng.formulas; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; @@ -42,7 +44,7 @@ /** * Unit Tests for the class {@link Or}. - * @version 2.3.0 + * @version 2.5.0 * @since 1.0 */ public class OrTest extends TestWithExampleFormulas { @@ -71,6 +73,16 @@ public void testCreator() { assertThat(this.f.or(this.A, this.B, this.X, this.TRUE)).isEqualTo(this.TRUE); assertThat(this.f.or(this.f.or(this.A, this.B), this.f.or(this.X, this.Y))).isEqualTo(this.f.or(this.A, this.B, this.X, this.Y)); assertThat(this.f.or(this.f.and(this.A, this.B), this.f.or(this.f.and(this.f.and(this.NA, this.NB)), this.f.and(this.f.or(this.NA, this.FALSE), this.NB)))).isEqualTo(this.OR3); + assertThat(this.f.dnf(emptyList())).isEqualTo(this.f.falsum()); + assertThat(this.f.dnf(singletonList(this.f.falsum()))).isEqualTo(this.f.falsum()); + assertThat(this.f.dnf(singletonList(this.f.verum()))).isEqualTo(this.f.verum()); + assertThat(this.f.dnf(this.f.or(this.f.and(this.A, this.B), this.f.and(this.NA, this.NB)))).isEqualTo(this.OR3); + assertThat(this.f.clause()).isEqualTo(this.f.falsum()); + assertThat(this.f.clause(this.A)).isEqualTo(this.A); + assertThat(this.f.clause(this.A, this.NB)).isEqualTo(this.f.or(this.A, this.NB)); + assertThat(this.f.clause(emptyList())).isEqualTo(this.f.falsum()); + assertThat(this.f.clause(singletonList(this.A))).isEqualTo(this.A); + assertThat(this.f.clause(Arrays.asList(this.A, this.NB))).isEqualTo(this.f.or(this.A, this.NB)); assertThat(this.f.naryOperator(FType.OR, Arrays.asList(this.X, this.Y, this.X, this.Y, this.X))).isEqualTo(this.OR1); } @@ -210,6 +222,10 @@ public void testIsDNF() { assertThat(this.OR1.isDNF()).isTrue(); assertThat(this.OR2.isDNF()).isTrue(); assertThat(this.OR3.isDNF()).isTrue(); + assertThat(this.f.clause().isDNF()).isTrue(); + assertThat(this.f.clause(this.A).isDNF()).isTrue(); + assertThat(this.f.clause(this.A, this.NB).isDNF()).isTrue(); + assertThat(this.f.dnf(this.f.or(this.f.and(this.A, this.B), this.f.and(this.NA, this.NB))).isDNF()).isTrue(); } @Test @@ -217,5 +233,12 @@ public void testIsCNF() { assertThat(this.OR1.isCNF()).isTrue(); assertThat(this.OR2.isCNF()).isTrue(); assertThat(this.OR3.isCNF()).isFalse(); + assertThat(this.f.clause().isCNF()).isTrue(); + assertThat(this.f.clause(this.A).isCNF()).isTrue(); + assertThat(this.f.clause(this.A, this.NB).isCNF()).isTrue(); + assertThat(this.f.dnf(this.A).isCNF()).isTrue(); + assertThat(this.f.dnf(this.A, this.NB, this.C).isCNF()).isTrue(); + assertThat(this.f.dnf(this.A, this.NB, this.f.and(this.A, this.C)).isCNF()).isFalse(); + assertThat(this.f.dnf(this.f.or(this.f.and(this.A, this.B), this.f.and(this.NA, this.NB))).isCNF()).isFalse(); } } From 0533c045f99a07c99774ae5e7409bec1bf064bcb Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Tue, 6 Feb 2024 00:30:18 +0100 Subject: [PATCH 12/44] minor performance improvement in some DNF/CNF generating algorithms --- CHANGELOG.md | 3 ++- .../org/logicng/transformations/CanonicalEnumeration.java | 6 +++--- src/main/java/org/logicng/transformations/Subsumption.java | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b6fa80a..efa6b128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,14 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added -- Added unsafe methods `term` and `dnf` to the `FormulaFactory` to create a term (conjunction of literals) or a DNF (c.f. with method `FormulaFactory#clause` and `FormulaFactory#cnf`). Both methods do not perform reduction operations and therefore are faster. Only use these methods if you are sure the input is free of complementary and redundant operands. +- Added unsafe methods `term` and `dnf` to the `FormulaFactory` to create a term (conjunction of literals) or a DNF (c.f. with method `FormulaFactory#clause` and `FormulaFactory#cnf`). Both methods do not perform reduction operations and therefore are faster. Only use these methods if you are sure the input is free of complementary and redundant operands. - Class `UBTree` offers new method `generateSubsumedUBTree` to directly generate a subsumed UBTree for the given sets. ### Changed - UBTree data structure now supports empty sets. - Added side effect note in `SATSolver` for the four assumption solving methods. +- Minor performance improvements in some DNF/CNF generating algorithms by using faster `cnf`/`dnf`. ### Fixed diff --git a/src/main/java/org/logicng/transformations/CanonicalEnumeration.java b/src/main/java/org/logicng/transformations/CanonicalEnumeration.java index 35b9033a..91188056 100644 --- a/src/main/java/org/logicng/transformations/CanonicalEnumeration.java +++ b/src/main/java/org/logicng/transformations/CanonicalEnumeration.java @@ -43,7 +43,7 @@ /** * Superclass for canonical normal form enumeration (CNF or DNF) via enumeration of the falsifying/satisfying assignments. - * @version 2.3.0 + * @version 2.5.0 * @since 2.3.0 */ public abstract class CanonicalEnumeration { @@ -65,9 +65,9 @@ protected static Formula compute(final Formula formula, final boolean cnf) { final List ops = new ArrayList<>(); for (final Assignment a : enumeration) { final SortedSet literals = a.literals(); - final Formula term = cnf ? f.or(FormulaHelper.negate(literals, ArrayList::new)) : f.and(a.literals()); + final Formula term = cnf ? f.clause(FormulaHelper.negateLiterals(literals, ArrayList::new)) : f.term(a.literals()); ops.add(term); } - return cnf ? f.and(ops) : f.or(ops); + return cnf ? f.cnf(ops) : f.dnf(ops); } } diff --git a/src/main/java/org/logicng/transformations/Subsumption.java b/src/main/java/org/logicng/transformations/Subsumption.java index faba0203..9407b236 100644 --- a/src/main/java/org/logicng/transformations/Subsumption.java +++ b/src/main/java/org/logicng/transformations/Subsumption.java @@ -62,8 +62,8 @@ private static List> getTerms(final NAryOperator nary) { private static Formula toNormalForm(final UBTree ubTree, final boolean cnf, final FormulaFactory f) { final List terms = new ArrayList<>(); for (final SortedSet term : ubTree.allSets()) { - terms.add(cnf ? f.or(term) : f.and(term)); + terms.add(cnf ? f.clause(term) : f.term(term)); } - return cnf ? f.cnf(terms) : f.or(terms); + return cnf ? f.cnf(terms) : f.dnf(terms); } } From a9c9e5a0bf5d74223cb0fb2e9daaeeba835f88f1 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Mon, 11 Mar 2024 16:10:42 +0100 Subject: [PATCH 13/44] add maven compiler plugin + update versions --- pom.xml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 66b1acb9..58c3533f 100644 --- a/pom.xml +++ b/pom.xml @@ -76,22 +76,22 @@ 4.9.3 - 5.9.0 - 3.23.1 - 4.7.0 + 5.10.2 + 3.25.3 + 5.2.0 4.9.3 - 0.8.8 + 0.8.11 4.3.0 - 3.0.0-M7 + 3.2.5 1.6.8 1.6 - 5.1.8 - 3.2.1 - 3.2.0 - 3.2.0 - + 5.1.9 + 3.12.1 + 3.3.0 + 3.6.3 + 3.3.0 @@ -124,6 +124,12 @@ + + org.apache.maven.plugins + maven-compiler-plugin + ${version.maven-compiler} + + org.apache.maven.plugins @@ -385,4 +391,3 @@ - From 9d893c7d895af1b7daed08e26587e83ad0c4ef83 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Mon, 11 Mar 2024 16:17:55 +0100 Subject: [PATCH 14/44] bugfix in BDD.toFormula + more tests with BDD reordering and formula conversion --- .../bdds/jbuddy/BDDOperations.java | 2 +- .../bdds/BDDReorderingTest.java | 71 ++++++++++++++++--- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDOperations.java b/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDOperations.java index 5f0705b8..691f65d0 100644 --- a/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDOperations.java +++ b/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDOperations.java @@ -484,7 +484,7 @@ protected Formula toFormulaRec(final int r, final boolean followPathsToTrue) { if (this.k.isZero(r)) { return f.constant(!followPathsToTrue); } - final Variable var = this.k.idx2var.get(this.k.level(r)); + final Variable var = this.k.getVariableForIndex(this.k.level2var[this.k.level(r)]); final int low = this.k.low(r); final Formula lowFormula = isRelevant(low, followPathsToTrue) ? f.and(var.negate(), toFormulaRec(low, followPathsToTrue)) diff --git a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java index 2a10bfe7..142325ed 100644 --- a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java @@ -69,10 +69,15 @@ public class BDDReorderingTest extends TestWithExampleFormulas { private final SwapStats stats = new SwapStats(); - private static final List REORDER_METHODS = - Arrays.asList(BDDReorderingMethod.BDD_REORDER_WIN2, BDDReorderingMethod.BDD_REORDER_WIN2ITE, BDDReorderingMethod.BDD_REORDER_WIN3, BDDReorderingMethod.BDD_REORDER_WIN3ITE, - BDDReorderingMethod.BDD_REORDER_SIFT, - BDDReorderingMethod.BDD_REORDER_SIFTITE, BDDReorderingMethod.BDD_REORDER_RANDOM); + private static final List REORDER_METHODS = Arrays.asList( + BDDReorderingMethod.BDD_REORDER_WIN2, + BDDReorderingMethod.BDD_REORDER_WIN2ITE, + BDDReorderingMethod.BDD_REORDER_WIN3, + BDDReorderingMethod.BDD_REORDER_WIN3ITE, + BDDReorderingMethod.BDD_REORDER_SIFT, + BDDReorderingMethod.BDD_REORDER_SIFTITE, + BDDReorderingMethod.BDD_REORDER_RANDOM + ); @Test public void testExceptionalBehavior() { @@ -140,6 +145,56 @@ public void testSwappingMultipleBdds() throws ParserException { new BDDInnerNode(this.A, BDDConstant.getFalsumNode(this.f), BDDConstant.getVerumNode(this.f)))); } + @Test + public void testReorderingAndFormulaGeneration() throws ParserException { + final List order = this.f.variables("a", "b", "c", "d", "e", "f"); + final Formula formula1 = this.f.parse("a & b <=> (~c | d) & f"); + final Formula formula2 = this.f.parse("a => c & ~d | e | f"); + final Formula formula3 = this.f.parse("a => b <=> (~a | d) & c | f"); + + for (final BDDReorderingMethod method : REORDER_METHODS) { + final BDDKernel kernel = new BDDKernel(this.f, order, 100, 100); + final BDD bdd1 = BDDFactory.build(formula1, kernel); + final BDD bdd2 = BDDFactory.build(formula2, kernel); + kernel.getReordering().addVariableBlockAll(); + kernel.getReordering().reorder(method); + final BDD bdd3 = BDDFactory.build(formula3, kernel); + + assertThat(bdd1.toFormula().isEquivalentTo(formula1)).isTrue(); + assertThat(bdd2.toFormula().isEquivalentTo(formula2)).isTrue(); + assertThat(bdd3.toFormula().isEquivalentTo(formula3)).isTrue(); + } + } + + @Test + public void testSwappingAndFormulaGeneration() throws ParserException { + final List order = this.f.variables("a", "b", "c", "d", "e", "f"); + final Formula formula1 = this.f.parse("a | b | c"); + final Formula formula2 = this.f.parse("a => b & ~c | ~d"); + final Formula formula3 = this.f.parse("a & b <=> (~c | d) & f"); + + final BDDKernel kernel = new BDDKernel(this.f, order, 100, 100); + final BDD bdd1 = BDDFactory.build(formula1, kernel); + final BDD bdd2 = BDDFactory.build(formula2, kernel); + + assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~a & (~b & c | b) | a")); + assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~a | a & (~b & ~d | b & (~c | c & ~d))")); + + bdd1.swapVariables(this.f.variable("a"), this.f.variable("b")); // also affects bdd2 and upcoming bdd3 + + assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~b & (~a & c | a) | b")); + assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~b & (~a | a & ~d) | b & (~a | a & (~c | c & ~d))")); + + final BDD bdd3 = BDDFactory.build(formula3, kernel); + assertThat(bdd3.toFormula()).isEqualTo(this.f.parse("~b & (~c & ~f | c & (~d | d & ~f)) | b & (~a & (~c & ~f | c & (~d | d & ~f)) | a & (~c & f | c & d & f))")); + + bdd3.swapVariables(this.f.variable("a"), this.f.variable("d")); + + assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~b & (~c & a | c) | b")); + assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~b & (~d | d & ~a) | b & (~d | d & (~c | c & ~a))")); + assertThat(bdd3.toFormula()).isEqualTo(this.f.parse("~b & (~d & (~c & ~f | c) | d & ~f) | b & (~d & (~c & (~a & ~f | a & f) | ~a & c) | d & (~a & ~f | a & f))")); + } + @Test public void testRandomReorderingQuick() { testRandomReordering(25, 30, false); @@ -182,7 +237,7 @@ private void testRandomReordering(final int minVars, final int maxVars, final bo private Formula randomFormula(final int vars, final int depth, final FormulaFactory f) { final FormulaRandomizer randomizer = new FormulaRandomizer(f, FormulaRandomizerConfig.builder() - .numVars(vars).seed(vars * depth * 42) + .numVars(vars).seed(vars * depth * 42L) .weightEquiv(0).weightImpl(0).weightNot(0).build()); return Stream.generate(() -> randomizer.and(depth)) .filter(fm -> fm.variables().size() == vars && fm.holds(new SATPredicate(f))) @@ -206,7 +261,7 @@ private void performReorder(final FormulaFactory f, final Formula formula, final } final double reduction = (usedBefore - usedAfter) / (double) usedBefore * 100; if (verbose) { - System.out.println(String.format("%-20s: Reduced %7s blocks in %5dms by %.2f%% from %d to %d", reorderMethod, withBlocks ? "with" : "without", duration, reduction, usedBefore, usedAfter)); + System.out.printf("%-20s: Reduced %7s blocks in %5dms by %.2f%% from %d to %d%n", reorderMethod, withBlocks ? "with" : "without", duration, reduction, usedBefore, usedAfter); } } @@ -235,7 +290,7 @@ private void testReorderOnBuild(final int minVars, final int maxVars, final bool final FormulaFactory f = new FormulaFactory(); final Formula formula = randomFormula(vars, depth, f); if (verbose) { - System.out.println(String.format("vars = %2d, depth = %2d, nodes = %5d", vars, depth, formula.numberOfNodes())); + System.out.printf("vars = %2d, depth = %2d, nodes = %5d%n", vars, depth, formula.numberOfNodes()); } final BDDKernel kernel = new BDDKernel(f, new ArrayList<>(formula.variables()), 1000, 10000); final BDD bdd = BDDFactory.build(formula, kernel); @@ -264,7 +319,7 @@ private void reorderOnBuild(final FormulaFactory f, final Formula formula, final verifyBddConsistency(f, formula, bdd, originalCount); final double reduction = (originalUsedNodes - usedAfter) / (double) originalUsedNodes * 100; if (verbose) { - System.out.println(String.format("%-20s: Built in %5d ms, reduction by %6.2f%% from %6d to %6d", method, duration, reduction, originalUsedNodes, usedAfter)); + System.out.printf("%-20s: Built in %5d ms, reduction by %6.2f%% from %6d to %6d%n", method, duration, reduction, originalUsedNodes, usedAfter); } } From f3ef3fe3587bfaebeed20d4796de1151798ff392 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Mon, 11 Mar 2024 16:30:25 +0100 Subject: [PATCH 15/44] revert to mockito 4.x, since 5.x is not compatible with Java 8 --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 58c3533f..1ee82267 100644 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,8 @@ 4.9.3 5.10.2 3.25.3 - 5.2.0 + + 4.11.0 4.9.3 From fedef469123666d1eb0fe653afab6a3495d2bd82 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Tue, 12 Mar 2024 10:43:59 +0100 Subject: [PATCH 16/44] BDD reordering refactoring --- CHANGELOG.md | 10 +- .../knowledgecompilation/bdds/BDD.java | 20 ++- .../bdds/jbuddy/BDDKernel.java | 157 +++++++++++++++++- .../bdds/jbuddy/BDDReordering.java | 36 +++- .../bdds/BDDReorderingTest.java | 47 +++--- 5 files changed, 226 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21fa545b..bd115890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,18 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Changed - UBTree data structure now supports empty sets. -- Added side effect note in `SATSolver` for the four assumption solving methods. +- Added side effect note in `SATSolver` for the four assumption solving methods. +- Methods for reordering and swapping variables on BDD were refactored: `BDD.getReordering`, `BDDKernel.getReordering`, and `BDD.swapVariables` are now deprecated and should not be used anymore. Instead, there are new methods on the `BDDKernel`. Note that these actions affect all BDDs generated by the kernel. + - `BDDKernel.swapVariables` for swapping two variables (or variable indices) + - `BDDKernel.reorder` for automatically reordering the BDD + - `BDDKernel.activateReorderDuringBuild` for activating reordering during build + - `BDDKernel.addVariableBlock` for defining a variable block for reordering + - `BDDKernel.addAllVariablesAsBlock` for defining one block for each variable (s.t. all variables are allowed to be reordered independently) ### Fixed - Fixed edge case in method `add(Formula formula, Proposition proposition)` in `MiniSat`. If a formula is added to the SAT solver, it can happen that a variable is not added to the solver because it was removed during the CNF transformation. A `model()` call or model enumeration will not produce models containing this variable since it was not added to the solver. The fix ensures that all variables of the original formula are added to the solver and thus, a found model includes the variable. +- The formula generation on BDDs was broken when the ordering was changed by `BDDKernel.reorder` or `BDDKernel.swapVariables`. This is now fixed. ## [2.4.1] - 2022-12-01 @@ -374,4 +381,3 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added - Initial Release of LogicNG - diff --git a/src/main/java/org/logicng/knowledgecompilation/bdds/BDD.java b/src/main/java/org/logicng/knowledgecompilation/bdds/BDD.java index df387198..ec114090 100644 --- a/src/main/java/org/logicng/knowledgecompilation/bdds/BDD.java +++ b/src/main/java/org/logicng/knowledgecompilation/bdds/BDD.java @@ -439,22 +439,24 @@ public List getVariableOrder() { * BDDs, the variables are swapped in all of these BDDs. * @param first the first variable to swap * @param second the second variable to swap + * @deprecated dangerous API, will be removed in version 3.0, use {@link BDDKernel#swapVariables} instead */ + @Deprecated public void swapVariables(final Variable first, final Variable second) { - final int firstVar = this.kernel.getIndexForVariable(first); - final int secondVar = this.kernel.getIndexForVariable(second); - if (firstVar < 0) { - throw new IllegalArgumentException("Unknown variable: " + first); - } else if (secondVar < 0) { - throw new IllegalArgumentException("Unknown variable: " + second); - } - this.kernel.getReordering().swapVariables(firstVar, secondVar); + this.kernel.swapVariables(first, second); } /** * Returns the reordering object for the BDD kernel. * @return the reordering object - */ + * @deprecated the relevant methods should now be access via the {@link #underlyingKernel() kernel}: + *

    + *
  • Add a variable block: {@link BDDKernel#addVariableBlock}
  • + *
  • Add blocks for all variables: {@link BDDKernel#addAllVariablesAsBlock}
  • + *
  • Instant reordering: {@link BDDKernel#reorder}
  • + *
+ */ + @Deprecated public BDDReordering getReordering() { return this.kernel.getReordering(); } diff --git a/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDKernel.java b/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDKernel.java index d036fb76..c6eb639a 100644 --- a/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDKernel.java +++ b/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDKernel.java @@ -152,7 +152,7 @@ public BDDKernel(final FormulaFactory f, final int numVars, final int nodeSize, this.var2idx = new TreeMap<>(); this.idx2var = new TreeMap<>(); this.reordering = new BDDReordering(this); - this.nodesize = prime.primeGTE(Math.max(nodeSize, 3)); + this.nodesize = this.prime.primeGTE(Math.max(nodeSize, 3)); this.nodes = new int[this.nodesize * 6]; this.minfreenodes = 20; for (int n = 0; n < this.nodesize; n++) { @@ -261,7 +261,16 @@ public FormulaFactory factory() { /** * Returns the reordering object for this kernel. * @return the reordering object + * @deprecated the relevant methods of this object are now exposed directly + * on this kernel: + *
    + *
  • Reordering during BDD construction: {@link #activateReorderDuringConstruction}
  • + *
  • Instant reordering: {@link #reorder}
  • + *
  • Add a variable block: {@link #addVariableBlock}
  • + *
  • Add blocks for all variables: {@link #addAllVariablesAsBlock}
  • + *
*/ + @Deprecated public BDDReordering getReordering() { return this.reordering; } @@ -319,6 +328,148 @@ public int[] getCurrentVarOrder() { return Arrays.copyOf(this.level2var, this.level2var.length - 1); // last var is always 0 } + /** + * Swaps the variables {@code v1} and {@code v2}. This affects all BDDs + * created by this kernel. + * @param v1 the first variable to swap + * @param v2 the second variable to swap + */ + public void swapVariables(final int v1, final int v2) { + this.reordering.swapVariables(v1, v2); + } + + /** + * Swaps the variables {@code v1} and {@code v2}. This affects all BDDs + * created by this kernel. + * @param v1 the first variable to swap + * @param v2 the second variable to swap + */ + public void swapVariables(final Variable v1, final Variable v2) { + swapVariables(getIndexForVariable(v1), getIndexForVariable(v2)); + } + + /** + * Activates or deactivates the automatic reordering during the construction of a BDD. + *

+ * Automatic reordering can be deactivated by passing {@link BDDReorderingMethod#BDD_REORDER_NONE} + * for the {@code method} parameter, otherwise the reordering is activated with the + * given method. The reordering is executed at most {@code num} times. + * @param method the method to be used for reordering + * @param num the maximum number of reorders to be performed + */ + public void activateReorderDuringConstruction(final BDDReorderingMethod method, final int num) { + this.reordering.activateReorderDuringConstruction(method, num); + } + + /** + * Adds a variable block starting at variable {@code first} and ending in variable + * {@code last} (both inclusive). + *

+ * Variable blocks are used in the {@link #reorder BDD reordering} + * or in the automatic reordering during the construction of the BDD (configured by + * {@link #activateReorderDuringConstruction}). Variable blocks can be nested, i.e. one block can + * contain an arbitrary number of ("child") blocks. Furthermore, a variable block can also + * be a single variable. + *

+ * During reordering, the child blocks of a parent block can be reordered, but they are kept + * together. So no other block can be moved in between the child blocks. Furthermore, + * variables in a block which are not in a child block will be left untouched. + *

+ * Example: Lets assume we have a BDD with the variable ordering {@code v1, v2, v3, v4, v5, v6, v7}. + * We create the following blocks: + *

    + *
  • {@code A} reaching from {@code v1} to {@code v5}
  • + *
  • {@code B} reaching from {@code v6} to {@code v7}
  • + *
  • {@code A1} reaching from {@code v1} to {@code v2}
  • + *
  • {@code A2} reaching from {@code v3} to {@code v3}
  • + *
  • {@code A3} reaching from {@code v4} to {@code v5}
  • + *
+ * This means that the variables of {@code A} and {@code B} can never be mixed up in the order. + * So during reordering the variables {@code v6} and {@code v7} can either be moved to the + * front (before {@code A}) or remain at their position. + * Furthermore, for example {@code v1} and {@code v2} will always stay together and neither + * {@code v3} nor any other variable can be moved in between them. On the other hand, the blocks + * {@code A1}, {@code A2}, and {@code A3} can be swapped arbitrarily. + *

+ * These are valid result of a reordering based on the above blocks: + *

    + *
  • {@code v3, v1, v2, v4, v5, v6, v7}
  • + *
  • {@code v6, v7, v4, v5, v3, v1, v2}
  • + *
  • {@code v6, v7, v1, v2, v3, v4, v5}
  • + *
+ * These however would be illegal: + *
    + *
  • {@code v2, v1, v3, v4, v5, v6, v7} (variables in a block which are not in a child block will not be reordered)
  • + *
  • {@code v1, v3, v2, v4, v5, v6, v7} (variables of different block will not be mixed up)
  • + *
+ *

+ * If a block is fixed (the example above assumed always blocks which are not fixed), its + * immediate child blocks will remain in their order. E.g. if block {@code A} was fixed, the blocks + * {@code A1}, {@code A2}, and {@code A3} would not be allowed to be swapped. + * Let's assume block {@code A} to be fixed and that we have two other unfixed blocks: + *

    + *
  • {@code A11} reaching from {@code v1} to {@code v1}
  • + *
  • {@code A12} reaching from {@code v2} to {@code v2}
  • + *
+ * These are examples for legal reorderings: + *
    + *
  • {@code v2, v1, v3, v4, v5, v6, v7} (block {@code A} is fixed, but "grandchildren" are still allowed to be reordered
  • + *
  • {@code v6, v7, v2, v1, v3, v4, v5}
  • + *
+ * These are examples for illegal reorderings: + *
    + *
  • {@code v3, v2, v1, v4, v5, v6, v7} (block {@code A} is fixed, so it's child blocks must be be reordered
  • + *
  • {@code v1, v2, v4, v5, v3, v6, v7}
  • + *
+ *

+ * Each block (including all nested blocks) must be defined by a separate call to this method. The blocks + * may be added in an arbitrary order, so it is not required to add them top-down or bottom-up. + * However, the blocks must not intersect, except of one block containing the other. Furthermore, + * both the {@code first} and the {@code last} variable must be known by the kernel and the level {@code first} + * must be lower than the level of {@code last}. + * @param first the variable at which the block starts (inclusive) + * @param last the variable at which the block ends (inclusive) + * @param fixed whether the block should be fixed or not + */ + public void addVariableBlock(final int first, final int last, final boolean fixed) { + this.reordering.addVariableBlock(first, last, fixed); + } + + /** + * Adds a variable block starting at variable {@code first} and ending in variable + * {@code last} (both inclusive). + *

+ * See {@link #addVariableBlock(int, int, boolean)} for details. + * @param first the variable at which the block starts (inclusive) + * @param last the variable at which the block ends (inclusive) + * @param fixed whether the block should be fixed or not + * @see #addVariableBlock(int, int, boolean) + */ + public void addVariableBlock(final Variable first, final Variable last, final boolean fixed) { + addVariableBlock(getIndexForVariable(first), getIndexForVariable(last), fixed); + } + + /** + * Adds a single variable block for all variables known by the kernel. + */ + public void addAllVariablesAsBlock() { + this.reordering.addAllVariablesAsBlock(); + } + + /** + * Reorders the levels in the kernel using the given reordering method. + * Only blocks of variables will be reordered. See the documentation of + * {@link #addVariableBlock} to learn more about such variable blocks. + * Without the definition of any block, nothing will be reordered. + *

+ * If the reordering should be performed without any restrictions, + * {@link #addAllVariablesAsBlock()} can be called before this method. + * @param method the method to be used for the reordering + */ + public void reorder(final BDDReorderingMethod method) { + this.reordering.reorder(method); + } + protected int doWithPotentialReordering(final BddOperation operation) { try { initRef(); @@ -601,7 +752,7 @@ protected void nodeResize(final boolean doRehash) { if (this.nodesize > oldsize + this.maxnodeincrease) { this.nodesize = oldsize + this.maxnodeincrease; } - this.nodesize = prime.primeLTE(this.nodesize); + this.nodesize = this.prime.primeLTE(this.nodesize); final int[] newnodes = new int[this.nodesize * 6]; System.arraycopy(this.nodes, 0, newnodes, 0, this.nodes.length); this.nodes = newnodes; @@ -862,6 +1013,6 @@ protected interface BddOperation { } public BDDPrime getPrime() { - return prime; + return this.prime; } } diff --git a/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDReordering.java b/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDReordering.java index 58fff4f5..9b39324e 100644 --- a/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDReordering.java +++ b/src/main/java/org/logicng/knowledgecompilation/bdds/jbuddy/BDDReordering.java @@ -47,11 +47,11 @@ *

    *
  • Swapping two variables in the kernel can be performed via {@link #swapVariables}
  • *
  • Reordering all variables can be performed via {@link #reorder}
  • - *
  • Reordering during construction of the BDD can be configured via {@link #setReorderDuringConstruction}
  • + *
  • Reordering during construction of the BDD can be configured via {@link #activateReorderDuringConstruction}
  • *
* The last two operations only have an effect, if variable blocks were added. {@link #addVariableBlock(int, int, boolean) The docuentation} * gives more information on variable blocks. - * To make all variables freely movable, {@link #addVariableBlockAll()} can be used. + * To make all variables freely movable, {@link #addAllVariablesAsBlock()} can be used. * @version 2.0.0 * @since 2.0.0 */ @@ -101,7 +101,7 @@ protected void init() { this.reorderDisabled = false; this.varTree = null; clrVarBlocks(); - setReorderDuringConstruction(BDDReorderingMethod.BDD_REORDER_NONE, 0); + activateReorderDuringConstruction(BDDReorderingMethod.BDD_REORDER_NONE, 0); this.usednumBefore = this.usednumAfter = 0; this.blockId = 0; } @@ -165,7 +165,7 @@ public void swapVariables(int v1, int v2) { * Without the definition of any block, nothing will be reordered. *

* If the reordering should be performed without any restrictions, - * {@link #addVariableBlockAll()} can be called before this method. + * {@link #addAllVariablesAsBlock()} can be called before this method. * @param method the method to be used for the reordering */ public void reorder(final BDDReorderingMethod method) { @@ -201,8 +201,23 @@ public void reorder(final BDDReorderingMethod method) { * given method. The reordering is executed at most {@code num} times. * @param method the method to be used for reordering * @param num the maximum number of reorders to be performed + * @deprecated use {@link BDDKernel#activateReorderDuringConstruction} instead */ + @Deprecated public void setReorderDuringConstruction(final BDDReorderingMethod method, final int num) { + activateReorderDuringConstruction(method, num); + } + + /** + * Activates or deactivates the automatic reordering during the construction of a BDD. + *

+ * Automatic reordering can be deactivated by passing {@link BDDReorderingMethod#BDD_REORDER_NONE} + * for the {@code method} parameter, otherwise the reordering is activated with the + * given method. The reordering is executed at most {@code num} times. + * @param method the method to be used for reordering + * @param num the maximum number of reorders to be performed + */ + protected void activateReorderDuringConstruction(final BDDReorderingMethod method, final int num) { this.reorderMethod = method; this.bddreorderTimes = num; } @@ -213,7 +228,7 @@ public void setReorderDuringConstruction(final BDDReorderingMethod method, final *

* Variable blocks are used in the {@link #reorder BDD reordering} * or in the automatic reordering during the construction of the BDD (configured by - * {@link #setReorderDuringConstruction}). Variable blocks can be nested, i.e. one block can + * {@link #activateReorderDuringConstruction}). Variable blocks can be nested, i.e. one block can * contain an arbitrary number of ("child") blocks. Furthermore, a variable block can also * be a single variable. *

@@ -292,12 +307,21 @@ public void addVariableBlock(final int first, final int last, final boolean fixe /** * Adds a single variable block for all variables known by the kernel. */ - public void addVariableBlockAll() { + public void addAllVariablesAsBlock() { for (int n = 0; n < this.k.varnum; n++) { addVariableBlock(n, n, false); } } + /** + * Adds a single variable block for all variables known by the kernel. + * @deprecated use {@link #addAllVariablesAsBlock()} instead + */ + @Deprecated + public void addVariableBlockAll() { + addAllVariablesAsBlock(); + } + /** * IMPORTANT: * The semantics of the "level" field in the BddNode struct changes during diff --git a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java index 142325ed..858f8f6d 100644 --- a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java @@ -105,15 +105,15 @@ public void testSwapping() throws ParserException { final Formula formula = this.f.parse("a | b | c"); final BDD bdd = BDDFactory.build(formula, kernel); assertThat(bdd.getVariableOrder()).containsExactly(this.A, this.B, this.C); - bdd.swapVariables(this.A, this.B); + kernel.swapVariables(this.A, this.B); assertThat(bdd.getVariableOrder()).containsExactly(this.B, this.A, this.C); - bdd.swapVariables(this.A, this.B); + kernel.swapVariables(this.A, this.B); assertThat(bdd.getVariableOrder()).containsExactly(this.A, this.B, this.C); - bdd.swapVariables(this.A, this.A); + kernel.swapVariables(this.A, this.A); assertThat(bdd.getVariableOrder()).containsExactly(this.A, this.B, this.C); - bdd.swapVariables(this.A, this.C); + kernel.swapVariables(this.A, this.C); assertThat(bdd.getVariableOrder()).containsExactly(this.C, this.B, this.A); - bdd.swapVariables(this.B, this.C); + kernel.swapVariables(this.B, this.C); assertThat(bdd.getVariableOrder()).containsExactly(this.B, this.C, this.A); assertThat(this.f.equivalence(formula, bdd.cnf()).holds(new TautologyPredicate(this.f))).isTrue(); assertThat(bdd.apply(LngBDDFunction.get())).isEqualTo( @@ -122,7 +122,7 @@ public void testSwapping() throws ParserException { new BDDInnerNode(this.A, BDDConstant.getFalsumNode(this.f), BDDConstant.getVerumNode(this.f)), BDDConstant.getVerumNode(this.f)), BDDConstant.getVerumNode(this.f))); - assertThatThrownBy(() -> bdd.swapVariables(this.B, this.X)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> kernel.swapVariables(this.B, this.X)).isInstanceOf(IllegalArgumentException.class); } @Test @@ -137,7 +137,7 @@ public void testSwappingMultipleBdds() throws ParserException { assertThat(bdd2.apply(LngBDDFunction.get())).isEqualTo( new BDDInnerNode(this.A, BDDConstant.getFalsumNode(this.f), new BDDInnerNode(this.B, BDDConstant.getFalsumNode(this.f), BDDConstant.getVerumNode(this.f)))); - bdd1.swapVariables(this.A, this.B); + kernel.swapVariables(this.A, this.B); assertThat(bdd1.getVariableOrder()).containsExactly(this.B, this.A, this.C); assertThat(bdd2.getVariableOrder()).containsExactly(this.B, this.A, this.C); assertThat(bdd2.apply(LngBDDFunction.get())).isEqualTo( @@ -156,8 +156,8 @@ public void testReorderingAndFormulaGeneration() throws ParserException { final BDDKernel kernel = new BDDKernel(this.f, order, 100, 100); final BDD bdd1 = BDDFactory.build(formula1, kernel); final BDD bdd2 = BDDFactory.build(formula2, kernel); - kernel.getReordering().addVariableBlockAll(); - kernel.getReordering().reorder(method); + kernel.addAllVariablesAsBlock(); + kernel.reorder(method); final BDD bdd3 = BDDFactory.build(formula3, kernel); assertThat(bdd1.toFormula().isEquivalentTo(formula1)).isTrue(); @@ -180,7 +180,7 @@ public void testSwappingAndFormulaGeneration() throws ParserException { assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~a & (~b & c | b) | a")); assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~a | a & (~b & ~d | b & (~c | c & ~d))")); - bdd1.swapVariables(this.f.variable("a"), this.f.variable("b")); // also affects bdd2 and upcoming bdd3 + kernel.swapVariables(this.f.variable("a"), this.f.variable("b")); // also affects bdd2 and upcoming bdd3 assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~b & (~a & c | a) | b")); assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~b & (~a | a & ~d) | b & (~a | a & (~c | c & ~d))")); @@ -188,7 +188,7 @@ public void testSwappingAndFormulaGeneration() throws ParserException { final BDD bdd3 = BDDFactory.build(formula3, kernel); assertThat(bdd3.toFormula()).isEqualTo(this.f.parse("~b & (~c & ~f | c & (~d | d & ~f)) | b & (~a & (~c & ~f | c & (~d | d & ~f)) | a & (~c & f | c & d & f))")); - bdd3.swapVariables(this.f.variable("a"), this.f.variable("d")); + kernel.swapVariables(this.f.variable("a"), this.f.variable("d")); assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~b & (~c & a | c) | b")); assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~b & (~d | d & ~a) | b & (~d | d & (~c | c & ~a))")); @@ -251,7 +251,7 @@ private void performReorder(final FormulaFactory f, final Formula formula, final final int usedBefore = new BDDOperations(kernel).nodeCount(bdd.index()); final long start = System.currentTimeMillis(); addVariableBlocks(formula.variables().size(), withBlocks, kernel); - kernel.getReordering().reorder(reorderMethod); + kernel.reorder(reorderMethod); final long duration = System.currentTimeMillis() - start; final int usedAfter = new BDDOperations(kernel).nodeCount(bdd.index()); assertThat(verifyBddConsistency(f, formula, bdd, count)).isTrue(); @@ -266,21 +266,20 @@ private void performReorder(final FormulaFactory f, final Formula formula, final } private void addVariableBlocks(final int numVars, final boolean withBlocks, final BDDKernel kernel) { - final BDDReordering reordering = kernel.getReordering(); if (withBlocks) { - reordering.addVariableBlockAll(); - reordering.addVariableBlock(0, 20, true); - reordering.addVariableBlock(0, 10, false); - reordering.addVariableBlock(11, 20, false); - reordering.addVariableBlock(15, 19, false); - reordering.addVariableBlock(15, 17, true); - reordering.addVariableBlock(18, 19, false); - reordering.addVariableBlock(21, numVars - 1, false); + kernel.addAllVariablesAsBlock(); + kernel.addVariableBlock(0, 20, true); + kernel.addVariableBlock(0, 10, false); + kernel.addVariableBlock(11, 20, false); + kernel.addVariableBlock(15, 19, false); + kernel.addVariableBlock(15, 17, true); + kernel.addVariableBlock(18, 19, false); + kernel.addVariableBlock(21, numVars - 1, false); if (numVars > 33) { - reordering.addVariableBlock(30, 33, false); + kernel.addVariableBlock(30, 33, false); } } else { - reordering.addVariableBlockAll(); + kernel.addAllVariablesAsBlock(); } } @@ -310,7 +309,7 @@ private void reorderOnBuild(final FormulaFactory f, final Formula formula, final final boolean verbose) { final BDDKernel kernel = new BDDKernel(f, new ArrayList<>(formula.variables()), 1000, 10000); addVariableBlocks(formula.variables().size(), withBlocks, kernel); - kernel.getReordering().setReorderDuringConstruction(method, 10000); + kernel.activateReorderDuringConstruction(method, 10000); final long start = System.currentTimeMillis(); final BDD bdd = BDDFactory.build(formula, kernel); final long duration = System.currentTimeMillis() - start; From 9fdb76e8c886d339f21ba53cf142f5349560496d Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Thu, 14 Mar 2024 16:10:27 +0100 Subject: [PATCH 17/44] added possibility to pass a DNNF handler in the DNNF factory --- CHANGELOG.md | 1 + .../dnnf/DnnfCompiler.java | 2 +- .../dnnf/DnnfFactory.java | 21 ++++++++++++---- .../dnnf/DnnfCompilerTest.java | 25 +++++++++++++++++++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd115890..fefd2d09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added - Class `UBTree` offers new method `generateSubsumedUBTree` to directly generate a subsumed UBTree for the given sets. +- The `DnnfFactory` now offers a method to compile a DNNF with a `DnnfCompilationHandler` ### Changed diff --git a/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfCompiler.java b/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfCompiler.java index 493d293a..d8efb8a1 100644 --- a/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfCompiler.java +++ b/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfCompiler.java @@ -108,7 +108,7 @@ public Formula compile(final DTreeGenerator generator) { * Performs the compilation using the given DTree generator and the compilation handler. * @param generator the DTree generator * @param handler the compilation handler - * @return the compiled DNNF + * @return the compiled DNNF or {@code null} if the compilation was aborted by the handler */ public Formula compile(final DTreeGenerator generator, final DnnfCompilationHandler handler) { if (!this.cnf.holds(new SATPredicate(this.f))) { diff --git a/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfFactory.java b/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfFactory.java index b695045a..9de374ca 100644 --- a/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfFactory.java +++ b/src/main/java/org/logicng/knowledgecompilation/dnnf/DnnfFactory.java @@ -30,6 +30,7 @@ import org.logicng.formulas.Formula; import org.logicng.formulas.Variable; +import org.logicng.handlers.DnnfCompilationHandler; import org.logicng.knowledgecompilation.dnnf.datastructures.Dnnf; import org.logicng.knowledgecompilation.dnnf.datastructures.dtree.MinFillDTreeGenerator; import org.logicng.transformations.cnf.CNFSubsumption; @@ -57,18 +58,28 @@ public DnnfFactory() { } /** - * Compiles the given formula to a DNNF instance. + * Compiles the given formula to a DNNF instance using the given handler. * @param formula the formula - * @return the compiled DNNF + * @param handler the DNNF handler + * @return the compiled DNNF or {@code null} if the computation was aborted by the handler */ - public Dnnf compile(final Formula formula) { + public Dnnf compile(final Formula formula, final DnnfCompilationHandler handler) { final SortedSet originalVariables = new TreeSet<>(formula.variables()); final Formula cnf = formula.cnf(); originalVariables.addAll(cnf.variables()); final Formula simplifedFormula = simplifyFormula(cnf); final DnnfCompiler compiler = new DnnfCompiler(simplifedFormula); - final Formula dnnf = compiler.compile(new MinFillDTreeGenerator()); - return new Dnnf(originalVariables, dnnf); + final Formula dnnf = compiler.compile(new MinFillDTreeGenerator(), handler); + return dnnf == null ? null : new Dnnf(originalVariables, dnnf); + } + + /** + * Compiles the given formula to a DNNF instance. + * @param formula the formula + * @return the compiled DNNF + */ + public Dnnf compile(final Formula formula) { + return compile(formula, null); } protected Formula simplifyFormula(final Formula formula) { diff --git a/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfCompilerTest.java b/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfCompilerTest.java index 79402c1c..6343f6ad 100644 --- a/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfCompilerTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfCompilerTest.java @@ -42,6 +42,7 @@ import org.logicng.graphs.datastructures.Graph; import org.logicng.graphs.datastructures.Node; import org.logicng.graphs.generators.ConstraintGraphGenerator; +import org.logicng.handlers.DnnfCompilationHandler; import org.logicng.io.parsers.FormulaParser; import org.logicng.io.parsers.ParserException; import org.logicng.io.parsers.PseudoBooleanParser; @@ -114,6 +115,16 @@ public void testDnnfProperties() throws ParserException { assertThat(dnnf.getOriginalVariables()).extracting(Variable::name).containsExactlyInAnyOrder("a", "b", "c", "d", "e"); } + @Test + public void testCompilationHandler() throws IOException { + final FormulaFactory f = new FormulaFactory(); + final Formula formula = f.and(DimacsReader.readCNF("src/test/resources/dnnf/both_bdd_dnnf_1.cnf", f)); + final Dnnf dnnfSuccessful = new DnnfFactory().compile(formula, new MaxShannonHandler(100)); + assertThat(dnnfSuccessful).isNotNull(); + final Dnnf dnnfAborted = new DnnfFactory().compile(formula, new MaxShannonHandler(50)); + assertThat(dnnfAborted).isNull(); + } + @Test @LongRunningTag public void testAllSmallFormulas() throws IOException, ParserException { @@ -173,4 +184,18 @@ private BigInteger countWithBdd(final Formula formula) { final BDD bdd = BDDFactory.build(formula, kernel); return bdd.modelCount(); } + + private static class MaxShannonHandler implements DnnfCompilationHandler { + private int currentShannons = 0; + private final int maxShannons; + + private MaxShannonHandler(final int maxShannons) { + this.maxShannons = maxShannons; + } + + @Override + public boolean shannonExpansion() { + return ++this.currentShannons <= this.maxShannons; + } + } } From f972d93ec08b8aa40121847a9a1e92e1876fcc87 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Fri, 15 Mar 2024 16:43:59 +0100 Subject: [PATCH 18/44] improved performance of DTree generation by removing duplicate egdes --- CHANGELOG.md | 1 + .../dtree/MinFillDTreeGenerator.java | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fefd2d09..7e495903 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `BDDKernel.activateReorderDuringBuild` for activating reordering during build - `BDDKernel.addVariableBlock` for defining a variable block for reordering - `BDDKernel.addAllVariablesAsBlock` for defining one block for each variable (s.t. all variables are allowed to be reordered independently) +- Significant performance improvements in the DTree generation for DNNFs ### Fixed diff --git a/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/MinFillDTreeGenerator.java b/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/MinFillDTreeGenerator.java index 0aa2e70c..626fa77f 100644 --- a/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/MinFillDTreeGenerator.java +++ b/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/MinFillDTreeGenerator.java @@ -36,8 +36,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.SortedSet; /** @@ -73,7 +75,7 @@ public static class Graph { /** * The edges of the graph as a list of edges per node ({{2,3},{1},{1}} means that there are the edges 1-2 and 1-3) */ - protected final List edgeList; + protected final List> edgeList; /** * Computes the DTree from the given CNF. @@ -94,7 +96,7 @@ public Graph(final Formula cnf) { this.adjMatrix = new boolean[this.numberOfVertices][this.numberOfVertices]; this.edgeList = new ArrayList<>(this.numberOfVertices); for (int i = 0; i < this.numberOfVertices; i++) { - this.edgeList.add(new LNGIntVector()); + this.edgeList.add(new LinkedHashSet<>()); } for (final Formula clause : cnf) { @@ -106,8 +108,8 @@ public Graph(final Formula cnf) { } for (int i = 0; i < varNums.length; i++) { for (int j = i + 1; j < varNums.length; j++) { - this.edgeList.get(varNums[i]).push(varNums[j]); - this.edgeList.get(varNums[j]).push(varNums[i]); + this.edgeList.get(varNums[i]).add(varNums[j]); + this.edgeList.get(varNums[j]).add(varNums[i]); this.adjMatrix[varNums[i]][varNums[j]] = true; this.adjMatrix[varNums[j]][varNums[i]] = true; } @@ -117,8 +119,8 @@ public Graph(final Formula cnf) { protected List getCopyOfEdgeList() { final List result = new ArrayList<>(); - for (final LNGIntVector edge : this.edgeList) { - result.add(new LNGIntVector(edge)); + for (final Set edge : this.edgeList) { + result.add(new LNGIntVector(edge.stream().mapToInt(i -> i).toArray())); } return result; } @@ -196,7 +198,7 @@ protected List getMinFillOrdering() { int currentNumberOfEdges = 0; for (int k = 0; k < this.numberOfVertices; k++) { - if (fillAdjMatrix[bestVertex][k] && !processed[k]) { + if (k != bestVertex && !processed[k] && fillAdjMatrix[bestVertex][k]) { currentNumberOfEdges++; } } From 87da23b9c1458dbd728b8385c2271e5eaa2912e0 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Fri, 15 Mar 2024 17:02:34 +0100 Subject: [PATCH 19/44] added possibility to pass a DNNF handler to the model counter --- CHANGELOG.md | 1 + .../logicng/modelcounting/ModelCounter.java | 33 +++++++++++++++++-- .../modelcounting/ModelCounterTest.java | 27 +++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e495903..60568f49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Class `UBTree` offers new method `generateSubsumedUBTree` to directly generate a subsumed UBTree for the given sets. - The `DnnfFactory` now offers a method to compile a DNNF with a `DnnfCompilationHandler` +- The `ModelCounter` now offers a method to pass a `DnnfCompilationHandler` in order to control long-running computations ### Changed diff --git a/src/main/java/org/logicng/modelcounting/ModelCounter.java b/src/main/java/org/logicng/modelcounting/ModelCounter.java index 0dccda96..e6561a49 100644 --- a/src/main/java/org/logicng/modelcounting/ModelCounter.java +++ b/src/main/java/org/logicng/modelcounting/ModelCounter.java @@ -28,6 +28,8 @@ package org.logicng.modelcounting; +import static org.logicng.handlers.Handler.aborted; + import org.logicng.datastructures.Assignment; import org.logicng.formulas.FType; import org.logicng.formulas.Formula; @@ -38,6 +40,7 @@ import org.logicng.graphs.datastructures.Graph; import org.logicng.graphs.datastructures.Node; import org.logicng.graphs.generators.ConstraintGraphGenerator; +import org.logicng.handlers.DnnfCompilationHandler; import org.logicng.knowledgecompilation.dnnf.DnnfFactory; import org.logicng.knowledgecompilation.dnnf.datastructures.Dnnf; import org.logicng.knowledgecompilation.dnnf.functions.DnnfModelCountFunction; @@ -53,6 +56,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.function.Supplier; import java.util.stream.Collectors; /** @@ -78,6 +82,22 @@ private ModelCounter() { * @return the model count of the formulas for the variables */ public static BigInteger count(final Collection formulas, final SortedSet variables) { + return count(formulas, variables, () -> null); + } + + /** + * Computes the model count for a given set of formulas (interpreted as conjunction) + * and a set of relevant variables. This set can only be a superset of the original + * formulas' variables. No projected model counting is supported. + * @param formulas the list of formulas + * @param variables the relevant variables + * @param dnnfHandlerSupplier a supplier for a DNNF handler, it may return a new handler on each call or always the same. + * Since multiple DNNFs may be computed, the supplier may be called several times. It must not + * be {@code null}, but it may return {@code null} (i.e. return no handler). + * @return the model count of the formulas for the variables or {@code null} if the DNNF handler aborted the DNNF computation + */ + public static BigInteger count(final Collection formulas, final SortedSet variables, + final Supplier dnnfHandlerSupplier) { if (!variables.containsAll(FormulaHelper.variables(formulas))) { throw new IllegalArgumentException("Expected variables to contain all of the formulas' variables."); } @@ -88,7 +108,10 @@ public static BigInteger count(final Collection formulas, final SortedS final FormulaFactory f = variables.first().factory(); final List cnfs = encodeAsCnf(formulas, f); final SimplificationResult simplification = simplify(cnfs); - final BigInteger count = count(simplification.simplifiedFormulas, f); + final BigInteger count = count(simplification.simplifiedFormulas, dnnfHandlerSupplier, f); + if (count == null) { + return null; + } final SortedSet dontCareVariables = simplification.getDontCareVariables(variables); return count.multiply(BigInteger.valueOf(2).pow(dontCareVariables.size())); } @@ -122,14 +145,18 @@ private static SimplificationResult simplify(final Collection formulas) return new SimplificationResult(simplified, backboneVariables); } - private static BigInteger count(final Collection formulas, final FormulaFactory f) { + private static BigInteger count(final Collection formulas, final Supplier dnnfHandlerSupplier, final FormulaFactory f) { final Graph constraintGraph = ConstraintGraphGenerator.generateFromFormulas(formulas); final Set>> ccs = ConnectedComponentsComputation.compute(constraintGraph); final List> components = ConnectedComponentsComputation.splitFormulasByComponent(formulas, ccs); final DnnfFactory factory = new DnnfFactory(); BigInteger count = BigInteger.ONE; for (final List component : components) { - final Dnnf dnnf = factory.compile(f.and(component)); + final DnnfCompilationHandler handler = dnnfHandlerSupplier.get(); + final Dnnf dnnf = factory.compile(f.and(component), handler); + if (dnnf == null || aborted(handler)) { + return null; + } count = count.multiply(dnnf.execute(DnnfModelCountFunction.get())); } return count; diff --git a/src/test/java/org/logicng/modelcounting/ModelCounterTest.java b/src/test/java/org/logicng/modelcounting/ModelCounterTest.java index f735a2f4..f74ef892 100644 --- a/src/test/java/org/logicng/modelcounting/ModelCounterTest.java +++ b/src/test/java/org/logicng/modelcounting/ModelCounterTest.java @@ -41,7 +41,9 @@ import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.PBConstraint; import org.logicng.formulas.Variable; +import org.logicng.handlers.DnnfCompilationHandler; import org.logicng.io.parsers.ParserException; +import org.logicng.io.readers.DimacsReader; import org.logicng.knowledgecompilation.bdds.orderings.VariableOrdering; import org.logicng.solvers.MiniSat; import org.logicng.testutils.NQueensGenerator; @@ -51,6 +53,7 @@ import org.logicng.util.FormulaRandomizer; import org.logicng.util.FormulaRandomizerConfig; +import java.io.IOException; import java.math.BigInteger; import java.util.Arrays; import java.util.Collections; @@ -164,6 +167,16 @@ public void testCornerCases() { } } + @Test + public void testCompilationHandler() throws IOException { + final FormulaFactory f = new FormulaFactory(); + final Formula formula = f.and(DimacsReader.readCNF("src/test/resources/dnnf/both_bdd_dnnf_1.cnf", f)); + final BigInteger countSuccessful = ModelCounter.count(Collections.singletonList(formula), formula.variables(), () -> new MaxShannonHandler(100)); + assertThat(countSuccessful).isNotNull(); + final BigInteger countAborted = ModelCounter.count(Collections.singletonList(formula), formula.variables(), () -> new MaxShannonHandler(50)); + assertThat(countAborted).isNull(); + } + @Test @RandomTag public void testRandom() { @@ -249,4 +262,18 @@ private static BigInteger modelCount(final List models, final Sorted return BigInteger.valueOf(models.size()).multiply(BigInteger.valueOf(2).pow(dontCareVars.size())); } } + + private static class MaxShannonHandler implements DnnfCompilationHandler { + private int currentShannons = 0; + private final int maxShannons; + + private MaxShannonHandler(final int maxShannons) { + this.maxShannons = maxShannons; + } + + @Override + public boolean shannonExpansion() { + return ++this.currentShannons <= this.maxShannons; + } + } } From b2a8e7c96628580a1f6472a87859d46011de781b Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Wed, 24 Apr 2024 14:25:11 +0200 Subject: [PATCH 20/44] Revert "fixed SATSolver#add: Ensure all variables are added to the internal solver" This reverts commit 5cdab69e166bb7366bf4b3c66dacdae47cf48cb1. --- .../java/org/logicng/solvers/MiniSat.java | 14 +------- .../cardinalityconstraints/CCALKTest.java | 4 +-- .../cardinalityconstraints/CCAMKTest.java | 6 ++-- .../ModelEnumerationFunctionTest.java | 32 +------------------ .../java/org/logicng/solvers/sat/SATTest.java | 31 +++--------------- .../transformations/cnf/BDDCNFTest.java | 4 +-- .../transformations/dnf/BDDDNFTest.java | 4 +-- 7 files changed, 16 insertions(+), 79 deletions(-) diff --git a/src/main/java/org/logicng/solvers/MiniSat.java b/src/main/java/org/logicng/solvers/MiniSat.java index 797dffe5..112a2862 100644 --- a/src/main/java/org/logicng/solvers/MiniSat.java +++ b/src/main/java/org/logicng/solvers/MiniSat.java @@ -67,7 +67,7 @@ /** * Wrapper for the MiniSAT-style SAT solvers. - * @version 2.4.2 + * @version 2.4.0 * @since 1.0 */ public class MiniSat extends SATSolver { @@ -271,18 +271,6 @@ public void add(final Formula formula, final Proposition proposition) { } else { addFormulaAsCNF(formula, proposition); } - addAllOriginalVariables(formula); - } - - /** - * Adds all variables of the given formula to the solver if not already present. - * This method can be used to ensure that the internal solver knows the given variables. - * @param originalFormula the original formula - */ - private void addAllOriginalVariables(final Formula originalFormula) { - for (final Variable var : originalFormula.variables()) { - getOrAddIndex(var); - } } protected void addFormulaAsCNF(final Formula formula, final Proposition proposition) { diff --git a/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java b/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java index fdebac98..6270f631 100644 --- a/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java +++ b/src/test/java/org/logicng/cardinalityconstraints/CCALKTest.java @@ -46,7 +46,7 @@ /** * Unit tests for the at-least-k configs. - * @version 2.4.2 + * @version 2.0.0 * @since 1.0 */ public class CCALKTest implements LogicNGTest { @@ -66,7 +66,7 @@ public void testALK() { int counter = 0; for (final CCConfig config : this.configs) { f.putConfiguration(config); - testCC(10, 0, 1024, f); + testCC(10, 0, 1, f); testCC(10, 1, 1023, f); testCC(10, 2, 1013, f); testCC(10, 3, 968, f); diff --git a/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java b/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java index 611f0e67..984dba52 100644 --- a/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java +++ b/src/test/java/org/logicng/cardinalityconstraints/CCAMKTest.java @@ -43,7 +43,7 @@ /** * Unit tests for the at-most-k encoders. - * @version 2.4.2 + * @version 2.0.0 * @since 1.0 */ public class CCAMKTest implements LogicNGTest { @@ -73,8 +73,8 @@ public void testAMK() { testCC(10, 7, 968, f, false); testCC(10, 8, 1013, f, false); testCC(10, 9, 1023, f, false); - testCC(10, 10, 1024, f, false); - testCC(10, 15, 1024, f, false); + testCC(10, 10, 1, f, false); + testCC(10, 15, 1, f, false); assertThat(f.newCCVariable().name()).endsWith("_" + counter++); } } diff --git a/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java b/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java index 73fa7237..0e3aa04b 100644 --- a/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java +++ b/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java @@ -1,24 +1,19 @@ package org.logicng.solvers.functions; import static org.assertj.core.api.Assertions.assertThat; -import static org.logicng.util.FormulaHelper.variables; import org.junit.jupiter.api.Test; import org.logicng.datastructures.Assignment; -import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.formulas.FormulaFactoryConfig; -import org.logicng.formulas.Variable; import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; -import org.logicng.solvers.sat.MiniSatConfig; import java.util.List; /** * Units tests for {@link ModelEnumerationFunction}. - * @version 2.4.2 + * @version 2.3.0 * @since 2.3.0 */ public class ModelEnumerationFunctionTest { @@ -52,29 +47,4 @@ public void testFastEvaluable() throws ParserException { models = solver.execute(ModelEnumerationFunction.builder().fastEvaluable(true).build()); assertThat(models).extracting(Assignment::fastEvaluable).containsOnly(true); } - - @Test - public void testVariableRemovedBySimplificationOccursInModels() throws ParserException { - final FormulaFactory f = new FormulaFactory(FormulaFactoryConfig.builder().simplifyComplementaryOperands(true).build()); - final SATSolver solver = MiniSat.miniSat(this.f, MiniSatConfig.builder().cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()); - final Variable a = f.variable("A"); - final Variable b = f.variable("B"); - final Formula formula = this.f.parse("A & B => A"); - solver.add(formula); // during NNF conversion, used by the PG transformation, the formula simplifies to verum when added to the solver - final List models = solver.execute(ModelEnumerationFunction.builder().variables(formula.variables()).build()); - assertThat(models).hasSize(4); - for (final Assignment model : models) { - assertThat(variables(model.literals())).containsExactlyInAnyOrder(a, b); - } - } - - @Test - public void testUnknownVariableNotOccurringInModel() { - final SATSolver solver = MiniSat.miniSat(this.f); - final Variable a = this.f.variable("A"); - solver.add(a); - final List models = solver.execute(ModelEnumerationFunction.builder().variables(this.f.variables("A", "X")).build()); - assertThat(models).hasSize(1); - assertThat(models.get(0).literals()).containsExactly(a); - } } diff --git a/src/test/java/org/logicng/solvers/sat/SATTest.java b/src/test/java/org/logicng/solvers/sat/SATTest.java index 079e96fa..d2949650 100644 --- a/src/test/java/org/logicng/solvers/sat/SATTest.java +++ b/src/test/java/org/logicng/solvers/sat/SATTest.java @@ -33,7 +33,6 @@ import static org.logicng.datastructures.Tristate.UNDEF; import static org.logicng.solvers.sat.MiniSatConfig.ClauseMinimization.BASIC; import static org.logicng.solvers.sat.MiniSatConfig.ClauseMinimization.NONE; -import static org.logicng.util.FormulaHelper.variables; import org.junit.jupiter.api.Test; import org.logicng.LogicNGTest; @@ -44,7 +43,6 @@ import org.logicng.formulas.CType; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.formulas.FormulaFactoryConfig; import org.logicng.formulas.Literal; import org.logicng.formulas.Variable; import org.logicng.handlers.ModelEnumerationHandler; @@ -63,6 +61,7 @@ import org.logicng.solvers.functions.ModelEnumerationFunction; import org.logicng.solvers.functions.UpZeroLiteralsFunction; import org.logicng.testutils.PigeonHoleGenerator; +import org.logicng.util.FormulaHelper; import java.io.BufferedReader; import java.io.File; @@ -82,7 +81,7 @@ /** * Unit tests for the SAT solvers. - * @version 2.4.1 + * @version 1.6 * @since 1.0 */ public class SATTest extends TestWithExampleFormulas implements LogicNGTest { @@ -297,28 +296,6 @@ public void testPartialModel() { } } - @Test - public void testVariableRemovedBySimplificationOccursInModel() throws ParserException { - final FormulaFactory f = new FormulaFactory(FormulaFactoryConfig.builder().simplifyComplementaryOperands(true).build()); - final SATSolver solver = MiniSat.miniSat(f, MiniSatConfig.builder().cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()); - final Variable a = f.variable("A"); - final Variable b = f.variable("B"); - final Formula formula = this.f.parse("A & B => A"); - solver.add(formula); // during NNF conversion, used by the PG transformation, the formula simplifies to verum when added to the solver - assertThat(solver.sat()).isEqualTo(Tristate.TRUE); - assertThat(solver.knownVariables()).containsExactlyInAnyOrder(a, b); - assertThat(variables(solver.model().literals())).containsExactlyInAnyOrder(a, b); - } - - @Test - public void testUnknownVariableNotOccurringInModel() { - final SATSolver solver = MiniSat.miniSat(this.f); - final Variable a = this.f.variable("A"); - solver.add(a); - assertThat(solver.sat()).isEqualTo(Tristate.TRUE); - assertThat(solver.model(this.f.variables("A", "X")).literals()).containsExactly(a); - } - @Test public void testModelEnumerationHandler() { for (final SATSolver s : this.solvers) { @@ -364,6 +341,7 @@ public boolean foundModel(final Assignment assignment) { } @Test + @SuppressWarnings("deprecation") public void testWithRelaxation() throws ParserException { final PropositionalParser parser = new PropositionalParser(this.f); final Formula one = parser.parse("a & b & (c | ~d)"); @@ -844,6 +822,7 @@ public void testKnownVariables() throws ParserException { } @Test + @SuppressWarnings("deprecation") public void testAddWithoutUnknown() throws ParserException { final PropositionalParser parser = new PropositionalParser(this.f); final Formula phi = parser.parse("x1 & (~x2 | x3) & (x4 | ~x5)"); @@ -1107,7 +1086,7 @@ public void testDimacsFilesWithSelectionOrder() throws IOException { if (fileName.endsWith(".cnf")) { readCNF(solver, file); final List selectionOrder = new ArrayList<>(); - for (final Variable var : variables(solver.execute(FormulaOnSolverFunction.get()))) { + for (final Variable var : FormulaHelper.variables(solver.execute(FormulaOnSolverFunction.get()))) { if (selectionOrder.size() < 10) { selectionOrder.add(var.negate()); } diff --git a/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java b/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java index f0768f33..1ff65372 100644 --- a/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java +++ b/src/test/java/org/logicng/transformations/cnf/BDDCNFTest.java @@ -42,7 +42,7 @@ /** * Unit Tests for {@link BDDCNFTransformation}. - * @version 2.4.2 + * @version 2.3.0 * @since 1.4.0 */ public class BDDCNFTest extends TestWithExampleFormulas { @@ -160,7 +160,7 @@ public void testNot() throws ParserException { @Test public void testCC() throws ParserException { final PseudoBooleanParser p = new PseudoBooleanParser(this.f); - final Formula f1 = p.parse("a <=> (1 * b <= 0)"); + final Formula f1 = p.parse("a <=> (1 * b <= 1)"); final Formula f2 = p.parse("~(1 * b <= 1)"); final Formula f3 = p.parse("(1 * b + 1 * c + 1 * d <= 1)"); final Formula f4 = p.parse("~(1 * b + 1 * c + 1 * d <= 1)"); diff --git a/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java b/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java index 581b528f..9ce2cff8 100644 --- a/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java +++ b/src/test/java/org/logicng/transformations/dnf/BDDDNFTest.java @@ -43,7 +43,7 @@ /** * Unit Tests for {@link BDDDNFTransformation}. - * @version 2.4.2 + * @version 2.3.0 * @since 2.3.0 */ public class BDDDNFTest extends TestWithExampleFormulas { @@ -162,7 +162,7 @@ public void testNot() throws ParserException { @Test public void testCC() throws ParserException { final PseudoBooleanParser p = new PseudoBooleanParser(this.f); - final Formula f1 = p.parse("a <=> (1 * b <= 0)"); + final Formula f1 = p.parse("a <=> (1 * b <= 1)"); final Formula f2 = p.parse("~(1 * b <= 1)"); final Formula f3 = p.parse("(1 * b + 1 * c + 1 * d <= 1)"); final Formula f4 = p.parse("~(1 * b + 1 * c + 1 * d <= 1)"); From e17a8908a249a0cab75fa243274a720f116a4d99 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Sun, 28 Apr 2024 21:38:13 +0200 Subject: [PATCH 21/44] extracted the parser(s) to its own artifact org.logicng.logicng-parser-j8/11 and removed ANTLR as compile dependency (ANTLR and a copy of the parsers is still used in the tests) --- CHANGELOG.md | 6 + doc/codestyle/intellij/LogicNG.xml | 329 -------- pom.xml | 108 +-- .../org/logicng/formulas/FormulaFactory.java | 14 - .../antlr/LogicNGPropositional.g4 | 0 .../antlr/LogicNGPseudoBoolean.g4 | 0 .../org/logicng/TestWithExampleFormulas.java | 10 + .../datastructures/AssignmentTest.java | 8 +- .../logicng/explanations/drup/DRUPTest.java | 176 ++-- .../smus/SmusComputationTest.java | 244 +++--- .../formulas/ExtendedFormulaFactoryTest.java | 6 +- .../logicng/formulas/FormulaFactoryTest.java | 6 +- ...aFactoryWithoutContradictionCheckTest.java | 70 +- .../org/logicng/formulas/FormulaTest.java | 44 +- .../functions/FormulaDepthFunctionTest.java | 5 +- .../functions/MinimumPrimeImplicantTest.java | 29 +- .../ConnectedComponentsComputerTest.java | 3 +- .../io/conditions/ContainsCondition.java | 2 +- .../handlers/TimeoutBDDHandlerTest.java | 14 +- .../handlers/TimeoutMaxSATHandlerTest.java | 10 +- .../TimeoutModelEnumerationHandlerTest.java | 14 +- .../TimeoutOptimizationHandlerTest.java | 6 +- .../handlers/TimeoutSATHandlerTest.java | 12 +- .../logicng/io/FormulaWriterReaderTest.java | 12 +- .../generators/BddGraphicalGeneratorTest.java | 4 +- .../FormulaAstGraphicalGeneratorTest.java | 10 +- .../FormulaDagGraphicalGeneratorTest.java | 8 +- .../org/logicng/io/parsers/FormulaParser.java | 0 .../logicng/io/parsers/LexerException.java | 0 .../logicng/io/parsers/ParserException.java | 0 .../logicng/io/parsers/ParserWithFormula.java | 0 .../io/parsers/PropositionalLexer.java | 0 .../io/parsers/PropositionalParser.java | 0 .../io/parsers/PropositionalParserTest.java | 270 ------ .../io/parsers/PseudoBooleanLexer.java | 0 .../io/parsers/PseudoBooleanParser.java | 0 .../io/parsers/PseudoBooleanParserTest.java | 288 ------- .../org/logicng/io/readers/FormulaReader.java | 0 .../writers/FormulaDimacsFileWriterTest.java | 2 +- .../bdds/BDDConstructionTests.java | 8 +- .../bdds/BDDOperationsTest.java | 15 +- .../bdds/BDDReorderingTest.java | 47 +- .../bdds/FormulaBDDTest.java | 7 +- .../bdds/LargeBDDTest.java | 6 +- .../datastructures/dtree/DTreeNodeTest.java | 5 +- .../modelcounting/ModelCounterTest.java | 27 +- .../predicates/ContainsPBCPredicateTest.java | 31 +- .../EvaluatesToConstantPredicateTest.java | 785 +++++++++--------- .../primecomputation/PrimeCompilerTest.java | 25 +- .../PrimeImplicantReductionTest.java | 14 +- .../PrimeImplicateReductionTest.java | 14 +- .../logicng/pseudobooleans/PBEncoderTest.java | 6 +- .../java/org/logicng/solvers/ModelTest.java | 40 +- .../functions/BackboneFunctionTest.java | 61 +- .../ModelEnumerationFunctionTest.java | 10 +- .../functions/OptimizationFunctionTest.java | 25 +- .../functions/UnsatCoreFunctionTest.java | 2 +- .../solvers/maxsat/PartialMaxSATTest.java | 27 +- .../maxsat/PartialWeightedMaxSATTest.java | 27 +- .../solvers/maxsat/PureMaxSATTest.java | 18 +- .../org/logicng/solvers/sat/MiniSatTest.java | 6 +- .../java/org/logicng/solvers/sat/SATTest.java | 24 +- .../LiteralSubstitutionTest.java | 44 +- .../PureExpansionTransformationTest.java | 43 +- .../cnf/CanonicalCNFEnumerationTest.java | 30 +- ...stedGreenbaumTransformationSolverTest.java | 33 +- .../dnf/CanonicalDNFEnumerationTest.java | 28 +- .../qmc/QuineMcCluskeyTest.java | 4 +- .../AdvancedSimplifierTest.java | 18 +- .../FactorOutSimplificationTest.java | 29 +- .../simplification/NegationMinimizerTest.java | 47 +- 71 files changed, 1161 insertions(+), 2055 deletions(-) delete mode 100644 doc/codestyle/intellij/LogicNG.xml rename src/{main => test}/antlr/LogicNGPropositional.g4 (100%) rename src/{main => test}/antlr/LogicNGPseudoBoolean.g4 (100%) rename src/{main => test}/java/org/logicng/io/parsers/FormulaParser.java (100%) rename src/{main => test}/java/org/logicng/io/parsers/LexerException.java (100%) rename src/{main => test}/java/org/logicng/io/parsers/ParserException.java (100%) rename src/{main => test}/java/org/logicng/io/parsers/ParserWithFormula.java (100%) rename src/{main => test}/java/org/logicng/io/parsers/PropositionalLexer.java (100%) rename src/{main => test}/java/org/logicng/io/parsers/PropositionalParser.java (100%) delete mode 100644 src/test/java/org/logicng/io/parsers/PropositionalParserTest.java rename src/{main => test}/java/org/logicng/io/parsers/PseudoBooleanLexer.java (100%) rename src/{main => test}/java/org/logicng/io/parsers/PseudoBooleanParser.java (100%) delete mode 100644 src/test/java/org/logicng/io/parsers/PseudoBooleanParserTest.java rename src/{main => test}/java/org/logicng/io/readers/FormulaReader.java (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69c878df..b6da053a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [2.5.0] - 2024-xx-xx +### Removed (Potentially Breaking Change!) + +- All parser classes from `org.logicng.io.parsers` (including in particular the two main parsers `LogicNGPropositionalParsers` and `LogicNGPseudoBooleanParser`) as well as the class `org.logicng.io.readers.FormulaReader` were moved to the new artifacts `org.logicng.logicng-parser-j8` (or `org.logicng.logicng-parser-j11` for Java 11). So there LogicNG now consists of two artifacts: + - All the core functionality of LogicNG except for the parser is located in the "old" `org.logicng:logicng` artifact. This artifact does *not* depend on ANTLR anymore (which was the reason for splitting the library). For the time being this library will be based on Java 8, but nothing should prevent its usage in higher Java versions. + - The parser functionality is located in `org.logicng:logicng-parser-j8` (for Java 8 and ANTLR 4.9.3) and `org.logicng:logicng-parser-j11` (for Java 11 and the most recent ANTLR version). The version of this library will stay in sync with the core library. + ### Added - Added unsafe methods `term` and `dnf` to the `FormulaFactory` to create a term (conjunction of literals) or a DNF (c.f. with method `FormulaFactory#clause` and `FormulaFactory#cnf`). Both methods do not perform reduction operations and therefore are faster. Only use these methods if you are sure the input is free of complementary and redundant operands. diff --git a/doc/codestyle/intellij/LogicNG.xml b/doc/codestyle/intellij/LogicNG.xml deleted file mode 100644 index 7736883d..00000000 --- a/doc/codestyle/intellij/LogicNG.xml +++ /dev/null @@ -1,329 +0,0 @@ - - -

- - - true - - -
-
- - - - true - true - true - true - - - -
-
- - - - true - true - true - true - - - -
-
- - - - true - true - true - true - - - -
-
- - - - true - true - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - true - - - -
-
- - - - true - true - - - -
-
- - - - true - true - - - -
-
- - - - true - true - - - -
-
- - - - true - true - - - -
-
- - - true - - -
-
- - - true - - -
-
- - - true - - -
-
- - - - true - true - - - -
-
- - - true - - -
-
- - - true - - -
-
- - - - true - true - - - -
-
- - - true - - -
- - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1ee82267..415a9139 100644 --- a/pom.xml +++ b/pom.xml @@ -42,20 +42,11 @@ - Christoph Zengler - christoph.zengler@booleworks.com - - - Steffen Hildebrandt - steffen.hildebrandt@booleworks.com - - - Rouven Walter - rouven.walter@booleworks.com - - - Elena Natterer - elena.natterer@booleworks.com + BooleWorks + BooleWorks Team + BooleWorks GmbH + https://www.booleworks.com + info@booleworks.com @@ -72,17 +63,16 @@ 1.8 java - **/LogicNGPropositional*.java,**/LogicNGPseudoBoolean*.java - 4.9.3 5.10.2 3.25.3 4.11.0 + + 4.9.3 - 4.9.3 0.8.11 4.3.0 3.2.5 @@ -93,6 +83,7 @@ 3.3.0 3.6.3 3.3.0 + 1.9.1 @@ -107,24 +98,6 @@ - - - org.antlr - antlr4-maven-plugin - ${version.antlr-plugin} - - src/main/antlr - target/generated-sources/antlr/org/logicng/io/parsers - - - - - antlr4 - - - - - org.apache.maven.plugins maven-compiler-plugin @@ -156,6 +129,13 @@ org.apache.maven.plugins maven-source-plugin ${version.maven-source} + + + + LogicNGPropositional* + LogicNGPseudo* + + attach-sources @@ -171,6 +151,9 @@ org.apache.maven.plugins maven-javadoc-plugin ${version.maven-javadoc} + + ${project.build.sourceDirectory} + attach-javadocs @@ -186,12 +169,6 @@ org.jacoco jacoco-maven-plugin ${version.jacoco} - - - **/LogicNGPropositional* - **/LogicNGPseudoBoolean* - - default-prepare-agent @@ -240,36 +217,63 @@ org.eluder.coveralls coveralls-maven-plugin ${version.coveralls} - - - target/generated-sources/antlr - - - org.apache.maven.plugins maven-surefire-plugin ${version.surefire} + + + + + org.antlr + antlr4-maven-plugin + ${version.antlr} - false - false - -Xmx2g + src/test/antlr + target/generated-test-sources/antlr/org/logicng/io/parsers + + + generate-test-sources + + antlr4 + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${version.build-helper-plugin} + + + add-parser-sources + generate-test-sources + + add-test-source + + + + target/generated-test-sources/antlr + + + + - + org.antlr antlr4-runtime ${version.antlr} + test - org.junit.jupiter junit-jupiter diff --git a/src/main/java/org/logicng/formulas/FormulaFactory.java b/src/main/java/org/logicng/formulas/FormulaFactory.java index 58e77ab5..2a082926 100644 --- a/src/main/java/org/logicng/formulas/FormulaFactory.java +++ b/src/main/java/org/logicng/formulas/FormulaFactory.java @@ -45,8 +45,6 @@ import org.logicng.formulas.cache.CacheEntry; import org.logicng.formulas.printer.FormulaStringRepresentation; import org.logicng.functions.SubNodeFunction; -import org.logicng.io.parsers.ParserException; -import org.logicng.io.parsers.PseudoBooleanParser; import org.logicng.pseudobooleans.PBConfig; import org.logicng.pseudobooleans.PBEncoder; import org.logicng.solvers.maxsat.algorithms.MaxSATConfig; @@ -103,7 +101,6 @@ public class FormulaFactory { private final SubNodeFunction subformulaFunction; private final PBEncoder pbEncoder; private final CNFEncoder cnfEncoder; - private final PseudoBooleanParser parser; Map posLiterals; Map negLiterals; Set generatedVariables; @@ -155,7 +152,6 @@ public FormulaFactory(final FormulaFactoryConfig config) { this.cnfPrefix = CNF_PREFIX; } this.pbEncoder = new PBEncoder(this); - this.parser = new PseudoBooleanParser(this); } /** @@ -1400,16 +1396,6 @@ public long numberOfNodes(final Formula formula) { return formula.apply(this.subformulaFunction).size(); } - /** - * Parses a given string to a formula using a pseudo boolean parser. - * @param string a string representing the formula - * @return the formula - * @throws ParserException if the parser throws an exception - */ - public Formula parse(final String string) throws ParserException { - return this.parser.parse(string); - } - /** * Adds a given formula to a list of operands. If the formula is the neutral element for the respective n-ary * operation it will be skipped. If a complementary formula is already present in the list of operands or the diff --git a/src/main/antlr/LogicNGPropositional.g4 b/src/test/antlr/LogicNGPropositional.g4 similarity index 100% rename from src/main/antlr/LogicNGPropositional.g4 rename to src/test/antlr/LogicNGPropositional.g4 diff --git a/src/main/antlr/LogicNGPseudoBoolean.g4 b/src/test/antlr/LogicNGPseudoBoolean.g4 similarity index 100% rename from src/main/antlr/LogicNGPseudoBoolean.g4 rename to src/test/antlr/LogicNGPseudoBoolean.g4 diff --git a/src/test/java/org/logicng/TestWithExampleFormulas.java b/src/test/java/org/logicng/TestWithExampleFormulas.java index b6c1fe5f..fb953713 100644 --- a/src/test/java/org/logicng/TestWithExampleFormulas.java +++ b/src/test/java/org/logicng/TestWithExampleFormulas.java @@ -34,6 +34,8 @@ import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Literal; import org.logicng.formulas.Variable; +import org.logicng.io.parsers.ParserException; +import org.logicng.io.parsers.PseudoBooleanParser; public abstract class TestWithExampleFormulas { protected final FormulaFactory f = new FormulaFactory(); @@ -89,4 +91,12 @@ public abstract class TestWithExampleFormulas { protected final Formula PBC3 = this.f.pbc(CType.GE, 2, this.literals, this.coefficients); protected final Formula PBC4 = this.f.pbc(CType.LT, 2, this.literals, this.coefficients); protected final Formula PBC5 = this.f.pbc(CType.LE, 2, this.literals, this.coefficients); + + public static Formula parse(final FormulaFactory f, final String formula) { + try { + return new PseudoBooleanParser(f).parse(formula); + } catch (final ParserException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/test/java/org/logicng/datastructures/AssignmentTest.java b/src/test/java/org/logicng/datastructures/AssignmentTest.java index 39600551..10121152 100644 --- a/src/test/java/org/logicng/datastructures/AssignmentTest.java +++ b/src/test/java/org/logicng/datastructures/AssignmentTest.java @@ -207,7 +207,7 @@ public void testEquals() { } @Test - public void testBlockingClause() throws ParserException { + public void testBlockingClause() { final Assignment ass = new Assignment(); ass.addLiteral(this.A); ass.addLiteral(this.B); @@ -215,14 +215,14 @@ public void testBlockingClause() throws ParserException { ass.addLiteral(this.NY); final Formula bc01 = ass.blockingClause(this.f); assertThat(bc01.containsVariable(this.C)).isFalse(); - assertThat(bc01).isEqualTo(this.f.parse("~a | ~b | x | y")); + assertThat(bc01).isEqualTo(parse(this.f, "~a | ~b | x | y")); final Formula bc02 = ass.blockingClause(this.f, null); assertThat(bc02.containsVariable(this.C)).isFalse(); - assertThat(bc02).isEqualTo(this.f.parse("~a | ~b | x | y")); + assertThat(bc02).isEqualTo(parse(this.f, "~a | ~b | x | y")); final List lits = Arrays.asList(this.A, this.X, this.C); final Formula bcProjected = ass.blockingClause(this.f, lits); assertThat(bcProjected.containsVariable(this.C)).isFalse(); - assertThat(bcProjected).isEqualTo(this.f.parse("~a | x")); + assertThat(bcProjected).isEqualTo(parse(this.f, "~a | x")); } @Test diff --git a/src/test/java/org/logicng/explanations/drup/DRUPTest.java b/src/test/java/org/logicng/explanations/drup/DRUPTest.java index 1c573032..018b4569 100644 --- a/src/test/java/org/logicng/explanations/drup/DRUPTest.java +++ b/src/test/java/org/logicng/explanations/drup/DRUPTest.java @@ -29,6 +29,7 @@ package org.logicng.explanations.drup; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import static org.logicng.datastructures.Tristate.FALSE; import static org.logicng.datastructures.Tristate.TRUE; @@ -40,7 +41,6 @@ import org.logicng.explanations.UNSATCore; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.io.readers.DimacsReader; import org.logicng.propositions.ExtendedProposition; import org.logicng.propositions.Proposition; @@ -145,16 +145,16 @@ public void testUnsatCoresAimTestset() throws IOException { } @Test - public void testPropositionHandling() throws ParserException { + public void testPropositionHandling() { final List propositions = new ArrayList<>(); - propositions.add(new StandardProposition("P1", this.f.parse("((a & b) => c) & ((a & b) => d)"))); - propositions.add(new StandardProposition("P2", this.f.parse("(c & d) <=> ~e"))); - propositions.add(new StandardProposition("P3", this.f.parse("~e => f | g"))); - propositions.add(new StandardProposition("P4", this.f.parse("(f => ~a) & (g => ~b) & p & q"))); - propositions.add(new StandardProposition("P5", this.f.parse("a => b"))); - propositions.add(new StandardProposition("P6", this.f.parse("a"))); - propositions.add(new StandardProposition("P7", this.f.parse("g | h"))); - propositions.add(new StandardProposition("P8", this.f.parse("(x => ~y | z) & (z | w)"))); + propositions.add(new StandardProposition("P1", parse(this.f, "((a & b) => c) & ((a & b) => d)"))); + propositions.add(new StandardProposition("P2", parse(this.f, "(c & d) <=> ~e"))); + propositions.add(new StandardProposition("P3", parse(this.f, "~e => f | g"))); + propositions.add(new StandardProposition("P4", parse(this.f, "(f => ~a) & (g => ~b) & p & q"))); + propositions.add(new StandardProposition("P5", parse(this.f, "a => b"))); + propositions.add(new StandardProposition("P6", parse(this.f, "a"))); + propositions.add(new StandardProposition("P7", parse(this.f, "g | h"))); + propositions.add(new StandardProposition("P8", parse(this.f, "(x => ~y | z) & (z | w)"))); for (final SATSolver solver : this.solvers) { solver.addPropositions(propositions); @@ -167,19 +167,19 @@ public void testPropositionHandling() throws ParserException { } @Test - public void testPropositionIncDec() throws ParserException { + public void testPropositionIncDec() { final SATSolver solver = this.solvers[0]; - final StandardProposition p1 = new StandardProposition("P1", this.f.parse("((a & b) => c) & ((a & b) => d)")); - final StandardProposition p2 = new StandardProposition("P2", this.f.parse("(c & d) <=> ~e")); - final StandardProposition p3 = new StandardProposition("P3", this.f.parse("~e => f | g")); - final StandardProposition p4 = new StandardProposition("P4", this.f.parse("(f => ~a) & (g => ~b) & p & q")); - final StandardProposition p5 = new StandardProposition("P5", this.f.parse("a => b")); - final StandardProposition p6 = new StandardProposition("P6", this.f.parse("a")); - final StandardProposition p7 = new StandardProposition("P7", this.f.parse("g | h")); - final StandardProposition p8 = new StandardProposition("P8", this.f.parse("(x => ~y | z) & (z | w)")); - final StandardProposition p9 = new StandardProposition("P9", this.f.parse("a & b")); - final StandardProposition p10 = new StandardProposition("P10", this.f.parse("(p => q) & p")); - final StandardProposition p11 = new StandardProposition("P11", this.f.parse("a & ~q")); + final StandardProposition p1 = new StandardProposition("P1", parse(this.f, "((a & b) => c) & ((a & b) => d)")); + final StandardProposition p2 = new StandardProposition("P2", parse(this.f, "(c & d) <=> ~e")); + final StandardProposition p3 = new StandardProposition("P3", parse(this.f, "~e => f | g")); + final StandardProposition p4 = new StandardProposition("P4", parse(this.f, "(f => ~a) & (g => ~b) & p & q")); + final StandardProposition p5 = new StandardProposition("P5", parse(this.f, "a => b")); + final StandardProposition p6 = new StandardProposition("P6", parse(this.f, "a")); + final StandardProposition p7 = new StandardProposition("P7", parse(this.f, "g | h")); + final StandardProposition p8 = new StandardProposition("P8", parse(this.f, "(x => ~y | z) & (z | w)")); + final StandardProposition p9 = new StandardProposition("P9", parse(this.f, "a & b")); + final StandardProposition p10 = new StandardProposition("P10", parse(this.f, "(p => q) & p")); + final StandardProposition p11 = new StandardProposition("P11", parse(this.f, "a & ~q")); solver.addPropositions(p1, p2, p3, p4); final SolverState state1 = solver.saveState(); @@ -218,10 +218,10 @@ public void testPropositionIncDec() throws ParserException { } @Test - public void testTrivialCasesPropositions() throws ParserException { + public void testTrivialCasesPropositions() { for (final SATSolver solver : this.solvers) { assertSolverSat(solver); - final StandardProposition p1 = new StandardProposition("P1", this.f.parse("$false")); + final StandardProposition p1 = new StandardProposition("P1", parse(this.f, "$false")); solver.add(p1); assertSolverUnsat(solver); UNSATCore unsatCore = solver.unsatCore(); @@ -229,10 +229,10 @@ public void testTrivialCasesPropositions() throws ParserException { solver.reset(); assertSolverSat(solver); - final StandardProposition p2 = new StandardProposition("P2", this.f.parse("a")); + final StandardProposition p2 = new StandardProposition("P2", parse(this.f, "a")); solver.add(p2); assertSolverSat(solver); - final StandardProposition p3 = new StandardProposition("P3", this.f.parse("~a")); + final StandardProposition p3 = new StandardProposition("P3", parse(this.f, "~a")); solver.add(p3); assertSolverUnsat(solver); unsatCore = solver.unsatCore(); @@ -241,15 +241,15 @@ public void testTrivialCasesPropositions() throws ParserException { } @Test - public void testCoreAndAssumptions() throws ParserException { + public void testCoreAndAssumptions() { final FormulaFactory f = new FormulaFactory(); final SATSolver[] solvers = new SATSolver[]{ MiniSat.miniSat(f, MiniSatConfig.builder().proofGeneration(true).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()), MiniSat.glucose(f, MiniSatConfig.builder().proofGeneration(true).incremental(false).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build(), GlucoseConfig.builder().build()) }; for (final SATSolver solver : solvers) { - final StandardProposition p1 = new StandardProposition(f.parse("A => B")); - final StandardProposition p2 = new StandardProposition(f.parse("A & B => G")); + final StandardProposition p1 = new StandardProposition(parse(f, "A => B")); + final StandardProposition p2 = new StandardProposition(parse(f, "A & B => G")); final StandardProposition p3 = new StandardProposition(f.or(f.literal("X", false), f.literal("A", true))); final StandardProposition p4 = new StandardProposition(f.or(f.literal("X", false), f.literal("G", false))); final StandardProposition p5 = new StandardProposition(f.literal("G", false)); @@ -271,28 +271,28 @@ public void testCoreAndAssumptions() throws ParserException { } @Test - public void testCoreAndAssumptions2() throws ParserException { + public void testCoreAndAssumptions2() { final FormulaFactory f = new FormulaFactory(); final SATSolver[] solvers = new SATSolver[]{ MiniSat.miniSat(f, MiniSatConfig.builder().proofGeneration(true).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()), MiniSat.glucose(f, MiniSatConfig.builder().proofGeneration(true).incremental(false).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build(), GlucoseConfig.builder().build()) }; for (final SATSolver solver : solvers) { - solver.add(f.parse("~C => D")); - solver.add(f.parse("C => D")); - solver.add(f.parse("D => B | A")); - solver.add(f.parse("B => X")); - solver.add(f.parse("B => ~X")); + solver.add(parse(f, "~C => D")); + solver.add(parse(f, "C => D")); + solver.add(parse(f, "D => B | A")); + solver.add(parse(f, "B => X")); + solver.add(parse(f, "B => ~X")); solver.sat(f.literal("A", false)); - solver.add(f.parse("~A")); + solver.add(parse(f, "~A")); solver.sat(); assertThat(solver.unsatCore()).isNotNull(); } } @Test - public void testCoreAndAssumptions3() throws ParserException { + public void testCoreAndAssumptions3() { // Unit test for DRUP issue which led to java.lang.ArrayIndexOutOfBoundsException: -1 final FormulaFactory f = new FormulaFactory(); final SATSolver[] solvers = new SATSolver[]{ @@ -300,21 +300,21 @@ public void testCoreAndAssumptions3() throws ParserException { MiniSat.glucose(f, MiniSatConfig.builder().proofGeneration(true).incremental(false).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build(), GlucoseConfig.builder().build()) }; for (final SATSolver solver : solvers) { - solver.add(f.parse("X => Y")); - solver.add(f.parse("X => Z")); - solver.add(f.parse("C => E")); - solver.add(f.parse("D => ~F")); - solver.add(f.parse("B => M")); - solver.add(f.parse("D => N")); - solver.add(f.parse("G => O")); - solver.add(f.parse("A => B")); - solver.add(f.parse("T1 <=> A & K & ~B & ~C")); - solver.add(f.parse("T2 <=> A & B & C & K")); - solver.add(f.parse("T1 + T2 = 1")); + solver.add(parse(f, "X => Y")); + solver.add(parse(f, "X => Z")); + solver.add(parse(f, "C => E")); + solver.add(parse(f, "D => ~F")); + solver.add(parse(f, "B => M")); + solver.add(parse(f, "D => N")); + solver.add(parse(f, "G => O")); + solver.add(parse(f, "A => B")); + solver.add(parse(f, "T1 <=> A & K & ~B & ~C")); + solver.add(parse(f, "T2 <=> A & B & C & K")); + solver.add(parse(f, "T1 + T2 = 1")); solver.sat(); // required for DRUP issue - solver.add(f.parse("Y => ~X & D")); - solver.add(f.parse("X")); + solver.add(parse(f, "Y => ~X & D")); + solver.add(parse(f, "X")); solver.sat(); assertThat(solver.unsatCore()).isNotNull(); @@ -322,35 +322,35 @@ public void testCoreAndAssumptions3() throws ParserException { } @Test - public void testCoreAndAssumptions4() throws ParserException { + public void testCoreAndAssumptions4() { final SATSolver[] solvers = new SATSolver[]{ MiniSat.miniSat(this.f, MiniSatConfig.builder().proofGeneration(true).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()), MiniSat.glucose(this.f, MiniSatConfig.builder().proofGeneration(true).incremental(false).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build(), GlucoseConfig.builder().build()) }; for (final SATSolver solver : solvers) { - solver.add(this.f.parse("~X1")); + solver.add(parse(this.f, "~X1")); solver.sat(this.f.variable("X1")); // caused the bug solver.add(this.f.variable("A1")); - solver.add(this.f.parse("A1 => A2")); - solver.add(this.f.parse("R & A2 => A3")); - solver.add(this.f.parse("L & A2 => A3")); - solver.add(this.f.parse("R & A3 => A4")); - solver.add(this.f.parse("L & A3 => A4")); - solver.add(this.f.parse("~A4")); - solver.add(this.f.parse("L | R")); + solver.add(parse(this.f, "A1 => A2")); + solver.add(parse(this.f, "R & A2 => A3")); + solver.add(parse(this.f, "L & A2 => A3")); + solver.add(parse(this.f, "R & A3 => A4")); + solver.add(parse(this.f, "L & A3 => A4")); + solver.add(parse(this.f, "~A4")); + solver.add(parse(this.f, "L | R")); solver.sat(); assertThat(solver.unsatCore()).isNotNull(); } } @Test - public void testWithCcPropositions() throws ParserException { + public void testWithCcPropositions() { final FormulaFactory f = new FormulaFactory(); final SATSolver solver = MiniSat.miniSat(f, MiniSatConfig.builder().proofGeneration(true).cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()); - final ExtendedProposition p1 = new ExtendedProposition<>(new StringBackpack("CC"), f.parse("A + B + C <= 1")); - final StandardProposition p2 = new StandardProposition(f.parse("A")); - final StandardProposition p3 = new StandardProposition(f.parse("B")); - final StandardProposition p4 = new StandardProposition(f.parse("X & Y")); + final ExtendedProposition p1 = new ExtendedProposition<>(new StringBackpack("CC"), parse(f, "A + B + C <= 1")); + final StandardProposition p2 = new StandardProposition(parse(f, "A")); + final StandardProposition p3 = new StandardProposition(parse(f, "B")); + final StandardProposition p4 = new StandardProposition(parse(f, "X & Y")); solver.add(p1); solver.add(p2); solver.add(p3); @@ -360,20 +360,20 @@ public void testWithCcPropositions() throws ParserException { } @Test - public void testWithSpecialUnitCaseMiniSat() throws ParserException { + public void testWithSpecialUnitCaseMiniSat() { final FormulaFactory f = new FormulaFactory(); final SATSolver solver = MiniSat.miniSat(f, MiniSatConfig.builder().proofGeneration(true).build()); - final StandardProposition p1 = new StandardProposition(f.parse("a => b")); - final StandardProposition p2 = new StandardProposition(f.parse("a => c | d")); - final StandardProposition p3 = new StandardProposition(f.parse("b => c | d")); - final StandardProposition p4 = new StandardProposition(f.parse("e | f | g | h => i")); - final StandardProposition p5 = new StandardProposition(f.parse("~j => k | j")); - final StandardProposition p6 = new StandardProposition(f.parse("b => ~(e | f)")); - final StandardProposition p7 = new StandardProposition(f.parse("c => ~j")); - final StandardProposition p8 = new StandardProposition(f.parse("l | m => ~i")); - final StandardProposition p9 = new StandardProposition(f.parse("j => (f + g + h = 1)")); - final StandardProposition p10 = new StandardProposition(f.parse("d => (l + m + e + f = 1)")); - final StandardProposition p11 = new StandardProposition(f.parse("~k")); + final StandardProposition p1 = new StandardProposition(parse(f, "a => b")); + final StandardProposition p2 = new StandardProposition(parse(f, "a => c | d")); + final StandardProposition p3 = new StandardProposition(parse(f, "b => c | d")); + final StandardProposition p4 = new StandardProposition(parse(f, "e | f | g | h => i")); + final StandardProposition p5 = new StandardProposition(parse(f, "~j => k | j")); + final StandardProposition p6 = new StandardProposition(parse(f, "b => ~(e | f)")); + final StandardProposition p7 = new StandardProposition(parse(f, "c => ~j")); + final StandardProposition p8 = new StandardProposition(parse(f, "l | m => ~i")); + final StandardProposition p9 = new StandardProposition(parse(f, "j => (f + g + h = 1)")); + final StandardProposition p10 = new StandardProposition(parse(f, "d => (l + m + e + f = 1)")); + final StandardProposition p11 = new StandardProposition(parse(f, "~k")); solver.addPropositions(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); assertThat(solver.sat()).isEqualTo(TRUE); solver.add(f.variable("a")); @@ -382,20 +382,20 @@ public void testWithSpecialUnitCaseMiniSat() throws ParserException { } @Test - public void testWithSpecialUnitCaseGlucose() throws ParserException { + public void testWithSpecialUnitCaseGlucose() { final FormulaFactory f = new FormulaFactory(); final SATSolver solver = MiniSat.glucose(f, MiniSatConfig.builder().proofGeneration(true).incremental(false).build(), GlucoseConfig.builder().build()); - final StandardProposition p1 = new StandardProposition(f.parse("a => b")); - final StandardProposition p2 = new StandardProposition(f.parse("a => c | d")); - final StandardProposition p3 = new StandardProposition(f.parse("b => c | d")); - final StandardProposition p4 = new StandardProposition(f.parse("e | f | g | h => i")); - final StandardProposition p5 = new StandardProposition(f.parse("~j => k | j")); - final StandardProposition p6 = new StandardProposition(f.parse("b => ~(e | f)")); - final StandardProposition p7 = new StandardProposition(f.parse("c => ~j")); - final StandardProposition p8 = new StandardProposition(f.parse("l | m => ~i")); - final StandardProposition p9 = new StandardProposition(f.parse("j => (f + g + h = 1)")); - final StandardProposition p10 = new StandardProposition(f.parse("d => (l + m + e + f = 1)")); - final StandardProposition p11 = new StandardProposition(f.parse("~k")); + final StandardProposition p1 = new StandardProposition(parse(f, "a => b")); + final StandardProposition p2 = new StandardProposition(parse(f, "a => c | d")); + final StandardProposition p3 = new StandardProposition(parse(f, "b => c | d")); + final StandardProposition p4 = new StandardProposition(parse(f, "e | f | g | h => i")); + final StandardProposition p5 = new StandardProposition(parse(f, "~j => k | j")); + final StandardProposition p6 = new StandardProposition(parse(f, "b => ~(e | f)")); + final StandardProposition p7 = new StandardProposition(parse(f, "c => ~j")); + final StandardProposition p8 = new StandardProposition(parse(f, "l | m => ~i")); + final StandardProposition p9 = new StandardProposition(parse(f, "j => (f + g + h = 1)")); + final StandardProposition p10 = new StandardProposition(parse(f, "d => (l + m + e + f = 1)")); + final StandardProposition p11 = new StandardProposition(parse(f, "~k")); solver.addPropositions(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); assertThat(solver.sat()).isEqualTo(TRUE); solver.add(f.variable("a")); diff --git a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java index d2553b85..e160bd82 100644 --- a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java +++ b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java @@ -55,185 +55,185 @@ public class SmusComputationTest extends TestWithExampleFormulas { @Test - public void testFromPaper() throws ParserException { + public void testFromPaper() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p"), - this.f.parse("~p|m"), - this.f.parse("~m|n"), - this.f.parse("~n"), - this.f.parse("~m|l"), - this.f.parse("~l") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p"), + parse(this.f, "~p|m"), + parse(this.f, "~m|n"), + parse(this.f, "~n"), + parse(this.f, "~m|l"), + parse(this.f, "~l") ); final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); - assertThat(result).containsExactlyInAnyOrder(this.f.parse("~s"), this.f.parse("s|~p"), this.f.parse("p")); + assertThat(result).containsExactlyInAnyOrder(parse(this.f, "~s"), parse(this.f, "s|~p"), parse(this.f, "p")); } @Test - public void testWithAdditionalConstraint() throws ParserException { + public void testWithAdditionalConstraint() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p"), - this.f.parse("~p|m"), - this.f.parse("~m|n"), - this.f.parse("~n"), - this.f.parse("~m|l"), - this.f.parse("~l") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p"), + parse(this.f, "~p|m"), + parse(this.f, "~m|n"), + parse(this.f, "~n"), + parse(this.f, "~m|l"), + parse(this.f, "~l") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(this.f.parse("n|l")), this.f); - assertThat(result).containsExactlyInAnyOrder(this.f.parse("~n"), this.f.parse("~l")); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); + assertThat(result).containsExactlyInAnyOrder(parse(this.f, "~n"), parse(this.f, "~l")); } @Test - public void testSatisfiable() throws ParserException { + public void testSatisfiable() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("~p|m"), - this.f.parse("~m|n"), - this.f.parse("~n"), - this.f.parse("~m|l") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "~p|m"), + parse(this.f, "~m|n"), + parse(this.f, "~n"), + parse(this.f, "~m|l") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(this.f.parse("n|l")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); assertThat(result).isNull(); } @Test - public void testUnsatisfiableAdditionalConstraints() throws ParserException { + public void testUnsatisfiableAdditionalConstraints() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("~p|m"), - this.f.parse("~m|n"), - this.f.parse("~n|s") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "~p|m"), + parse(this.f, "~m|n"), + parse(this.f, "~n|s") ); - final List result = SmusComputation.computeSmusForFormulas(input, Arrays.asList(this.f.parse("~a&b"), this.f.parse("a|~b")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Arrays.asList(parse(this.f, "~a&b"), parse(this.f, "a|~b")), this.f); assertThat(result).isEmpty(); } @Test - public void testTrivialUnsatFormula() throws ParserException { + public void testTrivialUnsatFormula() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p"), - this.f.parse("~p|m"), - this.f.parse("~m|n"), - this.f.parse("~n"), - this.f.parse("~m|l"), - this.f.parse("~l"), - this.f.parse("a&~a") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p"), + parse(this.f, "~p|m"), + parse(this.f, "~m|n"), + parse(this.f, "~n"), + parse(this.f, "~m|l"), + parse(this.f, "~l"), + parse(this.f, "a&~a") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(this.f.parse("n|l")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); assertThat(result).containsExactly(this.f.falsum()); } @Test - public void testUnsatFormula() throws ParserException { + public void testUnsatFormula() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p"), - this.f.parse("~p|m"), - this.f.parse("~m|n"), - this.f.parse("~n"), - this.f.parse("~m|l"), - this.f.parse("~l"), - this.f.parse("(a<=>b)&(~a<=>b)") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p"), + parse(this.f, "~p|m"), + parse(this.f, "~m|n"), + parse(this.f, "~n"), + parse(this.f, "~m|l"), + parse(this.f, "~l"), + parse(this.f, "(a<=>b)&(~a<=>b)") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(this.f.parse("n|l")), this.f); - assertThat(result).containsExactly(this.f.parse("(a<=>b)&(~a<=>b)")); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); + assertThat(result).containsExactly(parse(this.f, "(a<=>b)&(~a<=>b)")); } @Test - public void testShorterConflict() throws ParserException { + public void testShorterConflict() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p"), - this.f.parse("p&~s"), - this.f.parse("~p|m"), - this.f.parse("~m|n"), - this.f.parse("~n"), - this.f.parse("~m|l"), - this.f.parse("~l") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p"), + parse(this.f, "p&~s"), + parse(this.f, "~p|m"), + parse(this.f, "~m|n"), + parse(this.f, "~n"), + parse(this.f, "~m|l"), + parse(this.f, "~l") ); final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); - assertThat(result).containsExactlyInAnyOrder(this.f.parse("s|~p"), this.f.parse("p&~s")); + assertThat(result).containsExactlyInAnyOrder(parse(this.f, "s|~p"), parse(this.f, "p&~s")); } @Test - public void testCompleteConflict() throws ParserException { + public void testCompleteConflict() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p|~m"), - this.f.parse("m|~n"), - this.f.parse("n|~l"), - this.f.parse("l|s") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p|~m"), + parse(this.f, "m|~n"), + parse(this.f, "n|~l"), + parse(this.f, "l|s") ); final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); assertThat(result).containsExactlyInAnyOrderElementsOf(input); } @Test - public void testLongConflictWithShortcut() throws ParserException { + public void testLongConflictWithShortcut() { final List input = Arrays.asList( - this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p|~m"), - this.f.parse("m|~n"), - this.f.parse("n|~l"), - this.f.parse("l|s"), - this.f.parse("n|s") + parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p|~m"), + parse(this.f, "m|~n"), + parse(this.f, "n|~l"), + parse(this.f, "l|s"), + parse(this.f, "n|s") ); final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); - assertThat(result).containsExactlyInAnyOrder(this.f.parse("~s"), - this.f.parse("s|~p"), - this.f.parse("p|~m"), - this.f.parse("m|~n"), - this.f.parse("n|s")); + assertThat(result).containsExactlyInAnyOrder(parse(this.f, "~s"), + parse(this.f, "s|~p"), + parse(this.f, "p|~m"), + parse(this.f, "m|~n"), + parse(this.f, "n|s")); } @Test - public void testManyConflicts() throws ParserException { + public void testManyConflicts() { final List input = Arrays.asList( - this.f.parse("a"), - this.f.parse("~a|b"), - this.f.parse("~b|c"), - this.f.parse("~c|~a"), - this.f.parse("a1"), - this.f.parse("~a1|b1"), - this.f.parse("~b1|c1"), - this.f.parse("~c1|~a1"), - this.f.parse("a2"), - this.f.parse("~a2|b2"), - this.f.parse("~b2|c2"), - this.f.parse("~c2|~a2"), - this.f.parse("a3"), - this.f.parse("~a3|b3"), - this.f.parse("~b3|c3"), - this.f.parse("~c3|~a3"), - this.f.parse("a1|a2|a3|a4|b1|x|y"), - this.f.parse("x&~y"), - this.f.parse("x=>y") + parse(this.f, "a"), + parse(this.f, "~a|b"), + parse(this.f, "~b|c"), + parse(this.f, "~c|~a"), + parse(this.f, "a1"), + parse(this.f, "~a1|b1"), + parse(this.f, "~b1|c1"), + parse(this.f, "~c1|~a1"), + parse(this.f, "a2"), + parse(this.f, "~a2|b2"), + parse(this.f, "~b2|c2"), + parse(this.f, "~c2|~a2"), + parse(this.f, "a3"), + parse(this.f, "~a3|b3"), + parse(this.f, "~b3|c3"), + parse(this.f, "~c3|~a3"), + parse(this.f, "a1|a2|a3|a4|b1|x|y"), + parse(this.f, "x&~y"), + parse(this.f, "x=>y") ); final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); - assertThat(result).containsExactlyInAnyOrder(this.f.parse("x&~y"), this.f.parse("x=>y")); + assertThat(result).containsExactlyInAnyOrder(parse(this.f, "x&~y"), parse(this.f, "x=>y")); } @Test - public void testTimeoutHandlerSmall() throws ParserException { + public void testTimeoutHandlerSmall() { final List handlers = Arrays.asList( new TimeoutOptimizationHandler(5_000L, TimeoutHandler.TimerType.SINGLE_TIMEOUT), new TimeoutOptimizationHandler(5_000L, TimeoutHandler.TimerType.RESTARTING_TIMEOUT), new TimeoutOptimizationHandler(System.currentTimeMillis() + 5_000L, TimeoutHandler.TimerType.FIXED_END) ); final List formulas = Arrays.asList( - this.f.parse("a"), - this.f.parse("~a") + parse(this.f, "a"), + parse(this.f, "~a") ); for (final TimeoutOptimizationHandler handler : handlers) { testHandler(handler, formulas, false); @@ -241,7 +241,7 @@ public void testTimeoutHandlerSmall() throws ParserException { } @Test - public void testTimeoutHandlerLarge() throws ParserException, IOException { + public void testTimeoutHandlerLarge() throws IOException, ParserException { final List handlers = Arrays.asList( new TimeoutOptimizationHandler(1L, TimeoutHandler.TimerType.SINGLE_TIMEOUT), new TimeoutOptimizationHandler(1L, TimeoutHandler.TimerType.RESTARTING_TIMEOUT), @@ -266,22 +266,22 @@ public void testCancellationPoints() throws IOException { } @Test - public void testMinimumHittingSetCancelled() throws ParserException { + public void testMinimumHittingSetCancelled() { final OptimizationHandler handler = new BoundedOptimizationHandler(-1, 0); final List formulas = Arrays.asList( - this.f.parse("a"), - this.f.parse("~a") + parse(this.f, "a"), + parse(this.f, "~a") ); testHandler(handler, formulas, true); } @Test - public void testHSolverCancelled() throws ParserException { + public void testHSolverCancelled() { final OptimizationHandler handler = new BoundedOptimizationHandler(-1, 3); final List formulas = Arrays.asList( - this.f.parse("a"), - this.f.parse("~a"), - this.f.parse("c") + parse(this.f, "a"), + parse(this.f, "~a"), + parse(this.f, "c") ); testHandler(handler, formulas, true); } diff --git a/src/test/java/org/logicng/formulas/ExtendedFormulaFactoryTest.java b/src/test/java/org/logicng/formulas/ExtendedFormulaFactoryTest.java index 2eb41501..a25b678e 100644 --- a/src/test/java/org/logicng/formulas/ExtendedFormulaFactoryTest.java +++ b/src/test/java/org/logicng/formulas/ExtendedFormulaFactoryTest.java @@ -31,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.data.MapEntry.entry; +import static org.logicng.TestWithExampleFormulas.parse; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.Test; @@ -38,7 +39,6 @@ import org.logicng.datastructures.Tristate; import org.logicng.formulas.cache.PredicateCacheEntry; import org.logicng.formulas.cache.TransformationCacheEntry; -import org.logicng.io.parsers.ParserException; import org.logicng.testutils.PigeonHoleGenerator; import org.logicng.transformations.cnf.CNFFactorization; import org.logicng.transformations.cnf.PlaistedGreenbaumTransformation; @@ -133,7 +133,7 @@ public void testLoad01() { } @Test - public void testLoad02() throws ParserException { + public void testLoad02() { final SoftAssertions softly = new SoftAssertions(); final ExtendedFormulaFactory eff = new ExtendedFormulaFactory(); final Variable a = eff.variable("A"); @@ -151,7 +151,7 @@ public void testLoad02() throws ParserException { final Or or3 = (Or) eff.or(a, b, c); final Or or4 = (Or) eff.or(a, b, c, d); final Or or5 = (Or) eff.or(a, b, c, d, e); - eff.parse("A | B & C").transform(new PlaistedGreenbaumTransformation(0)); + parse(eff, "A | B & C").transform(new PlaistedGreenbaumTransformation(0)); softly.assertThat(eff.posLiterals).containsValue(b); softly.assertThat(eff.ands2).containsValue(and); softly.assertThat(eff.ands3).containsValue(and3); diff --git a/src/test/java/org/logicng/formulas/FormulaFactoryTest.java b/src/test/java/org/logicng/formulas/FormulaFactoryTest.java index 5649f5d3..80a62dd1 100644 --- a/src/test/java/org/logicng/formulas/FormulaFactoryTest.java +++ b/src/test/java/org/logicng/formulas/FormulaFactoryTest.java @@ -30,11 +30,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.configurations.Configuration; import org.logicng.configurations.ConfigurationType; -import org.logicng.io.parsers.ParserException; import org.logicng.io.parsers.PropositionalParser; import org.logicng.solvers.maxsat.algorithms.MaxSATConfig; import org.logicng.solvers.sat.GlucoseConfig; @@ -170,12 +170,12 @@ public void testCNF() { } @Test - public void testImportFormula() throws ParserException { + public void testImportFormula() { final FormulaFactory f = new FormulaFactory(FormulaFactoryConfig.builder().name("Factory F").build()); final FormulaFactory g = new FormulaFactory(FormulaFactoryConfig.builder().name("Factory G").build()); final PropositionalParser pf = new PropositionalParser(f); final String formula = "x1 & x2 & ~x3 => (x4 | (x5 <=> ~x1))"; - final Formula ff = pf.parse(formula); + final Formula ff = parse(f, formula); final Formula fg = g.importFormula(ff); assertThat(fg).isEqualTo(ff); assertThat(ff.factory()).isSameAs(f); diff --git a/src/test/java/org/logicng/formulas/FormulaFactoryWithoutContradictionCheckTest.java b/src/test/java/org/logicng/formulas/FormulaFactoryWithoutContradictionCheckTest.java index 95b50d42..ed34e39a 100644 --- a/src/test/java/org/logicng/formulas/FormulaFactoryWithoutContradictionCheckTest.java +++ b/src/test/java/org/logicng/formulas/FormulaFactoryWithoutContradictionCheckTest.java @@ -29,11 +29,11 @@ package org.logicng.formulas; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.datastructures.Assignment; import org.logicng.datastructures.Tristate; -import org.logicng.io.parsers.ParserException; import org.logicng.predicates.NNFPredicate; import org.logicng.predicates.satisfiability.ContingencyPredicate; import org.logicng.predicates.satisfiability.ContradictionPredicate; @@ -55,33 +55,33 @@ public class FormulaFactoryWithoutContradictionCheckTest { private final Formula contradiction = this.f.and(this.a, this.f.literal("A", false)); @Test - public void testSimpleFormulas() throws ParserException { - assertThat(this.f.parse("$true").toString()).isEqualTo("$true"); - assertThat(this.f.parse("$false").toString()).isEqualTo("$false"); - assertThat(this.f.parse("A").toString()).isEqualTo("A"); - assertThat(this.f.parse("~A").toString()).isEqualTo("~A"); - assertThat(this.f.parse("A & A & B").toString()).isEqualTo("A & B"); - assertThat(this.f.parse("A | A | B").toString()).isEqualTo("A | B"); - assertThat(this.f.parse("A => A & B").toString()).isEqualTo("A => A & B"); - assertThat(this.f.parse("A <=> A & B").toString()).isEqualTo("A <=> A & B"); + public void testSimpleFormulas() { + assertThat(parse(this.f, "$true").toString()).isEqualTo("$true"); + assertThat(parse(this.f, "$false").toString()).isEqualTo("$false"); + assertThat(parse(this.f, "A").toString()).isEqualTo("A"); + assertThat(parse(this.f, "~A").toString()).isEqualTo("~A"); + assertThat(parse(this.f, "A & A & B").toString()).isEqualTo("A & B"); + assertThat(parse(this.f, "A | A | B").toString()).isEqualTo("A | B"); + assertThat(parse(this.f, "A => A & B").toString()).isEqualTo("A => A & B"); + assertThat(parse(this.f, "A <=> A & B").toString()).isEqualTo("A <=> A & B"); } @Test - public void testContradictions() throws ParserException { - assertThat(this.f.parse("A & ~A").toString()).isEqualTo("A & ~A"); - assertThat(this.f.parse("~A & A").toString()).isEqualTo("A & ~A"); - assertThat(this.f.parse("~A & A & A & ~A & A & A & ~A").toString()).isEqualTo("A & ~A"); - assertThat(this.f.parse("(A | B) & ~(A | B)").toString()).isEqualTo("(A | B) & ~(A | B)"); - assertThat(this.f.parse("(A | B) & ~(B | A)").toString()).isEqualTo("(A | B) & ~(A | B)"); + public void testContradictions() { + assertThat(parse(this.f, "A & ~A").toString()).isEqualTo("A & ~A"); + assertThat(parse(this.f, "~A & A").toString()).isEqualTo("A & ~A"); + assertThat(parse(this.f, "~A & A & A & ~A & A & A & ~A").toString()).isEqualTo("A & ~A"); + assertThat(parse(this.f, "(A | B) & ~(A | B)").toString()).isEqualTo("(A | B) & ~(A | B)"); + assertThat(parse(this.f, "(A | B) & ~(B | A)").toString()).isEqualTo("(A | B) & ~(A | B)"); } @Test - public void testTautologies() throws ParserException { - assertThat(this.f.parse("A | ~A").toString()).isEqualTo("A | ~A"); - assertThat(this.f.parse("~A | A").toString()).isEqualTo("A | ~A"); - assertThat(this.f.parse("~A | A | A | ~A | A | A | ~A").toString()).isEqualTo("A | ~A"); - assertThat(this.f.parse("(A & B) | ~(A & B)").toString()).isEqualTo("A & B | ~(A & B)"); - assertThat(this.f.parse("(A & B) | ~(B & A)").toString()).isEqualTo("A & B | ~(A & B)"); + public void testTautologies() { + assertThat(parse(this.f, "A | ~A").toString()).isEqualTo("A | ~A"); + assertThat(parse(this.f, "~A | A").toString()).isEqualTo("A | ~A"); + assertThat(parse(this.f, "~A | A | A | ~A | A | A | ~A").toString()).isEqualTo("A | ~A"); + assertThat(parse(this.f, "(A & B) | ~(A & B)").toString()).isEqualTo("A & B | ~(A & B)"); + assertThat(parse(this.f, "(A & B) | ~(B & A)").toString()).isEqualTo("A & B | ~(A & B)"); } @Test @@ -159,15 +159,15 @@ public void testPredicates() { } @Test - public void testSatSolverWithTautologies() throws ParserException { + public void testSatSolverWithTautologies() { final SATSolver solver = MiniSat.miniSat(this.f); - solver.add(this.f.parse("A")); - solver.add(this.f.parse("A => B")); - solver.add(this.f.parse("C | ~C")); + solver.add(parse(this.f, "A")); + solver.add(parse(this.f, "A => B")); + solver.add(parse(this.f, "C | ~C")); List models = solver.enumerateAllModels(); assertThat(models).hasSize(2); models.forEach(m -> assertThat(m.literals()).containsAnyOf(this.f.literal("C", true), this.f.literal("C", false))); - solver.add(this.f.parse("D | ~D")); + solver.add(parse(this.f, "D | ~D")); models = solver.enumerateAllModels(); assertThat(models).hasSize(4); models.forEach(m -> assertThat(m.literals()).containsAnyOf(this.f.literal("C", true), this.f.literal("C", false), @@ -175,24 +175,24 @@ public void testSatSolverWithTautologies() throws ParserException { } @Test - public void testSatSolverWithContradictions() throws ParserException { + public void testSatSolverWithContradictions() { final SATSolver solver = MiniSat.miniSat(this.f); - solver.add(this.f.parse("A")); - solver.add(this.f.parse("A => B")); - solver.add(this.f.parse("C | ~C")); + solver.add(parse(this.f, "A")); + solver.add(parse(this.f, "A => B")); + solver.add(parse(this.f, "C | ~C")); final List models = solver.enumerateAllModels(); assertThat(models).hasSize(2); models.forEach(m -> assertThat(m.literals()).containsAnyOf(this.f.literal("C", true), this.f.literal("C", false))); - solver.add(this.f.parse("D & ~D")); + solver.add(parse(this.f, "D & ~D")); assertThat(solver.sat()).isEqualTo(Tristate.FALSE); } @Test - public void testSubsumption() throws ParserException { + public void testSubsumption() { assertThat(this.tautology.substitute(this.a, this.notA)).isEqualTo(this.tautology); assertThat(this.contradiction.substitute(this.a, this.notA)).isEqualTo(this.contradiction); - assertThat(this.tautology.substitute(this.a, this.f.variable("B"))).isEqualTo(this.f.parse("B | ~B")); - assertThat(this.contradiction.substitute(this.a, this.f.variable("B"))).isEqualTo(this.f.parse("B & ~B")); + assertThat(this.tautology.substitute(this.a, this.f.variable("B"))).isEqualTo(parse(this.f, "B | ~B")); + assertThat(this.contradiction.substitute(this.a, this.f.variable("B"))).isEqualTo(parse(this.f, "B & ~B")); } @Test diff --git a/src/test/java/org/logicng/formulas/FormulaTest.java b/src/test/java/org/logicng/formulas/FormulaTest.java index 45830955..3c87b552 100644 --- a/src/test/java/org/logicng/formulas/FormulaTest.java +++ b/src/test/java/org/logicng/formulas/FormulaTest.java @@ -29,6 +29,7 @@ package org.logicng.formulas; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import static org.logicng.formulas.cache.PredicateCacheEntry.IS_CNF; import static org.logicng.formulas.cache.PredicateCacheEntry.IS_DNF; import static org.logicng.formulas.cache.TransformationCacheEntry.FACTORIZED_CNF; @@ -36,7 +37,6 @@ import org.junit.jupiter.api.Test; import org.logicng.datastructures.Tristate; import org.logicng.formulas.cache.CacheEntry; -import org.logicng.io.parsers.ParserException; import org.logicng.transformations.cnf.BDDCNFTransformation; import java.util.Arrays; @@ -119,10 +119,10 @@ public void testCType() { } @Test - public void testIsSatisfiable() throws ParserException { + public void testIsSatisfiable() { final FormulaFactory f = new FormulaFactory(); - final Formula f1 = f.parse("(a | b) & (c | ~d)"); - final Formula f2 = f.parse("~a & ~b & (a | b)"); + final Formula f1 = parse(f, "(a | b) & (c | ~d)"); + final Formula f2 = parse(f, "~a & ~b & (a | b)"); assertThat(f.falsum().isSatisfiable()).isFalse(); assertThat(f.verum().isSatisfiable()).isTrue(); assertThat(f1.isSatisfiable()).isTrue(); @@ -130,10 +130,10 @@ public void testIsSatisfiable() throws ParserException { } @Test - public void testIsTautology() throws ParserException { + public void testIsTautology() { final FormulaFactory f = new FormulaFactory(); - final Formula f1 = f.parse("(a | b) & (c | ~d)"); - final Formula f2 = f.parse("(a & b) | (~a & b) | (a & ~b) | (~a & ~b)"); + final Formula f1 = parse(f, "(a | b) & (c | ~d)"); + final Formula f2 = parse(f, "(a & b) | (~a & b) | (a & ~b) | (~a & ~b)"); assertThat(f.falsum().isTautology()).isFalse(); assertThat(f.verum().isTautology()).isTrue(); assertThat(f1.isTautology()).isFalse(); @@ -141,10 +141,10 @@ public void testIsTautology() throws ParserException { } @Test - public void testIsContradiction() throws ParserException { + public void testIsContradiction() { final FormulaFactory f = new FormulaFactory(); - final Formula f1 = f.parse("(a | b) & (c | ~d)"); - final Formula f2 = f.parse("~a & ~b & (a | b)"); + final Formula f1 = parse(f, "(a | b) & (c | ~d)"); + final Formula f2 = parse(f, "~a & ~b & (a | b)"); assertThat(f.falsum().isContradiction()).isTrue(); assertThat(f.verum().isContradiction()).isFalse(); assertThat(f1.isContradiction()).isFalse(); @@ -152,11 +152,11 @@ public void testIsContradiction() throws ParserException { } @Test - public void testImplies() throws ParserException { + public void testImplies() { final FormulaFactory f = new FormulaFactory(); - final Formula f1 = f.parse("(a | b) & (c | ~d)"); - final Formula f2 = f.parse("(a | b) & (c | ~d) & (e | ~f)"); - final Formula f3 = f.parse("(a | b) & (c | d)"); + final Formula f1 = parse(f, "(a | b) & (c | ~d)"); + final Formula f2 = parse(f, "(a | b) & (c | ~d) & (e | ~f)"); + final Formula f3 = parse(f, "(a | b) & (c | d)"); assertThat(f1.implies(f2)).isFalse(); assertThat(f2.implies(f1)).isTrue(); assertThat(f1.implies(f3)).isFalse(); @@ -165,11 +165,11 @@ public void testImplies() throws ParserException { } @Test - public void testIsImpliedBy() throws ParserException { + public void testIsImpliedBy() { final FormulaFactory f = new FormulaFactory(); - final Formula f1 = f.parse("(a | b) & (c | ~d)"); - final Formula f2 = f.parse("(a | b) & (c | ~d) & (e | ~f)"); - final Formula f3 = f.parse("(a | b) & (c | d)"); + final Formula f1 = parse(f, "(a | b) & (c | ~d)"); + final Formula f2 = parse(f, "(a | b) & (c | ~d) & (e | ~f)"); + final Formula f3 = parse(f, "(a | b) & (c | d)"); assertThat(f1.isImpliedBy(f2)).isTrue(); assertThat(f2.isImpliedBy(f1)).isFalse(); assertThat(f1.isImpliedBy(f3)).isFalse(); @@ -178,11 +178,11 @@ public void testIsImpliedBy() throws ParserException { } @Test - public void testIsEquivalentTo() throws ParserException { + public void testIsEquivalentTo() { final FormulaFactory f = new FormulaFactory(); - final Formula f1 = f.parse("(a | b) & (c | ~d)"); - final Formula f2 = f.parse("(a | b) & (c | ~d) & (e | ~f)"); - final Formula f3 = f.parse("(a & c) | (a & ~d) | (b & c) | (b & ~d)"); + final Formula f1 = parse(f, "(a | b) & (c | ~d)"); + final Formula f2 = parse(f, "(a | b) & (c | ~d) & (e | ~f)"); + final Formula f3 = parse(f, "(a & c) | (a & ~d) | (b & c) | (b & ~d)"); assertThat(f1.isEquivalentTo(f2)).isFalse(); assertThat(f2.isEquivalentTo(f1)).isFalse(); assertThat(f1.isEquivalentTo(f3)).isTrue(); diff --git a/src/test/java/org/logicng/functions/FormulaDepthFunctionTest.java b/src/test/java/org/logicng/functions/FormulaDepthFunctionTest.java index 7110a076..7f9f235a 100644 --- a/src/test/java/org/logicng/functions/FormulaDepthFunctionTest.java +++ b/src/test/java/org/logicng/functions/FormulaDepthFunctionTest.java @@ -36,7 +36,6 @@ import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Variable; import org.logicng.formulas.cache.FunctionCacheEntry; -import org.logicng.io.parsers.ParserException; /** * Unit Tests for the class {@link FormulaDepthFunction}. @@ -89,9 +88,9 @@ public void testDeeperFormulas() { } @Test - public void testCache() throws ParserException { + public void testCache() { final FormulaFactory f = new FormulaFactory(); - final Formula formula = f.parse("A & B | C"); + final Formula formula = parse(f, "A & B | C"); assertThat(formula.functionCacheEntry(FunctionCacheEntry.DEPTH)).isNull(); assertThat(formula.apply(FormulaDepthFunction.get())).isEqualTo(2); assertThat(formula.functionCacheEntry(FunctionCacheEntry.DEPTH)).isEqualTo(2); diff --git a/src/test/java/org/logicng/functions/MinimumPrimeImplicantTest.java b/src/test/java/org/logicng/functions/MinimumPrimeImplicantTest.java index b507671d..75e791a5 100644 --- a/src/test/java/org/logicng/functions/MinimumPrimeImplicantTest.java +++ b/src/test/java/org/logicng/functions/MinimumPrimeImplicantTest.java @@ -29,6 +29,7 @@ package org.logicng.functions; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.cardinalityconstraints.CCConfig; @@ -57,65 +58,65 @@ public MinimumPrimeImplicantTest() { } @Test - public void testSimpleCases() throws ParserException { - Formula formula = this.f.parse("a"); + public void testSimpleCases() { + Formula formula = parse(this.f, "a"); SortedSet pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(1); isPrimeImplicant(formula, pi); - formula = this.f.parse("a | b | c"); + formula = parse(this.f, "a | b | c"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(1); isPrimeImplicant(formula, pi); - formula = this.f.parse("a & b & (~a|~b)"); + formula = parse(this.f, "a & b & (~a|~b)"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).isNull(); - formula = this.f.parse("a & b & c"); + formula = parse(this.f, "a & b & c"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(3); isPrimeImplicant(formula, pi); - formula = this.f.parse("a | b | ~c => e & d & f"); + formula = parse(this.f, "a | b | ~c => e & d & f"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(3); isPrimeImplicant(formula, pi); - formula = this.f.parse("a | b | ~c <=> e & d & f"); + formula = parse(this.f, "a | b | ~c <=> e & d & f"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(4); isPrimeImplicant(formula, pi); - formula = this.f.parse("(a | b | ~c <=> e & d & f) | (a | b | ~c => e & d & f)"); + formula = parse(this.f, "(a | b | ~c <=> e & d & f) | (a | b | ~c => e & d & f)"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(3); isPrimeImplicant(formula, pi); - formula = this.f.parse("(a | b | ~c <=> e & d & f) | (a | b | ~c => e & d & f) | (a & b)"); + formula = parse(this.f, "(a | b | ~c <=> e & d & f) | (a | b | ~c => e & d & f) | (a & b)"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(2); isPrimeImplicant(formula, pi); - formula = this.f.parse("(a | b | ~c <=> e & d & f) | (a | b | ~c => e & d & f) | (a & b) | (f => g)"); + formula = parse(this.f, "(a | b | ~c <=> e & d & f) | (a | b | ~c => e & d & f) | (a & b) | (f => g)"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(1); isPrimeImplicant(formula, pi); } @Test - public void testSmallExamples() throws ParserException { - Formula formula = this.f.parse("(~(v17 | v18) | ~v1494 & (v17 | v18)) & ~v687 => v686"); + public void testSmallExamples() { + Formula formula = parse(this.f, "(~(v17 | v18) | ~v1494 & (v17 | v18)) & ~v687 => v686"); SortedSet pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(1); isPrimeImplicant(formula, pi); - formula = this.f.parse("(~(v17 | v18) | ~v1494 & (v17 | v18)) & v687 => ~v686"); + formula = parse(this.f, "(~(v17 | v18) | ~v1494 & (v17 | v18)) & v687 => ~v686"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(1); isPrimeImplicant(formula, pi); - formula = this.f.parse("v173 + v174 + v451 + v258 + v317 + v259 + v452 + v453 + v175 + v176 + v177 + v178 + v179 + v180 + v181 + v182 + v183 + v102 + v103 + v104 + v105 = 1"); + formula = parse(this.f, "v173 + v174 + v451 + v258 + v317 + v259 + v452 + v453 + v175 + v176 + v177 + v178 + v179 + v180 + v181 + v182 + v183 + v102 + v103 + v104 + v105 = 1"); pi = formula.apply(MinimumPrimeImplicantFunction.get()); assertThat(pi).hasSize(21); isPrimeImplicant(formula, pi); diff --git a/src/test/java/org/logicng/graphs/algorithms/ConnectedComponentsComputerTest.java b/src/test/java/org/logicng/graphs/algorithms/ConnectedComponentsComputerTest.java index e4a48007..3b4246a6 100644 --- a/src/test/java/org/logicng/graphs/algorithms/ConnectedComponentsComputerTest.java +++ b/src/test/java/org/logicng/graphs/algorithms/ConnectedComponentsComputerTest.java @@ -155,8 +155,7 @@ public void testFormulaSplit() throws IOException, ParserException { @Test public void testFormulaSplitIllegal() { final FormulaFactory f = new FormulaFactory(); - @SuppressWarnings("deprecation") - final Graph graph = ConstraintGraphGenerator.generateFromCnf(f.variable("B")); + @SuppressWarnings("deprecation") final Graph graph = ConstraintGraphGenerator.generateFromCnf(f.variable("B")); final Set>> ccs = Collections.singleton(Collections.singleton(graph.node(f.variable("B")))); assertThatThrownBy(() -> ConnectedComponentsComputation.splitFormulasByComponent(Collections.singletonList(f.variable("A")), ccs)) .isInstanceOf(IllegalArgumentException.class); diff --git a/src/test/java/org/logicng/graphs/io/conditions/ContainsCondition.java b/src/test/java/org/logicng/graphs/io/conditions/ContainsCondition.java index 52c2c317..1f18d818 100644 --- a/src/test/java/org/logicng/graphs/io/conditions/ContainsCondition.java +++ b/src/test/java/org/logicng/graphs/io/conditions/ContainsCondition.java @@ -33,7 +33,7 @@ import java.util.List; /** - * A condition needed for AssertJ-Assertions for {@link org.logicng.graphs.io.GraphDotFileWriterTest} and {@link org.logicng.graphs.io.GraphDimacsFileWriterTest}. + * A condition needed for AssertJ-Assertions for {@link org.logicng.graphs.io.GraphDimacsFileWriterTest}. * @version 1.2 * @since 1.2 */ diff --git a/src/test/java/org/logicng/handlers/TimeoutBDDHandlerTest.java b/src/test/java/org/logicng/handlers/TimeoutBDDHandlerTest.java index 57b2bcd7..920f6e46 100644 --- a/src/test/java/org/logicng/handlers/TimeoutBDDHandlerTest.java +++ b/src/test/java/org/logicng/handlers/TimeoutBDDHandlerTest.java @@ -1,6 +1,7 @@ package org.logicng.handlers; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -11,7 +12,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.knowledgecompilation.bdds.BDD; import org.logicng.knowledgecompilation.bdds.BDDFactory; import org.logicng.knowledgecompilation.bdds.jbuddy.BDDKernel; @@ -45,8 +45,8 @@ public void testNewRefAdded() throws InterruptedException { } @Test - public void testThatMethodsAreCalled() throws ParserException { - final Formula formula = f.parse("(A => ~B) & ((A & C) | (D & ~C)) & (A | Y | X)"); + public void testThatMethodsAreCalled() { + final Formula formula = parse(this.f, "(A => ~B) & ((A & C) | (D & ~C)) & (A | Y | X)"); final VariableOrderingProvider provider = VariableOrdering.BFS.provider(); final BDDKernel kernel = new BDDKernel(this.f, provider.getOrder(formula), 100, 100); final TimeoutBDDHandler handler = Mockito.mock(TimeoutBDDHandler.class); @@ -58,8 +58,8 @@ public void testThatMethodsAreCalled() throws ParserException { } @Test - public void testThatNewRefAddedHandledProperly() throws ParserException { - final Formula formula = f.parse("(A => ~B) & ((A & C) | ~(D & ~C)) & (A | Y | X)"); + public void testThatNewRefAddedHandledProperly() { + final Formula formula = parse(this.f, "(A => ~B) & ((A & C) | ~(D & ~C)) & (A | Y | X)"); final VariableOrderingProvider provider = VariableOrdering.BFS.provider(); final BDDKernel kernel = new BDDKernel(this.f, provider.getOrder(formula), 100, 100); final TimeoutBDDHandler handler = Mockito.mock(TimeoutBDDHandler.class); @@ -76,7 +76,7 @@ public void testThatNewRefAddedHandledProperly() throws ParserException { @Test public void testTimeoutHandlerSingleTimeout() { - final Formula formula = pg.generate(10); + final Formula formula = this.pg.generate(10); final VariableOrderingProvider provider = VariableOrdering.BFS.provider(); final BDDKernel kernel = new BDDKernel(this.f, provider.getOrder(formula), 100, 100); final TimeoutBDDHandler handler = new TimeoutBDDHandler(100L); @@ -89,7 +89,7 @@ public void testTimeoutHandlerSingleTimeout() { @Test public void testTimeoutHandlerFixedEnd() { - final Formula formula = pg.generate(10); + final Formula formula = this.pg.generate(10); final VariableOrderingProvider provider = VariableOrdering.BFS.provider(); final BDDKernel kernel = new BDDKernel(this.f, provider.getOrder(formula), 100, 100); final TimeoutBDDHandler handler = new TimeoutBDDHandler(System.currentTimeMillis() + 100L, TimeoutHandler.TimerType.FIXED_END); diff --git a/src/test/java/org/logicng/handlers/TimeoutMaxSATHandlerTest.java b/src/test/java/org/logicng/handlers/TimeoutMaxSATHandlerTest.java index 8724e6c1..2d26f0d4 100644 --- a/src/test/java/org/logicng/handlers/TimeoutMaxSATHandlerTest.java +++ b/src/test/java/org/logicng/handlers/TimeoutMaxSATHandlerTest.java @@ -1,6 +1,7 @@ package org.logicng.handlers; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeast; @@ -15,7 +16,6 @@ import org.logicng.datastructures.Assignment; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.io.readers.DimacsReader; import org.logicng.solvers.MaxSATSolver; import org.logicng.solvers.maxsat.algorithms.MaxSAT; @@ -67,12 +67,12 @@ public void testTimeoutForUpperBound() throws InterruptedException { } @Test - public void testThatMethodsAreCalled() throws ParserException { + public void testThatMethodsAreCalled() { for (final MaxSATSolver solver : this.solvers) { final int weight = solver.isWeighted() ? 2 : 1; - solver.addHardFormula(this.f.parse("A&B")); - solver.addSoftFormula(this.f.parse("~A"), weight); - solver.addSoftFormula(this.f.parse("~B"), weight); + solver.addHardFormula(parse(this.f, "A&B")); + solver.addSoftFormula(parse(this.f, "~A"), weight); + solver.addSoftFormula(parse(this.f, "~B"), weight); final TimeoutMaxSATHandler handler = Mockito.mock(TimeoutMaxSATHandler.class); solver.solve(handler); diff --git a/src/test/java/org/logicng/handlers/TimeoutModelEnumerationHandlerTest.java b/src/test/java/org/logicng/handlers/TimeoutModelEnumerationHandlerTest.java index b02d2f9a..22072b5c 100644 --- a/src/test/java/org/logicng/handlers/TimeoutModelEnumerationHandlerTest.java +++ b/src/test/java/org/logicng/handlers/TimeoutModelEnumerationHandlerTest.java @@ -1,6 +1,7 @@ package org.logicng.handlers; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.times; @@ -13,7 +14,6 @@ import org.logicng.datastructures.Assignment; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; import org.logicng.solvers.functions.ModelEnumerationFunction; @@ -36,7 +36,7 @@ class TimeoutModelEnumerationHandlerTest { @BeforeEach public void init() { this.f = new FormulaFactory(); - this.pg = new PigeonHoleGenerator(f); + this.pg = new PigeonHoleGenerator(this.f); this.solvers = new SATSolver[8]; this.solvers[0] = MiniSat.miniSat(this.f, MiniSatConfig.builder().incremental(true).build()); this.solvers[1] = MiniSat.miniSat(this.f, MiniSatConfig.builder().incremental(false).build()); @@ -59,8 +59,8 @@ public void testFoundModel() throws InterruptedException { } @Test - public void testThatMethodsAreCalled() throws ParserException { - final Formula formula = f.parse("A & B | C"); + public void testThatMethodsAreCalled() { + final Formula formula = parse(this.f, "A & B | C"); for (final SATSolver solver : this.solvers) { solver.add(formula); final TimeoutModelEnumerationHandler handler = Mockito.mock(TimeoutModelEnumerationHandler.class); @@ -75,7 +75,7 @@ public void testThatMethodsAreCalled() throws ParserException { @Test public void testThatSatHandlerIsHandledProperly() { - final Formula formula = pg.generate(10).negate(); + final Formula formula = this.pg.generate(10).negate(); for (final SATSolver solver : this.solvers) { solver.add(formula); final TimeoutSATHandler satHandler = Mockito.mock(TimeoutSATHandler.class); @@ -99,7 +99,7 @@ public void testThatSatHandlerIsHandledProperly() { @Test public void testTimeoutHandlerSingleTimeout() { - final Formula formula = pg.generate(10).negate(); + final Formula formula = this.pg.generate(10).negate(); for (final SATSolver solver : this.solvers) { solver.add(formula); final TimeoutModelEnumerationHandler handler = new TimeoutModelEnumerationHandler(100L); @@ -114,7 +114,7 @@ public void testTimeoutHandlerSingleTimeout() { @Test public void testTimeoutHandlerFixedEnd() { - final Formula formula = pg.generate(10).negate(); + final Formula formula = this.pg.generate(10).negate(); for (final SATSolver solver : this.solvers) { solver.add(formula); final TimeoutModelEnumerationHandler handler = new TimeoutModelEnumerationHandler(System.currentTimeMillis() + 100L, TimeoutHandler.TimerType.FIXED_END); diff --git a/src/test/java/org/logicng/handlers/TimeoutOptimizationHandlerTest.java b/src/test/java/org/logicng/handlers/TimeoutOptimizationHandlerTest.java index e6d5bfda..2161b0fe 100644 --- a/src/test/java/org/logicng/handlers/TimeoutOptimizationHandlerTest.java +++ b/src/test/java/org/logicng/handlers/TimeoutOptimizationHandlerTest.java @@ -1,6 +1,7 @@ package org.logicng.handlers; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -11,7 +12,6 @@ import org.logicng.datastructures.Assignment; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.io.readers.DimacsReader; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; @@ -56,8 +56,8 @@ public void testTimeoutFoundBetterBound() throws InterruptedException { } @Test - public void testThatMethodsAreCalled() throws ParserException { - final Formula formula = f.parse("a & b & (~a => b)"); + public void testThatMethodsAreCalled() { + final Formula formula = parse(this.f, "a & b & (~a => b)"); for (final SATSolver solver : this.solvers) { solver.add(formula); final TimeoutOptimizationHandler handler = Mockito.mock(TimeoutOptimizationHandler.class); diff --git a/src/test/java/org/logicng/handlers/TimeoutSATHandlerTest.java b/src/test/java/org/logicng/handlers/TimeoutSATHandlerTest.java index 0964d201..31425d69 100644 --- a/src/test/java/org/logicng/handlers/TimeoutSATHandlerTest.java +++ b/src/test/java/org/logicng/handlers/TimeoutSATHandlerTest.java @@ -1,6 +1,7 @@ package org.logicng.handlers; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -11,7 +12,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.logicng.datastructures.Tristate; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; import org.logicng.solvers.sat.GlucoseConfig; @@ -55,9 +55,9 @@ public void testDetectedConflict() throws InterruptedException { } @Test - public void testThatMethodsAreCalled() throws ParserException { + public void testThatMethodsAreCalled() { for (final SATSolver solver : this.solvers) { - solver.add(this.f.parse("(x => y) & (~x => y) & (y => z) & (z => ~y)")); + solver.add(parse(this.f, "(x => y) & (~x => y) & (y => z) & (z => ~y)")); final TimeoutSATHandler handler = Mockito.mock(TimeoutSATHandler.class); solver.sat(handler); @@ -71,7 +71,7 @@ public void testThatMethodsAreCalled() throws ParserException { @Test public void testThatDetectedConflictIsHandledProperly() { for (final SATSolver solver : this.solvers) { - solver.add(pg.generate(10)); + solver.add(this.pg.generate(10)); final TimeoutSATHandler handler = Mockito.mock(TimeoutSATHandler.class); final AtomicInteger count = new AtomicInteger(0); when(handler.detectedConflict()).then(invocationOnMock -> count.addAndGet(1) < 5); @@ -89,7 +89,7 @@ public void testThatDetectedConflictIsHandledProperly() { @Test public void testTimeoutHandlerSingleTimeout() { for (final SATSolver solver : this.solvers) { - solver.add(pg.generate(10)); + solver.add(this.pg.generate(10)); final TimeoutSATHandler handler = new TimeoutSATHandler(100L); final Tristate result = solver.sat(handler); @@ -102,7 +102,7 @@ public void testTimeoutHandlerSingleTimeout() { @Test public void testTimeoutHandlerFixedEnd() { for (final SATSolver solver : this.solvers) { - solver.add(pg.generate(10)); + solver.add(this.pg.generate(10)); final TimeoutSATHandler handler = new TimeoutSATHandler(System.currentTimeMillis() + 100L, TimeoutHandler.TimerType.FIXED_END); final Tristate result = solver.sat(handler); diff --git a/src/test/java/org/logicng/io/FormulaWriterReaderTest.java b/src/test/java/org/logicng/io/FormulaWriterReaderTest.java index 96aee91e..ad98e38c 100644 --- a/src/test/java/org/logicng/io/FormulaWriterReaderTest.java +++ b/src/test/java/org/logicng/io/FormulaWriterReaderTest.java @@ -57,7 +57,7 @@ public class FormulaWriterReaderTest { @Test - public void testSimpleFormulaOneLine() throws ParserException, IOException { + public void testSimpleFormulaOneLine() throws IOException, ParserException { final String fileName = "src/test/resources/writers/temp/simple_formula1.txt"; final File file = new File(fileName); final FormulaFactory f = new FormulaFactory(); @@ -79,7 +79,7 @@ public void testSimpleFormulaOneLine() throws ParserException, IOException { } @Test - public void testSimpleFormulaMultiLine() throws ParserException, IOException { + public void testSimpleFormulaMultiLine() throws IOException, ParserException { final String fileName = "src/test/resources/writers/temp/simple_formula2.txt"; final File file = new File(fileName); final FormulaFactory f = new FormulaFactory(); @@ -99,7 +99,7 @@ public void testSimpleFormulaMultiLine() throws ParserException, IOException { } @Test - public void testPBFormulaOneLine() throws ParserException, IOException { + public void testPBFormulaOneLine() throws IOException, ParserException { final String fileName = "src/test/resources/writers/temp/simple_formula3.txt"; final File file = new File(fileName); final FormulaFactory f = new FormulaFactory(); @@ -121,7 +121,7 @@ public void testPBFormulaOneLine() throws ParserException, IOException { } @Test - public void testPBFormulaMultiLine() throws ParserException, IOException { + public void testPBFormulaMultiLine() throws IOException, ParserException { final String fileName = "src/test/resources/writers/temp/simple_formula4.txt"; final File file = new File(fileName); final FormulaFactory f = new FormulaFactory(); @@ -141,7 +141,7 @@ public void testPBFormulaMultiLine() throws ParserException, IOException { } @Test - public void testSimpleFormulaOneLineFormatter() throws ParserException, IOException { + public void testSimpleFormulaOneLineFormatter() throws IOException, ParserException { final String fileName = "src/test/resources/writers/temp/simple_formula5.txt"; final File file = new File(fileName); final FormulaFactory f = new FormulaFactory(); @@ -154,7 +154,7 @@ public void testSimpleFormulaOneLineFormatter() throws ParserException, IOExcept } @Test - public void testSimpleFormulaMultiLineFormatter() throws ParserException, IOException { + public void testSimpleFormulaMultiLineFormatter() throws IOException, ParserException { final String fileName = "src/test/resources/writers/temp/simple_formula6.txt"; final File file = new File(fileName); final FormulaFactory f = new FormulaFactory(); diff --git a/src/test/java/org/logicng/io/graphical/generators/BddGraphicalGeneratorTest.java b/src/test/java/org/logicng/io/graphical/generators/BddGraphicalGeneratorTest.java index ee4edb98..e739a487 100644 --- a/src/test/java/org/logicng/io/graphical/generators/BddGraphicalGeneratorTest.java +++ b/src/test/java/org/logicng/io/graphical/generators/BddGraphicalGeneratorTest.java @@ -84,7 +84,7 @@ public void testFormulas() throws IOException, ParserException { } @Test - public void testFixedStyle() throws ParserException, IOException { + public void testFixedStyle() throws IOException, ParserException { final FormulaFactory f = new FormulaFactory(); final PropositionalParser p = new PropositionalParser(f); final List ordering = Arrays.asList(f.variable("A"), f.variable("B"), f.variable("C"), f.variable("D")); @@ -104,7 +104,7 @@ public void testFixedStyle() throws ParserException, IOException { } @Test - public void testDynamic() throws ParserException, IOException { + public void testDynamic() throws IOException, ParserException { final FormulaFactory f = new FormulaFactory(); final PropositionalParser p = new PropositionalParser(f); final List ordering = Arrays.asList(f.variable("A"), f.variable("B"), f.variable("C"), f.variable("D")); diff --git a/src/test/java/org/logicng/io/graphical/generators/FormulaAstGraphicalGeneratorTest.java b/src/test/java/org/logicng/io/graphical/generators/FormulaAstGraphicalGeneratorTest.java index 664ab322..771f5a15 100644 --- a/src/test/java/org/logicng/io/graphical/generators/FormulaAstGraphicalGeneratorTest.java +++ b/src/test/java/org/logicng/io/graphical/generators/FormulaAstGraphicalGeneratorTest.java @@ -100,7 +100,7 @@ public void testFormulas() throws IOException, ParserException { } @Test - public void testDuplicateFormulaParts() throws ParserException, IOException { + public void testDuplicateFormulaParts() throws IOException, ParserException { final Formula f6 = this.p.parse("(a & b) | (c & ~(a & b))"); testFiles("f6", f6, FormulaAstGraphicalGenerator.builder().build()); final Formula f7 = this.p.parse("(c & d) | (a & b) | ((c & d) <=> (a & b))"); @@ -108,7 +108,7 @@ public void testDuplicateFormulaParts() throws ParserException, IOException { } @Test - public void testFixedStyle() throws ParserException, IOException { + public void testFixedStyle() throws IOException, ParserException { final Formula f8 = this.p.parse("(A <=> B & (~A | C | X)) => a + b + c <= 2"); final FormulaAstGraphicalGenerator generator = FormulaAstGraphicalGenerator.builder() .backgroundColor("#020202") @@ -120,7 +120,7 @@ public void testFixedStyle() throws ParserException, IOException { } @Test - public void testDynamicStyle() throws ParserException, IOException { + public void testDynamicStyle() throws IOException, ParserException { final Formula f9 = this.p.parse("(A <=> B & (~A | C | X)) => a + b + c <= 2 & (~a | d => X & ~B)"); final GraphicalNodeStyle style1 = GraphicalNodeStyle.rectangle(GRAY_DARK, GRAY_DARK, GRAY_LIGHT); @@ -149,7 +149,7 @@ public void testDynamicStyle() throws ParserException, IOException { } @Test - public void testEdgeMapper() throws ParserException, IOException { + public void testEdgeMapper() throws IOException, ParserException { final Formula f10 = this.p.parse("(A <=> B & (~A | C | X)) => a + b + c <= 2 & (~a | d => X & ~B)"); final GraphicalEdgeStyle style1 = GraphicalEdgeStyle.dotted(GRAY_DARK); @@ -172,7 +172,7 @@ public void testEdgeMapper() throws ParserException, IOException { } @Test - public void testWithLabelMapper() throws ParserException, IOException { + public void testWithLabelMapper() throws IOException, ParserException { final Formula f8 = this.p.parse("(A <=> B & (~A | C | X)) => a + b + c <= 2"); final FormulaAstGraphicalGenerator generator = FormulaAstGraphicalGenerator.builder() .backgroundColor("#020202") diff --git a/src/test/java/org/logicng/io/graphical/generators/FormulaDagGraphicalGeneratorTest.java b/src/test/java/org/logicng/io/graphical/generators/FormulaDagGraphicalGeneratorTest.java index 4166755a..790f9072 100644 --- a/src/test/java/org/logicng/io/graphical/generators/FormulaDagGraphicalGeneratorTest.java +++ b/src/test/java/org/logicng/io/graphical/generators/FormulaDagGraphicalGeneratorTest.java @@ -100,7 +100,7 @@ public void testFormulas() throws IOException, ParserException { } @Test - public void testDuplicateFormulaParts() throws ParserException, IOException { + public void testDuplicateFormulaParts() throws IOException, ParserException { final Formula f6 = this.p.parse("(a & b) | (c & ~(a & b))"); testFiles("f6", f6, FormulaDagGraphicalGenerator.builder().build()); final Formula f7 = this.p.parse("(c & d) | (a & b) | ((c & d) <=> (a & b))"); @@ -108,7 +108,7 @@ public void testDuplicateFormulaParts() throws ParserException, IOException { } @Test - public void testFixedStyle() throws ParserException, IOException { + public void testFixedStyle() throws IOException, ParserException { final Formula f8 = this.p.parse("(A <=> B & (~A | C | X)) => a + b + c <= 2"); final FormulaDagGraphicalGenerator generator = FormulaDagGraphicalGenerator.builder() .backgroundColor("#020202") @@ -120,7 +120,7 @@ public void testFixedStyle() throws ParserException, IOException { } @Test - public void testDynamicStyle() throws ParserException, IOException { + public void testDynamicStyle() throws IOException, ParserException { final Formula f9 = this.p.parse("(A <=> B & (~A | C | X)) => a + b + c <= 2 & (~a | d => X & ~B)"); final GraphicalNodeStyle style1 = GraphicalNodeStyle.rectangle(GRAY_DARK, GRAY_DARK, GRAY_LIGHT); @@ -149,7 +149,7 @@ public void testDynamicStyle() throws ParserException, IOException { } @Test - public void testEdgeMapper() throws ParserException, IOException { + public void testEdgeMapper() throws IOException, ParserException { final Formula f10 = this.p.parse("(A <=> B & (~A | C | X)) => a + b + c <= 2 & (~a | d => X & ~B)"); final GraphicalEdgeStyle style1 = GraphicalEdgeStyle.dotted(GRAY_DARK); diff --git a/src/main/java/org/logicng/io/parsers/FormulaParser.java b/src/test/java/org/logicng/io/parsers/FormulaParser.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/FormulaParser.java rename to src/test/java/org/logicng/io/parsers/FormulaParser.java diff --git a/src/main/java/org/logicng/io/parsers/LexerException.java b/src/test/java/org/logicng/io/parsers/LexerException.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/LexerException.java rename to src/test/java/org/logicng/io/parsers/LexerException.java diff --git a/src/main/java/org/logicng/io/parsers/ParserException.java b/src/test/java/org/logicng/io/parsers/ParserException.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/ParserException.java rename to src/test/java/org/logicng/io/parsers/ParserException.java diff --git a/src/main/java/org/logicng/io/parsers/ParserWithFormula.java b/src/test/java/org/logicng/io/parsers/ParserWithFormula.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/ParserWithFormula.java rename to src/test/java/org/logicng/io/parsers/ParserWithFormula.java diff --git a/src/main/java/org/logicng/io/parsers/PropositionalLexer.java b/src/test/java/org/logicng/io/parsers/PropositionalLexer.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/PropositionalLexer.java rename to src/test/java/org/logicng/io/parsers/PropositionalLexer.java diff --git a/src/main/java/org/logicng/io/parsers/PropositionalParser.java b/src/test/java/org/logicng/io/parsers/PropositionalParser.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/PropositionalParser.java rename to src/test/java/org/logicng/io/parsers/PropositionalParser.java diff --git a/src/test/java/org/logicng/io/parsers/PropositionalParserTest.java b/src/test/java/org/logicng/io/parsers/PropositionalParserTest.java deleted file mode 100644 index 331f5f1b..00000000 --- a/src/test/java/org/logicng/io/parsers/PropositionalParserTest.java +++ /dev/null @@ -1,270 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// __ _ _ ________ // -// / / ____ ____ _(_)____/ | / / ____/ // -// / / / __ \/ __ `/ / ___/ |/ / / __ // -// / /___/ /_/ / /_/ / / /__/ /| / /_/ / // -// /_____/\____/\__, /_/\___/_/ |_/\____/ // -// /____/ // -// // -// The Next Generation Logic Library // -// // -/////////////////////////////////////////////////////////////////////////// -// // -// Copyright 2015-20xx Christoph Zengler // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // -// implied. See the License for the specific language governing // -// permissions and limitations under the License. // -// // -/////////////////////////////////////////////////////////////////////////// - -package org.logicng.io.parsers; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import org.junit.jupiter.api.Test; -import org.logicng.TestWithExampleFormulas; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - -/** - * Unit Tests for the class {@link PropositionalParser}. - * @version 2.4.1 - * @since 1.0 - */ -public class PropositionalParserTest extends TestWithExampleFormulas { - - @Test - public void testExceptions() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse("")).isEqualTo(this.f.verum()); - final String s = null; - assertThat(parser.parse(s)).isEqualTo(this.f.verum()); - } - - @Test - public void testParseConstants() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse("$true")).isEqualTo(this.f.verum()); - assertThat(parser.parse("$false")).isEqualTo(this.f.falsum()); - } - - @Test - public void testParseLiterals() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse("A")).isEqualTo(this.f.variable("A")); - assertThat(parser.parse("a")).isEqualTo(this.f.variable("a")); - assertThat(parser.parse("a1")).isEqualTo(this.f.variable("a1")); - assertThat(parser.parse("aA_Bb_Cc_12_3")).isEqualTo(this.f.variable("aA_Bb_Cc_12_3")); - assertThat(parser.parse("~A")).isEqualTo(this.f.literal("A", false)); - assertThat(parser.parse("~a")).isEqualTo(this.f.literal("a", false)); - assertThat(parser.parse("~a1")).isEqualTo(this.f.literal("a1", false)); - assertThat(parser.parse("~aA_Bb_Cc_12_3")).isEqualTo(this.f.literal("aA_Bb_Cc_12_3", false)); - assertThat(parser.parse("~@aA_Bb_Cc_12_3")).isEqualTo(this.f.literal("@aA_Bb_Cc_12_3", false)); - assertThat(parser.parse("#")).isEqualTo(this.f.literal("#", true)); - assertThat(parser.parse("~#")).isEqualTo(this.f.literal("#", false)); - assertThat(parser.parse("~A#B")).isEqualTo(this.f.literal("A#B", false)); - assertThat(parser.parse("A#B")).isEqualTo(this.f.literal("A#B", true)); - assertThat(parser.parse("~A#B")).isEqualTo(this.f.literal("A#B", false)); - assertThat(parser.parse("#A#B_")).isEqualTo(this.f.literal("#A#B_", true)); - assertThat(parser.parse("~#A#B_")).isEqualTo(this.f.literal("#A#B_", false)); - } - - @Test - public void testParseOperators() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse("~a")).isEqualTo(this.f.not(this.f.variable("a"))); - assertThat(parser.parse("~Var")).isEqualTo(this.f.not(this.f.variable("Var"))); - assertThat(parser.parse("a & b")).isEqualTo(this.f.and(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a & ~b")).isEqualTo(this.f.and(this.f.literal("a", false), this.f.literal("b", false))); - assertThat(parser.parse("~a & b & ~c & d")).isEqualTo(this.f.and(this.f.literal("a", false), this.f.variable("b"), this.f.literal("c", false), this.f.variable("d"))); - assertThat(parser.parse("a | b")).isEqualTo(this.f.or(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a | ~b")).isEqualTo(this.f.or(this.f.literal("a", false), this.f.literal("b", false))); - assertThat(parser.parse("~a | b | ~c | d")).isEqualTo(this.f.or(this.f.literal("a", false), this.f.variable("b"), this.f.literal("c", false), this.f.variable("d"))); - assertThat(parser.parse("a => b")).isEqualTo(this.f.implication(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a => ~b")).isEqualTo(this.f.implication(this.f.literal("a", false), this.f.literal("b", false))); - assertThat(parser.parse("a <=> b")).isEqualTo(this.f.equivalence(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a <=> ~b")).isEqualTo(this.f.equivalence(this.f.literal("a", false), this.f.literal("b", false))); - } - - @Test - public void testParsePrecedences() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse("x | y & z")).isEqualTo(this.f.or(this.f.variable("x"), this.f.and(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x & y | z")).isEqualTo(this.f.or(this.f.and(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => y & z")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.and(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x & y => z")).isEqualTo(this.f.implication(this.f.and(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x <=> y & z")).isEqualTo(this.f.equivalence(this.f.variable("x"), this.f.and(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x & y <=> z")).isEqualTo(this.f.equivalence(this.f.and(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => y | z")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.or(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x | y => z")).isEqualTo(this.f.implication(this.f.or(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x <=> y | z")).isEqualTo(this.f.equivalence(this.f.variable("x"), this.f.or(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x | y <=> z")).isEqualTo(this.f.equivalence(this.f.or(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => y => z")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.implication(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x <=> y <=> z")).isEqualTo(this.f.equivalence(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x | y) & z")).isEqualTo(this.f.and(this.f.or(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x & (y | z)")).isEqualTo(this.f.and(this.f.variable("x"), this.f.or(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x => y) & z")).isEqualTo(this.f.and(this.f.implication(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x & (y => z)")).isEqualTo(this.f.and(this.f.variable("x"), this.f.implication(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x => y) | z")).isEqualTo(this.f.or(this.f.implication(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x | (y => z)")).isEqualTo(this.f.or(this.f.variable("x"), this.f.implication(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x <=> y) & z")).isEqualTo(this.f.and(this.f.equivalence(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x & (y <=> z)")).isEqualTo(this.f.and(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x <=> y) | z")).isEqualTo(this.f.or(this.f.equivalence(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x | (y <=> z)")).isEqualTo(this.f.or(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x => y <=> z")).isEqualTo(this.f.equivalence(this.f.implication(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => (y <=> z)")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - } - - @Test - public void parseInputStream() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - final String string = "A & B => D | ~C"; - final InputStream stream = new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); - assertThat(parser.parse(stream)).isEqualTo(parser.parse(string)); - assertThat(parser.parse((InputStream) null)).isEqualTo(this.f.verum()); - } - - @Test - public void parseEmptyString() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse("")).isEqualTo(this.f.verum()); - assertThat(parser.parse((String) null)).isEqualTo(this.f.verum()); - } - - @Test - public void testFormulaFactory() { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.factory()).isEqualTo(this.f); - } - - @Test - public void testSkipSymbols() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse(" ")).isEqualTo(this.f.verum()); - assertThat(parser.parse("\t")).isEqualTo(this.f.verum()); - assertThat(parser.parse("\n")).isEqualTo(this.f.verum()); - assertThat(parser.parse("\r")).isEqualTo(this.f.verum()); - assertThat(parser.parse(" \r\n\n \t")).isEqualTo(this.f.verum()); - assertThat(parser.parse("a\n&\tb")).isEqualTo(this.AND1); - assertThat(parser.parse(" a\r=>\t\tb")).isEqualTo(this.IMP1); - } - - @Test - public void testNumericalLiteral() throws ParserException { - final PropositionalParser parser = new PropositionalParser(this.f); - assertThat(parser.parse("12")).isEqualTo(this.f.variable("12")); - } - - @Test - public void testIllegalVariable1() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("$$%")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalVariable3() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse(";;23")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalVariable4() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("{0}")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator1() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("A + B")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator2() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("A &")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator3() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("A /")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator4() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("-A")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator5() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("A * B")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalBrackets1() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("(A & B")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula1() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("((A & B)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula2() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("(A & (C & D) B)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula3() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("A | A + (C | B + C)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula4() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("A | A & (C | B & C")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula5() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("A & ~B)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula6() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("12)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula7() { - assertThatThrownBy(() -> new PropositionalParser(this.f).parse("ab@cd)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula8() { - final String string = "A & B => D | ~"; - final InputStream stream = new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); - assertThatThrownBy(() -> new PropositionalParser(this.f).parse(stream)).isInstanceOf(ParserException.class); - - } - - @Test - public void testIllegalFormula9() { - final String string = "@A@B"; - final InputStream stream = new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); - assertThatThrownBy(() -> new PropositionalParser(this.f).parse(stream)).isInstanceOf(ParserException.class); - } - - @Test - public void testToStrings() { - assertThat(new PropositionalLexer(null).toString()).isEqualTo("PropositionalLexer"); - assertThat(new PropositionalParser(this.f).toString()).isEqualTo("PropositionalParser"); - } -} diff --git a/src/main/java/org/logicng/io/parsers/PseudoBooleanLexer.java b/src/test/java/org/logicng/io/parsers/PseudoBooleanLexer.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/PseudoBooleanLexer.java rename to src/test/java/org/logicng/io/parsers/PseudoBooleanLexer.java diff --git a/src/main/java/org/logicng/io/parsers/PseudoBooleanParser.java b/src/test/java/org/logicng/io/parsers/PseudoBooleanParser.java similarity index 100% rename from src/main/java/org/logicng/io/parsers/PseudoBooleanParser.java rename to src/test/java/org/logicng/io/parsers/PseudoBooleanParser.java diff --git a/src/test/java/org/logicng/io/parsers/PseudoBooleanParserTest.java b/src/test/java/org/logicng/io/parsers/PseudoBooleanParserTest.java deleted file mode 100644 index c98547e8..00000000 --- a/src/test/java/org/logicng/io/parsers/PseudoBooleanParserTest.java +++ /dev/null @@ -1,288 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// __ _ _ ________ // -// / / ____ ____ _(_)____/ | / / ____/ // -// / / / __ \/ __ `/ / ___/ |/ / / __ // -// / /___/ /_/ / /_/ / / /__/ /| / /_/ / // -// /_____/\____/\__, /_/\___/_/ |_/\____/ // -// /____/ // -// // -// The Next Generation Logic Library // -// // -/////////////////////////////////////////////////////////////////////////// -// // -// Copyright 2015-20xx Christoph Zengler // -// // -// Licensed under the Apache License, Version 2.0 (the "License"); // -// you may not use this file except in compliance with the License. // -// You may obtain a copy of the License at // -// // -// http://www.apache.org/licenses/LICENSE-2.0 // -// // -// Unless required by applicable law or agreed to in writing, software // -// distributed under the License is distributed on an "AS IS" BASIS, // -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // -// implied. See the License for the specific language governing // -// permissions and limitations under the License. // -// // -/////////////////////////////////////////////////////////////////////////// - -package org.logicng.io.parsers; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import org.junit.jupiter.api.Test; -import org.logicng.TestWithExampleFormulas; -import org.logicng.formulas.CType; -import org.logicng.formulas.Formula; -import org.logicng.formulas.FormulaFactory; -import org.logicng.formulas.Literal; - -/** - * Unit Tests for the class {@link PseudoBooleanParser}. - * @version 4.4.1 - * @since 1.0 - */ -public class PseudoBooleanParserTest extends TestWithExampleFormulas { - - @Test - public void testExceptions() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("")).isEqualTo(this.f.verum()); - assertThat(parser.parse((String) null)).isEqualTo(this.f.verum()); - } - - @Test - public void testParseConstants() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("$true")).isEqualTo(this.f.verum()); - assertThat(parser.parse("$false")).isEqualTo(this.f.falsum()); - } - - @Test - public void testParseLiterals() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("A")).isEqualTo(this.f.variable("A")); - assertThat(parser.parse("a")).isEqualTo(this.f.variable("a")); - assertThat(parser.parse("a1")).isEqualTo(this.f.variable("a1")); - assertThat(parser.parse("aA_Bb_Cc_12_3")).isEqualTo(this.f.variable("aA_Bb_Cc_12_3")); - assertThat(parser.parse("~A")).isEqualTo(this.f.literal("A", false)); - assertThat(parser.parse("~a")).isEqualTo(this.f.literal("a", false)); - assertThat(parser.parse("~aA_Bb_Cc_12_3")).isEqualTo(this.f.literal("aA_Bb_Cc_12_3", false)); - assertThat(parser.parse("#")).isEqualTo(this.f.literal("#", true)); - assertThat(parser.parse("~#")).isEqualTo(this.f.literal("#", false)); - assertThat(parser.parse("~A#B")).isEqualTo(this.f.literal("A#B", false)); - assertThat(parser.parse("A#B")).isEqualTo(this.f.literal("A#B", true)); - assertThat(parser.parse("~A#B")).isEqualTo(this.f.literal("A#B", false)); - assertThat(parser.parse("#A#B_")).isEqualTo(this.f.literal("#A#B_", true)); - assertThat(parser.parse("~#A#B_")).isEqualTo(this.f.literal("#A#B_", false)); - } - - @Test - public void testParseOperators() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("~a")).isEqualTo(this.f.not(this.f.variable("a"))); - assertThat(parser.parse("~Var")).isEqualTo(this.f.not(this.f.variable("Var"))); - assertThat(parser.parse("a & b")).isEqualTo(this.f.and(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a & ~b")).isEqualTo(this.f.and(this.f.literal("a", false), this.f.literal("b", false))); - assertThat(parser.parse("~a & b & ~c & d")).isEqualTo(this.f.and(this.f.literal("a", false), this.f.variable("b"), this.f.literal("c", false), this.f.variable("d"))); - assertThat(parser.parse("a | b")).isEqualTo(this.f.or(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a | ~b")).isEqualTo(this.f.or(this.f.literal("a", false), this.f.literal("b", false))); - assertThat(parser.parse("~a | b | ~c | d")).isEqualTo(this.f.or(this.f.literal("a", false), this.f.variable("b"), this.f.literal("c", false), this.f.variable("d"))); - assertThat(parser.parse("a => b")).isEqualTo(this.f.implication(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a => ~b")).isEqualTo(this.f.implication(this.f.literal("a", false), this.f.literal("b", false))); - assertThat(parser.parse("a <=> b")).isEqualTo(this.f.equivalence(this.f.variable("a"), this.f.variable("b"))); - assertThat(parser.parse("~a <=> ~b")).isEqualTo(this.f.equivalence(this.f.literal("a", false), this.f.literal("b", false))); - } - - @Test - public void testParseMultiplication() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("13 * abc = 4")).isEqualTo(this.f.pbc(CType.EQ, 4, new Literal[]{this.f.variable("abc")}, new int[]{13})); - assertThat(parser.parse("-13 * a = 4")).isEqualTo(this.f.pbc(CType.EQ, 4, new Literal[]{this.f.variable("a")}, new int[]{-13})); - assertThat(parser.parse("13 * ~abc = -442")).isEqualTo(this.f.pbc(CType.EQ, -442, new Literal[]{this.f.literal("abc", false)}, new int[]{13})); - assertThat(parser.parse("-13 * ~a = -442")).isEqualTo(this.f.pbc(CType.EQ, -442, new Literal[]{this.f.literal("a", false)}, new int[]{-13})); - assertThat(parser.parse("13 * abc = 4")).isEqualTo(this.f.pbc(CType.EQ, 4, new Literal[]{this.f.variable("abc")}, new int[]{13})); - assertThat(parser.parse("13 * abc > 4")).isEqualTo(this.f.pbc(CType.GT, 4, new Literal[]{this.f.variable("abc")}, new int[]{13})); - assertThat(parser.parse("13 * abc >= 4")).isEqualTo(this.f.pbc(CType.GE, 4, new Literal[]{this.f.variable("abc")}, new int[]{13})); - assertThat(parser.parse("13 * abc < 4")).isEqualTo(this.f.pbc(CType.LT, 4, new Literal[]{this.f.variable("abc")}, new int[]{13})); - assertThat(parser.parse("13 * abc <= 4")).isEqualTo(this.f.pbc(CType.LE, 4, new Literal[]{this.f.variable("abc")}, new int[]{13})); - } - - @Test - public void testParseAddition() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("4 * c + -4 * ~d < -4")).isEqualTo(this.f.pbc(CType.LT, -4, new Literal[]{this.f.variable("c"), this.f.literal("d", false)}, new int[]{4, -4})); - assertThat(parser.parse("5 * c + -5 * ~c >= -5")).isEqualTo(this.f.pbc(CType.GE, -5, new Literal[]{this.f.variable("c"), this.f.literal("c", false)}, new int[]{5, -5})); - assertThat(parser.parse("6 * a + -6 * ~b + 12 * ~c > -6")).isEqualTo(this.f.pbc(CType.GT, -6, new Literal[]{this.f.variable("a"), this.f.literal("b", false), this.f.literal("c", false)}, new int[]{6, -6, 12})); - assertThat(parser.parse("c + -4 * ~d < -4")).isEqualTo(this.f.pbc(CType.LT, -4, new Literal[]{this.f.variable("c"), this.f.literal("d", false)}, new int[]{1, -4})); - assertThat(parser.parse("5 * c + ~c >= -5")).isEqualTo(this.f.pbc(CType.GE, -5, new Literal[]{this.f.variable("c"), this.f.literal("c", false)}, new int[]{5, 1})); - assertThat(parser.parse("c + d >= -5")).isEqualTo(this.f.pbc(CType.GE, -5, new Literal[]{this.f.variable("c"), this.f.literal("d", true)}, new int[]{1, 1})); - assertThat(parser.parse("~c + ~d >= -5")).isEqualTo(this.f.pbc(CType.GE, -5, new Literal[]{this.f.literal("c", false), this.f.literal("d", false)}, new int[]{1, 1})); - assertThat(parser.parse("~c = -5")).isEqualTo(this.f.pbc(CType.EQ, -5, new Literal[]{this.f.literal("c", false)}, new int[]{1})); - assertThat(parser.parse("~(c = -5)")).isEqualTo(this.f.not(this.f.pbc(CType.EQ, -5, new Literal[]{this.f.literal("c", true)}, new int[]{1}))); - } - - @Test - public void testCombination() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - final Formula pbc = this.f.pbc(CType.GT, -6, new Literal[]{this.f.variable("a"), this.f.literal("b", false), this.f.literal("c", false)}, new int[]{6, -6, 12}); - assertThat(parser.parse("(x => y & z) & (6 * a + -6 * ~b + 12 * ~c > -6)")).isEqualTo(this.f.and(this.f.implication(this.f.variable("x"), this.f.and(this.f.variable("y"), this.f.variable("z"))), pbc)); - assertThat(parser.parse("~(6 * a - 6 * ~b - -12 * ~c > -6)")).isEqualTo(this.f.not(pbc)); - } - - @Test - public void testParsePrecedences() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("x | y & z")).isEqualTo(this.f.or(this.f.variable("x"), this.f.and(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x & y | z")).isEqualTo(this.f.or(this.f.and(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => y & z")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.and(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x & y => z")).isEqualTo(this.f.implication(this.f.and(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x <=> y & z")).isEqualTo(this.f.equivalence(this.f.variable("x"), this.f.and(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x & y <=> z")).isEqualTo(this.f.equivalence(this.f.and(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => y | z")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.or(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x | y => z")).isEqualTo(this.f.implication(this.f.or(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x <=> y | z")).isEqualTo(this.f.equivalence(this.f.variable("x"), this.f.or(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x | y <=> z")).isEqualTo(this.f.equivalence(this.f.or(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => y => z")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.implication(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x <=> y <=> z")).isEqualTo(this.f.equivalence(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x | y) & z")).isEqualTo(this.f.and(this.f.or(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x & (y | z)")).isEqualTo(this.f.and(this.f.variable("x"), this.f.or(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x => y) & z")).isEqualTo(this.f.and(this.f.implication(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x & (y => z)")).isEqualTo(this.f.and(this.f.variable("x"), this.f.implication(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x => y) | z")).isEqualTo(this.f.or(this.f.implication(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x | (y => z)")).isEqualTo(this.f.or(this.f.variable("x"), this.f.implication(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x <=> y) & z")).isEqualTo(this.f.and(this.f.equivalence(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x & (y <=> z)")).isEqualTo(this.f.and(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("(x <=> y) | z")).isEqualTo(this.f.or(this.f.equivalence(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x | (y <=> z)")).isEqualTo(this.f.or(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - assertThat(parser.parse("x => y <=> z")).isEqualTo(this.f.equivalence(this.f.implication(this.f.variable("x"), this.f.variable("y")), this.f.variable("z"))); - assertThat(parser.parse("x => (y <=> z)")).isEqualTo(this.f.implication(this.f.variable("x"), this.f.equivalence(this.f.variable("y"), this.f.variable("z")))); - } - - @Test - public void parseEmptyString() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse("")).isEqualTo(this.f.verum()); - } - - @Test - public void testSkipSymbols() throws ParserException { - final PseudoBooleanParser parser = new PseudoBooleanParser(this.f); - assertThat(parser.parse(" ")).isEqualTo(this.f.verum()); - assertThat(parser.parse("\t")).isEqualTo(this.f.verum()); - assertThat(parser.parse("\n")).isEqualTo(this.f.verum()); - assertThat(parser.parse("\r")).isEqualTo(this.f.verum()); - assertThat(parser.parse(" \r\n\n \t")).isEqualTo(this.f.verum()); - assertThat(parser.parse("a\n&\tb")).isEqualTo(this.AND1); - assertThat(parser.parse(" a\r=>\t\tb")).isEqualTo(this.IMP1); - assertThat(parser.parse(" 2\n*a\r+\n\n-4*\tb +3*x=2")).isEqualTo(this.PBC1); - } - - @Test - public void testNumberLiterals() throws ParserException { - final FormulaFactory f = new FormulaFactory(); - final PseudoBooleanParser parser = new PseudoBooleanParser(f); - assertThat(parser.parse("12 & A")).isEqualTo(f.and(f.variable("12"), f.variable("A"))); - assertThat(parser.parse("~12 & A")).isEqualTo(f.and(f.literal("12", false), f.variable("A"))); - assertThat(parser.parse("12 * 12 + 13 * A + 10 * B <= 25")).isEqualTo(f.pbc(CType.LE, 25, new Literal[]{f.variable("12"), f.variable("A"), f.variable("B")}, new int[]{12, 13, 10})); - assertThat(parser.parse("-12 * ~12 + 13 * A + 10 * B <= 25")).isEqualTo(f.pbc(CType.LE, 25, new Literal[]{f.literal("12", false), f.variable("A"), f.variable("B")}, new int[]{-12, 13, 10})); - } - - @Test - public void testFormulaFactoryParser() throws ParserException { - assertThat(this.f.parse("a & b")).isEqualTo(this.f.and(this.f.variable("a"), this.f.variable("b"))); - assertThat(this.f.parse("2*a + -4*b + 3*x = 2")).isEqualTo(this.PBC1); - } - - @Test - public void testIllegalVariable1() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("$$%")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalVariable3() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse(";;23")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalVariable4() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("{0}")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator1() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("A + B")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator2() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("A &")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator3() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("A /")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator4() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("-A")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalOperator5() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("A * B")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalBrackets1() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("(A & B")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula1() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("((A & B)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula2() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("(A & (C & D) B)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula3() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("A | A + (C | B + C)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula4() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("A | A & (C | B & C")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula5() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("A & ~B)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula6() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("12)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalFormula7() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("ab@cd)")).isInstanceOf(ParserException.class); - } - - @Test - public void testIllegalSkipPosition() { - assertThatThrownBy(() -> new PseudoBooleanParser(this.f).parse("- 1*x <= 3")).isInstanceOf(ParserException.class); - } - - @Test - public void testToStrings() { - assertThat(new PseudoBooleanLexer(null).toString()).isEqualTo("PseudoBooleanLexer"); - assertThat(new PseudoBooleanParser(this.f).toString()).isEqualTo("PseudoBooleanParser"); - } -} diff --git a/src/main/java/org/logicng/io/readers/FormulaReader.java b/src/test/java/org/logicng/io/readers/FormulaReader.java similarity index 100% rename from src/main/java/org/logicng/io/readers/FormulaReader.java rename to src/test/java/org/logicng/io/readers/FormulaReader.java diff --git a/src/test/java/org/logicng/io/writers/FormulaDimacsFileWriterTest.java b/src/test/java/org/logicng/io/writers/FormulaDimacsFileWriterTest.java index 5316bfce..927ba190 100644 --- a/src/test/java/org/logicng/io/writers/FormulaDimacsFileWriterTest.java +++ b/src/test/java/org/logicng/io/writers/FormulaDimacsFileWriterTest.java @@ -90,7 +90,7 @@ public void testFormulas() throws IOException, ParserException { } @Test - public void testDuplicateFormulaParts() throws ParserException, IOException { + public void testDuplicateFormulaParts() throws IOException, ParserException { final Formula f6 = this.encoder.encode(this.p.parse("(a & b) | (c & ~(a & b))")); testFiles("f6", f6); final Formula f7 = this.encoder.encode(this.p.parse("(c & d) | (a & b) | ((c & d) <=> (a & b))")); diff --git a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDConstructionTests.java b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDConstructionTests.java index 5f7baa42..9ba6cc5f 100644 --- a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDConstructionTests.java +++ b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDConstructionTests.java @@ -29,13 +29,13 @@ package org.logicng.knowledgecompilation.bdds; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Variable; -import org.logicng.io.parsers.ParserException; import org.logicng.knowledgecompilation.bdds.jbuddy.BDDKernel; import java.util.List; @@ -56,12 +56,12 @@ public class BDDConstructionTests { BDD secondBdd; @BeforeEach - public void init() throws ParserException { + public void init() { this.f = new FormulaFactory(); this.variables = this.f.variables("a", "b", "c", "d", "e", "f", "g"); this.kernel = new BDDKernel(this.f, this.variables, 1000, 10000); - this.initFormula = this.f.parse("(a & b) => (c | d & ~e)"); - this.secondFormula = this.f.parse("(g & f) <=> (c | ~a | ~d)"); + this.initFormula = parse(this.f, "(a & b) => (c | d & ~e)"); + this.secondFormula = parse(this.f, "(g & f) <=> (c | ~a | ~d)"); this.initBdd = BDDFactory.build(this.initFormula, this.kernel); this.secondBdd = BDDFactory.build(this.secondFormula, this.kernel); } diff --git a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDOperationsTest.java b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDOperationsTest.java index 11a1b0b7..a19ae29c 100644 --- a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDOperationsTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDOperationsTest.java @@ -29,6 +29,7 @@ package org.logicng.knowledgecompilation.bdds; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -87,7 +88,7 @@ public void init() throws ParserException { } @Test - public void testToFormula() throws ParserException { + public void testToFormula() { assertThat(this.bddVerum.toFormula()).isEqualTo(this.f.verum()); assertThat(this.bddFalsum.toFormula()).isEqualTo(this.f.falsum()); assertThat(this.bddPosLit.toFormula()).isEqualTo(this.f.literal("A", true)); @@ -101,12 +102,12 @@ public void testToFormula() throws ParserException { } @Test - public void testToFormulaStyles() throws ParserException { - final BDD bdd = BDDFactory.build(this.f.parse("~A | ~B | ~C"), this.kernel); - final Formula expFollowPathsToTrue = this.f.parse("~A | A & (~B | B & ~C)"); + public void testToFormulaStyles() { + final BDD bdd = BDDFactory.build(parse(this.f, "~A | ~B | ~C"), this.kernel); + final Formula expFollowPathsToTrue = parse(this.f, "~A | A & (~B | B & ~C)"); assertThat(bdd.toFormula()).isEqualTo(expFollowPathsToTrue); assertThat(bdd.toFormula(true)).isEqualTo(expFollowPathsToTrue); - assertThat(bdd.toFormula(false)).isEqualTo(this.f.parse("~(A & B & C)")); + assertThat(bdd.toFormula(false)).isEqualTo(parse(this.f, "~(A & B & C)")); } @RandomTag @@ -329,8 +330,8 @@ public void testVariableProfile() { assertThat(this.bddAnd.variableProfile()).containsExactly(a1, b1, c1); } - private void compareFormula(final BDD bdd, final String formula) throws ParserException { - compareFormula(bdd, bdd.kernel.factory().parse(formula)); + private void compareFormula(final BDD bdd, final String formula) { + compareFormula(bdd, parse(bdd.kernel.factory(), formula)); } private void compareFormula(final BDD bdd, final Formula compareFormula) { diff --git a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java index 858f8f6d..f27986b6 100644 --- a/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/bdds/BDDReorderingTest.java @@ -37,7 +37,6 @@ import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Variable; -import org.logicng.io.parsers.ParserException; import org.logicng.knowledgecompilation.bdds.datastructures.BDDConstant; import org.logicng.knowledgecompilation.bdds.datastructures.BDDInnerNode; import org.logicng.knowledgecompilation.bdds.functions.LngBDDFunction; @@ -84,7 +83,7 @@ public void testExceptionalBehavior() { assertThatThrownBy(() -> { final BDDKernel kernel = new BDDKernel(this.f, Arrays.asList(this.A, this.B), 100, 100); final BDDReordering reordering = new BDDReordering(kernel); - final Formula formula = this.f.parse("a | b"); + final Formula formula = parse(this.f, "a | b"); BDDFactory.build(formula, kernel); reordering.swapVariables(0, 2); }).isInstanceOf(IllegalArgumentException.class) @@ -92,7 +91,7 @@ public void testExceptionalBehavior() { assertThatThrownBy(() -> { final BDDKernel kernel = new BDDKernel(this.f, Arrays.asList(this.A, this.B), 100, 100); final BDDReordering reordering = new BDDReordering(kernel); - final Formula formula = this.f.parse("a | b"); + final Formula formula = parse(this.f, "a | b"); BDDFactory.build(formula, kernel); reordering.swapVariables(3, 0); }).isInstanceOf(IllegalArgumentException.class) @@ -100,9 +99,9 @@ public void testExceptionalBehavior() { } @Test - public void testSwapping() throws ParserException { + public void testSwapping() { final BDDKernel kernel = new BDDKernel(this.f, Arrays.asList(this.A, this.B, this.C), 100, 100); - final Formula formula = this.f.parse("a | b | c"); + final Formula formula = parse(this.f, "a | b | c"); final BDD bdd = BDDFactory.build(formula, kernel); assertThat(bdd.getVariableOrder()).containsExactly(this.A, this.B, this.C); kernel.swapVariables(this.A, this.B); @@ -126,10 +125,10 @@ public void testSwapping() throws ParserException { } @Test - public void testSwappingMultipleBdds() throws ParserException { + public void testSwappingMultipleBdds() { final BDDKernel kernel = new BDDKernel(this.f, Arrays.asList(this.A, this.B, this.C), 100, 100); - final Formula formula1 = this.f.parse("a | b | c"); - final Formula formula2 = this.f.parse("a & b"); + final Formula formula1 = parse(this.f, "a | b | c"); + final Formula formula2 = parse(this.f, "a & b"); final BDD bdd1 = BDDFactory.build(formula1, kernel); final BDD bdd2 = BDDFactory.build(formula2, kernel); assertThat(bdd1.getVariableOrder()).containsExactly(this.A, this.B, this.C); @@ -146,11 +145,11 @@ public void testSwappingMultipleBdds() throws ParserException { } @Test - public void testReorderingAndFormulaGeneration() throws ParserException { + public void testReorderingAndFormulaGeneration() { final List order = this.f.variables("a", "b", "c", "d", "e", "f"); - final Formula formula1 = this.f.parse("a & b <=> (~c | d) & f"); - final Formula formula2 = this.f.parse("a => c & ~d | e | f"); - final Formula formula3 = this.f.parse("a => b <=> (~a | d) & c | f"); + final Formula formula1 = parse(this.f, "a & b <=> (~c | d) & f"); + final Formula formula2 = parse(this.f, "a => c & ~d | e | f"); + final Formula formula3 = parse(this.f, "a => b <=> (~a | d) & c | f"); for (final BDDReorderingMethod method : REORDER_METHODS) { final BDDKernel kernel = new BDDKernel(this.f, order, 100, 100); @@ -167,32 +166,32 @@ public void testReorderingAndFormulaGeneration() throws ParserException { } @Test - public void testSwappingAndFormulaGeneration() throws ParserException { + public void testSwappingAndFormulaGeneration() { final List order = this.f.variables("a", "b", "c", "d", "e", "f"); - final Formula formula1 = this.f.parse("a | b | c"); - final Formula formula2 = this.f.parse("a => b & ~c | ~d"); - final Formula formula3 = this.f.parse("a & b <=> (~c | d) & f"); + final Formula formula1 = parse(this.f, "a | b | c"); + final Formula formula2 = parse(this.f, "a => b & ~c | ~d"); + final Formula formula3 = parse(this.f, "a & b <=> (~c | d) & f"); final BDDKernel kernel = new BDDKernel(this.f, order, 100, 100); final BDD bdd1 = BDDFactory.build(formula1, kernel); final BDD bdd2 = BDDFactory.build(formula2, kernel); - assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~a & (~b & c | b) | a")); - assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~a | a & (~b & ~d | b & (~c | c & ~d))")); + assertThat(bdd1.toFormula()).isEqualTo(parse(this.f, "~a & (~b & c | b) | a")); + assertThat(bdd2.toFormula()).isEqualTo(parse(this.f, "~a | a & (~b & ~d | b & (~c | c & ~d))")); kernel.swapVariables(this.f.variable("a"), this.f.variable("b")); // also affects bdd2 and upcoming bdd3 - assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~b & (~a & c | a) | b")); - assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~b & (~a | a & ~d) | b & (~a | a & (~c | c & ~d))")); + assertThat(bdd1.toFormula()).isEqualTo(parse(this.f, "~b & (~a & c | a) | b")); + assertThat(bdd2.toFormula()).isEqualTo(parse(this.f, "~b & (~a | a & ~d) | b & (~a | a & (~c | c & ~d))")); final BDD bdd3 = BDDFactory.build(formula3, kernel); - assertThat(bdd3.toFormula()).isEqualTo(this.f.parse("~b & (~c & ~f | c & (~d | d & ~f)) | b & (~a & (~c & ~f | c & (~d | d & ~f)) | a & (~c & f | c & d & f))")); + assertThat(bdd3.toFormula()).isEqualTo(parse(this.f, "~b & (~c & ~f | c & (~d | d & ~f)) | b & (~a & (~c & ~f | c & (~d | d & ~f)) | a & (~c & f | c & d & f))")); kernel.swapVariables(this.f.variable("a"), this.f.variable("d")); - assertThat(bdd1.toFormula()).isEqualTo(this.f.parse("~b & (~c & a | c) | b")); - assertThat(bdd2.toFormula()).isEqualTo(this.f.parse("~b & (~d | d & ~a) | b & (~d | d & (~c | c & ~a))")); - assertThat(bdd3.toFormula()).isEqualTo(this.f.parse("~b & (~d & (~c & ~f | c) | d & ~f) | b & (~d & (~c & (~a & ~f | a & f) | ~a & c) | d & (~a & ~f | a & f))")); + assertThat(bdd1.toFormula()).isEqualTo(parse(this.f, "~b & (~c & a | c) | b")); + assertThat(bdd2.toFormula()).isEqualTo(parse(this.f, "~b & (~d | d & ~a) | b & (~d | d & (~c | c & ~a))")); + assertThat(bdd3.toFormula()).isEqualTo(parse(this.f, "~b & (~d & (~c & ~f | c) | d & ~f) | b & (~d & (~c & (~a & ~f | a & f) | ~a & c) | d & (~a & ~f | a & f))")); } @Test diff --git a/src/test/java/org/logicng/knowledgecompilation/bdds/FormulaBDDTest.java b/src/test/java/org/logicng/knowledgecompilation/bdds/FormulaBDDTest.java index dd0d5c31..efb97a39 100644 --- a/src/test/java/org/logicng/knowledgecompilation/bdds/FormulaBDDTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/bdds/FormulaBDDTest.java @@ -29,6 +29,7 @@ package org.logicng.knowledgecompilation.bdds; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.datastructures.Assignment; @@ -89,9 +90,9 @@ public void testBDDGeneration() throws ParserException { } @Test - public void testNonNnfs() throws ParserException { + public void testNonNnfs() { final FormulaFactory f = new FormulaFactory(); - assertThat(f.parse("A + 2*B - C = 1").bdd()).isNotNull(); - assertThat(f.parse("(A & B & C | D & E & F) & (A - 2*B -D <= 0) | (C + 3*D - F > 0)").bdd()).isNotNull(); + assertThat(parse(f, "A + 2*B - C = 1").bdd()).isNotNull(); + assertThat(parse(f, "(A & B & C | D & E & F) & (A - 2*B -D <= 0) | (C + 3*D - F > 0)").bdd()).isNotNull(); } } diff --git a/src/test/java/org/logicng/knowledgecompilation/bdds/LargeBDDTest.java b/src/test/java/org/logicng/knowledgecompilation/bdds/LargeBDDTest.java index 3bf2fc56..c76eebed 100644 --- a/src/test/java/org/logicng/knowledgecompilation/bdds/LargeBDDTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/bdds/LargeBDDTest.java @@ -29,13 +29,13 @@ package org.logicng.knowledgecompilation.bdds; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.handlers.NumberOfNodesBDDHandler; import org.logicng.handlers.TimeoutBDDHandler; -import org.logicng.io.parsers.ParserException; import org.logicng.knowledgecompilation.bdds.jbuddy.BDDKernel; import org.logicng.testutils.NQueensGenerator; import org.logicng.testutils.PigeonHoleGenerator; @@ -142,9 +142,9 @@ public void testNumberOfNodesHandlerLarge() { } @Test - public void testNumberOfNodesHandler() throws ParserException { + public void testNumberOfNodesHandler() { final FormulaFactory f = new FormulaFactory(); - final Formula formula = f.parse("A <=> ~(B => C & F & G & ~H | A & D & ~E)"); + final Formula formula = parse(f, "A <=> ~(B => C & F & G & ~H | A & D & ~E)"); final BDDKernel kernel = new BDDKernel(f, formula.variables().size(), 10000, 10000); final NumberOfNodesBDDHandler handler = new NumberOfNodesBDDHandler(5); final BDD bdd = BDDFactory.build(formula, kernel, handler); diff --git a/src/test/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/DTreeNodeTest.java b/src/test/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/DTreeNodeTest.java index 48029cc5..4d50f0e1 100644 --- a/src/test/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/DTreeNodeTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/dnnf/datastructures/dtree/DTreeNodeTest.java @@ -32,7 +32,6 @@ import org.junit.jupiter.api.Test; import org.logicng.TestWithExampleFormulas; -import org.logicng.io.parsers.ParserException; /** * Unit tests for {@link DTreeNode}. @@ -42,8 +41,8 @@ public class DTreeNodeTest extends TestWithExampleFormulas { @Test - public void testToString() throws ParserException { - final DTreeNode node = new DTreeNode(new DTreeLeaf(1, this.f.parse("a | b")), new DTreeLeaf(2, this.f.parse("c | d"))); + public void testToString() { + final DTreeNode node = new DTreeNode(new DTreeLeaf(1, parse(this.f, "a | b")), new DTreeLeaf(2, parse(this.f, "c | d"))); assertThat(node.toString()).isEqualTo("DTreeNode: [DTreeLeaf: 1, a | b, DTreeLeaf: 2, c | d]"); } } diff --git a/src/test/java/org/logicng/modelcounting/ModelCounterTest.java b/src/test/java/org/logicng/modelcounting/ModelCounterTest.java index f74ef892..178f6dcb 100644 --- a/src/test/java/org/logicng/modelcounting/ModelCounterTest.java +++ b/src/test/java/org/logicng/modelcounting/ModelCounterTest.java @@ -42,7 +42,6 @@ import org.logicng.formulas.PBConstraint; import org.logicng.formulas.Variable; import org.logicng.handlers.DnnfCompilationHandler; -import org.logicng.io.parsers.ParserException; import org.logicng.io.readers.DimacsReader; import org.logicng.knowledgecompilation.bdds.orderings.VariableOrdering; import org.logicng.solvers.MiniSat; @@ -77,7 +76,7 @@ private SortedSet vars(final String... vars) { @Test public void testWrongArgument() { assertThrows(IllegalArgumentException.class, () -> - ModelCounter.count(Collections.singletonList(this.f.parse("a & b")), new TreeSet<>(Collections.singletonList(this.A)))); + ModelCounter.count(Collections.singletonList(parse(this.f, "a & b")), new TreeSet<>(Collections.singletonList(this.A)))); } @Test @@ -94,40 +93,40 @@ public void testConstants() { } @Test - public void testSimple() throws ParserException { - final Formula formula01 = this.f.parse("(~v1 => ~v0) | ~v1 | v0"); + public void testSimple() { + final Formula formula01 = parse(this.f, "(~v1 => ~v0) | ~v1 | v0"); assertThat(ModelCounter.count(Collections.singletonList(formula01), formula01.variables())).isEqualTo(BigInteger.valueOf(4)); - final List formulas02 = Arrays.asList(this.f.parse("(a & b) | ~b"), this.f.parse("a")); + final List formulas02 = Arrays.asList(parse(this.f, "(a & b) | ~b"), parse(this.f, "a")); assertThat(ModelCounter.count(formulas02, FormulaHelper.variables(formulas02))).isEqualTo(BigInteger.valueOf(2)); - final List formulas03 = Arrays.asList(this.f.parse("a & b & c"), this.f.parse("c & d")); + final List formulas03 = Arrays.asList(parse(this.f, "a & b & c"), parse(this.f, "c & d")); assertThat(ModelCounter.count(formulas03, FormulaHelper.variables(formulas03))).isEqualTo(BigInteger.valueOf(1)); } @Test - public void testAmoAndExo() throws ParserException { - final List formulas01 = Arrays.asList(this.f.parse("a & b"), this.f.parse("a + b + c + d <= 1")); + public void testAmoAndExo() { + final List formulas01 = Arrays.asList(parse(this.f, "a & b"), parse(this.f, "a + b + c + d <= 1")); assertThat(ModelCounter.count(formulas01, FormulaHelper.variables(formulas01))).isEqualTo(BigInteger.valueOf(0)); - final List formulas02 = Arrays.asList(this.f.parse("a & b & (a + b + c + d <= 1)"), this.f.parse("a | b")); + final List formulas02 = Arrays.asList(parse(this.f, "a & b & (a + b + c + d <= 1)"), parse(this.f, "a | b")); assertThat(ModelCounter.count(formulas02, FormulaHelper.variables(formulas02))).isEqualTo(BigInteger.valueOf(0)); - final List formulas03 = Arrays.asList(this.f.parse("a & (a + b + c + d <= 1)"), this.f.parse("a | b")); + final List formulas03 = Arrays.asList(parse(this.f, "a & (a + b + c + d <= 1)"), parse(this.f, "a | b")); assertThat(ModelCounter.count(formulas03, FormulaHelper.variables(formulas03))).isEqualTo(BigInteger.valueOf(1)); - final List formulas04 = Arrays.asList(this.f.parse("a & (a + b + c + d = 1)"), this.f.parse("a | b")); + final List formulas04 = Arrays.asList(parse(this.f, "a & (a + b + c + d = 1)"), parse(this.f, "a | b")); assertThat(ModelCounter.count(formulas04, FormulaHelper.variables(formulas04))).isEqualTo(BigInteger.valueOf(1)); } @Test - public void testNonAmoAndExo() throws ParserException { - final List formulas01 = Arrays.asList(this.f.parse("a & b"), this.f.parse("a + b + c + d = 2")); + public void testNonAmoAndExo() { + final List formulas01 = Arrays.asList(parse(this.f, "a & b"), parse(this.f, "a + b + c + d = 2")); assertThatThrownBy(() -> ModelCounter.count(formulas01, FormulaHelper.variables(formulas01))) .isInstanceOf(UnsupportedOperationException.class) .hasMessage("Pure encoding for a PBC of type other than AMO or EXO is currently not supported."); - final List formulas02 = Arrays.asList(this.f.parse("a & b"), this.f.parse("c | a & (b + c + d <= 4)")); + final List formulas02 = Arrays.asList(parse(this.f, "a & b"), parse(this.f, "c | a & (b + c + d <= 4)")); assertThatThrownBy(() -> ModelCounter.count(formulas02, FormulaHelper.variables(formulas02))) .isInstanceOf(UnsupportedOperationException.class) .hasMessage("Pure encoding for a PBC of type other than AMO or EXO is currently not supported."); diff --git a/src/test/java/org/logicng/predicates/ContainsPBCPredicateTest.java b/src/test/java/org/logicng/predicates/ContainsPBCPredicateTest.java index 1ac622e9..076c37ba 100644 --- a/src/test/java/org/logicng/predicates/ContainsPBCPredicateTest.java +++ b/src/test/java/org/logicng/predicates/ContainsPBCPredicateTest.java @@ -35,7 +35,6 @@ import org.logicng.TestWithExampleFormulas; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.util.FormulaRandomizer; import org.logicng.util.FormulaRandomizerConfig; @@ -61,26 +60,26 @@ public void testLiterals() { } @Test - public void testNot() throws ParserException { - assertThat(this.f.parse("~a").holds(this.predicate)).isFalse(); - assertThat(this.f.parse("~(a | b)").holds(this.predicate)).isFalse(); + public void testNot() { + assertThat(parse(this.f, "~a").holds(this.predicate)).isFalse(); + assertThat(parse(this.f, "~(a | b)").holds(this.predicate)).isFalse(); - assertThat(this.f.parse("~(a | (a + b = 3))").holds(this.predicate)).isTrue(); - assertThat(this.f.parse("~(a & ~(a + b = 3))").holds(this.predicate)).isTrue(); + assertThat(parse(this.f, "~(a | (a + b = 3))").holds(this.predicate)).isTrue(); + assertThat(parse(this.f, "~(a & ~(a + b = 3))").holds(this.predicate)).isTrue(); } @Test - public void testMixed() throws ParserException { - assertThat(this.f.parse("a => b").holds(this.predicate)).isFalse(); - assertThat(this.f.parse("a <=> b").holds(this.predicate)).isFalse(); - assertThat(this.f.parse("a => (b | c & ~(e | d))").holds(this.predicate)).isFalse(); - assertThat(this.f.parse("a <=> (b | c & ~(e | d))").holds(this.predicate)).isFalse(); + public void testMixed() { + assertThat(parse(this.f, "a => b").holds(this.predicate)).isFalse(); + assertThat(parse(this.f, "a <=> b").holds(this.predicate)).isFalse(); + assertThat(parse(this.f, "a => (b | c & ~(e | d))").holds(this.predicate)).isFalse(); + assertThat(parse(this.f, "a <=> (b | c & ~(e | d))").holds(this.predicate)).isFalse(); - assertThat(this.f.parse("a => (3*a + ~b <= 4)").holds(this.predicate)).isTrue(); - assertThat(this.f.parse("(3*a + ~b <= 4) <=> b").holds(this.predicate)).isTrue(); - assertThat(this.f.parse("a => (b | c & (3*a + ~b <= 4) & ~(e | d))").holds(this.predicate)).isTrue(); - assertThat(this.f.parse("a <=> (b | c & ~(e | (3*a + ~b <= 4) | d))").holds(this.predicate)).isTrue(); - assertThat(this.f.parse("3*a + ~b <= 4").holds(this.predicate)).isTrue(); + assertThat(parse(this.f, "a => (3*a + ~b <= 4)").holds(this.predicate)).isTrue(); + assertThat(parse(this.f, "(3*a + ~b <= 4) <=> b").holds(this.predicate)).isTrue(); + assertThat(parse(this.f, "a => (b | c & (3*a + ~b <= 4) & ~(e | d))").holds(this.predicate)).isTrue(); + assertThat(parse(this.f, "a <=> (b | c & ~(e | (3*a + ~b <= 4) | d))").holds(this.predicate)).isTrue(); + assertThat(parse(this.f, "3*a + ~b <= 4").holds(this.predicate)).isTrue(); } @Test diff --git a/src/test/java/org/logicng/predicates/EvaluatesToConstantPredicateTest.java b/src/test/java/org/logicng/predicates/EvaluatesToConstantPredicateTest.java index 098e8a7d..30f588fe 100644 --- a/src/test/java/org/logicng/predicates/EvaluatesToConstantPredicateTest.java +++ b/src/test/java/org/logicng/predicates/EvaluatesToConstantPredicateTest.java @@ -42,7 +42,6 @@ import org.logicng.formulas.Literal; import org.logicng.formulas.PBConstraint; import org.logicng.formulas.Variable; -import org.logicng.io.parsers.ParserException; import org.logicng.util.FormulaCornerCases; import org.logicng.util.FormulaRandomizer; import org.logicng.util.FormulaRandomizerConfig; @@ -123,166 +122,166 @@ public void testLiteralsToFalse() { } @Test - public void testNotToFalse() throws ParserException { - assertThat(this.f.parse("~~a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~~a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~~a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~~~a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~~~a").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~~~a").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~(a & b)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~(a & b)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~(a & b)").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~(~a & b)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~(~a & b)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~(~a & b)").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~(a & ~b)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~(a & ~b)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~(a & ~b)").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~(~a & ~b)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~(~a & ~b)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~(~a & ~b)").holds(this.aNotBToFalse)).isFalse(); + public void testNotToFalse() { + assertThat(parse(this.f, "~~a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~~a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~~a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~~~a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~~~a").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~~~a").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~(a & b)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~(a & b)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~(a & b)").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~(~a & b)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~(~a & b)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~(~a & b)").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~(a & ~b)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~(a & ~b)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~(a & ~b)").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~(~a & ~b)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~(~a & ~b)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~(~a & ~b)").holds(this.aNotBToFalse)).isFalse(); } @Test - public void testAndToFalse() throws ParserException { - assertThat(this.f.parse("a & ~a").holds(this.emptyToFalse)).isTrue(); - assertThat(this.f.parse("a & ~a").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("a & ~a").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("a & b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & b").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~a & b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a & b").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~a & b").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("a & ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & ~b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & ~b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~a & ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a & ~b").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~a & ~b").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~a & ~b & c & ~d").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a & ~b & c & ~d").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~a & ~b & c & ~d").holds(this.aNotBToFalse)).isTrue(); + public void testAndToFalse() { + assertThat(parse(this.f, "a & ~a").holds(this.emptyToFalse)).isTrue(); + assertThat(parse(this.f, "a & ~a").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "a & ~a").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "a & b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & b").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~a & b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a & b").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~a & b").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "a & ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & ~b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & ~b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~a & ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a & ~b").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~a & ~b").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~a & ~b & c & ~d").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a & ~b & c & ~d").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~a & ~b & c & ~d").holds(this.aNotBToFalse)).isTrue(); } @Test - public void testOrToFalse() throws ParserException { - assertThat(this.f.parse("a | b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a | b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a | b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~a | b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a | b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~a | b").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("a | ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a | ~b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a | ~b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~a | ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a | ~b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~a | ~b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~a | ~b | c | ~d").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a | ~b | c | ~d").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~a | ~b | c | ~d").holds(this.aNotBToFalse)).isFalse(); + public void testOrToFalse() { + assertThat(parse(this.f, "a | b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a | b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a | b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~a | b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a | b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~a | b").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "a | ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a | ~b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a | ~b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~a | ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a | ~b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~a | ~b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~a | ~b | c | ~d").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a | ~b | c | ~d").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~a | ~b | c | ~d").holds(this.aNotBToFalse)).isFalse(); } @Test - public void testImplicationToFalse() throws ParserException { - assertThat(this.f.parse("a => a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a => a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a => a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("b => b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("b => b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("b => b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a => b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a => b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a => b").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~a => b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a => b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~a => b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a => ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a => ~b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a => ~b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~a => ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a => ~b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~a => ~b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("b => a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("b => a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("b => a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~b => a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~b => a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~b => a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("b => ~a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("b => ~a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("b => ~a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~b => ~a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~b => ~a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~b => ~a").holds(this.aNotBToFalse)).isTrue(); + public void testImplicationToFalse() { + assertThat(parse(this.f, "a => a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a => a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a => a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "b => b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "b => b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "b => b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a => b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a => b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a => b").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~a => b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a => b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~a => b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a => ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a => ~b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a => ~b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~a => ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a => ~b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~a => ~b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "b => a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "b => a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "b => a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~b => a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~b => a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~b => a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "b => ~a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "b => ~a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "b => ~a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~b => ~a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~b => ~a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~b => ~a").holds(this.aNotBToFalse)).isTrue(); } @Test - public void testEquivalenceToFalse() throws ParserException { - assertThat(this.f.parse("a <=> a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a <=> a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a <=> a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("b <=> b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("b <=> b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("b <=> b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a <=> b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a <=> b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a <=> b").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~a <=> b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a <=> b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~a <=> b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a <=> ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a <=> ~b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a <=> ~b").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~a <=> ~b").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a <=> ~b").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~a <=> ~b").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("b <=> a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("b <=> a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("b <=> a").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~b <=> a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~b <=> a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~b <=> a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("b <=> ~a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("b <=> ~a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("b <=> ~a").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("~b <=> ~a").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~b <=> ~a").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("~b <=> ~a").holds(this.aNotBToFalse)).isTrue(); + public void testEquivalenceToFalse() { + assertThat(parse(this.f, "a <=> a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a <=> a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a <=> a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "b <=> b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "b <=> b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "b <=> b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a <=> b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a <=> b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a <=> b").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~a <=> b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a <=> b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~a <=> b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a <=> ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a <=> ~b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a <=> ~b").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~a <=> ~b").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a <=> ~b").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~a <=> ~b").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "b <=> a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "b <=> a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "b <=> a").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~b <=> a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~b <=> a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~b <=> a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "b <=> ~a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "b <=> ~a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "b <=> ~a").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "~b <=> ~a").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~b <=> ~a").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "~b <=> ~a").holds(this.aNotBToFalse)).isTrue(); } @Test @@ -307,50 +306,50 @@ public void testPBCToFalse() { } @Test - public void testMixedToFalse() throws ParserException { - assertThat(this.f.parse("~a & (a | ~b)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b)").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~a & (a | ~b)").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~b & (b | ~a)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~b & (b | ~a)").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~b & (b | ~a)").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~a & (a | ~b) & c & (a => b | e)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b) & c & (a => b | e)").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("~a & ~(a | ~b) & c & (a => b | e)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("~a & ~(a | ~b) & c & (a => b | e)").holds(this.aToFalse)).isTrue(); - assertThat(this.f.parse("~a & ~(a | ~b) & c & (a => b | e)").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("a & (a | ~b) & c & (a => b | e)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => b | e)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & c & (a => ~b | e)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => ~b | e)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => ~b | e)").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & (a => b | e)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a => b | e)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a => b | e)").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & c & (a <=> ~b | e)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & (a <=> b | e)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b | e)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b | e)").holds(this.aNotBToFalse)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & (a <=> b)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b)").holds(this.aNotBToFalse)).isTrue(); - - assertThat(this.f.parse("a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.emptyToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aToFalse)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aNotBToFalse)).isTrue(); + public void testMixedToFalse() { + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~a & (a | ~b) & c & (a => b | e)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b) & c & (a => b | e)").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "~a & ~(a | ~b) & c & (a => b | e)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "~a & ~(a | ~b) & c & (a => b | e)").holds(this.aToFalse)).isTrue(); + assertThat(parse(this.f, "~a & ~(a | ~b) & c & (a => b | e)").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "a & (a | ~b) & c & (a => b | e)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => b | e)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & c & (a => ~b | e)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => ~b | e)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => ~b | e)").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & (a => b | e)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a => b | e)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a => b | e)").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & c & (a <=> ~b | e)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b | e)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b | e)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b | e)").holds(this.aNotBToFalse)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b)").holds(this.aNotBToFalse)).isTrue(); + + assertThat(parse(this.f, "a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.emptyToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aToFalse)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aNotBToFalse)).isTrue(); } @Test @@ -384,166 +383,166 @@ public void testLiteralsToTrue() { } @Test - public void testNotToTrue() throws ParserException { - assertThat(this.f.parse("~~a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~~a").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("~~a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~~~a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~~~a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~~~a").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~(a & b)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~(a & b)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~(a & b)").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~(~a & b)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~(~a & b)").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("~(~a & b)").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~(a & ~b)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~(a & ~b)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~(a & ~b)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~(~a & ~b)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~(~a & ~b)").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("~(~a & ~b)").holds(this.aNotBToTrue)).isTrue(); + public void testNotToTrue() { + assertThat(parse(this.f, "~~a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~~a").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "~~a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~~~a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~~~a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~~~a").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~(a & b)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~(a & b)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~(a & b)").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~(~a & b)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~(~a & b)").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "~(~a & b)").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~(a & ~b)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~(a & ~b)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~(a & ~b)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~(~a & ~b)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~(~a & ~b)").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "~(~a & ~b)").holds(this.aNotBToTrue)).isTrue(); } @Test - public void testAndToTrue() throws ParserException { - assertThat(this.f.parse("a & ~a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & ~a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & ~a").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & b").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~a & b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a & b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a & b").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & ~b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & ~b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~a & ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a & ~b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a & ~b").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~a & ~b & c & ~d").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a & ~b & c & ~d").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a & ~b & c & ~d").holds(this.aNotBToTrue)).isFalse(); + public void testAndToTrue() { + assertThat(parse(this.f, "a & ~a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & ~a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & ~a").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & b").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~a & b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a & b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a & b").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & ~b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & ~b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~a & ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a & ~b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a & ~b").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~a & ~b & c & ~d").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a & ~b & c & ~d").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a & ~b & c & ~d").holds(this.aNotBToTrue)).isFalse(); } @Test - public void testOrToTrue() throws ParserException { - assertThat(this.f.parse("a | b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a | b").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("a | b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~a | b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a | b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a | b").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a | ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a | ~b").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("a | ~b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~a | ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a | ~b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a | ~b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~a | ~b | c | ~d").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a | ~b | c | ~d").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a | ~b | c | ~d").holds(this.aNotBToTrue)).isTrue(); + public void testOrToTrue() { + assertThat(parse(this.f, "a | b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a | b").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "a | b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~a | b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a | b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a | b").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a | ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a | ~b").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "a | ~b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~a | ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a | ~b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a | ~b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~a | ~b | c | ~d").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a | ~b | c | ~d").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a | ~b | c | ~d").holds(this.aNotBToTrue)).isTrue(); } @Test - public void testImplicationToTrue() throws ParserException { - assertThat(this.f.parse("a => a").holds(this.emptyToTrue)).isTrue(); - assertThat(this.f.parse("a => a").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("a => a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("b => b").holds(this.emptyToTrue)).isTrue(); - assertThat(this.f.parse("b => b").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("b => b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("a => b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a => b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a => b").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~a => b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a => b").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("~a => b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("a => ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a => ~b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a => ~b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~a => ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a => ~b").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("~a => ~b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("b => a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("b => a").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("b => a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~b => a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~b => a").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("~b => a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("b => ~a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("b => ~a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("b => ~a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~b => ~a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~b => ~a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~b => ~a").holds(this.aNotBToTrue)).isFalse(); + public void testImplicationToTrue() { + assertThat(parse(this.f, "a => a").holds(this.emptyToTrue)).isTrue(); + assertThat(parse(this.f, "a => a").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "a => a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "b => b").holds(this.emptyToTrue)).isTrue(); + assertThat(parse(this.f, "b => b").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "b => b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "a => b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a => b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a => b").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~a => b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a => b").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "~a => b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "a => ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a => ~b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a => ~b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~a => ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a => ~b").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "~a => ~b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "b => a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "b => a").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "b => a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~b => a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~b => a").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "~b => a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "b => ~a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "b => ~a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "b => ~a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~b => ~a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~b => ~a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~b => ~a").holds(this.aNotBToTrue)).isFalse(); } @Test - public void testEquivalenceToTrue() throws ParserException { - assertThat(this.f.parse("a <=> a").holds(this.emptyToTrue)).isTrue(); - assertThat(this.f.parse("a <=> a").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("a <=> a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("b <=> b").holds(this.emptyToTrue)).isTrue(); - assertThat(this.f.parse("b <=> b").holds(this.aToTrue)).isTrue(); - assertThat(this.f.parse("b <=> b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("a <=> b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a <=> b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a <=> b").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~a <=> b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a <=> b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a <=> b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("a <=> ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a <=> ~b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a <=> ~b").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~a <=> ~b").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a <=> ~b").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a <=> ~b").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("b <=> a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("b <=> a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("b <=> a").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~b <=> a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~b <=> a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~b <=> a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("b <=> ~a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("b <=> ~a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("b <=> ~a").holds(this.aNotBToTrue)).isTrue(); - - assertThat(this.f.parse("~b <=> ~a").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~b <=> ~a").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~b <=> ~a").holds(this.aNotBToTrue)).isFalse(); + public void testEquivalenceToTrue() { + assertThat(parse(this.f, "a <=> a").holds(this.emptyToTrue)).isTrue(); + assertThat(parse(this.f, "a <=> a").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "a <=> a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "b <=> b").holds(this.emptyToTrue)).isTrue(); + assertThat(parse(this.f, "b <=> b").holds(this.aToTrue)).isTrue(); + assertThat(parse(this.f, "b <=> b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "a <=> b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a <=> b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a <=> b").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~a <=> b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a <=> b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a <=> b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "a <=> ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a <=> ~b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a <=> ~b").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~a <=> ~b").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a <=> ~b").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a <=> ~b").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "b <=> a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "b <=> a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "b <=> a").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~b <=> a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~b <=> a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~b <=> a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "b <=> ~a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "b <=> ~a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "b <=> ~a").holds(this.aNotBToTrue)).isTrue(); + + assertThat(parse(this.f, "~b <=> ~a").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~b <=> ~a").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~b <=> ~a").holds(this.aNotBToTrue)).isFalse(); } @Test @@ -568,58 +567,58 @@ public void testPBCToTrue() { } @Test - public void testMixedToTrue() throws ParserException { - assertThat(this.f.parse("~a & (a | ~b)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~b & (b | ~a)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~b & (b | ~a)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~b & (b | ~a)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~a & (a | ~b)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~b & (b | ~a)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~b & (b | ~a)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~b & (b | ~a)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~a & (a | ~b) & c & (a => b | e)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b) & c & (a => b | e)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("~a & ~(a | ~b) & c & (a => b | e)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("~a & ~(a | ~b) & c & (a => b | e)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("~a & ~(a | ~b) & c & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & c & (a => b | e)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => b | e)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & c & (a => ~b | e)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => ~b | e)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a => ~b | e)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & (a => b | e)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a => b | e)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & c & (a <=> ~b | e)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & (a <=> b | e)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b | e)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b | e)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & (a <=> b)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (a <=> b)").holds(this.aNotBToTrue)).isFalse(); - - assertThat(this.f.parse("a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.emptyToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aToTrue)).isFalse(); - assertThat(this.f.parse("a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aNotBToTrue)).isFalse(); + public void testMixedToTrue() { + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~b & (b | ~a)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~a & (a | ~b) & c & (a => b | e)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b) & c & (a => b | e)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "~a & ~(a | ~b) & c & (a => b | e)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "~a & ~(a | ~b) & c & (a => b | e)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "~a & ~(a | ~b) & c & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & c & (a => b | e)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => b | e)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & c & (a => ~b | e)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => ~b | e)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a => ~b | e)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & (a => b | e)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a => b | e)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a => b | e)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & c & (a <=> ~b | e)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & c & (a <=> ~b | e)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b | e)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b | e)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b | e)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (a <=> b)").holds(this.aNotBToTrue)).isFalse(); + + assertThat(parse(this.f, "a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.emptyToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aToTrue)).isFalse(); + assertThat(parse(this.f, "a & (a | ~b) & (3 * a + 2 * b > 4)").holds(this.aNotBToTrue)).isFalse(); } @Test diff --git a/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java b/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java index 6005b473..061cacf7 100644 --- a/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java +++ b/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java @@ -29,7 +29,6 @@ package org.logicng.primecomputation; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; import org.junit.jupiter.api.Test; import org.logicng.RandomTag; @@ -116,20 +115,16 @@ public void testOriginalFormulas() throws IOException { Files.lines(Paths.get("src/test/resources/formulas/simplify_formulas.txt")) .filter(s -> !s.isEmpty()) .forEach(s -> { - try { - final Formula formula = this.f.parse(s); - final PrimeResult resultImplicantsMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICANTS_COMPLETE); - verify(resultImplicantsMin, formula); - final PrimeResult resultImplicatesMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICATES_COMPLETE); - verify(resultImplicatesMin, formula); - } catch (final ParserException e) { - fail(e.toString()); - } + final Formula formula = parse(this.f, s); + final PrimeResult resultImplicantsMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICANTS_COMPLETE); + verify(resultImplicantsMin, formula); + final PrimeResult resultImplicatesMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICATES_COMPLETE); + verify(resultImplicatesMin, formula); }); } @Test - public void testTimeoutHandlerSmall() throws ParserException { + public void testTimeoutHandlerSmall() { final List> compilers = Arrays.asList( new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE), @@ -141,7 +136,7 @@ public void testTimeoutHandlerSmall() throws ParserException { new TimeoutOptimizationHandler(5_000L, TimeoutHandler.TimerType.RESTARTING_TIMEOUT), new TimeoutOptimizationHandler(System.currentTimeMillis() + 5_000L, TimeoutHandler.TimerType.FIXED_END) ); - final Formula formula = this.f.parse("a & b | ~c & a"); + final Formula formula = parse(this.f, "a & b | ~c & a"); for (final TimeoutOptimizationHandler handler : handlers) { testHandler(handler, formula, compiler.first(), compiler.second(), false); } @@ -149,7 +144,7 @@ public void testTimeoutHandlerSmall() throws ParserException { } @Test - public void testTimeoutHandlerLarge() throws ParserException, IOException { + public void testTimeoutHandlerLarge() throws IOException, ParserException { final List> compilers = Arrays.asList( new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE), @@ -169,8 +164,8 @@ public void testTimeoutHandlerLarge() throws ParserException, IOException { } @Test - public void testCancellationPoints() throws IOException, ParserException { - final Formula formula = this.f.parse(Files.readAllLines(Paths.get("src/test/resources/formulas/simplify_formulas.txt")).get(0)); + public void testCancellationPoints() throws IOException { + final Formula formula = parse(this.f, Files.readAllLines(Paths.get("src/test/resources/formulas/simplify_formulas.txt")).get(0)); final List> compilers = Arrays.asList( new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE), diff --git a/src/test/java/org/logicng/primecomputation/PrimeImplicantReductionTest.java b/src/test/java/org/logicng/primecomputation/PrimeImplicantReductionTest.java index cc5636ff..a71af686 100644 --- a/src/test/java/org/logicng/primecomputation/PrimeImplicantReductionTest.java +++ b/src/test/java/org/logicng/primecomputation/PrimeImplicantReductionTest.java @@ -62,23 +62,23 @@ public class PrimeImplicantReductionTest extends TestWithExampleFormulas { @Test - public void testSimple() throws ParserException { + public void testSimple() { final NaivePrimeReduction naiveTautology = new NaivePrimeReduction(this.f.verum()); assertThat(naiveTautology.reduceImplicant(new TreeSet<>(Arrays.asList(this.A, this.B)))).isEmpty(); - final NaivePrimeReduction naive01 = new NaivePrimeReduction(this.f.parse("a&b|c&d")); + final NaivePrimeReduction naive01 = new NaivePrimeReduction(parse(this.f, "a&b|c&d")); assertThat(naive01.reduceImplicant(new TreeSet<>(Arrays.asList(this.A, this.B, this.C, this.D.negate())))) .containsExactlyInAnyOrder(this.A, this.B); assertThat(naive01.reduceImplicant(new TreeSet<>(Arrays.asList(this.A.negate(), this.B, this.C, this.D)))) .containsExactlyInAnyOrder(this.C, this.D); - final NaivePrimeReduction naive02 = new NaivePrimeReduction(this.f.parse("a|b|~a&~b")); + final NaivePrimeReduction naive02 = new NaivePrimeReduction(parse(this.f, "a|b|~a&~b")); assertThat(naive02.reduceImplicant(new TreeSet<>(Arrays.asList(this.A.negate(), this.B)))) .containsExactlyInAnyOrder(); assertThat(naive02.reduceImplicant(new TreeSet<>(Arrays.asList(this.A.negate(), this.B)))) .containsExactlyInAnyOrder(); - final NaivePrimeReduction naive03 = new NaivePrimeReduction(this.f.parse("(a => b) | b | c")); + final NaivePrimeReduction naive03 = new NaivePrimeReduction(parse(this.f, "(a => b) | b | c")); assertThat(naive03.reduceImplicant(new TreeSet<>(Arrays.asList(this.A, this.B, this.C.negate())))) .containsExactlyInAnyOrder(this.B); assertThat(naive03.reduceImplicant(new TreeSet<>(Arrays.asList(this.A, this.B.negate(), this.C)))) @@ -104,10 +104,10 @@ public void testLargeFormula() throws IOException, ParserException { } @Test - public void testSmallFormulas() throws IOException, ParserException { + public void testSmallFormulas() throws IOException { final List lines = Files.readAllLines(Paths.get("src/test/resources/formulas/small_formulas.txt")); for (final String line : lines) { - testFormula(this.f.parse(line)); + testFormula(parse(this.f, line)); } } @@ -130,7 +130,7 @@ public void testRandom() { } @Test - public void testCancellationPoints() throws ParserException, IOException { + public void testCancellationPoints() throws IOException, ParserException { final Formula formula = FormulaReader.readPseudoBooleanFormula("src/test/resources/formulas/large_formula.txt", this.f); for (int numStarts = 0; numStarts < 20; numStarts++) { final SATHandler handler = new BoundedSatHandler(numStarts); diff --git a/src/test/java/org/logicng/primecomputation/PrimeImplicateReductionTest.java b/src/test/java/org/logicng/primecomputation/PrimeImplicateReductionTest.java index 70889a11..f3f4bcd7 100644 --- a/src/test/java/org/logicng/primecomputation/PrimeImplicateReductionTest.java +++ b/src/test/java/org/logicng/primecomputation/PrimeImplicateReductionTest.java @@ -63,16 +63,16 @@ public class PrimeImplicateReductionTest extends TestWithExampleFormulas { @Test - public void testPrimeImplicateNaive() throws ParserException { - final NaivePrimeReduction naive01 = new NaivePrimeReduction(this.f.parse("a&b")); + public void testPrimeImplicateNaive() { + final NaivePrimeReduction naive01 = new NaivePrimeReduction(parse(this.f, "a&b")); assertThat(naive01.reduceImplicate(new TreeSet<>(Arrays.asList(this.A, this.B)))) .containsAnyOf(this.A, this.B).hasSize(1); - final NaivePrimeReduction naive02 = new NaivePrimeReduction(this.f.parse("(a => b) | b | c")); + final NaivePrimeReduction naive02 = new NaivePrimeReduction(parse(this.f, "(a => b) | b | c")); assertThat(naive02.reduceImplicate(new TreeSet<>(Arrays.asList(this.A.negate(), this.B, this.C)))) .containsExactly(this.A.negate(), this.B, this.C); - final NaivePrimeReduction naive03 = new NaivePrimeReduction(this.f.parse("(a => b) & b & c")); + final NaivePrimeReduction naive03 = new NaivePrimeReduction(parse(this.f, "(a => b) & b & c")); assertThat(naive03.reduceImplicate(new TreeSet<>(Arrays.asList(this.B, this.C)))) .containsAnyOf(this.B, this.C).hasSize(1); } @@ -96,10 +96,10 @@ public void testLargeFormula() throws IOException, ParserException { } @Test - public void testSmallFormulas() throws IOException, ParserException { + public void testSmallFormulas() throws IOException { final List lines = Files.readAllLines(Paths.get("src/test/resources/formulas/small_formulas.txt")); for (final String line : lines) { - testFormula(this.f.parse(line)); + testFormula(parse(this.f, line)); } } @@ -122,7 +122,7 @@ public void testRandom() { } @Test - public void testCancellationPoints() throws ParserException, IOException { + public void testCancellationPoints() throws IOException, ParserException { final Formula formula = FormulaReader.readPseudoBooleanFormula("src/test/resources/formulas/large_formula.txt", this.f); for (int numStarts = 0; numStarts < 20; numStarts++) { final SATHandler handler = new BoundedSatHandler(numStarts); diff --git a/src/test/java/org/logicng/pseudobooleans/PBEncoderTest.java b/src/test/java/org/logicng/pseudobooleans/PBEncoderTest.java index d6ca75d8..aa44a5ba 100644 --- a/src/test/java/org/logicng/pseudobooleans/PBEncoderTest.java +++ b/src/test/java/org/logicng/pseudobooleans/PBEncoderTest.java @@ -28,6 +28,7 @@ package org.logicng.pseudobooleans; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.LogicNGTest; @@ -39,7 +40,6 @@ import org.logicng.formulas.Literal; import org.logicng.formulas.PBConstraint; import org.logicng.formulas.Variable; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; @@ -163,7 +163,7 @@ public void testSpecialCases() { } @Test - public void testCCNormalized() throws ParserException { + public void testCCNormalized() { final List lits = new ArrayList<>(); lits.add(this.f.literal("m", true)); lits.add(this.f.literal("n", true)); @@ -171,7 +171,7 @@ public void testCCNormalized() throws ParserException { coeffs2.add(2); coeffs2.add(2); final PBConstraint normCC = (PBConstraint) this.f.pbc(CType.LE, 2, lits, coeffs2); - assertThat(this.encoders[0].encode(normCC)).containsExactly(this.f.parse("~m | ~n")); + assertThat(this.encoders[0].encode(normCC)).containsExactly(parse(this.f, "~m | ~n")); } @Test diff --git a/src/test/java/org/logicng/solvers/ModelTest.java b/src/test/java/org/logicng/solvers/ModelTest.java index b3b4099d..4648e421 100644 --- a/src/test/java/org/logicng/solvers/ModelTest.java +++ b/src/test/java/org/logicng/solvers/ModelTest.java @@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -38,7 +39,6 @@ import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Variable; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.functions.ModelEnumerationFunction; import org.logicng.solvers.sat.GlucoseConfig; import org.logicng.solvers.sat.MiniSatConfig; @@ -83,17 +83,17 @@ public static Collection solvers() { @ParameterizedTest @MethodSource("solvers") - public void testNoModel(final SATSolver solver) throws ParserException { + public void testNoModel(final SATSolver solver) { solver.reset(); solver.add(f.falsum()); solver.sat(); assertThat(solver.model()).isNull(); solver.reset(); - solver.add(f.parse("A & ~A")); + solver.add(parse(f, "A & ~A")); solver.sat(); assertThat(solver.model()).isNull(); solver.reset(); - solver.add(f.parse("(A => (B & C)) & A & C & (C <=> ~B)")); + solver.add(parse(f, "(A => (B & C)) & A & C & (C <=> ~B)")); solver.sat(); assertThat(solver.model()).isNull(); } @@ -129,9 +129,9 @@ public void testSimpleModel(final SATSolver solver) { @ParameterizedTest @MethodSource("solvers") - public void testCNFFormula(final SATSolver solver) throws ParserException { + public void testCNFFormula(final SATSolver solver) { solver.reset(); - final Formula formula = f.parse("(A|B|C) & (~A|~B|~C) & (A|~B|~C) & (~A|~B|C)"); + final Formula formula = parse(f, "(A|B|C) & (~A|~B|~C) & (A|~B|~C) & (~A|~B|C)"); solver.add(formula); solver.sat(); final Assignment model = solver.model(); @@ -144,9 +144,9 @@ public void testCNFFormula(final SATSolver solver) throws ParserException { @ParameterizedTest @MethodSource("solvers") - public void testCNFWithAuxiliaryVars(final MiniSat solver) throws ParserException { + public void testCNFWithAuxiliaryVars(final MiniSat solver) { solver.reset(); - final Formula formula = f.parse("(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); + final Formula formula = parse(f, "(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); final Formula cnf = formula.transform(new TseitinTransformation(0)); solver.add(cnf); solver.sat(); @@ -171,9 +171,9 @@ public void testCNFWithAuxiliaryVars(final MiniSat solver) throws ParserExceptio @ParameterizedTest @MethodSource("solvers") - public void testCNFWithAuxiliaryVarsRestrictedToOriginal(final SATSolver solver) throws ParserException { + public void testCNFWithAuxiliaryVarsRestrictedToOriginal(final SATSolver solver) { solver.reset(); - final Formula formula = f.parse("(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); + final Formula formula = parse(f, "(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); final Formula cnf = formula.transform(new TseitinTransformation(0)); solver.add(cnf); solver.sat(); @@ -190,9 +190,9 @@ public void testCNFWithAuxiliaryVarsRestrictedToOriginal(final SATSolver solver) @ParameterizedTest @MethodSource("solvers") - public void testNonCNFAllVars(final MiniSat solver) throws ParserException { + public void testNonCNFAllVars(final MiniSat solver) { solver.reset(); - final Formula formula = f.parse("(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); + final Formula formula = parse(f, "(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); solver.add(formula); solver.sat(); final Assignment model = solver.model(); @@ -215,9 +215,9 @@ public void testNonCNFAllVars(final MiniSat solver) throws ParserException { @ParameterizedTest @MethodSource("solvers") - public void testNonCNFOnlyFormulaVars(final SATSolver solver) throws ParserException { + public void testNonCNFOnlyFormulaVars(final SATSolver solver) { solver.reset(); - final Formula formula = f.parse("(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); + final Formula formula = parse(f, "(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); solver.add(formula); solver.sat(); final Assignment model = solver.model(formula.variables()); @@ -233,9 +233,9 @@ public void testNonCNFOnlyFormulaVars(final SATSolver solver) throws ParserExcep @ParameterizedTest @MethodSource("solvers") - public void testNonCNFRestrictedVars(final SATSolver solver) throws ParserException { + public void testNonCNFRestrictedVars(final SATSolver solver) { solver.reset(); - final Formula formula = f.parse("(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); + final Formula formula = parse(f, "(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); final MiniSat miniSat = MiniSat.miniSat(f); miniSat.add(formula); solver.add(formula); @@ -254,9 +254,9 @@ public void testNonCNFRestrictedVars(final SATSolver solver) throws ParserExcept @ParameterizedTest @MethodSource("solvers") - public void testNonCNFRestrictedAndAdditionalVars(final SATSolver solver) throws ParserException { + public void testNonCNFRestrictedAndAdditionalVars(final SATSolver solver) { solver.reset(); - final Formula formula = f.parse("(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); + final Formula formula = parse(f, "(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); final MiniSat miniSat = MiniSat.miniSat(f); miniSat.add(formula); solver.add(formula); @@ -278,9 +278,9 @@ public void testNonCNFRestrictedAndAdditionalVars(final SATSolver solver) throws @ParameterizedTest @MethodSource("solvers") - public void testUnsolvedFormula(final SATSolver solver) throws ParserException { + public void testUnsolvedFormula(final SATSolver solver) { solver.reset(); - final Formula formula = f.parse("(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); + final Formula formula = parse(f, "(A => B & C) & (~A => C & ~D) & (C => (D & E | ~E & B)) & ~F"); solver.add(formula); assertThatThrownBy(solver::model).isInstanceOf(IllegalStateException.class); } diff --git a/src/test/java/org/logicng/solvers/functions/BackboneFunctionTest.java b/src/test/java/org/logicng/solvers/functions/BackboneFunctionTest.java index 8fff3812..d01bb274 100644 --- a/src/test/java/org/logicng/solvers/functions/BackboneFunctionTest.java +++ b/src/test/java/org/logicng/solvers/functions/BackboneFunctionTest.java @@ -29,6 +29,7 @@ package org.logicng.solvers.functions; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -125,13 +126,13 @@ public void testConstants(final MiniSat solver) { @ParameterizedTest @MethodSource("solvers") - public void testSimpleBackbones(final MiniSat solver) throws ParserException { + public void testSimpleBackbones(final MiniSat solver) { solver.reset(); SolverState state = null; if (solver.underlyingSolver() instanceof MiniSat2Solver) { state = solver.saveState(); } - solver.add(f.parse("a & b & ~c")); + solver.add(parse(f, "a & b & ~c")); Backbone backbone = solver.backbone(v("a b c")); assertThat(backbone.isSat()).isTrue(); assertThat(backbone.getCompleteBackbone()).containsExactly(f.variable("a"), f.variable("b"), f.literal("c", false)); @@ -140,7 +141,7 @@ public void testSimpleBackbones(final MiniSat solver) throws ParserException { } else { solver.reset(); } - solver.add(f.parse("~a & ~b & c")); + solver.add(parse(f, "~a & ~b & c")); backbone = solver.backbone(v("a c")); assertThat(backbone.isSat()).isTrue(); assertThat(backbone.getCompleteBackbone()).containsExactly(f.literal("a", false), f.variable("c")); @@ -148,15 +149,15 @@ public void testSimpleBackbones(final MiniSat solver) throws ParserException { @ParameterizedTest @MethodSource("solvers") - public void testSimpleFormulas(final MiniSat solver) throws ParserException { + public void testSimpleFormulas(final MiniSat solver) { solver.reset(); - solver.add(f.parse("(a => c | d) & (b => d | ~e) & (a | b)")); + solver.add(parse(f, "(a => c | d) & (b => d | ~e) & (a | b)")); Backbone backbone = solver.backbone(v("a b c d e f")); assertThat(backbone.isSat()).isTrue(); assertThat(backbone.getCompleteBackbone()).isEmpty(); - solver.add(f.parse("a => b")); - solver.add(f.parse("b => a")); - solver.add(f.parse("~d")); + solver.add(parse(f, "a => b")); + solver.add(parse(f, "b => a")); + solver.add(parse(f, "~d")); backbone = solver.backbone(v("a b c d e f g h")); assertThat(backbone.isSat()).isTrue(); assertThat(backbone.getCompleteBackbone()).containsExactly(f.variable("a"), f.variable("b"), f.variable("c"), @@ -165,17 +166,17 @@ public void testSimpleFormulas(final MiniSat solver) throws ParserException { @ParameterizedTest @MethodSource("solvers") - public void testSimpleFormulasWithBuilderUsage(final MiniSat solver) throws ParserException { + public void testSimpleFormulasWithBuilderUsage(final MiniSat solver) { solver.reset(); - solver.add(f.parse("(a => c | d) & (b => d | ~e) & (a | b)")); + solver.add(parse(f, "(a => c | d) & (b => d | ~e) & (a | b)")); Backbone backbone = solver.execute(BackboneFunction.builder().variables( f.variable("a"), f.variable("b"), f.variable("c"), f.variable("d"), f.variable("e"), f.variable("f")) .build()); assertThat(backbone.isSat()).isTrue(); assertThat(backbone.getCompleteBackbone()).isEmpty(); - solver.add(f.parse("a => b")); - solver.add(f.parse("b => a")); - solver.add(f.parse("~d")); + solver.add(parse(f, "a => b")); + solver.add(parse(f, "b => a")); + solver.add(parse(f, "~d")); backbone = solver.backbone(v("a b c d e f g h")); assertThat(backbone.isSat()).isTrue(); assertThat(backbone.getCompleteBackbone()).containsExactly(f.variable("a"), f.variable("b"), f.variable("c"), @@ -285,31 +286,31 @@ public void testRealFormulaIncrementalDecremental1(final MiniSat solver) throws assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v411 & v385")); + solver.add(parse(f, "v411 & v385")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(2))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v411 & v385 & v275")); + solver.add(parse(f, "v411 & v385 & v275")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(3))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v411 & v385 & v275 & v188")); + solver.add(parse(f, "v411 & v385 & v275 & v188")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(4))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v411 & v385 & v275 & v188 & v103")); + solver.add(parse(f, "v411 & v385 & v275 & v188 & v103")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(5))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v411 & v385 & v275 & v188 & v103 & v404")); + solver.add(parse(f, "v411 & v385 & v275 & v188 & v103 & v404")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEmpty(); assertThat(backbone.isSat()).isFalse(); @@ -339,31 +340,31 @@ public void testRealFormulaIncrementalDecremental2(final MiniSat solver) throws assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v2609 & v2416")); + solver.add(parse(f, "v2609 & v2416")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(2))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v2609 & v2416 & v2048")); + solver.add(parse(f, "v2609 & v2416 & v2048")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(3))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v2609 & v2416 & v2048 & v39")); + solver.add(parse(f, "v2609 & v2416 & v2048 & v39")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(4))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v2609 & v2416 & v2048 & v39 & v1663")); + solver.add(parse(f, "v2609 & v2416 & v2048 & v39 & v1663")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEqualTo(parseBackbone(expectedBackbones.get(5))); assertThat(backbone.isSat()).isTrue(); solver.loadState(state); - solver.add(f.parse("v2609 & v2416 & v2048 & v39 & v1663 & v2238")); + solver.add(parse(f, "v2609 & v2416 & v2048 & v39 & v1663 & v2238")); backbone = solver.backbone(formula.variables()); assertThat(backbone.getCompleteBackbone()).isEmpty(); assertThat(backbone.isSat()).isFalse(); @@ -371,13 +372,13 @@ public void testRealFormulaIncrementalDecremental2(final MiniSat solver) throws } @Test - public void testMiniCardSpecialCase() throws ParserException { + public void testMiniCardSpecialCase() { final FormulaFactory f = new FormulaFactory(); final SATSolver miniCard = MiniSat.miniCard(f); - miniCard.add(f.parse("v1 + v2 + v3 + v4 + v5 + v6 = 1")); - miniCard.add(f.parse("v1234 + v50 + v60 = 1")); - miniCard.add(f.parse("(v1 => v1234) & (v2 => v1234) & (v3 => v1234) & (v4 => v1234) & (v5 => v50) & (v6 => v60)")); - miniCard.add(f.parse("~v6")); + miniCard.add(parse(f, "v1 + v2 + v3 + v4 + v5 + v6 = 1")); + miniCard.add(parse(f, "v1234 + v50 + v60 = 1")); + miniCard.add(parse(f, "(v1 => v1234) & (v2 => v1234) & (v3 => v1234) & (v4 => v1234) & (v5 => v50) & (v6 => v60)")); + miniCard.add(parse(f, "~v6")); final Backbone backboneMC = miniCard.backbone(Arrays.asList(f.variable("v6"), f.variable("v60"))); assertThat(backboneMC.getNegativeBackbone()).extracting(Variable::name).containsExactlyInAnyOrder("v6", "v60"); } @@ -390,10 +391,10 @@ private SortedSet v(final String s) { return vars; } - private SortedSet parseBackbone(final String string) throws ParserException { + private SortedSet parseBackbone(final String string) { final SortedSet literals = new TreeSet<>(); for (final String lit : string.split(" ")) { - literals.add((Literal) f.parse(lit)); + literals.add((Literal) parse(f, lit)); } return literals; } diff --git a/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java b/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java index 0e3aa04b..b2c9357f 100644 --- a/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java +++ b/src/test/java/org/logicng/solvers/functions/ModelEnumerationFunctionTest.java @@ -1,11 +1,11 @@ package org.logicng.solvers.functions; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.datastructures.Assignment; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; @@ -25,9 +25,9 @@ public ModelEnumerationFunctionTest() { } @Test - public void testModelEnumerationSimple() throws ParserException { + public void testModelEnumerationSimple() { final SATSolver solver = MiniSat.miniSat(this.f); - solver.add(this.f.parse("A & (B | C)")); + solver.add(parse(this.f, "A & (B | C)")); final List models = solver.execute(ModelEnumerationFunction.builder().build()); assertThat(models).containsExactlyInAnyOrder( new Assignment(this.f.variable("A"), this.f.variable("B"), this.f.variable("C")), @@ -37,9 +37,9 @@ public void testModelEnumerationSimple() throws ParserException { } @Test - public void testFastEvaluable() throws ParserException { + public void testFastEvaluable() { final SATSolver solver = MiniSat.miniSat(this.f); - solver.add(this.f.parse("A & (B | C)")); + solver.add(parse(this.f, "A & (B | C)")); List models = solver.execute(ModelEnumerationFunction.builder().build()); assertThat(models).extracting(Assignment::fastEvaluable).containsOnly(false); models = solver.execute(ModelEnumerationFunction.builder().fastEvaluable(false).build()); diff --git a/src/test/java/org/logicng/solvers/functions/OptimizationFunctionTest.java b/src/test/java/org/logicng/solvers/functions/OptimizationFunctionTest.java index 3f9c2ce9..f35ce60a 100644 --- a/src/test/java/org/logicng/solvers/functions/OptimizationFunctionTest.java +++ b/src/test/java/org/logicng/solvers/functions/OptimizationFunctionTest.java @@ -30,6 +30,7 @@ import static java.util.stream.Collectors.toCollection; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -102,8 +103,8 @@ public static Collection solvers() { @ParameterizedTest @MethodSource("solvers") - public void testUnsatFormula(final SATSolver solver) throws ParserException { - final Formula formula = solver.factory().parse("a & b & (a => ~b)"); + public void testUnsatFormula(final SATSolver solver) { + final Formula formula = parse(solver.factory(), "a & b & (a => ~b)"); final Assignment minimumModel = optimize(Collections.singleton(formula), formula.variables(), Collections.emptyList(), false, solver, null); assertThat(minimumModel).isNull(); final Assignment maximumModel = optimize(Collections.singleton(formula), formula.variables(), Collections.emptyList(), true, solver, null); @@ -112,8 +113,8 @@ public void testUnsatFormula(final SATSolver solver) throws ParserException { @ParameterizedTest @MethodSource("solvers") - public void testSingleModel(final SATSolver solver) throws ParserException { - final Formula formula = solver.factory().parse("~a & ~b & ~c"); + public void testSingleModel(final SATSolver solver) { + final Formula formula = parse(solver.factory(), "~a & ~b & ~c"); final Assignment minimumModel = optimize(Collections.singleton(formula), formula.variables(), Collections.emptyList(), false, solver, null); testMinimumModel(formula, minimumModel, formula.variables()); final Assignment maximumModel = optimize(Collections.singleton(formula), formula.variables(), Collections.emptyList(), true, solver, null); @@ -185,13 +186,13 @@ private static SortedSet randomTargetLiterals(final Random random, fina @ParameterizedTest @MethodSource("solvers") - public void testIncrementalityMinimizeAndMaximize(final MiniSat solver) throws ParserException { + public void testIncrementalityMinimizeAndMaximize(final MiniSat solver) { final FormulaFactory f = solver.factory(); if (!solver.canSaveLoadState()) { return; } solver.reset(); - Formula formula = f.parse("(a|b|c|d|e) & (p|q) & (x|y|z)"); + Formula formula = parse(f, "(a|b|c|d|e) & (p|q) & (x|y|z)"); final SortedSet vars = new TreeSet<>(formula.variables()); solver.add(formula); @@ -200,7 +201,7 @@ public void testIncrementalityMinimizeAndMaximize(final MiniSat solver) throws P assertThat(minimumModel.positiveVariables()).hasSize(3); assertThat(maximumModel.positiveVariables()).hasSize(10); - formula = f.parse("~p"); + formula = parse(f, "~p"); vars.addAll(formula.variables()); solver.add(formula); minimumModel = solver.execute(OptimizationFunction.builder().minimize().literals(vars).build()); @@ -208,7 +209,7 @@ public void testIncrementalityMinimizeAndMaximize(final MiniSat solver) throws P assertThat(minimumModel.positiveVariables()).hasSize(3).contains(f.variable("q")); assertThat(maximumModel.positiveVariables()).hasSize(9).contains(f.variable("q")); - formula = f.parse("(x => n) & (y => m) & (a => ~b & ~c)"); + formula = parse(f, "(x => n) & (y => m) & (a => ~b & ~c)"); vars.addAll(formula.variables()); solver.add(formula); minimumModel = solver.execute(OptimizationFunction.builder().minimize().literals(vars).build()); @@ -218,7 +219,7 @@ public void testIncrementalityMinimizeAndMaximize(final MiniSat solver) throws P .contains(f.variable("q"), f.variable("z")) .doesNotContain(f.variable("a")); - formula = f.parse("(z => v & w) & (m => v) & (b => ~c & ~d & ~e)"); + formula = parse(f, "(z => v & w) & (m => v) & (b => ~c & ~d & ~e)"); vars.addAll(formula.variables()); solver.add(formula); minimumModel = solver.execute(OptimizationFunction.builder().minimize().literals(vars).build()); @@ -228,7 +229,7 @@ public void testIncrementalityMinimizeAndMaximize(final MiniSat solver) throws P .contains(f.variable("q"), f.variable("x"), f.variable("n"), f.variable("v"), f.variable("w")) .doesNotContain(f.variable("b")); - formula = f.parse("~q"); + formula = parse(f, "~q"); vars.addAll(formula.variables()); solver.add(formula); minimumModel = solver.execute(OptimizationFunction.builder().minimize().literals(vars).build()); @@ -239,7 +240,7 @@ public void testIncrementalityMinimizeAndMaximize(final MiniSat solver) throws P @ParameterizedTest @MethodSource("solvers") - public void testAdditionalVariables(final SATSolver solver) throws ParserException { + public void testAdditionalVariables(final SATSolver solver) { final FormulaFactory f = solver.factory(); final Variable a = f.variable("a"); final Literal na = f.literal("a", false); @@ -251,7 +252,7 @@ public void testAdditionalVariables(final SATSolver solver) throws ParserExcepti final Variable y = f.variable("y"); solver.reset(); - final Formula formula = f.parse("(a|b) & (~a => c) & (x|y)"); + final Formula formula = parse(f, "(a|b) & (~a => c) & (x|y)"); final List literalsANBX = Arrays.asList(a, nb, x); final Assignment minimumModel = optimize(Collections.singleton(formula), literalsANBX, Collections.emptyList(), false, solver, null); diff --git a/src/test/java/org/logicng/solvers/functions/UnsatCoreFunctionTest.java b/src/test/java/org/logicng/solvers/functions/UnsatCoreFunctionTest.java index a7cb24de..454bfb44 100644 --- a/src/test/java/org/logicng/solvers/functions/UnsatCoreFunctionTest.java +++ b/src/test/java/org/logicng/solvers/functions/UnsatCoreFunctionTest.java @@ -63,7 +63,7 @@ public void testExceptionalBehavior() { .hasMessage("Cannot generate an unsat core before the formula was solved."); assertThatThrownBy(() -> { final SATSolver solver = MiniSat.miniCard(this.f, MiniSatConfig.builder().proofGeneration(true).build()); - solver.add(this.f.parse("A & (A => B) & (B => ~A)")); + solver.add(parse(f, "A & (A => B) & (B => ~A)")); solver.sat(); solver.execute(UnsatCoreFunction.get()); }).isInstanceOf(IllegalStateException.class) diff --git a/src/test/java/org/logicng/solvers/maxsat/PartialMaxSATTest.java b/src/test/java/org/logicng/solvers/maxsat/PartialMaxSATTest.java index 76c61707..ffd28139 100644 --- a/src/test/java/org/logicng/solvers/maxsat/PartialMaxSATTest.java +++ b/src/test/java/org/logicng/solvers/maxsat/PartialMaxSATTest.java @@ -38,7 +38,6 @@ import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.handlers.TimeoutMaxSATHandler; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MaxSATSolver; import org.logicng.solvers.maxsat.algorithms.MaxSAT; import org.logicng.solvers.maxsat.algorithms.MaxSATConfig; @@ -79,7 +78,7 @@ public PartialMaxSATTest() throws FileNotFoundException { public void testExceptionalBehaviorForMSU3() { assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.msu3(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 2); solver.solve(); }).isInstanceOf(IllegalStateException.class) @@ -89,7 +88,7 @@ public void testExceptionalBehaviorForMSU3() { .incremental(MaxSATConfig.IncrementalStrategy.ITERATIVE) .cardinality(MaxSATConfig.CardinalityEncoding.MTOTALIZER) .build()); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 1); solver.solve(); }).isInstanceOf(IllegalStateException.class) @@ -289,13 +288,13 @@ public void testTimeoutHandlerUB() throws IOException { } @Test - public void testNonClauselSoftConstraints() throws ParserException { + public void testNonClauselSoftConstraints() { final MaxSATSolver[] solvers = new MaxSATSolver[2]; solvers[0] = MaxSATSolver.msu3(this.f); solvers[1] = MaxSATSolver.linearUS(this.f); for (final MaxSATSolver solver : solvers) { - solver.addHardFormula(this.f.parse("a & b & c")); - solver.addSoftFormula(this.f.parse("~a & ~b & ~c"), 1); + solver.addHardFormula(parse(this.f, "a & b & c")); + solver.addSoftFormula(parse(this.f, "~a & ~b & ~c"), 1); assertThat(solver.solve()).isEqualTo(MaxSAT.MaxSATResult.OPTIMUM); assertThat(solver.model().literals()).containsExactlyInAnyOrder( this.f.variable("a"), this.f.variable("b"), this.f.variable("c") @@ -305,14 +304,14 @@ public void testNonClauselSoftConstraints() throws ParserException { } @Test - public void testSoftConstraintsCornerCaseVerum() throws ParserException { + public void testSoftConstraintsCornerCaseVerum() { final MaxSATSolver[] solvers = new MaxSATSolver[2]; solvers[0] = MaxSATSolver.msu3(this.f); solvers[1] = MaxSATSolver.linearUS(this.f); for (final MaxSATSolver solver : solvers) { - solver.addHardFormula(this.f.parse("a & b & c")); - solver.addSoftFormula(this.f.parse("$true"), 1); - solver.addSoftFormula(this.f.parse("~a & ~b & ~c"), 1); + solver.addHardFormula(parse(this.f, "a & b & c")); + solver.addSoftFormula(parse(this.f, "$true"), 1); + solver.addSoftFormula(parse(this.f, "~a & ~b & ~c"), 1); assertThat(solver.solve()).isEqualTo(MaxSAT.MaxSATResult.OPTIMUM); assertThat(solver.model().literals()).containsExactlyInAnyOrder( this.f.variable("a"), this.f.variable("b"), this.f.variable("c") @@ -322,14 +321,14 @@ public void testSoftConstraintsCornerCaseVerum() throws ParserException { } @Test - public void testSoftConstraintsCornerCaseFalsum() throws ParserException { + public void testSoftConstraintsCornerCaseFalsum() { final MaxSATSolver[] solvers = new MaxSATSolver[2]; solvers[0] = MaxSATSolver.msu3(this.f); solvers[1] = MaxSATSolver.linearUS(this.f); for (final MaxSATSolver solver : solvers) { - solver.addHardFormula(this.f.parse("a & b & c")); - solver.addSoftFormula(this.f.parse("$false"), 1); - solver.addSoftFormula(this.f.parse("~a & ~b & ~c"), 1); + solver.addHardFormula(parse(this.f, "a & b & c")); + solver.addSoftFormula(parse(this.f, "$false"), 1); + solver.addSoftFormula(parse(this.f, "~a & ~b & ~c"), 1); assertThat(solver.solve()).isEqualTo(MaxSAT.MaxSATResult.OPTIMUM); assertThat(solver.model().literals()).containsExactlyInAnyOrder( this.f.variable("a"), this.f.variable("b"), this.f.variable("c") diff --git a/src/test/java/org/logicng/solvers/maxsat/PartialWeightedMaxSATTest.java b/src/test/java/org/logicng/solvers/maxsat/PartialWeightedMaxSATTest.java index 5be2ca8e..97679b8c 100644 --- a/src/test/java/org/logicng/solvers/maxsat/PartialWeightedMaxSATTest.java +++ b/src/test/java/org/logicng/solvers/maxsat/PartialWeightedMaxSATTest.java @@ -40,7 +40,6 @@ import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.handlers.TimeoutMaxSATHandler; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MaxSATSolver; import org.logicng.solvers.maxsat.algorithms.MaxSAT; import org.logicng.solvers.maxsat.algorithms.MaxSATConfig; @@ -88,7 +87,7 @@ public PartialWeightedMaxSATTest() throws FileNotFoundException { public void testExceptionalBehaviorForWMSU3() { assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.wmsu3(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 1); solver.solve(); }).isInstanceOf(IllegalStateException.class) @@ -99,7 +98,7 @@ public void testExceptionalBehaviorForWMSU3() { .incremental(MaxSATConfig.IncrementalStrategy.ITERATIVE) .cardinality(CardinalityEncoding.MTOTALIZER) .build()); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 2); solver.solve(); }).isInstanceOf(IllegalStateException.class) @@ -309,15 +308,15 @@ public void testTimeoutHandlerLineaerSUBMO() { } @Test - public void testWeightedNonClauselSoftConstraints() throws ParserException { + public void testWeightedNonClauselSoftConstraints() { final MaxSATSolver[] solvers = new MaxSATSolver[4]; solvers[0] = MaxSATSolver.incWBO(this.f); solvers[1] = MaxSATSolver.linearSU(this.f); solvers[2] = MaxSATSolver.wbo(this.f); solvers[3] = MaxSATSolver.wmsu3(this.f); for (final MaxSATSolver solver : solvers) { - solver.addHardFormula(this.f.parse("a & b & c")); - solver.addSoftFormula(this.f.parse("~a & ~b & ~c"), 2); + solver.addHardFormula(parse(this.f, "a & b & c")); + solver.addSoftFormula(parse(this.f, "~a & ~b & ~c"), 2); assertThat(solver.solve()).isEqualTo(MaxSAT.MaxSATResult.OPTIMUM); assertThat(solver.model().literals()).containsExactlyInAnyOrder( this.f.variable("a"), this.f.variable("b"), this.f.variable("c") @@ -328,16 +327,16 @@ public void testWeightedNonClauselSoftConstraints() throws ParserException { } @Test - public void testWeightedSoftConstraintsCornerCaseVerum() throws ParserException { + public void testWeightedSoftConstraintsCornerCaseVerum() { final MaxSATSolver[] solvers = new MaxSATSolver[4]; solvers[0] = MaxSATSolver.incWBO(this.f); solvers[1] = MaxSATSolver.linearSU(this.f); solvers[2] = MaxSATSolver.wbo(this.f); solvers[3] = MaxSATSolver.wmsu3(this.f); for (final MaxSATSolver solver : solvers) { - solver.addHardFormula(this.f.parse("a & b & c")); - solver.addSoftFormula(this.f.parse("$true"), 2); - solver.addSoftFormula(this.f.parse("~a & ~b & ~c"), 3); + solver.addHardFormula(parse(this.f, "a & b & c")); + solver.addSoftFormula(parse(this.f, "$true"), 2); + solver.addSoftFormula(parse(this.f, "~a & ~b & ~c"), 3); assertThat(solver.solve()).isEqualTo(MaxSAT.MaxSATResult.OPTIMUM); assertThat(solver.model().literals()).containsExactlyInAnyOrder( this.f.variable("a"), this.f.variable("b"), this.f.variable("c") @@ -347,16 +346,16 @@ public void testWeightedSoftConstraintsCornerCaseVerum() throws ParserException } @Test - public void testWeightedSoftConstraintsCornerCaseFalsum() throws ParserException { + public void testWeightedSoftConstraintsCornerCaseFalsum() { final MaxSATSolver[] solvers = new MaxSATSolver[4]; solvers[0] = MaxSATSolver.incWBO(this.f); solvers[1] = MaxSATSolver.linearSU(this.f); solvers[2] = MaxSATSolver.wbo(this.f); solvers[3] = MaxSATSolver.wmsu3(this.f); for (final MaxSATSolver solver : solvers) { - solver.addHardFormula(this.f.parse("a & b & c")); - solver.addSoftFormula(this.f.parse("$false"), 2); - solver.addSoftFormula(this.f.parse("~a & ~b & ~c"), 3); + solver.addHardFormula(parse(this.f, "a & b & c")); + solver.addSoftFormula(parse(this.f, "$false"), 2); + solver.addSoftFormula(parse(this.f, "~a & ~b & ~c"), 3); assertThat(solver.solve()).isEqualTo(MaxSAT.MaxSATResult.OPTIMUM); assertThat(solver.model().literals()).containsExactlyInAnyOrder( this.f.variable("a"), this.f.variable("b"), this.f.variable("c") diff --git a/src/test/java/org/logicng/solvers/maxsat/PureMaxSATTest.java b/src/test/java/org/logicng/solvers/maxsat/PureMaxSATTest.java index f9b12b4f..9f1df46a 100644 --- a/src/test/java/org/logicng/solvers/maxsat/PureMaxSATTest.java +++ b/src/test/java/org/logicng/solvers/maxsat/PureMaxSATTest.java @@ -78,7 +78,7 @@ public PureMaxSATTest() throws FileNotFoundException { public void testExceptionalBehavior() { assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.incWBO(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 1); solver.solve(); solver.addHardFormula(this.B); @@ -86,7 +86,7 @@ public void testExceptionalBehavior() { .hasMessage("The MaxSAT solver does currently not support an incremental interface. Reset the solver."); assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.incWBO(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 1); solver.solve(); solver.addSoftFormula(this.B, 1); @@ -94,20 +94,20 @@ public void testExceptionalBehavior() { .hasMessage("The MaxSAT solver does currently not support an incremental interface. Reset the solver."); assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.incWBO(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, -1); }).isInstanceOf(IllegalArgumentException.class) .hasMessage("The weight of a formula must be > 0"); assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.incWBO(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 1); solver.result(); }).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot get a result as long as the formula is not solved. Call 'solver' first."); assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.incWBO(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 1); solver.model(); }).isInstanceOf(IllegalStateException.class) @@ -118,7 +118,7 @@ public void testExceptionalBehavior() { public void testExceptionalBehaviorForLinearUS() { assertThatThrownBy(() -> { final MaxSATSolver solver = MaxSATSolver.linearUS(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 3); solver.solve(); }).isInstanceOf(IllegalStateException.class) @@ -128,7 +128,7 @@ public void testExceptionalBehaviorForLinearUS() { .incremental(MaxSATConfig.IncrementalStrategy.ITERATIVE) .cardinality(CardinalityEncoding.MTOTALIZER) .build()); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addSoftFormula(this.A, 1); solver.solve(); }).isInstanceOf(IllegalStateException.class) @@ -136,9 +136,9 @@ public void testExceptionalBehaviorForLinearUS() { } @Test - public void testCornerCase() throws ParserException { + public void testCornerCase() { final MaxSATSolver solver = MaxSATSolver.incWBO(this.f); - solver.addHardFormula(this.f.parse("a | b")); + solver.addHardFormula(parse(this.f, "a | b")); solver.addHardFormula(this.f.verum()); solver.addSoftFormula(this.A, 1); MaxSAT.MaxSATResult result = solver.solve(); diff --git a/src/test/java/org/logicng/solvers/sat/MiniSatTest.java b/src/test/java/org/logicng/solvers/sat/MiniSatTest.java index 3ad02c14..d590275b 100644 --- a/src/test/java/org/logicng/solvers/sat/MiniSatTest.java +++ b/src/test/java/org/logicng/solvers/sat/MiniSatTest.java @@ -30,13 +30,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.logicng.TestWithExampleFormulas.parse; import static org.logicng.datastructures.Tristate.FALSE; import static org.logicng.datastructures.Tristate.TRUE; import org.junit.jupiter.api.Test; import org.logicng.collections.LNGIntVector; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; @@ -127,10 +127,10 @@ public void testConfig() { } @Test - public void testAssumptionChecking() throws ParserException { + public void testAssumptionChecking() { final FormulaFactory f = new FormulaFactory(); final SATSolver solver = MiniSat.miniSat(f); - solver.add(f.parse("A & B")); + solver.add(parse(f, "A & B")); assertThat(solver.sat()).isEqualTo(TRUE); assertThat(solver.sat(f.literal("A", true))).isEqualTo(TRUE); assertThat(solver.sat(f.literal("B", true))).isEqualTo(TRUE); diff --git a/src/test/java/org/logicng/solvers/sat/SATTest.java b/src/test/java/org/logicng/solvers/sat/SATTest.java index d2949650..0e833039 100644 --- a/src/test/java/org/logicng/solvers/sat/SATTest.java +++ b/src/test/java/org/logicng/solvers/sat/SATTest.java @@ -391,11 +391,11 @@ public void testWithRelaxation() throws ParserException { } @Test - public void testRelaxationFormulas() throws ParserException { + public void testRelaxationFormulas() { for (final SATSolver s : this.solvers) { - s.add(this.f.parse("a & (b | c)")); + s.add(parse(this.f, "a & (b | c)")); assertSolverSat(s); - s.addWithRelaxation(this.f.variable("x"), this.f.parse("~a & ~b")); + s.addWithRelaxation(this.f.variable("x"), parse(this.f, "~a & ~b")); assertSolverSat(s); assertThat(s.model().positiveVariables()).contains(this.f.variable("x")); s.add(this.f.variable("x").negate()); @@ -875,7 +875,7 @@ public void testAddWithoutUnknown() throws ParserException { public void testUPZeroLiteralsForUndefState() { assertThatThrownBy(() -> { final SATSolver solver = MiniSat.miniSat(this.f); - solver.add(this.f.parse("a & b")); + solver.add(parse(this.f, "a & b")); solver.execute(UpZeroLiteralsFunction.get()); }).isInstanceOf(IllegalStateException.class) .hasMessage("Cannot get unit propagated literals on level 0 as long as the formula is not solved. Call 'sat' first."); @@ -969,22 +969,22 @@ public void testFormulaOnSolver() throws ParserException { } @Test - public void testFormulaOnSolverWithContradiction() throws ParserException { + public void testFormulaOnSolverWithContradiction() { for (final SATSolver solver : this.solvers) { if (solver instanceof MiniSat) { solver.add(this.f.variable("A")); solver.add(this.f.variable("B")); - solver.add(this.f.parse("C & (~A | ~B)")); + solver.add(parse(this.f, "C & (~A | ~B)")); assertThat(solver.execute(FormulaOnSolverFunction.get())) .containsExactlyInAnyOrder(this.f.variable("A"), this.f.variable("B"), this.f.variable("C"), this.f.falsum()); solver.reset(); - solver.add(this.f.parse("A <=> B")); - solver.add(this.f.parse("B <=> ~A")); + solver.add(parse(this.f, "A <=> B")); + solver.add(parse(this.f, "B <=> ~A")); assertThat(solver.execute(FormulaOnSolverFunction.get())) - .containsExactlyInAnyOrder(this.f.parse("A | ~B"), this.f.parse("~A | B"), this.f.parse("~B | ~A"), this.f.parse("B | A")); + .containsExactlyInAnyOrder(parse(this.f, "A | ~B"), parse(this.f, "~A | B"), parse(this.f, "~B | ~A"), parse(this.f, "B | A")); solver.sat(); assertThat(solver.execute(FormulaOnSolverFunction.get())) - .containsExactlyInAnyOrder(this.f.parse("A | ~B"), this.f.parse("~A | B"), this.f.parse("~B | ~A"), this.f.parse("B | A"), + .containsExactlyInAnyOrder(parse(this.f, "A | ~B"), parse(this.f, "~A | B"), parse(this.f, "~B | ~A"), parse(this.f, "B | A"), this.f.variable("A"), this.f.variable("B"), this.f.falsum()); } } @@ -1105,9 +1105,9 @@ public void testDimacsFilesWithSelectionOrder() throws IOException { } @Test - public void testModelEnumerationWithAdditionalVariables() throws ParserException { + public void testModelEnumerationWithAdditionalVariables() { final SATSolver solver = MiniSat.miniSat(this.f); - solver.add(this.f.parse("A | B | C | D | E")); + solver.add(parse(this.f, "A | B | C | D | E")); final List models = solver.execute(ModelEnumerationFunction.builder() .variables(Arrays.asList(this.f.variable("A"), this.f.variable("B"))) .additionalVariables(Arrays.asList(this.f.variable("B"), this.f.variable("C"))).build()); diff --git a/src/test/java/org/logicng/transformations/LiteralSubstitutionTest.java b/src/test/java/org/logicng/transformations/LiteralSubstitutionTest.java index 5955541d..ec994d07 100644 --- a/src/test/java/org/logicng/transformations/LiteralSubstitutionTest.java +++ b/src/test/java/org/logicng/transformations/LiteralSubstitutionTest.java @@ -29,12 +29,12 @@ package org.logicng.transformations; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Literal; -import org.logicng.io.parsers.ParserException; import java.util.HashMap; import java.util.Map; @@ -60,36 +60,36 @@ public void init() { } @Test - public void testSimpleFormula() throws ParserException { - assertThat(this.f.parse("$true").transform(this.s1)).isEqualTo(this.f.parse("$true")); - assertThat(this.f.parse("$false").transform(this.s1)).isEqualTo(this.f.parse("$false")); + public void testSimpleFormula() { + assertThat(parse(this.f, "$true").transform(this.s1)).isEqualTo(parse(this.f, "$true")); + assertThat(parse(this.f, "$false").transform(this.s1)).isEqualTo(parse(this.f, "$false")); } @Test - public void testLiterals() throws ParserException { - assertThat(this.f.parse("m").transform(this.s1)).isEqualTo(this.f.parse("m")); - assertThat(this.f.parse("~m").transform(this.s1)).isEqualTo(this.f.parse("~m")); - assertThat(this.f.parse("a").transform(this.s1)).isEqualTo(this.f.parse("a_t")); - assertThat(this.f.parse("~a").transform(this.s1)).isEqualTo(this.f.parse("a_f")); - assertThat(this.f.parse("b").transform(this.s1)).isEqualTo(this.f.parse("b")); - assertThat(this.f.parse("~b").transform(this.s1)).isEqualTo(this.f.parse("x")); - assertThat(this.f.parse("c").transform(this.s1)).isEqualTo(this.f.parse("y")); - assertThat(this.f.parse("~c").transform(this.s1)).isEqualTo(this.f.parse("~y")); + public void testLiterals() { + assertThat(parse(this.f, "m").transform(this.s1)).isEqualTo(parse(this.f, "m")); + assertThat(parse(this.f, "~m").transform(this.s1)).isEqualTo(parse(this.f, "~m")); + assertThat(parse(this.f, "a").transform(this.s1)).isEqualTo(parse(this.f, "a_t")); + assertThat(parse(this.f, "~a").transform(this.s1)).isEqualTo(parse(this.f, "a_f")); + assertThat(parse(this.f, "b").transform(this.s1)).isEqualTo(parse(this.f, "b")); + assertThat(parse(this.f, "~b").transform(this.s1)).isEqualTo(parse(this.f, "x")); + assertThat(parse(this.f, "c").transform(this.s1)).isEqualTo(parse(this.f, "y")); + assertThat(parse(this.f, "~c").transform(this.s1)).isEqualTo(parse(this.f, "~y")); } @Test - public void testFormulas() throws ParserException { - assertThat(this.f.parse("~(a & b & ~c & x)").transform(this.s1)).isEqualTo(this.f.parse("~(a_t & b & ~y & x)")); - assertThat(this.f.parse("a & b & ~c & x").transform(this.s1)).isEqualTo(this.f.parse("a_t & b & ~y & x")); - assertThat(this.f.parse("a | b | ~c | x").transform(this.s1)).isEqualTo(this.f.parse("a_t | b | ~y | x")); - assertThat(this.f.parse("(a | b) => (~c | x)").transform(this.s1)).isEqualTo(this.f.parse("(a_t | b) => (~y | x)")); - assertThat(this.f.parse("(a | b) <=> (~c | x)").transform(this.s1)).isEqualTo(this.f.parse("(a_t | b) <=> (~y | x)")); - assertThat(this.f.parse("2*a + 3*~b + -4*~c + x <= 5").transform(this.s1)).isEqualTo(this.f.parse("2*a_t + 3*x + -4*~y + x <= 5")); + public void testFormulas() { + assertThat(parse(this.f, "~(a & b & ~c & x)").transform(this.s1)).isEqualTo(parse(this.f, "~(a_t & b & ~y & x)")); + assertThat(parse(this.f, "a & b & ~c & x").transform(this.s1)).isEqualTo(parse(this.f, "a_t & b & ~y & x")); + assertThat(parse(this.f, "a | b | ~c | x").transform(this.s1)).isEqualTo(parse(this.f, "a_t | b | ~y | x")); + assertThat(parse(this.f, "(a | b) => (~c | x)").transform(this.s1)).isEqualTo(parse(this.f, "(a_t | b) => (~y | x)")); + assertThat(parse(this.f, "(a | b) <=> (~c | x)").transform(this.s1)).isEqualTo(parse(this.f, "(a_t | b) <=> (~y | x)")); + assertThat(parse(this.f, "2*a + 3*~b + -4*~c + x <= 5").transform(this.s1)).isEqualTo(parse(this.f, "2*a_t + 3*x + -4*~y + x <= 5")); } @Test - public void testEmptySubstitution() throws ParserException { - assertThat(this.f.parse("2*a + 3*~b + -4*~c + x <= 5").transform(new LiteralSubstitution())).isEqualTo(this.f.parse("2*a + 3*~b + -4*~c + x <= 5")); + public void testEmptySubstitution() { + assertThat(parse(this.f, "2*a + 3*~b + -4*~c + x <= 5").transform(new LiteralSubstitution())).isEqualTo(parse(this.f, "2*a + 3*~b + -4*~c + x <= 5")); } } diff --git a/src/test/java/org/logicng/transformations/PureExpansionTransformationTest.java b/src/test/java/org/logicng/transformations/PureExpansionTransformationTest.java index ea2bfcc6..f804d381 100644 --- a/src/test/java/org/logicng/transformations/PureExpansionTransformationTest.java +++ b/src/test/java/org/logicng/transformations/PureExpansionTransformationTest.java @@ -40,7 +40,6 @@ import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Not; import org.logicng.formulas.PBConstraint; -import org.logicng.io.parsers.ParserException; import org.logicng.modelcounting.ModelCounter; import org.logicng.predicates.satisfiability.TautologyPredicate; import org.logicng.util.FormulaCornerCases; @@ -71,20 +70,20 @@ public void testLiterals() { } @Test - public void testNot() throws ParserException { + public void testNot() { assertThat(this.NOT1.transform(transformation)).isEqualTo(this.NOT1); assertThat(this.NOT2.transform(transformation)).isEqualTo(this.NOT2); - assertThat(this.f.parse("~a").transform(transformation)).isEqualTo(this.f.parse("~a")); - assertThat(this.f.parse("~(a => b)").transform(transformation)).isEqualTo(this.f.parse("~(a => b)")); - assertThat(this.f.parse("~(~(a | b) => ~(x | y))").transform(transformation)).isEqualTo(this.f.parse("~(~(a | b) => ~(x | y))")); - assertThat(this.f.parse("~(a <=> b)").transform(transformation)).isEqualTo(this.f.parse("~(a <=> b)")); - assertThat(this.f.parse("~(a & b & ~x & ~y)").transform(transformation)).isEqualTo(this.f.parse("~(a & b & ~x & ~y)")); - assertThat(this.f.parse("~(a | b | (a + b <= 1) | ~y)").transform(transformation)).isEqualTo(this.f.parse("~(a | b | (~a | ~b) | ~y)")); + assertThat(parse(this.f, "~a").transform(transformation)).isEqualTo(parse(this.f, "~a")); + assertThat(parse(this.f, "~(a => b)").transform(transformation)).isEqualTo(parse(this.f, "~(a => b)")); + assertThat(parse(this.f, "~(~(a | b) => ~(x | y))").transform(transformation)).isEqualTo(parse(this.f, "~(~(a | b) => ~(x | y))")); + assertThat(parse(this.f, "~(a <=> b)").transform(transformation)).isEqualTo(parse(this.f, "~(a <=> b)")); + assertThat(parse(this.f, "~(a & b & ~x & ~y)").transform(transformation)).isEqualTo(parse(this.f, "~(a & b & ~x & ~y)")); + assertThat(parse(this.f, "~(a | b | (a + b <= 1) | ~y)").transform(transformation)).isEqualTo(parse(this.f, "~(a | b | (~a | ~b) | ~y)")); } @Test - public void testBinaryOperators() throws ParserException { + public void testBinaryOperators() { assertThat(this.IMP1.transform(transformation)).isEqualTo(this.IMP1); assertThat(this.IMP2.transform(transformation)).isEqualTo(this.IMP2); assertThat(this.IMP3.transform(transformation)).isEqualTo(this.IMP3); @@ -94,11 +93,11 @@ public void testBinaryOperators() throws ParserException { assertThat(this.EQ3.transform(transformation)).isEqualTo(this.EQ3); assertThat(this.EQ4.transform(transformation)).isEqualTo(this.EQ4); - assertThat(this.f.parse("~(a => (a + b = 1))").transform(transformation)).isEqualTo(this.f.parse("~(a => (a | b) & (~a | ~b))")); + assertThat(parse(this.f, "~(a => (a + b = 1))").transform(transformation)).isEqualTo(parse(this.f, "~(a => (a | b) & (~a | ~b))")); } @Test - public void testNAryOperators() throws ParserException { + public void testNAryOperators() { assertThat(this.AND1.transform(transformation)).isEqualTo(this.AND1); assertThat(this.AND2.transform(transformation)).isEqualTo(this.AND2); assertThat(this.AND3.transform(transformation)).isEqualTo(this.AND3); @@ -106,20 +105,20 @@ public void testNAryOperators() throws ParserException { assertThat(this.OR2.transform(transformation)).isEqualTo(this.OR2); assertThat(this.OR3.transform(transformation)).isEqualTo(this.OR3); - assertThat(this.f.parse("~(a & b) | c | ~(x | ~y)").transform(transformation)).isEqualTo(this.f.parse("~(a & b) | c | ~(x | ~y)")); - assertThat(this.f.parse("~(a | b) & (a + b = 1) & ~(x & ~(z + x = 1))").transform(transformation)) - .isEqualTo(this.f.parse("~(a | b) & ((a | b) & (~a | ~b)) & ~(x & ~((z | x) & (~z | ~x)))")); - assertThat(this.f.parse("a & b & (~x | ~y)").transform(transformation)).isEqualTo(this.f.parse("a & b & (~x | ~y)")); - assertThat(this.f.parse("~(a | b) & c & ~(x & ~y) & (w => z)").transform(transformation)).isEqualTo(this.f.parse("~(a | b) & c & ~(x & ~y) & (w => z)")); - assertThat(this.f.parse("~(a & b) | c | ~(x | ~y)").transform(transformation)).isEqualTo(this.f.parse("~(a & b) | c | ~(x | ~y)")); - assertThat(this.f.parse("a | b | (~x & ~y)").transform(transformation)).isEqualTo(this.f.parse("a | b | (~x & ~y)")); + assertThat(parse(this.f, "~(a & b) | c | ~(x | ~y)").transform(transformation)).isEqualTo(parse(this.f, "~(a & b) | c | ~(x | ~y)")); + assertThat(parse(this.f, "~(a | b) & (a + b = 1) & ~(x & ~(z + x = 1))").transform(transformation)) + .isEqualTo(parse(this.f, "~(a | b) & ((a | b) & (~a | ~b)) & ~(x & ~((z | x) & (~z | ~x)))")); + assertThat(parse(this.f, "a & b & (~x | ~y)").transform(transformation)).isEqualTo(parse(this.f, "a & b & (~x | ~y)")); + assertThat(parse(this.f, "~(a | b) & c & ~(x & ~y) & (w => z)").transform(transformation)).isEqualTo(parse(this.f, "~(a | b) & c & ~(x & ~y) & (w => z)")); + assertThat(parse(this.f, "~(a & b) | c | ~(x | ~y)").transform(transformation)).isEqualTo(parse(this.f, "~(a & b) | c | ~(x | ~y)")); + assertThat(parse(this.f, "a | b | (~x & ~y)").transform(transformation)).isEqualTo(parse(this.f, "a | b | (~x & ~y)")); } @Test - public void testPBCs() throws ParserException { - assertThat(this.f.parse("a + b <= 1").transform(transformation)).isEqualTo(this.f.parse("~a | ~b")); - assertThat(this.f.parse("a + b < 2").transform(transformation)).isEqualTo(this.f.parse("~a | ~b")); - assertThat(this.f.parse("a + b = 1").transform(transformation)).isEqualTo(this.f.parse("(a | b) & (~a | ~b)")); + public void testPBCs() { + assertThat(parse(this.f, "a + b <= 1").transform(transformation)).isEqualTo(parse(this.f, "~a | ~b")); + assertThat(parse(this.f, "a + b < 2").transform(transformation)).isEqualTo(parse(this.f, "~a | ~b")); + assertThat(parse(this.f, "a + b = 1").transform(transformation)).isEqualTo(parse(this.f, "(a | b) & (~a | ~b)")); } @Test diff --git a/src/test/java/org/logicng/transformations/cnf/CanonicalCNFEnumerationTest.java b/src/test/java/org/logicng/transformations/cnf/CanonicalCNFEnumerationTest.java index c55b48d8..2d97934a 100644 --- a/src/test/java/org/logicng/transformations/cnf/CanonicalCNFEnumerationTest.java +++ b/src/test/java/org/logicng/transformations/cnf/CanonicalCNFEnumerationTest.java @@ -1,12 +1,12 @@ package org.logicng.transformations.cnf; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.RandomTag; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.predicates.CNFPredicate; import org.logicng.predicates.satisfiability.TautologyPredicate; import org.logicng.util.FormulaCornerCases; @@ -21,21 +21,21 @@ public class CanonicalCNFEnumerationTest { @Test - public void testSamples() throws ParserException { + public void testSamples() { final FormulaFactory f = new FormulaFactory(); - assertThat(f.falsum().transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("$false")); - assertThat(f.verum().transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("$true")); - assertThat(f.parse("a").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("a")); - assertThat(f.parse("~a").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("~a")); - assertThat(f.parse("~a & b").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("(~a | b) & (~a | ~b) & (a | b)")); - assertThat(f.parse("~a | b").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("~a | b")); - assertThat(f.parse("a => b").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("~a | b")); - assertThat(f.parse("a <=> b").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("(~a | b) & (a | ~b)")); - assertThat(f.parse("a + b = 1").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("(a | b) & (~a | ~b)")); - assertThat(f.parse("a & (b | ~c)").transform(CanonicalCNFEnumeration.get())) - .isEqualTo(f.parse("(a | b | c) & (a | b | ~c) & (a | ~b | c) & (a | ~b | ~c) & (~a | b | ~c)")); - assertThat(f.parse("a & b & (~a | ~b)").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("(a | b) & (~a | b) & (~a | ~b) & (a | ~b)")); - assertThat(f.parse("a | b | ~a & ~b").transform(CanonicalCNFEnumeration.get())).isEqualTo(f.parse("$true")); + assertThat(f.falsum().transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "$false")); + assertThat(f.verum().transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "$true")); + assertThat(parse(f, "a").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "a")); + assertThat(parse(f, "~a").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "~a")); + assertThat(parse(f, "~a & b").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "(~a | b) & (~a | ~b) & (a | b)")); + assertThat(parse(f, "~a | b").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "~a | b")); + assertThat(parse(f, "a => b").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "~a | b")); + assertThat(parse(f, "a <=> b").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "(~a | b) & (a | ~b)")); + assertThat(parse(f, "a + b = 1").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "(a | b) & (~a | ~b)")); + assertThat(parse(f, "a & (b | ~c)").transform(CanonicalCNFEnumeration.get())) + .isEqualTo(parse(f, "(a | b | c) & (a | b | ~c) & (a | ~b | c) & (a | ~b | ~c) & (~a | b | ~c)")); + assertThat(parse(f, "a & b & (~a | ~b)").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "(a | b) & (~a | b) & (~a | ~b) & (a | ~b)")); + assertThat(parse(f, "a | b | ~a & ~b").transform(CanonicalCNFEnumeration.get())).isEqualTo(parse(f, "$true")); } @Test diff --git a/src/test/java/org/logicng/transformations/cnf/PlaistedGreenbaumTransformationSolverTest.java b/src/test/java/org/logicng/transformations/cnf/PlaistedGreenbaumTransformationSolverTest.java index 550cb9a7..c87a0ccc 100644 --- a/src/test/java/org/logicng/transformations/cnf/PlaistedGreenbaumTransformationSolverTest.java +++ b/src/test/java/org/logicng/transformations/cnf/PlaistedGreenbaumTransformationSolverTest.java @@ -37,7 +37,6 @@ import org.logicng.datastructures.Tristate; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.predicates.satisfiability.SATPredicate; import org.logicng.predicates.satisfiability.TautologyPredicate; import org.logicng.solvers.MiniSat; @@ -118,29 +117,29 @@ private static Formula randomSATFormula(final FormulaRandomizer randomizer, fina } @Test - public void simple() throws ParserException { - computeAndVerify(this.f.parse("(X => (A & B)) | ~(A & B)")); - computeAndVerify(this.f.parse("~((A | (C & D)) & ((X & ~Z) | (H & E)))")); + public void simple() { + computeAndVerify(parse(this.f, "(X => (A & B)) | ~(A & B)")); + computeAndVerify(parse(this.f, "~((A | (C & D)) & ((X & ~Z) | (H & E)))")); - computeAndVerify(this.f.parse("A | (B | ~C) & (D | ~E)")); - computeAndVerify(this.f.parse("A | B & (C | D)")); + computeAndVerify(parse(this.f, "A | (B | ~C) & (D | ~E)")); + computeAndVerify(parse(this.f, "A | B & (C | D)")); - computeAndVerify(this.f.parse("~(A&B)|X")); - computeAndVerify(this.f.parse("~(~(A&B)|X)")); + computeAndVerify(parse(this.f, "~(A&B)|X")); + computeAndVerify(parse(this.f, "~(~(A&B)|X)")); - computeAndVerify(this.f.parse("~(~(A&B)|X)")); - computeAndVerify(this.f.parse("~(A&B=>X)")); + computeAndVerify(parse(this.f, "~(~(A&B)|X)")); + computeAndVerify(parse(this.f, "~(A&B=>X)")); - computeAndVerify(this.f.parse("A&B => X")); - computeAndVerify(this.f.parse("~(A&B=>X)")); + computeAndVerify(parse(this.f, "A&B => X")); + computeAndVerify(parse(this.f, "~(A&B=>X)")); - computeAndVerify(this.f.parse("A&B <=> X")); - computeAndVerify(this.f.parse("~(A&B<=>X)")); + computeAndVerify(parse(this.f, "A&B <=> X")); + computeAndVerify(parse(this.f, "~(A&B<=>X)")); - computeAndVerify(this.f.parse("~(A&B)")); + computeAndVerify(parse(this.f, "~(A&B)")); - computeAndVerify(this.f.parse("A & (B | A => (A <=> ~B))")); - computeAndVerify(this.f.parse("(A => ~A) <=> (B <=> (~A => B))")); + computeAndVerify(parse(this.f, "A & (B | A => (A <=> ~B))")); + computeAndVerify(parse(this.f, "(A => ~A) <=> (B <=> (~A => B))")); } private static void computeAndVerify(final Formula formula) { diff --git a/src/test/java/org/logicng/transformations/dnf/CanonicalDNFEnumerationTest.java b/src/test/java/org/logicng/transformations/dnf/CanonicalDNFEnumerationTest.java index f5947e6d..a14547df 100644 --- a/src/test/java/org/logicng/transformations/dnf/CanonicalDNFEnumerationTest.java +++ b/src/test/java/org/logicng/transformations/dnf/CanonicalDNFEnumerationTest.java @@ -1,12 +1,12 @@ package org.logicng.transformations.dnf; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.TestWithExampleFormulas.parse; import org.junit.jupiter.api.Test; import org.logicng.RandomTag; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.predicates.DNFPredicate; import org.logicng.predicates.satisfiability.ContradictionPredicate; import org.logicng.predicates.satisfiability.TautologyPredicate; @@ -22,20 +22,20 @@ public class CanonicalDNFEnumerationTest { @Test - public void testSamples() throws ParserException { + public void testSamples() { final FormulaFactory f = new FormulaFactory(); - assertThat(f.falsum().transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("$false")); - assertThat(f.verum().transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("$true")); - assertThat(f.parse("a").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("a")); - assertThat(f.parse("~a").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("~a")); - assertThat(f.parse("~a & b").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("~a & b")); - assertThat(f.parse("~a | b").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("~a & ~b | ~a & b | a & b")); - assertThat(f.parse("a => b").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("~a & ~b | ~a & b | a & b")); - assertThat(f.parse("a <=> b").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("a & b | ~a & ~b")); - assertThat(f.parse("a + b = 1").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("~a & b | a & ~b")); - assertThat(f.parse("a & (b | ~c)").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("a & b & c | a & b & ~c | a & ~b & ~c")); - assertThat(f.parse("a & b & (~a | ~b)").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("$false")); - assertThat(f.parse("a | b | ~a & ~b").transform(CanonicalDNFEnumeration.get())).isEqualTo(f.parse("~a & b | a & b | a & ~b | ~a & ~b")); + assertThat(f.falsum().transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "$false")); + assertThat(f.verum().transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "$true")); + assertThat(parse(f, "a").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "a")); + assertThat(parse(f, "~a").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "~a")); + assertThat(parse(f, "~a & b").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "~a & b")); + assertThat(parse(f, "~a | b").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "~a & ~b | ~a & b | a & b")); + assertThat(parse(f, "a => b").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "~a & ~b | ~a & b | a & b")); + assertThat(parse(f, "a <=> b").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "a & b | ~a & ~b")); + assertThat(parse(f, "a + b = 1").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "~a & b | a & ~b")); + assertThat(parse(f, "a & (b | ~c)").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "a & b & c | a & b & ~c | a & ~b & ~c")); + assertThat(parse(f, "a & b & (~a | ~b)").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "$false")); + assertThat(parse(f, "a | b | ~a & ~b").transform(CanonicalDNFEnumeration.get())).isEqualTo(parse(f, "~a & b | a & b | a & ~b | ~a & ~b")); } @Test diff --git a/src/test/java/org/logicng/transformations/qmc/QuineMcCluskeyTest.java b/src/test/java/org/logicng/transformations/qmc/QuineMcCluskeyTest.java index d7a357f3..184a7e26 100644 --- a/src/test/java/org/logicng/transformations/qmc/QuineMcCluskeyTest.java +++ b/src/test/java/org/logicng/transformations/qmc/QuineMcCluskeyTest.java @@ -113,7 +113,7 @@ public void testLarge1() throws ParserException { } @Test - public void testLarge2() throws ParserException, IOException { + public void testLarge2() throws IOException, ParserException { final FormulaFactory f = new FormulaFactory(); final Formula formula = FormulaReader.readPseudoBooleanFormula("src/test/resources/formulas/large_formula.txt", f); final SATSolver solver = MiniSat.miniSat(f); @@ -140,7 +140,7 @@ public void testLarge2() throws ParserException, IOException { } @Test - public void testLarge3() throws ParserException, IOException { + public void testLarge3() throws IOException, ParserException { final FormulaFactory f = new FormulaFactory(); final Formula formula = FormulaReader.readPseudoBooleanFormula("src/test/resources/formulas/large_formula.txt", f); final SATSolver solver = MiniSat.miniSat(f); diff --git a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java index fb26a82d..be2b3cad 100644 --- a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java +++ b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java @@ -84,20 +84,20 @@ public void testRandomized() { } @Test - public void testTimeoutHandlerSmall() throws ParserException { + public void testTimeoutHandlerSmall() { final List handlers = Arrays.asList( new TimeoutOptimizationHandler(5_000L, TimeoutHandler.TimerType.SINGLE_TIMEOUT), new TimeoutOptimizationHandler(5_000L, TimeoutHandler.TimerType.RESTARTING_TIMEOUT), new TimeoutOptimizationHandler(System.currentTimeMillis() + 5_000L, TimeoutHandler.TimerType.FIXED_END) ); - final Formula formula = this.f.parse("a & b | ~c & a"); + final Formula formula = parse(this.f, "a & b | ~c & a"); for (final TimeoutOptimizationHandler handler : handlers) { testHandler(handler, formula, false); } } @Test - public void testTimeoutHandlerLarge() throws ParserException, IOException { + public void testTimeoutHandlerLarge() throws IOException, ParserException { final List handlers = Arrays.asList( new TimeoutOptimizationHandler(1L, TimeoutHandler.TimerType.SINGLE_TIMEOUT), new TimeoutOptimizationHandler(1L, TimeoutHandler.TimerType.RESTARTING_TIMEOUT), @@ -110,24 +110,24 @@ public void testTimeoutHandlerLarge() throws ParserException, IOException { } @Test - public void testPrimeCompilerIsCancelled() throws ParserException { + public void testPrimeCompilerIsCancelled() { final OptimizationHandler handler = new BoundedOptimizationHandler(-1, 0); - final Formula formula = this.f.parse("a&(b|c)"); + final Formula formula = parse(this.f, "a&(b|c)"); testHandler(handler, formula, true); } @Test - public void testSmusComputationIsCancelled() throws ParserException { + public void testSmusComputationIsCancelled() { final OptimizationHandler handler = new BoundedOptimizationHandler(-1, 5); - final Formula formula = this.f.parse("a&(b|c)"); + final Formula formula = parse(this.f, "a&(b|c)"); testHandler(handler, formula, true); } @LongRunningTag @Test - public void testCancellationPoints() throws ParserException { + public void testCancellationPoints() { final FormulaFactory f = new FormulaFactory(); - final Formula formula = f.parse("~v16 & ~v22 & ~v12 & (~v4 | ~v14) & (~v4 | ~v15) & (v3 | v4) & (v3 | ~v14) & (v3 | ~v15) " + + final Formula formula = parse(f, "~v16 & ~v22 & ~v12 & (~v4 | ~v14) & (~v4 | ~v15) & (v3 | v4) & (v3 | ~v14) & (v3 | ~v15) " + "& (~v20 | ~v8) & (v9 | ~v20) & (~v21 | ~v8) & (v9 | ~v21) & (~v21 | ~v10) & (~v21 | ~v11) & v19"); for (int numOptimizationStarts = 1; numOptimizationStarts < 30; numOptimizationStarts++) { for (int numSatHandlerStarts = 1; numSatHandlerStarts < 500; numSatHandlerStarts++) { diff --git a/src/test/java/org/logicng/transformations/simplification/FactorOutSimplificationTest.java b/src/test/java/org/logicng/transformations/simplification/FactorOutSimplificationTest.java index 0f53cc5c..cc5711df 100644 --- a/src/test/java/org/logicng/transformations/simplification/FactorOutSimplificationTest.java +++ b/src/test/java/org/logicng/transformations/simplification/FactorOutSimplificationTest.java @@ -35,7 +35,6 @@ import org.logicng.TestWithExampleFormulas; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.predicates.satisfiability.TautologyPredicate; import org.logicng.util.FormulaCornerCases; import org.logicng.util.FormulaRandomizer; @@ -51,29 +50,29 @@ public class FactorOutSimplificationTest extends TestWithExampleFormulas { private final FactorOutSimplifier factorOut = new FactorOutSimplifier(); @Test - public void testSimple() throws ParserException { + public void testSimple() { assertThat(this.f.falsum().transform(this.factorOut)).isEqualTo(this.f.falsum()); assertThat(this.f.verum().transform(this.factorOut)).isEqualTo(this.f.verum()); assertThat(this.A.transform(this.factorOut)).isEqualTo(this.A); assertThat(this.NA.transform(this.factorOut)).isEqualTo(this.NA); - assertThat(this.f.parse("A&~B&~C&~D").transform(this.factorOut)).isEqualTo(this.f.parse("A&~B&~C&~D")); - assertThat(this.f.parse("~A&~B&~C&~D").transform(this.factorOut)).isEqualTo(this.f.parse("~A&~B&~C&~D")); + assertThat(parse(this.f, "A&~B&~C&~D").transform(this.factorOut)).isEqualTo(parse(this.f, "A&~B&~C&~D")); + assertThat(parse(this.f, "~A&~B&~C&~D").transform(this.factorOut)).isEqualTo(parse(this.f, "~A&~B&~C&~D")); - assertThat(this.f.parse("A|A&B").transform(this.factorOut)).isEqualTo(this.f.parse("A")); - assertThat(this.f.parse("A|A&B|C&D").transform(this.factorOut)).isEqualTo(this.f.parse("A|C&D")); - assertThat(this.f.parse("~(A&(A|B))").transform(this.factorOut)).isEqualTo(this.f.parse("~A")); - assertThat(this.f.parse("A|A&B|C").transform(this.factorOut)).isEqualTo(this.f.parse("A|C")); + assertThat(parse(this.f, "A|A&B").transform(this.factorOut)).isEqualTo(parse(this.f, "A")); + assertThat(parse(this.f, "A|A&B|C&D").transform(this.factorOut)).isEqualTo(parse(this.f, "A|C&D")); + assertThat(parse(this.f, "~(A&(A|B))").transform(this.factorOut)).isEqualTo(parse(this.f, "~A")); + assertThat(parse(this.f, "A|A&B|C").transform(this.factorOut)).isEqualTo(parse(this.f, "A|C")); - assertThat(this.f.parse("A&(A|B)").transform(this.factorOut)).isEqualTo(this.f.parse("A")); - assertThat(this.f.parse("A&(A|B)&(C|D)").transform(this.factorOut)).isEqualTo(this.f.parse("A&(C|D)")); - assertThat(this.f.parse("~(A|A&B)").transform(this.factorOut)).isEqualTo(this.f.parse("~A")); - assertThat(this.f.parse("A&(A|B)&C").transform(this.factorOut)).isEqualTo(this.f.parse("A&C")); + assertThat(parse(this.f, "A&(A|B)").transform(this.factorOut)).isEqualTo(parse(this.f, "A")); + assertThat(parse(this.f, "A&(A|B)&(C|D)").transform(this.factorOut)).isEqualTo(parse(this.f, "A&(C|D)")); + assertThat(parse(this.f, "~(A|A&B)").transform(this.factorOut)).isEqualTo(parse(this.f, "~A")); + assertThat(parse(this.f, "A&(A|B)&C").transform(this.factorOut)).isEqualTo(parse(this.f, "A&C")); - assertThat(this.f.parse("A&X&Y|A&B&C|B&C&D|A&Z").transform(this.factorOut)).isEqualTo(this.f.parse("A&(X&Y|B&C|Z)|B&C&D")); - assertThat(this.f.parse("G&(A&X&Y|A&B&C|B&C&D|A&Z)").transform(this.factorOut)).isEqualTo(this.f.parse("G&(A&(X&Y|B&C|Z)|B&C&D)")); + assertThat(parse(this.f, "A&X&Y|A&B&C|B&C&D|A&Z").transform(this.factorOut)).isEqualTo(parse(this.f, "A&(X&Y|B&C|Z)|B&C&D")); + assertThat(parse(this.f, "G&(A&X&Y|A&B&C|B&C&D|A&Z)").transform(this.factorOut)).isEqualTo(parse(this.f, "G&(A&(X&Y|B&C|Z)|B&C&D)")); - assertThat(this.f.parse("G&(~(A&X&Y)|~(A&B&C))").transform(this.factorOut)).isEqualTo(this.f.parse("G&(~(A&X&Y)|~(A&B&C))")); + assertThat(parse(this.f, "G&(~(A&X&Y)|~(A&B&C))").transform(this.factorOut)).isEqualTo(parse(this.f, "G&(~(A&X&Y)|~(A&B&C))")); } @Test diff --git a/src/test/java/org/logicng/transformations/simplification/NegationMinimizerTest.java b/src/test/java/org/logicng/transformations/simplification/NegationMinimizerTest.java index 39182431..b41410a3 100644 --- a/src/test/java/org/logicng/transformations/simplification/NegationMinimizerTest.java +++ b/src/test/java/org/logicng/transformations/simplification/NegationMinimizerTest.java @@ -35,7 +35,6 @@ import org.logicng.TestWithExampleFormulas; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; -import org.logicng.io.parsers.ParserException; import org.logicng.predicates.satisfiability.TautologyPredicate; import org.logicng.util.FormulaCornerCases; import org.logicng.util.FormulaRandomizer; @@ -51,43 +50,43 @@ public class NegationMinimizerTest extends TestWithExampleFormulas { private final NegationSimplifier minimizer = NegationSimplifier.get(); @Test - public void testSimple() throws ParserException { + public void testSimple() { assertThat(this.f.falsum().transform(this.minimizer)).isEqualTo(this.f.falsum()); assertThat(this.f.verum().transform(this.minimizer)).isEqualTo(this.f.verum()); assertThat(this.A.transform(this.minimizer)).isEqualTo(this.A); assertThat(this.NA.transform(this.minimizer)).isEqualTo(this.NA); - assertThat(this.f.parse("A&~B&~C&~D").transform(this.minimizer)).isEqualTo(this.f.parse("A&~B&~C&~D")); - assertThat(this.f.parse("~A&~B&~C&~D").transform(this.minimizer)).isEqualTo(this.f.parse("~(A|B|C|D)")); + assertThat(parse(this.f, "A&~B&~C&~D").transform(this.minimizer)).isEqualTo(parse(this.f, "A&~B&~C&~D")); + assertThat(parse(this.f, "~A&~B&~C&~D").transform(this.minimizer)).isEqualTo(parse(this.f, "~(A|B|C|D)")); - assertThat(this.f.parse("A|~B|~C|~D").transform(this.minimizer)).isEqualTo(this.f.parse("A|~B|~C|~D")); - assertThat(this.f.parse("~A|~B|~C|~D").transform(this.minimizer)).isEqualTo(this.f.parse("~(A&B&C&D)")); + assertThat(parse(this.f, "A|~B|~C|~D").transform(this.minimizer)).isEqualTo(parse(this.f, "A|~B|~C|~D")); + assertThat(parse(this.f, "~A|~B|~C|~D").transform(this.minimizer)).isEqualTo(parse(this.f, "~(A&B&C&D)")); - assertThat(this.f.parse("~A|~B|~C|D|~E|~G").transform(this.minimizer)).isEqualTo(this.f.parse("D|~(A&B&C&E&G)")); - assertThat(this.f.parse("~A&~B&~C&D&~E&~G").transform(this.minimizer)).isEqualTo(this.f.parse("D&~(A|B|C|E|G)")); + assertThat(parse(this.f, "~A|~B|~C|D|~E|~G").transform(this.minimizer)).isEqualTo(parse(this.f, "D|~(A&B&C&E&G)")); + assertThat(parse(this.f, "~A&~B&~C&D&~E&~G").transform(this.minimizer)).isEqualTo(parse(this.f, "D&~(A|B|C|E|G)")); - assertThat(this.f.parse("~A|~B|~E&G|~H&~B&~C|~X").transform(this.minimizer)).isEqualTo(this.f.parse("~E&G|~(A&B&(H|B|C)&X)")); - assertThat(this.f.parse("~(A&B&~(~E&G)&(H|B|C)&X)").transform(this.minimizer)).isEqualTo(this.f.parse("~E&G|~(A&B&(H|B|C)&X)")); + assertThat(parse(this.f, "~A|~B|~E&G|~H&~B&~C|~X").transform(this.minimizer)).isEqualTo(parse(this.f, "~E&G|~(A&B&(H|B|C)&X)")); + assertThat(parse(this.f, "~(A&B&~(~E&G)&(H|B|C)&X)").transform(this.minimizer)).isEqualTo(parse(this.f, "~E&G|~(A&B&(H|B|C)&X)")); - assertThat(this.f.parse("~A|B|(~E&~G&~H&~K)").transform(this.minimizer)).isEqualTo(this.f.parse("~A|B|~(E|G|H|K)")); + assertThat(parse(this.f, "~A|B|(~E&~G&~H&~K)").transform(this.minimizer)).isEqualTo(parse(this.f, "~A|B|~(E|G|H|K)")); - assertThat(this.f.parse("~A|~B").transform(this.minimizer)).isEqualTo(this.f.parse("~A|~B")); - assertThat(this.f.parse("~A|~B|~C").transform(this.minimizer)).isEqualTo(this.f.parse("~A|~B|~C")); - assertThat(this.f.parse("~A|~B|~C|~D").transform(this.minimizer)).isEqualTo(this.f.parse("~(A&B&C&D)")); + assertThat(parse(this.f, "~A|~B").transform(this.minimizer)).isEqualTo(parse(this.f, "~A|~B")); + assertThat(parse(this.f, "~A|~B|~C").transform(this.minimizer)).isEqualTo(parse(this.f, "~A|~B|~C")); + assertThat(parse(this.f, "~A|~B|~C|~D").transform(this.minimizer)).isEqualTo(parse(this.f, "~(A&B&C&D)")); - assertThat(this.f.parse("X&(~A|~B)").transform(this.minimizer)).isEqualTo(this.f.parse("X&~(A&B)")); - assertThat(this.f.parse("X&(~A|~B|~C)").transform(this.minimizer)).isEqualTo(this.f.parse("X&~(A&B&C)")); - assertThat(this.f.parse("X&(~A|~B|~C|~D)").transform(this.minimizer)).isEqualTo(this.f.parse("X&~(A&B&C&D)")); + assertThat(parse(this.f, "X&(~A|~B)").transform(this.minimizer)).isEqualTo(parse(this.f, "X&~(A&B)")); + assertThat(parse(this.f, "X&(~A|~B|~C)").transform(this.minimizer)).isEqualTo(parse(this.f, "X&~(A&B&C)")); + assertThat(parse(this.f, "X&(~A|~B|~C|~D)").transform(this.minimizer)).isEqualTo(parse(this.f, "X&~(A&B&C&D)")); - assertThat(this.f.parse("~A&~B").transform(this.minimizer)).isEqualTo(this.f.parse("~A&~B")); - assertThat(this.f.parse("~A&~B&~C").transform(this.minimizer)).isEqualTo(this.f.parse("~A&~B&~C")); - assertThat(this.f.parse("~A&~B&~C&~D").transform(this.minimizer)).isEqualTo(this.f.parse("~(A|B|C|D)")); + assertThat(parse(this.f, "~A&~B").transform(this.minimizer)).isEqualTo(parse(this.f, "~A&~B")); + assertThat(parse(this.f, "~A&~B&~C").transform(this.minimizer)).isEqualTo(parse(this.f, "~A&~B&~C")); + assertThat(parse(this.f, "~A&~B&~C&~D").transform(this.minimizer)).isEqualTo(parse(this.f, "~(A|B|C|D)")); - assertThat(this.f.parse("X|~A&~B").transform(this.minimizer)).isEqualTo(this.f.parse("X|~A&~B")); - assertThat(this.f.parse("X|~A&~B&~C").transform(this.minimizer)).isEqualTo(this.f.parse("X|~A&~B&~C")); - assertThat(this.f.parse("X|~A&~B&~C&~D").transform(this.minimizer)).isEqualTo(this.f.parse("X|~(A|B|C|D)")); + assertThat(parse(this.f, "X|~A&~B").transform(this.minimizer)).isEqualTo(parse(this.f, "X|~A&~B")); + assertThat(parse(this.f, "X|~A&~B&~C").transform(this.minimizer)).isEqualTo(parse(this.f, "X|~A&~B&~C")); + assertThat(parse(this.f, "X|~A&~B&~C&~D").transform(this.minimizer)).isEqualTo(parse(this.f, "X|~(A|B|C|D)")); - assertThat(this.f.parse("A&(~B|~C|~D|~E|~G|X|Y|H)").transform(this.minimizer)).isEqualTo(this.f.parse("A&(~(B&C&D&E&G)|X|Y|H)")); + assertThat(parse(this.f, "A&(~B|~C|~D|~E|~G|X|Y|H)").transform(this.minimizer)).isEqualTo(parse(this.f, "A&(~(B&C&D&E&G)|X|Y|H)")); } @Test From 201585cabea517d36a957f45c0fa4e274a67fad8 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Sun, 28 Apr 2024 22:04:32 +0200 Subject: [PATCH 22/44] give surefire tests enough memory --- pom.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pom.xml b/pom.xml index 415a9139..89885210 100644 --- a/pom.xml +++ b/pom.xml @@ -223,6 +223,9 @@ org.apache.maven.plugins maven-surefire-plugin ${version.surefire} + + -Xmx4g + From 81624f1178566340192cb4f18f4b38dad5e12dd4 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Mon, 29 Apr 2024 11:25:08 +0200 Subject: [PATCH 23/44] adjust changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6da053a..2de8bfc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Removed (Potentially Breaking Change!) -- All parser classes from `org.logicng.io.parsers` (including in particular the two main parsers `LogicNGPropositionalParsers` and `LogicNGPseudoBooleanParser`) as well as the class `org.logicng.io.readers.FormulaReader` were moved to the new artifacts `org.logicng.logicng-parser-j8` (or `org.logicng.logicng-parser-j11` for Java 11). So there LogicNG now consists of two artifacts: +- All parser classes from `org.logicng.io.parsers` (including in particular the two main parsers `PropositionalParser` and `PseudoBooleanParser`) as well as the class `org.logicng.io.readers.FormulaReader` were moved to the new artifacts `org.logicng.logicng-parser-j8` (or `org.logicng.logicng-parser-j11` for Java 11). So there LogicNG now consists of two artifacts: - All the core functionality of LogicNG except for the parser is located in the "old" `org.logicng:logicng` artifact. This artifact does *not* depend on ANTLR anymore (which was the reason for splitting the library). For the time being this library will be based on Java 8, but nothing should prevent its usage in higher Java versions. - - The parser functionality is located in `org.logicng:logicng-parser-j8` (for Java 8 and ANTLR 4.9.3) and `org.logicng:logicng-parser-j11` (for Java 11 and the most recent ANTLR version). The version of this library will stay in sync with the core library. + - The parser functionality is located in `org.logicng:logicng-parser-j8` (for Java 8 and ANTLR 4.9.3) and `org.logicng:logicng-parser-j11` (for Java 11 and the most recent ANTLR version). The version of this library will stay in sync with the core library. +- The method `FormulaFactory.parse()` was removed. If you're using this method you should include one of the new parser artefacts and then just create your own `PropositionalParser` or `PseudoBooleanParser` and call `parse()` on them. ### Added From 4f47fcd945aed4f844d1597ffb3c1f838e326a99 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Wed, 1 May 2024 12:20:15 +0200 Subject: [PATCH 24/44] Some clarifications in the CHANGELOG --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2de8bfc9..d4dc62b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,19 +2,19 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [2.5.0] - 2024-xx-xx +## [2.5.0] - 2024-05-02 ### Removed (Potentially Breaking Change!) -- All parser classes from `org.logicng.io.parsers` (including in particular the two main parsers `PropositionalParser` and `PseudoBooleanParser`) as well as the class `org.logicng.io.readers.FormulaReader` were moved to the new artifacts `org.logicng.logicng-parser-j8` (or `org.logicng.logicng-parser-j11` for Java 11). So there LogicNG now consists of two artifacts: - - All the core functionality of LogicNG except for the parser is located in the "old" `org.logicng:logicng` artifact. This artifact does *not* depend on ANTLR anymore (which was the reason for splitting the library). For the time being this library will be based on Java 8, but nothing should prevent its usage in higher Java versions. +- All parser classes from `org.logicng.io.parsers` (including in particular the two main parsers `PropositionalParser` and `PseudoBooleanParser`) as well as the class `org.logicng.io.readers.FormulaReader` were moved to the new artifacts `org.logicng.logicng-parser-j8` (or `org.logicng.logicng-parser-j11` for Java 11). So LogicNG now consists of two artifacts: + - All the core functionality of LogicNG except for the parser is located in the "old" `org.logicng:logicng` artifact. This artifact does *not* depend on ANTLR anymore (which was the reason for splitting the library). This library will stay on Java 8, but nothing should prevent its usage in higher Java versions. - The parser functionality is located in `org.logicng:logicng-parser-j8` (for Java 8 and ANTLR 4.9.3) and `org.logicng:logicng-parser-j11` (for Java 11 and the most recent ANTLR version). The version of this library will stay in sync with the core library. - The method `FormulaFactory.parse()` was removed. If you're using this method you should include one of the new parser artefacts and then just create your own `PropositionalParser` or `PseudoBooleanParser` and call `parse()` on them. ### Added - Added unsafe methods `term` and `dnf` to the `FormulaFactory` to create a term (conjunction of literals) or a DNF (c.f. with method `FormulaFactory#clause` and `FormulaFactory#cnf`). Both methods do not perform reduction operations and therefore are faster. Only use these methods if you are sure the input is free of complementary and redundant operands. -- Class `UBTree` offers new method `generateSubsumedUBTree` to directly generate a subsumed UBTree for the given sets. +- Class `UBTree` offers new method `generateSubsumedUBTree` to directly generate a subsumed UBTree for the given sets. - The `DnnfFactory` now offers a method to compile a DNNF with a `DnnfCompilationHandler` - The `ModelCounter` now offers a method to pass a `DnnfCompilationHandler` in order to control long-running computations @@ -29,12 +29,12 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `BDDKernel.addVariableBlock` for defining a variable block for reordering - `BDDKernel.addAllVariablesAsBlock` for defining one block for each variable (s.t. all variables are allowed to be reordered independently) - Significant performance improvements in the DTree generation for DNNFs -- Added side effect note in `SATSolver` for the four assumption solving methods. +- Added side effect note in `SATSolver` for the four assumption solving methods. - Minor performance improvements in some DNF/CNF generating algorithms by using faster `cnf`/`dnf`. ### Fixed -- Fixed edge case in method `add(Formula formula, Proposition proposition)` in `MiniSat`. If a formula is added to the SAT solver, it can happen that a variable is not added to the solver because it was removed during the CNF transformation. A `model()` call or model enumeration will not produce models containing this variable since it was not added to the solver. The fix ensures that all variables of the original formula are added to the solver and thus, a found model includes the variable. +- Fixed edge case in method `add(Formula formula, Proposition proposition)` in `MiniSat`. If a formula is added to the SAT solver, it can happen that a variable is not added to the solver because it was removed during the CNF transformation. A `model()` call or model enumeration will not produce models containing this variable since it was not added to the solver. The fix ensures that all variables of the original formula are added to the solver and thus, a found model includes the variable. - The formula generation on BDDs was broken when the ordering was changed by `BDDKernel.reorder` or `BDDKernel.swapVariables`. This is now fixed. ## [2.4.1] - 2022-12-01 From 2b1b827ff3feab4490ed0d20182f8304d2bea8b1 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Thu, 2 May 2024 10:36:06 +0200 Subject: [PATCH 25/44] Updated version to 2.5.0 --- README.md | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 25518bed..79f654cb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ LogicNG is released in the Maven Central Repository. To include it just add org.logicng logicng - 2.4.1 + 2.5.0 ``` diff --git a/pom.xml b/pom.xml index 89885210..e69b3792 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.5.0-SNAPSHOT + 2.5.0 bundle LogicNG From e6f602475e1c0581f31407390a28ef8507ab5e9b Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Thu, 2 May 2024 11:01:05 +0200 Subject: [PATCH 26/44] Updated CHANGELOG to 2.5.0 --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4dc62b3..9fb1c7d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,12 +29,10 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `BDDKernel.addVariableBlock` for defining a variable block for reordering - `BDDKernel.addAllVariablesAsBlock` for defining one block for each variable (s.t. all variables are allowed to be reordered independently) - Significant performance improvements in the DTree generation for DNNFs -- Added side effect note in `SATSolver` for the four assumption solving methods. - Minor performance improvements in some DNF/CNF generating algorithms by using faster `cnf`/`dnf`. ### Fixed -- Fixed edge case in method `add(Formula formula, Proposition proposition)` in `MiniSat`. If a formula is added to the SAT solver, it can happen that a variable is not added to the solver because it was removed during the CNF transformation. A `model()` call or model enumeration will not produce models containing this variable since it was not added to the solver. The fix ensures that all variables of the original formula are added to the solver and thus, a found model includes the variable. - The formula generation on BDDs was broken when the ordering was changed by `BDDKernel.reorder` or `BDDKernel.swapVariables`. This is now fixed. ## [2.4.1] - 2022-12-01 From 85ef043265cc436f9db15908f9eef8d24888cab5 Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Thu, 2 May 2024 12:02:13 +0200 Subject: [PATCH 27/44] adjust codecov report generation --- .github/workflows/build.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 43045ada..7b06a3f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,10 +16,7 @@ jobs: java-version: 1.8 - name: Build with Maven run: mvn -B package - - name: Upload coverage to codecov.io - uses: codecov/codecov-action@v1 + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 with: - name: LogicNG - file: ./target/site/jacoco/jacoco.xml - flags: unittests - env_vars: OS + token: ${{ secrets.CODECOV_TOKEN }} From e6317bbdefa7052fc449707f8e4cae7e0a94efde Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Thu, 2 May 2024 12:12:12 +0200 Subject: [PATCH 28/44] updated codecov badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 79f654cb..376679a6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![build](https://github.com/logic-ng/LogicNG/workflows/build/badge.svg) [![codecov](https://codecov.io/gh/logic-ng/LogicNG/branch/development/graph/badge.svg)](https://codecov.io/gh/logic-ng/LogicNG) ![License](https://img.shields.io/badge/license-Apache%202-ff69b4.svg) [![Maven Central](https://img.shields.io/maven-central/v/org.logicng/logicng.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22org.logicng%22%20AND%20a:%22logicng%22) +![build](https://github.com/logic-ng/LogicNG/workflows/build/badge.svg) [![codecov](https://codecov.io/gh/logic-ng/LogicNG/branch/master/graph/badge.svg?token=RMmCetIVYf)](https://codecov.io/gh/logic-ng/LogicNG) ![License](https://img.shields.io/badge/license-Apache%202-ff69b4.svg) [![Maven Central](https://img.shields.io/maven-central/v/org.logicng/logicng.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22org.logicng%22%20AND%20a:%22logicng%22) logo From 87a662fae434728a51942ec3d7e761d54a1f0341 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Thu, 2 May 2024 14:03:19 +0200 Subject: [PATCH 29/44] Fixed JaCoCo Plugin --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e69b3792..6066e06f 100644 --- a/pom.xml +++ b/pom.xml @@ -224,7 +224,7 @@ maven-surefire-plugin ${version.surefire} - -Xmx4g + ${argLine} -Xmx4g From 10ab16ee1a67329434023906641b9457394bacc4 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Sat, 4 May 2024 12:01:12 +0200 Subject: [PATCH 30/44] Next development version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6066e06f..c68fd28d 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.5.0 + 2.5.1-SNAPSHOT bundle LogicNG From b6e69752a8ae694f3ff0d93c9cf8699b9f79fa53 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Sat, 4 May 2024 14:07:20 +0200 Subject: [PATCH 31/44] Preparations for formula and solver serializiation --- .../logicng/collections/LNGBooleanVector.java | 7 ++- .../org/logicng/collections/LNGIntVector.java | 7 ++- .../logicng/collections/LNGLongVector.java | 7 ++- .../datastructures/LNGBoundedIntQueue.java | 16 ++--- .../datastructures/LNGBoundedLongQueue.java | 16 ++--- .../solvers/datastructures/LNGHeap.java | 14 +++-- .../solvers/datastructures/MSClause.java | 8 +-- .../solvers/datastructures/MSVariable.java | 4 +- .../logicng/solvers/sat/GlucoseConfig.java | 52 ++++++++++++++++ .../logicng/solvers/sat/MiniSatConfig.java | 60 +++++++++++++++++++ 10 files changed, 162 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/logicng/collections/LNGBooleanVector.java b/src/main/java/org/logicng/collections/LNGBooleanVector.java index cca8786b..0cf8c14c 100644 --- a/src/main/java/org/logicng/collections/LNGBooleanVector.java +++ b/src/main/java/org/logicng/collections/LNGBooleanVector.java @@ -88,7 +88,12 @@ public LNGBooleanVector(final boolean... elems) { this.size = elems.length; } - LNGBooleanVector(final boolean[] elements, final int size) { + /** + * Creates a vector with the given elements and capacity. + * @param elements the elements + * @param size the capacity of the vector + */ + public LNGBooleanVector(final boolean[] elements, final int size) { this.elements = elements; this.size = size; } diff --git a/src/main/java/org/logicng/collections/LNGIntVector.java b/src/main/java/org/logicng/collections/LNGIntVector.java index c732168b..5f28b027 100644 --- a/src/main/java/org/logicng/collections/LNGIntVector.java +++ b/src/main/java/org/logicng/collections/LNGIntVector.java @@ -88,7 +88,12 @@ public LNGIntVector(final int... elems) { this.size = elems.length; } - LNGIntVector(final int[] elements, final int size) { + /** + * Creates a vector with the given elements and capacity. + * @param elements the elements + * @param size the capacity of the vector + */ + public LNGIntVector(final int[] elements, final int size) { this.elements = elements; this.size = size; } diff --git a/src/main/java/org/logicng/collections/LNGLongVector.java b/src/main/java/org/logicng/collections/LNGLongVector.java index 738bf030..6e05e22d 100644 --- a/src/main/java/org/logicng/collections/LNGLongVector.java +++ b/src/main/java/org/logicng/collections/LNGLongVector.java @@ -88,7 +88,12 @@ public LNGLongVector(final long... elems) { this.size = elems.length; } - LNGLongVector(final long[] elements, final int size) { + /** + * Creates a vector with the given elements and capacity. + * @param elements the elements + * @param size the capacity of the vector + */ + public LNGLongVector(final long[] elements, final int size) { this.elements = elements; this.size = size; } diff --git a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java index e9988e6b..83c2b343 100644 --- a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java +++ b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java @@ -104,8 +104,8 @@ public LNGBoundedIntQueue() { this.queueSize = 0; } - LNGBoundedIntQueue(final LNGIntVector elems, final int first, final int last, final long sumOfQueue, - final int maxSize, final int queueSize) { + public LNGBoundedIntQueue(final LNGIntVector elems, final int first, final int last, final long sumOfQueue, + final int maxSize, final int queueSize) { this.elems = elems; this.first = first; this.last = last; @@ -164,27 +164,27 @@ private void growTo(final int size) { this.last = 0; } - LNGIntVector getElems() { + public LNGIntVector getElems() { return this.elems; } - int getFirst() { + public int getFirst() { return this.first; } - int getLast() { + public int getLast() { return this.last; } - long getSumOfQueue() { + public long getSumOfQueue() { return this.sumOfQueue; } - int getMaxSize() { + public int getMaxSize() { return this.maxSize; } - int getQueueSize() { + public int getQueueSize() { return this.queueSize; } diff --git a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java index 753ccd30..63a1199e 100644 --- a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java +++ b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedLongQueue.java @@ -104,8 +104,8 @@ public LNGBoundedLongQueue() { this.queueSize = 0; } - LNGBoundedLongQueue(final LNGLongVector elems, final int first, final int last, final long sumOfQueue, - final int maxSize, final int queueSize) { + public LNGBoundedLongQueue(final LNGLongVector elems, final int first, final int last, final long sumOfQueue, + final int maxSize, final int queueSize) { this.elems = elems; this.first = first; this.last = last; @@ -182,27 +182,27 @@ public void fastClear() { this.sumOfQueue = 0; } - LNGLongVector getElems() { + public LNGLongVector getElems() { return this.elems; } - int getFirst() { + public int getFirst() { return this.first; } - int getLast() { + public int getLast() { return this.last; } - long getSumOfQueue() { + public long getSumOfQueue() { return this.sumOfQueue; } - int getMaxSize() { + public int getMaxSize() { return this.maxSize; } - int getQueueSize() { + public int getQueueSize() { return this.queueSize; } diff --git a/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java b/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java index 5b1db19f..cfbb2a8a 100644 --- a/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java +++ b/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java @@ -69,8 +69,14 @@ public LNGHeap(final MiniSatStyleSolver solver) { this.indices = new LNGIntVector(1000); } - LNGHeap(final MiniSatStyleSolver s, final LNGIntVector heap, final LNGIntVector indices) { - this.s = s; + /** + * Constructs a new heap for a given solver and content. + * @param solver the solver + * @param heap the heap content + * @param indices the indices content + */ + public LNGHeap(final MiniSatStyleSolver solver, final LNGIntVector heap, final LNGIntVector indices) { + this.s = solver; this.heap = heap; this.indices = indices; } @@ -258,11 +264,11 @@ private void percolateDown(final int pos) { this.indices.set(y, p); } - LNGIntVector getHeap() { + public LNGIntVector getHeap() { return this.heap; } - LNGIntVector getIndices() { + public LNGIntVector getIndices() { return this.indices; } diff --git a/src/main/java/org/logicng/solvers/datastructures/MSClause.java b/src/main/java/org/logicng/solvers/datastructures/MSClause.java index 1feb20bc..acc4c633 100644 --- a/src/main/java/org/logicng/solvers/datastructures/MSClause.java +++ b/src/main/java/org/logicng/solvers/datastructures/MSClause.java @@ -123,9 +123,9 @@ public MSClause(final LNGIntVector ps, final boolean learnt, final boolean isAtM this.atMostWatchers = -1; } - MSClause(final LNGIntVector data, final boolean learnt, final boolean isAtMost, final double activity, - final int szWithoutSelectors, final boolean seen, final long lbd, final boolean canBeDel, - final boolean oneWatched, final int atMostWatchers) { + public MSClause(final LNGIntVector data, final boolean learnt, final boolean isAtMost, final double activity, + final int szWithoutSelectors, final boolean seen, final long lbd, final boolean canBeDel, + final boolean oneWatched, final int atMostWatchers) { this.data = data; this.learnt = learnt; this.isAtMost = isAtMost; @@ -316,7 +316,7 @@ public int cardinality() { return this.data.size() - this.atMostWatchers + 1; } - LNGIntVector getData() { + public LNGIntVector getData() { return this.data; } diff --git a/src/main/java/org/logicng/solvers/datastructures/MSVariable.java b/src/main/java/org/logicng/solvers/datastructures/MSVariable.java index f7545b0b..249290b9 100644 --- a/src/main/java/org/logicng/solvers/datastructures/MSVariable.java +++ b/src/main/java/org/logicng/solvers/datastructures/MSVariable.java @@ -74,8 +74,8 @@ public MSVariable(final boolean polarity) { this.decision = false; } - MSVariable(final Tristate assignment, final int level, final MSClause reason, final double activity, - final boolean polarity, final boolean decision) { + public MSVariable(final Tristate assignment, final int level, final MSClause reason, final double activity, + final boolean polarity, final boolean decision) { this.assignment = assignment; this.level = level; this.reason = reason; diff --git a/src/main/java/org/logicng/solvers/sat/GlucoseConfig.java b/src/main/java/org/logicng/solvers/sat/GlucoseConfig.java index 626f96a5..26b41ab1 100644 --- a/src/main/java/org/logicng/solvers/sat/GlucoseConfig.java +++ b/src/main/java/org/logicng/solvers/sat/GlucoseConfig.java @@ -81,6 +81,58 @@ public static Builder builder() { return new Builder(); } + public int getLbLBDMinimizingClause() { + return this.lbLBDMinimizingClause; + } + + public int getLbLBDFrozenClause() { + return this.lbLBDFrozenClause; + } + + public int getLbSizeMinimizingClause() { + return this.lbSizeMinimizingClause; + } + + public int getFirstReduceDB() { + return this.firstReduceDB; + } + + public int getSpecialIncReduceDB() { + return this.specialIncReduceDB; + } + + public int getIncReduceDB() { + return this.incReduceDB; + } + + public double getFactorK() { + return this.factorK; + } + + public double getFactorR() { + return this.factorR; + } + + public int getSizeLBDQueue() { + return this.sizeLBDQueue; + } + + public int getSizeTrailQueue() { + return this.sizeTrailQueue; + } + + public boolean isReduceOnSize() { + return this.reduceOnSize; + } + + public int getReduceOnSizeSize() { + return this.reduceOnSizeSize; + } + + public double getMaxVarDecay() { + return this.maxVarDecay; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("GlucoseConfig{").append(System.lineSeparator()); diff --git a/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java b/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java index 691fc9a1..c3afef8d 100644 --- a/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java +++ b/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java @@ -167,6 +167,66 @@ public boolean isAuxiliaryVariablesInModels() { return this.auxiliaryVariablesInModels; } + public double getVarDecay() { + return this.varDecay; + } + + public double getVarInc() { + return this.varInc; + } + + public ClauseMinimization getClauseMin() { + return this.clauseMin; + } + + public int getRestartFirst() { + return this.restartFirst; + } + + public double getRestartInc() { + return this.restartInc; + } + + public double getClauseDecay() { + return this.clauseDecay; + } + + public boolean isRemoveSatisfied() { + return this.removeSatisfied; + } + + public double getLearntsizeFactor() { + return this.learntsizeFactor; + } + + public double getLearntsizeInc() { + return this.learntsizeInc; + } + + public boolean isIncremental() { + return this.incremental; + } + + public boolean isInitialPhase() { + return this.initialPhase; + } + + public boolean isProofGeneration() { + return this.proofGeneration; + } + + public boolean isBbInitialUBCheckForRotatableLiterals() { + return this.bbInitialUBCheckForRotatableLiterals; + } + + public boolean isBbCheckForComplementModelLiterals() { + return this.bbCheckForComplementModelLiterals; + } + + public boolean isBbCheckForRotatableLiterals() { + return this.bbCheckForRotatableLiterals; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("MiniSatConfig{").append(System.lineSeparator()); From d77cea2109e1b442edeb24856374e148cae9130e Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Fri, 12 Jul 2024 09:43:19 +0200 Subject: [PATCH 32/44] Prepare 2.6.0 release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c68fd28d..36e797ed 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.5.1-SNAPSHOT + 2.6.0-SNAPSHOT bundle LogicNG From 5ba79db0f2149ca4335affbf3c5278817d081998 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Mon, 22 Jul 2024 12:55:24 +0200 Subject: [PATCH 33/44] fixed MiniSatConfig doc for default CNF method --- src/main/java/org/logicng/solvers/sat/MiniSatConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java b/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java index c3afef8d..f60a9211 100644 --- a/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java +++ b/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java @@ -406,7 +406,7 @@ public Builder proofGeneration(final boolean proofGeneration) { /** * Sets the CNF method for converting formula which are not in CNF for the solver. The default value - * is {@code FACTORY_CNF}. + * is {@code PG_ON_SOLVER}. * @param cnfMethod the CNF method * @return the builder */ From 8fb005a88e9d7748e27a8751820622b5f2bc0259 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Tue, 30 Jul 2024 11:29:54 +0200 Subject: [PATCH 34/44] WIP configure optimization in algorithms --- .../explanations/smus/SmusComputation.java | 231 +++++++++++++++--- .../primecomputation/PrimeCompiler.java | 32 ++- .../solvers/maxsat/OptimizationConfig.java | 103 ++++++++ .../simplification/AdvancedSimplifier.java | 61 ++--- .../AdvancedSimplifierConfig.java | 18 +- .../java/org/logicng/LogicNGVersionTest.java | 14 ++ .../smus/SmusComputationTest.java | 97 +++++--- 7 files changed, 446 insertions(+), 110 deletions(-) create mode 100644 src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java diff --git a/src/main/java/org/logicng/explanations/smus/SmusComputation.java b/src/main/java/org/logicng/explanations/smus/SmusComputation.java index b8a10202..2e3f0585 100644 --- a/src/main/java/org/logicng/explanations/smus/SmusComputation.java +++ b/src/main/java/org/logicng/explanations/smus/SmusComputation.java @@ -31,20 +31,28 @@ import static org.logicng.handlers.Handler.aborted; import static org.logicng.handlers.Handler.start; import static org.logicng.handlers.OptimizationHandler.satHandler; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; import org.logicng.datastructures.Assignment; import org.logicng.datastructures.Tristate; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Variable; +import org.logicng.handlers.MaxSATHandler; import org.logicng.handlers.OptimizationHandler; +import org.logicng.handlers.SATHandler; import org.logicng.propositions.Proposition; import org.logicng.propositions.StandardProposition; +import org.logicng.solvers.MaxSATSolver; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; import org.logicng.solvers.SolverState; import org.logicng.solvers.functions.OptimizationFunction; +import org.logicng.solvers.maxsat.OptimizationConfig; +import org.logicng.solvers.maxsat.algorithms.MaxSAT; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -60,7 +68,7 @@ * Implementation is based on "Smallest MUS extraction with minimal * hitting set dualization" (Ignatiev, Previti, Liffiton, & * Marques-Silva, 2015). - * @version 2.1.0 + * @version 2.6.0 * @since 2.0.0 */ public final class SmusComputation { @@ -82,15 +90,18 @@ private SmusComputation() { * @param f the formula factory * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation */ - public static

List

computeSmus(final List

propositions, final List additionalConstraints, final FormulaFactory f) { - return computeSmus(propositions, additionalConstraints, f, null); + public static

List

computeSmus( + final List

propositions, final List additionalConstraints, final FormulaFactory f) { + final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, null, null); + return computeSmus(propositions, additionalConstraints, f, cfg); } /** * Computes the SMUS for the given list of propositions modulo some additional constraint. *

- * The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be used for every subsequent - * * {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's SAT handler is used for every subsequent SAT call. + * The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be + * used for every subsequent * {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's + * SAT handler is used for every subsequent SAT call. * @param

the subtype of the propositions * @param propositions the propositions * @param additionalConstraints the additional constraints @@ -98,8 +109,95 @@ public static

List

computeSmus(final List

proposit * @param handler the handler, can be {@code null} * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation */ - public static

List

computeSmus(final List

propositions, final List additionalConstraints, final FormulaFactory f, - final OptimizationHandler handler) { + public static

List

computeSmus( + final List

propositions, + final List additionalConstraints, + final FormulaFactory f, + final OptimizationHandler handler) { + final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, handler, null); + return computeSmus(propositions, additionalConstraints, f, cfg); + } + + /** + * Computes the SMUS for the given list of propositions modulo some additional constraint. + *

+ * The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be used + * for every subsequent {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's SAT + * handler is used for every subsequent SAT call. + * @param

the subtype of the propositions + * @param propositions the propositions + * @param additionalConstraints the additional constraints + * @param f the formula factory + * @param config the optimization configuration + * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation + */ + public static

List

computeSmus( + final List

propositions, + final List additionalConstraints, + final FormulaFactory f, + final OptimizationConfig config) { + if (config.getOptimizationType() == SAT_OPTIMIZATION) { + return computeSmusSat(propositions, additionalConstraints, f, config.getOptimizationHandler()); + } else { + return computeSmusMaxSAT(propositions, additionalConstraints, f, config); + } + } + + /** + * Computes the SMUS for the given list of formulas and some additional constraints. + * @param formulas the formulas + * @param additionalConstraints the additional constraints + * @param f the formula factory + * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation + */ + public static List computeSmusForFormulas( + final List formulas, + final List additionalConstraints, + final FormulaFactory f) { + final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, null, null); + return computeSmusForFormulas(formulas, additionalConstraints, f, cfg); + } + + /** + * Computes the SMUS for the given list of formulas and some additional constraints. + * @param formulas the formulas + * @param additionalConstraints the additional constraints + * @param f the formula factory + * @param handler the SMUS handler, can be {@code null} + * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation + */ + public static List computeSmusForFormulas( + final List formulas, + final List additionalConstraints, + final FormulaFactory f, + final OptimizationHandler handler) { + final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, handler, null); + return computeSmusForFormulas(formulas, additionalConstraints, f, cfg); + } + + /** + * Computes the SMUS for the given list of formulas and some additional constraints. + * @param formulas the formulas + * @param additionalConstraints the additional constraints + * @param f the formula factory + * @param config the optimization configuration + * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation + */ + public static List computeSmusForFormulas( + final List formulas, + final List additionalConstraints, + final FormulaFactory f, + final OptimizationConfig config) { + final List props = formulas.stream().map(StandardProposition::new).collect(Collectors.toList()); + final List smus = computeSmus(props, additionalConstraints, f, config); + return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList()); + } + + private static

List

computeSmusSat( + final List

propositions, + final List additionalConstraints, + final FormulaFactory f, + final OptimizationHandler handler) { start(handler); final SATSolver growSolver = MiniSat.miniSat(f); growSolver.add(additionalConstraints == null ? Collections.singletonList(f.verum()) : additionalConstraints); @@ -130,33 +228,49 @@ public static

List

computeSmus(final List

proposit } } - /** - * Computes the SMUS for the given list of formulas and some additional constraints. - * @param formulas the formulas - * @param additionalConstraints the additional constraints - * @param f the formula factory - * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation - */ - public static List computeSmusForFormulas(final List formulas, final List additionalConstraints, final FormulaFactory f) { - return computeSmusForFormulas(formulas, additionalConstraints, f, null); - } - - /** - * Computes the SMUS for the given list of formulas and some additional constraints. - * @param formulas the formulas - * @param additionalConstraints the additional constraints - * @param f the formula factory - * @param handler the SMUS handler, can be {@code null} - * @return the SMUS or {@code null} if the given propositions are satisfiable or the handler aborted the computation - */ - public static List computeSmusForFormulas(final List formulas, final List additionalConstraints, final FormulaFactory f, - final OptimizationHandler handler) { - final List props = formulas.stream().map(StandardProposition::new).collect(Collectors.toList()); - final List smus = computeSmus(props, additionalConstraints, f, handler); - return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList()); + private static

List

computeSmusMaxSAT( + final List

propositions, + final List addConstraints, + final FormulaFactory f, + final OptimizationConfig config) { + final MaxSATHandler handler = config.getMaxSATHandler(); + start(handler); + final Collection additionalConstraints = addConstraints == null + ? Collections.singletonList(f.verum()) + : addConstraints; + final List growSolverConstraints = new ArrayList<>(additionalConstraints); + final Map propositionMapping = new TreeMap<>(); + for (final P proposition : propositions) { + final Variable selector = f.variable(PROPOSITION_SELECTOR + propositionMapping.size()); + propositionMapping.put(selector, proposition); + growSolverConstraints.add(f.equivalence(selector, proposition.formula())); + } + final SATSolver satSolver = MiniSat.miniSat(f); + satSolver.add(growSolverConstraints); + final SATHandler satHandler = handler == null ? null : handler.satHandler(); + final boolean sat = satSolver.sat(satHandler, propositionMapping.keySet()) == Tristate.TRUE; + if (sat || aborted(satHandler)) { + return null; + } + final List hSolverConstraints = new ArrayList<>(); + while (true) { + final SortedSet h = minimumHs(hSolverConstraints, propositionMapping.keySet(), config, f); + if (h == null || aborted(handler)) { + return null; + } + final SortedSet c = grow(growSolverConstraints, h, propositionMapping.keySet(), config, f); + if (aborted(handler)) { + return null; + } + if (c == null) { + return h.stream().map(propositionMapping::get).collect(Collectors.toList()); + } + hSolverConstraints.add(f.or(c)); + } } - private static SortedSet minimumHs(final SATSolver hSolver, final Set variables, final OptimizationHandler handler) { + private static SortedSet minimumHs( + final SATSolver hSolver, final Set variables, final OptimizationHandler handler) { final Assignment minimumHsModel = hSolver.execute(OptimizationFunction.builder() .handler(handler) .literals(variables) @@ -164,7 +278,31 @@ private static SortedSet minimumHs(final SATSolver hSolver, final Set< return aborted(handler) ? null : new TreeSet<>(minimumHsModel.positiveVariables()); } - private static SortedSet grow(final SATSolver growSolver, final SortedSet h, final Set variables, final OptimizationHandler handler) { + private static SortedSet minimumHs( + final List constraints, + final Set variables, + final OptimizationConfig config, + final FormulaFactory f) { + if (variables.isEmpty()) { + return new TreeSet<>(); // TODO workaround: MaxSAT assertion fails for corner case + } + final MaxSATSolver maxSatSolver = config.genMaxSATSolver(f); + constraints.forEach(maxSatSolver::addHardFormula); + for (final Variable v : variables) { + maxSatSolver.addSoftFormula(v.negate(), 1); + } + final MaxSAT.MaxSATResult result = maxSatSolver.solve(config.getMaxSATHandler()); + if (result == MaxSAT.MaxSATResult.UNDEF) { + return null; + } + return new TreeSet<>(maxSatSolver.model().positiveVariables()); + } + + private static SortedSet grow( + final SATSolver growSolver, + final SortedSet h, + final Set variables, + final OptimizationHandler handler) { final SolverState solverState = growSolver.saveState(); growSolver.add(h); final Assignment maxModel = growSolver.execute(OptimizationFunction.builder() @@ -181,4 +319,31 @@ private static SortedSet grow(final SATSolver growSolver, final Sorted return minimumCorrectionSet; } } + + private static SortedSet grow( + final List constraints, + final SortedSet h, + final Set variables, + final OptimizationConfig config, + final FormulaFactory f) { + final MaxSATSolver maxSatSolver = config.genMaxSATSolver(f); + constraints.forEach(maxSatSolver::addHardFormula); + h.forEach(maxSatSolver::addHardFormula); + for (final Variable v : variables) { + maxSatSolver.addSoftFormula(v, 1); + } + final MaxSAT.MaxSATResult result = maxSatSolver.solve(config.getMaxSATHandler()); + if (result == MaxSAT.MaxSATResult.UNDEF) { + return null; + } + final Assignment maxModel = maxSatSolver.model(); + if (maxModel == null) { + return null; + } else { + final List maximumSatisfiableSet = maxModel.positiveVariables(); + final SortedSet minimumCorrectionSet = new TreeSet<>(variables); + maximumSatisfiableSet.forEach(minimumCorrectionSet::remove); + return minimumCorrectionSet; + } + } } diff --git a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java index a3e433af..634bc51e 100644 --- a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java +++ b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java @@ -42,6 +42,8 @@ import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; import org.logicng.solvers.functions.OptimizationFunction; +import org.logicng.solvers.maxsat.OptimizationConfig; +import org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType; import org.logicng.solvers.sat.MiniSatConfig; import org.logicng.transformations.LiteralSubstitution; import org.logicng.util.FormulaHelper; @@ -76,13 +78,17 @@ public final class PrimeCompiler { private static final String POS = "_POS"; private static final String NEG = "_NEG"; - private static final PrimeCompiler INSTANCE_MIN = new PrimeCompiler(false); - private static final PrimeCompiler INSTANCE_MAX = new PrimeCompiler(true); + private static final OptimizationConfig DEFAULT_CFG = + new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, null, null); + private static final PrimeCompiler INSTANCE_MIN = new PrimeCompiler(false, DEFAULT_CFG); + private static final PrimeCompiler INSTANCE_MAX = new PrimeCompiler(true, DEFAULT_CFG); private final boolean computeWithMaximization; + private final OptimizationConfig config; - private PrimeCompiler(final boolean computeWithMaximization) { + private PrimeCompiler(final boolean computeWithMaximization, final OptimizationConfig config) { this.computeWithMaximization = computeWithMaximization; + this.config = config; } /** @@ -101,6 +107,22 @@ public static PrimeCompiler getWithMaximization() { return INSTANCE_MAX; } + /** + * Returns a compiler which uses minimum models to compute the primes. + * @return a compiler which uses minimum models to compute the primes + */ + public static PrimeCompiler getWithMinimization(final OptimizationConfig config) { + return new PrimeCompiler(false, config); + } + + /** + * Returns a compiler which uses maximum models to compute the primes. + * @return a compiler which uses maximum models to compute the primes + */ + public static PrimeCompiler getWithMaximization(final OptimizationConfig config) { + return new PrimeCompiler(false, config); + } + /** * Computes prime implicants and prime implicates for a given formula. * The coverage type specifies if the implicants or the implicates will @@ -167,7 +189,9 @@ private Pair>, List>> computeGeneric( return null; } if (fSat == Tristate.FALSE) { - final SortedSet primeImplicant = this.computeWithMaximization ? primeReduction.reduceImplicant(fModel.literals(), satHandler(handler)) : fModel.literals(); + final SortedSet primeImplicant = this.computeWithMaximization + ? primeReduction.reduceImplicant(fModel.literals(), satHandler(handler)) + : fModel.literals(); if (primeImplicant == null || aborted(handler)) { return null; } diff --git a/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java new file mode 100644 index 00000000..35c8e1f9 --- /dev/null +++ b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java @@ -0,0 +1,103 @@ +package org.logicng.solvers.maxsat; + +import org.logicng.formulas.FormulaFactory; +import org.logicng.handlers.MaxSATHandler; +import org.logicng.handlers.OptimizationHandler; +import org.logicng.solvers.MaxSATSolver; +import org.logicng.solvers.maxsat.algorithms.MaxSATConfig; + +import java.util.Objects; + +public class OptimizationConfig { + public enum OptimizationType { + SAT_OPTIMIZATION, + MAXSAT_INCWBO, + MAXSAT_LINEAR_SU, + MAXSAT_LINEAR_US, + MAXSAT_MSU3, + MAXSAT_OLL, + MAXSAT_WBO, + } + + private final OptimizationType optimizationType; + private final MaxSATConfig maxSATConfig; + private final OptimizationHandler optimizationHandler; + private final MaxSATHandler maxSATHandler; + + public OptimizationConfig( + final OptimizationType optType, + final MaxSATConfig maxConfig, + final OptimizationHandler optHandler, + final MaxSATHandler maxHandler + ) { + this.optimizationType = optType; + this.maxSATConfig = maxConfig; + this.optimizationHandler = optHandler; + this.maxSATHandler = maxHandler; + } + + public OptimizationType getOptimizationType() { + return this.optimizationType; + } + + public MaxSATConfig getMaxSATConfig() { + return this.maxSATConfig; + } + + public OptimizationHandler getOptimizationHandler() { + return this.optimizationHandler; + } + + public MaxSATHandler getMaxSATHandler() { + return this.maxSATHandler; + } + + public MaxSATSolver genMaxSATSolver(final FormulaFactory f) { + switch (this.optimizationType) { + case MAXSAT_INCWBO: + return this.maxSATConfig == null ? MaxSATSolver.incWBO(f) : MaxSATSolver.incWBO(f, this.maxSATConfig); + case MAXSAT_LINEAR_SU: + return this.maxSATConfig == null ? MaxSATSolver.linearSU(f) : MaxSATSolver.linearSU(f, this.maxSATConfig); + case MAXSAT_LINEAR_US: + return this.maxSATConfig == null ? MaxSATSolver.linearUS(f) : MaxSATSolver.linearUS(f, this.maxSATConfig); + case MAXSAT_MSU3: + return this.maxSATConfig == null ? MaxSATSolver.msu3(f) : MaxSATSolver.msu3(f, this.maxSATConfig); + case MAXSAT_OLL: + return this.maxSATConfig == null ? MaxSATSolver.oll(f) : MaxSATSolver.oll(f, this.maxSATConfig); + case MAXSAT_WBO: + return this.maxSATConfig == null ? MaxSATSolver.wbo(f) : MaxSATSolver.wbo(f, this.maxSATConfig); + default: + throw new IllegalArgumentException("Not a valid MaxSAT algorithm: " + this.optimizationType); + } + } + + @Override + public boolean equals(final Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + final OptimizationConfig that = (OptimizationConfig) object; + return this.optimizationType == that.optimizationType && + Objects.equals(this.maxSATConfig, that.maxSATConfig) && + Objects.equals(this.optimizationHandler, that.optimizationHandler) && + Objects.equals(this.maxSATHandler, that.maxSATHandler); + } + + @Override + public int hashCode() { + return Objects.hash(this.optimizationType, this.maxSATConfig, this.optimizationHandler, this.maxSATHandler); + } + + @Override + public String toString() { + return "OptimizationConfig{" + + "optimizationType=" + this.optimizationType + + ", maxSATConfig=" + this.maxSATConfig + + ", optimizationHandler=" + this.optimizationHandler + + ", maxSATHandler=" + this.maxSATHandler + + '}'; + } +} diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java index 7d57439c..e5e78f80 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java @@ -28,32 +28,19 @@ package org.logicng.transformations.simplification; -import static org.logicng.handlers.Handler.aborted; -import static org.logicng.handlers.Handler.start; -import static org.logicng.handlers.OptimizationHandler.satHandler; - -import org.logicng.backbones.Backbone; -import org.logicng.backbones.BackboneGeneration; -import org.logicng.backbones.BackboneType; import org.logicng.configurations.ConfigurationType; -import org.logicng.datastructures.Assignment; -import org.logicng.explanations.smus.SmusComputation; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.FormulaTransformation; import org.logicng.formulas.Literal; import org.logicng.handlers.OptimizationHandler; -import org.logicng.primecomputation.PrimeCompiler; -import org.logicng.primecomputation.PrimeResult; import org.logicng.util.FormulaHelper; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; -import java.util.stream.Collectors; /** * An advanced simplifier for formulas. @@ -126,21 +113,21 @@ public Formula apply(final Formula formula, final boolean cache) { final AdvancedSimplifierConfig config = this.initConfig != null ? this.initConfig : (AdvancedSimplifierConfig) formula.factory().configurationFor(ConfigurationType.ADVANCED_SIMPLIFIER); - start(config.handler); + //start(config.handler); // TODO activate final FormulaFactory f = formula.factory(); Formula simplified = formula; final SortedSet backboneLiterals = new TreeSet<>(); if (config.restrictBackbone) { - final Backbone backbone = BackboneGeneration - .compute(Collections.singletonList(formula), formula.variables(), BackboneType.POSITIVE_AND_NEGATIVE, satHandler(config.handler)); - if (backbone == null || aborted(config.handler)) { - return null; - } - if (!backbone.isSat()) { - return f.falsum(); - } - backboneLiterals.addAll(backbone.getCompleteBackbone()); - simplified = formula.restrict(new Assignment(backboneLiterals)); + //final Backbone backbone = BackboneGeneration // TODO activate + // .compute(Collections.singletonList(formula), formula.variables(), BackboneType.POSITIVE_AND_NEGATIVE, satHandler(config.handler)); + //if (backbone == null || aborted(config.handler)) { + // return null; + //} + //if (!backbone.isSat()) { + // return f.falsum(); + //} + //backboneLiterals.addAll(backbone.getCompleteBackbone()); + //simplified = formula.restrict(new Assignment(backboneLiterals)); } final Formula simplifyMinDnf = computeMinDnf(f, simplified, config); if (simplifyMinDnf == null) { @@ -161,19 +148,19 @@ public Formula apply(final Formula formula, final boolean cache) { return simplified; } - private Formula computeMinDnf(final FormulaFactory f, Formula simplified, final AdvancedSimplifierConfig config) { - final PrimeResult primeResult = - PrimeCompiler.getWithMinimization().compute(simplified, PrimeResult.CoverageType.IMPLICANTS_COMPLETE, config.handler); - if (primeResult == null || aborted(config.handler)) { - return null; - } - final List> primeImplicants = primeResult.getPrimeImplicants(); - final List minimizedPIs = SmusComputation.computeSmusForFormulas(negateAllLiterals(primeImplicants, f), - Collections.singletonList(simplified), f, config.handler); - if (minimizedPIs == null || aborted(config.handler)) { - return null; - } - simplified = f.or(negateAllLiteralsInFormulas(minimizedPIs, f).stream().map(f::and).collect(Collectors.toList())); + private Formula computeMinDnf(final FormulaFactory f, final Formula simplified, final AdvancedSimplifierConfig config) { + //final PrimeResult primeResult = //TODO + // PrimeCompiler.getWithMinimization().compute(simplified, PrimeResult.CoverageType.IMPLICANTS_COMPLETE, config.handler); + //if (primeResult == null || aborted(config.handler)) { + // return null; + //} + //final List> primeImplicants = primeResult.getPrimeImplicants(); + //final List minimizedPIs = SmusComputation.computeSmusForFormulas(negateAllLiterals(primeImplicants, f), + // Collections.singletonList(simplified), f, config.handler); + //if (minimizedPIs == null || aborted(config.handler)) { + // return null; + //} + //simplified = f.or(negateAllLiteralsInFormulas(minimizedPIs, f).stream().map(f::and).collect(Collectors.toList())); return simplified; } diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java index f3f1af55..83c8d063 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java @@ -31,6 +31,7 @@ import org.logicng.configurations.Configuration; import org.logicng.configurations.ConfigurationType; import org.logicng.handlers.OptimizationHandler; +import org.logicng.solvers.maxsat.OptimizationConfig; /** * The configuration object for the {@link AdvancedSimplifier}. @@ -44,7 +45,7 @@ public class AdvancedSimplifierConfig extends Configuration { boolean factorOut; boolean simplifyNegations; RatingFunction ratingFunction; - OptimizationHandler handler; + OptimizationConfig optimizationConfig; @Override public String toString() { @@ -53,7 +54,7 @@ public String toString() { ", factorOut=" + this.factorOut + ", simplifyNegations=" + this.simplifyNegations + ", ratingFunction=" + this.ratingFunction + - ", handler=" + this.handler + + ", optimizationConfig=" + this.optimizationConfig + '}'; } @@ -67,7 +68,7 @@ private AdvancedSimplifierConfig(final Builder builder) { this.factorOut = builder.factorOut; this.simplifyNegations = builder.simplifyNegations; this.ratingFunction = builder.ratingFunction; - this.handler = builder.handler; + this.optimizationConfig = builder.optimizationConfig; } /** @@ -87,7 +88,7 @@ public static class Builder { boolean factorOut = true; boolean simplifyNegations = true; private RatingFunction ratingFunction = new DefaultRatingFunction(); - private OptimizationHandler handler = null; + private OptimizationConfig optimizationConfig = null; private Builder() { // Initialize only via factory @@ -138,9 +139,16 @@ public Builder ratingFunction(final RatingFunction ratingFunction) { * Sets the handler to control the computation. The default is 'no handler'. * @param handler the optimization handler * @return the current builder + * @deprecated use the {@link #optimizationConfig} */ + @Deprecated public Builder handler(final OptimizationHandler handler) { - this.handler = handler; + this.optimizationConfig = new OptimizationConfig(OptimizationConfig.OptimizationType.SAT_OPTIMIZATION, null, handler, null); + return this; + } + + public Builder optimizationConfig(final OptimizationConfig config) { + this.optimizationConfig = config; return this; } diff --git a/src/test/java/org/logicng/LogicNGVersionTest.java b/src/test/java/org/logicng/LogicNGVersionTest.java index 178fd82f..ed3a0628 100644 --- a/src/test/java/org/logicng/LogicNGVersionTest.java +++ b/src/test/java/org/logicng/LogicNGVersionTest.java @@ -34,9 +34,23 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.logicng.formulas.Formula; +import org.logicng.formulas.FormulaFactory; +import org.logicng.io.parsers.ParserException; +import org.logicng.io.parsers.PseudoBooleanParser; +import org.logicng.io.writers.FormulaWriter; +import org.logicng.transformations.Anonymizer; import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * Unit tests for {@link LogicNGVersion}. * @version 2.1.0 diff --git a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java index e160bd82..b3630a09 100644 --- a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java +++ b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java @@ -29,8 +29,17 @@ package org.logicng.explanations.smus; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_INCWBO; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_LINEAR_SU; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_LINEAR_US; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_MSU3; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_OLL; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_WBO; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.logicng.TestWithExampleFormulas; import org.logicng.formulas.Formula; import org.logicng.handlers.BoundedOptimizationHandler; @@ -40,22 +49,39 @@ import org.logicng.io.parsers.ParserException; import org.logicng.io.readers.DimacsReader; import org.logicng.io.readers.FormulaReader; +import org.logicng.solvers.maxsat.OptimizationConfig; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; /** * Unit Tests for the class {@link SmusComputation}. - * @version 2.1.0 + * @version 2.6.0 * @since 2.0.0 */ public class SmusComputationTest extends TestWithExampleFormulas { - @Test - public void testFromPaper() { + public static Collection configs() { + final List configs = new ArrayList<>(); + configs.add(new Object[]{new OptimizationConfig(SAT_OPTIMIZATION, null, null, null), "SAT"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_INCWBO, null, null, null), "INCWBO"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_SU, null, null, null), "LINEAR_SU"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_US, null, null, null), "LINEAR_US"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_MSU3, null, null, null), "MSU3"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_OLL, null, null, null), "OLL"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_WBO, null, null, null), "WBO"}); + return configs; + } + + + @ParameterizedTest + @MethodSource("configs") + public void testFromPaper(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -66,12 +92,13 @@ public void testFromPaper() { parse(this.f, "~m|l"), parse(this.f, "~l") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f, cfg); assertThat(result).containsExactlyInAnyOrder(parse(this.f, "~s"), parse(this.f, "s|~p"), parse(this.f, "p")); } - @Test - public void testWithAdditionalConstraint() { + @ParameterizedTest + @MethodSource("configs") + public void testWithAdditionalConstraint(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -82,12 +109,13 @@ public void testWithAdditionalConstraint() { parse(this.f, "~m|l"), parse(this.f, "~l") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f, cfg); assertThat(result).containsExactlyInAnyOrder(parse(this.f, "~n"), parse(this.f, "~l")); } - @Test - public void testSatisfiable() { + @ParameterizedTest + @MethodSource("configs") + public void testSatisfiable(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -96,12 +124,13 @@ public void testSatisfiable() { parse(this.f, "~n"), parse(this.f, "~m|l") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f, cfg); assertThat(result).isNull(); } - @Test - public void testUnsatisfiableAdditionalConstraints() { + @ParameterizedTest + @MethodSource("configs") + public void testUnsatisfiableAdditionalConstraints(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -109,12 +138,13 @@ public void testUnsatisfiableAdditionalConstraints() { parse(this.f, "~m|n"), parse(this.f, "~n|s") ); - final List result = SmusComputation.computeSmusForFormulas(input, Arrays.asList(parse(this.f, "~a&b"), parse(this.f, "a|~b")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Arrays.asList(parse(this.f, "~a&b"), parse(this.f, "a|~b")), this.f, cfg); assertThat(result).isEmpty(); } - @Test - public void testTrivialUnsatFormula() { + @ParameterizedTest + @MethodSource("configs") + public void testTrivialUnsatFormula(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -126,12 +156,13 @@ public void testTrivialUnsatFormula() { parse(this.f, "~l"), parse(this.f, "a&~a") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f, cfg); assertThat(result).containsExactly(this.f.falsum()); } - @Test - public void testUnsatFormula() { + @ParameterizedTest + @MethodSource("configs") + public void testUnsatFormula(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -143,12 +174,13 @@ public void testUnsatFormula() { parse(this.f, "~l"), parse(this.f, "(a<=>b)&(~a<=>b)") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.singletonList(parse(this.f, "n|l")), this.f, cfg); assertThat(result).containsExactly(parse(this.f, "(a<=>b)&(~a<=>b)")); } - @Test - public void testShorterConflict() { + @ParameterizedTest + @MethodSource("configs") + public void testShorterConflict(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -160,12 +192,13 @@ public void testShorterConflict() { parse(this.f, "~m|l"), parse(this.f, "~l") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f, cfg); assertThat(result).containsExactlyInAnyOrder(parse(this.f, "s|~p"), parse(this.f, "p&~s")); } - @Test - public void testCompleteConflict() { + @ParameterizedTest + @MethodSource("configs") + public void testCompleteConflict(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -174,12 +207,13 @@ public void testCompleteConflict() { parse(this.f, "n|~l"), parse(this.f, "l|s") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f, cfg); assertThat(result).containsExactlyInAnyOrderElementsOf(input); } - @Test - public void testLongConflictWithShortcut() { + @ParameterizedTest + @MethodSource("configs") + public void testLongConflictWithShortcut(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "~s"), parse(this.f, "s|~p"), @@ -189,7 +223,7 @@ public void testLongConflictWithShortcut() { parse(this.f, "l|s"), parse(this.f, "n|s") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f, cfg); assertThat(result).containsExactlyInAnyOrder(parse(this.f, "~s"), parse(this.f, "s|~p"), parse(this.f, "p|~m"), @@ -197,8 +231,9 @@ public void testLongConflictWithShortcut() { parse(this.f, "n|s")); } - @Test - public void testManyConflicts() { + @ParameterizedTest + @MethodSource("configs") + public void testManyConflicts(final OptimizationConfig cfg) { final List input = Arrays.asList( parse(this.f, "a"), parse(this.f, "~a|b"), @@ -220,7 +255,7 @@ public void testManyConflicts() { parse(this.f, "x&~y"), parse(this.f, "x=>y") ); - final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f, cfg); assertThat(result).containsExactlyInAnyOrder(parse(this.f, "x&~y"), parse(this.f, "x=>y")); } From 9aa1d299d6338e630fa24c0661c50d5e667b02d0 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Wed, 31 Jul 2024 11:06:36 +0200 Subject: [PATCH 35/44] Prepare 2.5.1 release --- CHANGELOG.md | 8 ++++++++ README.md | 2 +- pom.xml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fb1c7d6..40ca17f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.5.1] - 2024-07-31 + +### Changed + +- Changed visibility from some methods from package-private to public for formula and solver serializiation via the + new https://github.com/logic-ng/serialization library + + ## [2.5.0] - 2024-05-02 ### Removed (Potentially Breaking Change!) diff --git a/README.md b/README.md index 376679a6..9bc07c4b 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ LogicNG is released in the Maven Central Repository. To include it just add org.logicng logicng - 2.5.0 + 2.5.1 ``` diff --git a/pom.xml b/pom.xml index 36e797ed..c68fd28d 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.6.0-SNAPSHOT + 2.5.1-SNAPSHOT bundle LogicNG From 79bb7b0986ff7f2fe73571a6a03216df9fe0fca7 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Wed, 31 Jul 2024 16:33:25 +0200 Subject: [PATCH 36/44] Final 2.5.1 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c68fd28d..70ebfd72 100644 --- a/pom.xml +++ b/pom.xml @@ -26,17 +26,17 @@ 4.0.0 org.logicng logicng - 2.5.1-SNAPSHOT + 2.5.1 bundle LogicNG The Next Generation Logic Library - http://www.logicng.org + https://www.logicng.org The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt + https://www.apache.org/licenses/LICENSE-2.0.txt From f72daf21e4fa99657170bc1cf32253d949839aed Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Thu, 1 Aug 2024 21:29:06 +0200 Subject: [PATCH 37/44] Optimization config in prime compiler --- pom.xml | 2 +- .../explanations/smus/SmusComputation.java | 7 +- .../primecomputation/PrimeCompiler.java | 138 +++++++++++---- .../solvers/maxsat/algorithms/IncWBO.java | 2 - .../solvers/maxsat/algorithms/MaxSAT.java | 4 - .../smus/SmusComputationTest.java | 1 - .../primecomputation/PrimeCompilerTest.java | 157 +++++++++++------- 7 files changed, 207 insertions(+), 104 deletions(-) diff --git a/pom.xml b/pom.xml index 70ebfd72..00fb5a6b 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.5.1 + 2.6.0-SNAPSHOT bundle LogicNG diff --git a/src/main/java/org/logicng/explanations/smus/SmusComputation.java b/src/main/java/org/logicng/explanations/smus/SmusComputation.java index 2e3f0585..10cc940d 100644 --- a/src/main/java/org/logicng/explanations/smus/SmusComputation.java +++ b/src/main/java/org/logicng/explanations/smus/SmusComputation.java @@ -137,7 +137,7 @@ public static

List

computeSmus( final FormulaFactory f, final OptimizationConfig config) { if (config.getOptimizationType() == SAT_OPTIMIZATION) { - return computeSmusSat(propositions, additionalConstraints, f, config.getOptimizationHandler()); + return computeSmusSAT(propositions, additionalConstraints, f, config.getOptimizationHandler()); } else { return computeSmusMaxSAT(propositions, additionalConstraints, f, config); } @@ -193,7 +193,7 @@ public static List computeSmusForFormulas( return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList()); } - private static

List

computeSmusSat( + private static

List

computeSmusSAT( final List

propositions, final List additionalConstraints, final FormulaFactory f, @@ -283,9 +283,6 @@ private static SortedSet minimumHs( final Set variables, final OptimizationConfig config, final FormulaFactory f) { - if (variables.isEmpty()) { - return new TreeSet<>(); // TODO workaround: MaxSAT assertion fails for corner case - } final MaxSATSolver maxSatSolver = config.genMaxSATSolver(f); constraints.forEach(maxSatSolver::addHardFormula); for (final Variable v : variables) { diff --git a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java index 634bc51e..e2aa195e 100644 --- a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java +++ b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java @@ -39,12 +39,14 @@ import org.logicng.formulas.Literal; import org.logicng.formulas.Variable; import org.logicng.handlers.OptimizationHandler; +import org.logicng.handlers.SATHandler; +import org.logicng.solvers.MaxSATSolver; import org.logicng.solvers.MiniSat; import org.logicng.solvers.SATSolver; import org.logicng.solvers.functions.OptimizationFunction; import org.logicng.solvers.maxsat.OptimizationConfig; import org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType; -import org.logicng.solvers.sat.MiniSatConfig; +import org.logicng.solvers.maxsat.algorithms.MaxSAT; import org.logicng.transformations.LiteralSubstitution; import org.logicng.util.FormulaHelper; import org.logicng.util.Pair; @@ -71,24 +73,20 @@ * {@link #getWithMaximization()} and another which searches for minimum models * {@link #getWithMaximization()}. From experience, the one with minimum models usually * outperforms the one with maximum models. - * @version 2.1.0 + * @version 2.6.0 * @since 2.0.0 */ public final class PrimeCompiler { private static final String POS = "_POS"; private static final String NEG = "_NEG"; - private static final OptimizationConfig DEFAULT_CFG = - new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, null, null); - private static final PrimeCompiler INSTANCE_MIN = new PrimeCompiler(false, DEFAULT_CFG); - private static final PrimeCompiler INSTANCE_MAX = new PrimeCompiler(true, DEFAULT_CFG); + private static final PrimeCompiler INSTANCE_MIN = new PrimeCompiler(false); + private static final PrimeCompiler INSTANCE_MAX = new PrimeCompiler(true); private final boolean computeWithMaximization; - private final OptimizationConfig config; - private PrimeCompiler(final boolean computeWithMaximization, final OptimizationConfig config) { + private PrimeCompiler(final boolean computeWithMaximization) { this.computeWithMaximization = computeWithMaximization; - this.config = config; } /** @@ -108,31 +106,36 @@ public static PrimeCompiler getWithMaximization() { } /** - * Returns a compiler which uses minimum models to compute the primes. - * @return a compiler which uses minimum models to compute the primes - */ - public static PrimeCompiler getWithMinimization(final OptimizationConfig config) { - return new PrimeCompiler(false, config); - } - - /** - * Returns a compiler which uses maximum models to compute the primes. - * @return a compiler which uses maximum models to compute the primes + * Computes prime implicants and prime implicates for a given formula. + * The coverage type specifies if the implicants or the implicates will + * be complete, the other one will still be a cover of the given formula. + * @param formula the formula + * @param type the coverage type + * @return the prime result */ - public static PrimeCompiler getWithMaximization(final OptimizationConfig config) { - return new PrimeCompiler(false, config); + public PrimeResult compute(final Formula formula, final PrimeResult.CoverageType type) { + return compute(formula, type, new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, null, null)); } /** * Computes prime implicants and prime implicates for a given formula. * The coverage type specifies if the implicants or the implicates will * be complete, the other one will still be a cover of the given formula. + *

+ * The prime compiler can be called with an {@link OptimizationHandler}. + * The given handler instance will be used for every subsequent + * {@link org.logicng.solvers.functions.OptimizationFunction} call and + * the handler's SAT handler is used for every subsequent SAT call. * @param formula the formula * @param type the coverage type - * @return the prime result + * @param handler an optimization handler, can be {@code null} + * @return the prime result or null if the computation was aborted by the handler */ - public PrimeResult compute(final Formula formula, final PrimeResult.CoverageType type) { - return compute(formula, type, null); + public PrimeResult compute( + final Formula formula, + final PrimeResult.CoverageType type, + final OptimizationHandler handler) { + return compute(formula, type, new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, handler, null)); } /** @@ -146,15 +149,23 @@ public PrimeResult compute(final Formula formula, final PrimeResult.CoverageType * the handler's SAT handler is used for every subsequent SAT call. * @param formula the formula * @param type the coverage type - * @param handler an optimization handler, can be {@code null} + * @param cfg the optimization configuration * @return the prime result or null if the computation was aborted by the handler */ - public PrimeResult compute(final Formula formula, final PrimeResult.CoverageType type, final OptimizationHandler handler) { - start(handler); + public PrimeResult compute( + final Formula formula, + final PrimeResult.CoverageType type, + final OptimizationConfig cfg) { + final boolean completeImplicants = type == PrimeResult.CoverageType.IMPLICANTS_COMPLETE; final Formula formulaForComputation = completeImplicants ? formula : formula.negate(); - final Pair>, List>> result = computeGeneric(formulaForComputation, handler); - if (result == null || aborted(handler)) { + final Pair>, List>> result; + if (cfg.getOptimizationType() == OptimizationType.SAT_OPTIMIZATION) { + result = computeSAT(formulaForComputation, cfg.getOptimizationHandler()); + } else { + result = computeMaxSAT(formulaForComputation, cfg); + } + if (result == null) { return null; } return new PrimeResult( @@ -163,12 +174,15 @@ public PrimeResult compute(final Formula formula, final PrimeResult.CoverageType type); } - private Pair>, List>> computeGeneric(final Formula formula, final OptimizationHandler handler) { + private Pair>, List>> computeSAT( + final Formula formula, + final OptimizationHandler handler) { + start(handler); final FormulaFactory f = formula.factory(); final SubstitutionResult sub = createSubstitution(formula); - final SATSolver hSolver = MiniSat.miniSat(f, MiniSatConfig.builder().cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()); + final SATSolver hSolver = MiniSat.miniSat(f); hSolver.add(sub.constraintFormula); - final SATSolver fSolver = MiniSat.miniSat(f, MiniSatConfig.builder().cnfMethod(MiniSatConfig.CNFMethod.PG_ON_SOLVER).build()); + final SATSolver fSolver = MiniSat.miniSat(f); fSolver.add(formula.negate()); final NaivePrimeReduction primeReduction = new NaivePrimeReduction(formula); final List> primeImplicants = new ArrayList<>(); @@ -216,6 +230,66 @@ private Pair>, List>> computeGeneric( } } + private Pair>, List>> computeMaxSAT( + final Formula formula, + final OptimizationConfig cfg) { + start(cfg.getMaxSATHandler()); + final SATHandler handler = cfg.getMaxSATHandler() == null ? null : cfg.getMaxSATHandler().satHandler(); + final FormulaFactory f = formula.factory(); + final SubstitutionResult sub = createSubstitution(formula); + final List hSolverConstraints = new ArrayList<>(); + hSolverConstraints.add(sub.constraintFormula); + final SATSolver fSolver = MiniSat.miniSat(f); + fSolver.add(formula.negate()); + final NaivePrimeReduction primeReduction = new NaivePrimeReduction(formula); + final List> primeImplicants = new ArrayList<>(); + final List> primeImplicates = new ArrayList<>(); + while (true) { + final MaxSATSolver hSolver = cfg.genMaxSATSolver(f); + hSolverConstraints.forEach(hSolver::addHardFormula); + sub.newVar2oldLit.keySet().forEach(it -> + hSolver.addSoftFormula(f.literal(it.name(), this.computeWithMaximization), 1)); + final MaxSAT.MaxSATResult result = hSolver.solve(cfg.getMaxSATHandler()); + if (result == MaxSAT.MaxSATResult.UNDEF) { + return null; + } + final Assignment hModel = hSolver.model(); + if (hModel == null) { + return new Pair<>(primeImplicants, primeImplicates); + } + final Assignment fModel = transformModel(hModel, sub.newVar2oldLit); + final Tristate fSat = fSolver.sat(handler, fModel.literals()); + if (aborted(handler)) { + return null; + } + if (fSat == Tristate.FALSE) { + final SortedSet primeImplicant = this.computeWithMaximization + ? primeReduction.reduceImplicant(fModel.literals(), handler) + : fModel.literals(); + if (primeImplicant == null || aborted(handler)) { + return null; + } + primeImplicants.add(primeImplicant); + final List blockingClause = new ArrayList<>(); + for (final Literal lit : primeImplicant) { + blockingClause.add(((Literal) lit.transform(sub.substitution)).negate()); + } + hSolverConstraints.add(f.or(blockingClause)); + } else { + final SortedSet implicate = new TreeSet<>(); + for (final Literal lit : (this.computeWithMaximization ? fModel : fSolver.model(formula.variables())).literals()) { + implicate.add(lit.negate()); + } + final SortedSet primeImplicate = primeReduction.reduceImplicate(implicate, handler); + if (primeImplicate == null || aborted(handler)) { + return null; + } + primeImplicates.add(primeImplicate); + hSolverConstraints.add(f.or(primeImplicate).transform(sub.substitution)); + } + } + } + private SubstitutionResult createSubstitution(final Formula formula) { final Map newVar2oldLit = new HashMap<>(); final LiteralSubstitution substitution = new LiteralSubstitution(); diff --git a/src/main/java/org/logicng/solvers/maxsat/algorithms/IncWBO.java b/src/main/java/org/logicng/solvers/maxsat/algorithms/IncWBO.java index db3e9336..01bfa499 100644 --- a/src/main/java/org/logicng/solvers/maxsat/algorithms/IncWBO.java +++ b/src/main/java/org/logicng/solvers/maxsat/algorithms/IncWBO.java @@ -404,7 +404,6 @@ protected MaxSATResult weightSearch() { } protected int incComputeCostModel(final LNGBooleanVector currentModel) { - assert currentModel.size() != 0; int currentCost = 0; for (int i = 0; i < nSoft(); i++) { boolean unsatisfied = true; @@ -413,7 +412,6 @@ protected int incComputeCostModel(final LNGBooleanVector currentModel) { unsatisfied = false; continue; } - assert var(this.softClauses.get(i).clause().get(j)) < currentModel.size(); if ((sign(this.softClauses.get(i).clause().get(j)) && !currentModel.get(var(this.softClauses.get(i).clause().get(j)))) || (!sign(this.softClauses.get(i).clause().get(j)) && currentModel.get(var(this.softClauses.get(i).clause().get(j))))) { unsatisfied = false; diff --git a/src/main/java/org/logicng/solvers/maxsat/algorithms/MaxSAT.java b/src/main/java/org/logicng/solvers/maxsat/algorithms/MaxSAT.java index b0bc8fec..3104dce4 100644 --- a/src/main/java/org/logicng/solvers/maxsat/algorithms/MaxSAT.java +++ b/src/main/java/org/logicng/solvers/maxsat/algorithms/MaxSAT.java @@ -329,8 +329,6 @@ public MiniSatStyleSolver newSATSolver() { * @param currentModel the model found by the solver */ public void saveModel(final LNGBooleanVector currentModel) { - assert this.nbInitialVariables != 0; - assert currentModel.size() != 0; this.model.clear(); for (int i = 0; i < this.nbInitialVariables; i++) { this.model.push(currentModel.get(i)); @@ -346,7 +344,6 @@ public void saveModel(final LNGBooleanVector currentModel) { * @return the cost of the given model */ public int computeCostModel(final LNGBooleanVector currentModel, final int weight) { - assert currentModel.size() != 0; int currentCost = 0; for (int i = 0; i < nSoft(); i++) { boolean unsatisfied = true; @@ -355,7 +352,6 @@ public int computeCostModel(final LNGBooleanVector currentModel, final int weigh unsatisfied = false; continue; } - assert var(this.softClauses.get(i).clause().get(j)) < currentModel.size(); if ((sign(this.softClauses.get(i).clause().get(j)) && !currentModel.get(var(this.softClauses.get(i).clause().get(j)))) || (!sign(this.softClauses.get(i).clause().get(j)) && currentModel.get(var(this.softClauses.get(i).clause().get(j))))) { unsatisfied = false; diff --git a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java index b3630a09..bc445360 100644 --- a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java +++ b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java @@ -78,7 +78,6 @@ public static Collection configs() { return configs; } - @ParameterizedTest @MethodSource("configs") public void testFromPaper(final OptimizationConfig cfg) { diff --git a/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java b/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java index 061cacf7..78963778 100644 --- a/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java +++ b/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java @@ -29,8 +29,19 @@ package org.logicng.primecomputation; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.primecomputation.PrimeResult.CoverageType.IMPLICANTS_COMPLETE; +import static org.logicng.primecomputation.PrimeResult.CoverageType.IMPLICATES_COMPLETE; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_INCWBO; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_LINEAR_SU; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_LINEAR_US; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_MSU3; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_OLL; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_WBO; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.logicng.RandomTag; import org.logicng.TestWithExampleFormulas; import org.logicng.formulas.Formula; @@ -43,6 +54,7 @@ import org.logicng.io.parsers.ParserException; import org.logicng.io.readers.FormulaReader; import org.logicng.predicates.satisfiability.TautologyPredicate; +import org.logicng.solvers.maxsat.OptimizationConfig; import org.logicng.util.FormulaCornerCases; import org.logicng.util.FormulaRandomizer; import org.logicng.util.FormulaRandomizerConfig; @@ -53,72 +65,99 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.SortedSet; /** * Unit Tests for the class {@link PrimeCompiler}. - * @version 2.1.0 + * @version 2.6.0 * @since 2.0.0 */ public class PrimeCompilerTest extends TestWithExampleFormulas { - @Test - public void testSimple() { - computeAndVerify(this.TRUE); - computeAndVerify(this.FALSE); - computeAndVerify(this.A); - computeAndVerify(this.NA); - computeAndVerify(this.AND1); - computeAndVerify(this.AND2); - computeAndVerify(this.AND3); - computeAndVerify(this.OR1); - computeAndVerify(this.OR2); - computeAndVerify(this.OR3); - computeAndVerify(this.NOT1); - computeAndVerify(this.NOT2); - computeAndVerify(this.IMP1); - computeAndVerify(this.IMP2); - computeAndVerify(this.IMP3); - computeAndVerify(this.IMP4); - computeAndVerify(this.EQ1); - computeAndVerify(this.EQ2); - computeAndVerify(this.EQ3); - computeAndVerify(this.EQ4); - computeAndVerify(this.PBC1); - computeAndVerify(this.PBC2); - computeAndVerify(this.PBC3); - computeAndVerify(this.PBC4); - computeAndVerify(this.PBC5); + public static Collection configs() { + final List configs = new ArrayList<>(); + configs.add(new Object[]{new OptimizationConfig(SAT_OPTIMIZATION, null, null, null), "SAT"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_INCWBO, null, null, null), "INCWBO"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_SU, null, null, null), "LINEAR_SU"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_US, null, null, null), "LINEAR_US"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_MSU3, null, null, null), "MSU3"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_OLL, null, null, null), "OLL"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_WBO, null, null, null), "WBO"}); + return configs; } - @Test - public void testCornerCases() { + public static Collection fastConfigs() { + final List configs = new ArrayList<>(); + configs.add(new Object[]{new OptimizationConfig(SAT_OPTIMIZATION, null, null, null), "SAT"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_SU, null, null, null), "LINEAR_SU"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_US, null, null, null), "LINEAR_US"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_MSU3, null, null, null), "MSU3"}); + configs.add(new Object[]{new OptimizationConfig(MAXSAT_OLL, null, null, null), "OLL"}); + return configs; + } + + @ParameterizedTest + @MethodSource("configs") + public void testSimple(final OptimizationConfig cfg) { + computeAndVerify(cfg, this.TRUE); + computeAndVerify(cfg, this.FALSE); + computeAndVerify(cfg, this.A); + computeAndVerify(cfg, this.NA); + computeAndVerify(cfg, this.AND1); + computeAndVerify(cfg, this.AND2); + computeAndVerify(cfg, this.AND3); + computeAndVerify(cfg, this.OR1); + computeAndVerify(cfg, this.OR2); + computeAndVerify(cfg, this.OR3); + computeAndVerify(cfg, this.NOT1); + computeAndVerify(cfg, this.NOT2); + computeAndVerify(cfg, this.IMP1); + computeAndVerify(cfg, this.IMP2); + computeAndVerify(cfg, this.IMP3); + computeAndVerify(cfg, this.IMP4); + computeAndVerify(cfg, this.EQ1); + computeAndVerify(cfg, this.EQ2); + computeAndVerify(cfg, this.EQ3); + computeAndVerify(cfg, this.EQ4); + computeAndVerify(cfg, this.PBC1); + computeAndVerify(cfg, this.PBC2); + computeAndVerify(cfg, this.PBC3); + computeAndVerify(cfg, this.PBC4); + computeAndVerify(cfg, this.PBC5); + } + + @ParameterizedTest + @MethodSource("configs") + public void testCornerCases(final OptimizationConfig cfg) { final FormulaFactory f = new FormulaFactory(); final FormulaCornerCases cornerCases = new FormulaCornerCases(f); - cornerCases.cornerCases().forEach(this::computeAndVerify); + cornerCases.cornerCases().forEach(it -> computeAndVerify(cfg, it)); } - @Test + @ParameterizedTest + @MethodSource("configs") @RandomTag - public void testRandomized() { + public void testRandomized(final OptimizationConfig cfg) { for (int i = 0; i < 200; i++) { final FormulaFactory f = new FormulaFactory(); final FormulaRandomizer randomizer = new FormulaRandomizer(f, FormulaRandomizerConfig.builder().numVars(10).weightPbc(2).seed(i * 42).build()); final Formula formula = randomizer.formula(4); - computeAndVerify(formula); + computeAndVerify(cfg, formula); } } - @Test - public void testOriginalFormulas() throws IOException { + @ParameterizedTest + @MethodSource("fastConfigs") + public void testOriginalFormulas(final OptimizationConfig cfg) throws IOException { Files.lines(Paths.get("src/test/resources/formulas/simplify_formulas.txt")) .filter(s -> !s.isEmpty()) .forEach(s -> { final Formula formula = parse(this.f, s); - final PrimeResult resultImplicantsMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICANTS_COMPLETE); + final PrimeResult resultImplicantsMin = PrimeCompiler.getWithMinimization().compute(formula, IMPLICANTS_COMPLETE , cfg); verify(resultImplicantsMin, formula); - final PrimeResult resultImplicatesMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICATES_COMPLETE); + final PrimeResult resultImplicatesMin = PrimeCompiler.getWithMinimization().compute(formula, IMPLICATES_COMPLETE, cfg); verify(resultImplicatesMin, formula); }); } @@ -126,10 +165,10 @@ public void testOriginalFormulas() throws IOException { @Test public void testTimeoutHandlerSmall() { final List> compilers = Arrays.asList( - new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), - new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE), - new Pair<>(PrimeCompiler.getWithMinimization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), - new Pair<>(PrimeCompiler.getWithMinimization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE)); + new Pair<>(PrimeCompiler.getWithMaximization(), IMPLICANTS_COMPLETE), + new Pair<>(PrimeCompiler.getWithMaximization(), IMPLICATES_COMPLETE), + new Pair<>(PrimeCompiler.getWithMinimization(), IMPLICANTS_COMPLETE), + new Pair<>(PrimeCompiler.getWithMinimization(), IMPLICATES_COMPLETE)); for (final Pair compiler : compilers) { final List handlers = Arrays.asList( new TimeoutOptimizationHandler(5_000L, TimeoutHandler.TimerType.SINGLE_TIMEOUT), @@ -146,10 +185,10 @@ public void testTimeoutHandlerSmall() { @Test public void testTimeoutHandlerLarge() throws IOException, ParserException { final List> compilers = Arrays.asList( - new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), - new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE), - new Pair<>(PrimeCompiler.getWithMinimization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), - new Pair<>(PrimeCompiler.getWithMinimization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE)); + new Pair<>(PrimeCompiler.getWithMaximization(), IMPLICANTS_COMPLETE), + new Pair<>(PrimeCompiler.getWithMaximization(), IMPLICATES_COMPLETE), + new Pair<>(PrimeCompiler.getWithMinimization(), IMPLICANTS_COMPLETE), + new Pair<>(PrimeCompiler.getWithMinimization(), IMPLICATES_COMPLETE)); for (final Pair compiler : compilers) { final List handlers = Arrays.asList( new TimeoutOptimizationHandler(1L, TimeoutHandler.TimerType.SINGLE_TIMEOUT), @@ -167,10 +206,10 @@ public void testTimeoutHandlerLarge() throws IOException, ParserException { public void testCancellationPoints() throws IOException { final Formula formula = parse(this.f, Files.readAllLines(Paths.get("src/test/resources/formulas/simplify_formulas.txt")).get(0)); final List> compilers = Arrays.asList( - new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), - new Pair<>(PrimeCompiler.getWithMaximization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE), - new Pair<>(PrimeCompiler.getWithMinimization(), PrimeResult.CoverageType.IMPLICANTS_COMPLETE), - new Pair<>(PrimeCompiler.getWithMinimization(), PrimeResult.CoverageType.IMPLICATES_COMPLETE)); + new Pair<>(PrimeCompiler.getWithMaximization(), IMPLICANTS_COMPLETE), + new Pair<>(PrimeCompiler.getWithMaximization(), IMPLICATES_COMPLETE), + new Pair<>(PrimeCompiler.getWithMinimization(), IMPLICANTS_COMPLETE), + new Pair<>(PrimeCompiler.getWithMinimization(), IMPLICATES_COMPLETE)); for (final Pair compiler : compilers) { for (int numOptimizationStarts = 1; numOptimizationStarts < 5; numOptimizationStarts++) { for (int numSatHandlerStarts = 1; numSatHandlerStarts < 10; numSatHandlerStarts++) { @@ -181,21 +220,21 @@ public void testCancellationPoints() throws IOException { } } - private void computeAndVerify(final Formula formula) { - final PrimeResult resultImplicantsMax = PrimeCompiler.getWithMaximization().compute(formula, PrimeResult.CoverageType.IMPLICANTS_COMPLETE); + private void computeAndVerify(final OptimizationConfig cfg, final Formula formula) { + final PrimeResult resultImplicantsMax = PrimeCompiler.getWithMaximization().compute(formula, IMPLICANTS_COMPLETE, cfg); verify(resultImplicantsMax, formula); - final PrimeResult resultImplicantsMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICANTS_COMPLETE); + final PrimeResult resultImplicantsMin = PrimeCompiler.getWithMinimization().compute(formula, IMPLICANTS_COMPLETE, cfg); verify(resultImplicantsMin, formula); - assertThat(resultImplicantsMax.getCoverageType()).isEqualTo(PrimeResult.CoverageType.IMPLICANTS_COMPLETE); - assertThat(resultImplicantsMin.getCoverageType()).isEqualTo(PrimeResult.CoverageType.IMPLICANTS_COMPLETE); + assertThat(resultImplicantsMax.getCoverageType()).isEqualTo(IMPLICANTS_COMPLETE); + assertThat(resultImplicantsMin.getCoverageType()).isEqualTo(IMPLICANTS_COMPLETE); assertThat(resultImplicantsMax.getPrimeImplicants()).containsExactlyInAnyOrderElementsOf(resultImplicantsMin.getPrimeImplicants()); - final PrimeResult resultImplicatesMax = PrimeCompiler.getWithMaximization().compute(formula, PrimeResult.CoverageType.IMPLICATES_COMPLETE); + final PrimeResult resultImplicatesMax = PrimeCompiler.getWithMaximization().compute(formula, IMPLICATES_COMPLETE, cfg); verify(resultImplicatesMax, formula); - final PrimeResult resultImplicatesMin = PrimeCompiler.getWithMinimization().compute(formula, PrimeResult.CoverageType.IMPLICATES_COMPLETE); + final PrimeResult resultImplicatesMin = PrimeCompiler.getWithMinimization().compute(formula, IMPLICATES_COMPLETE, cfg); verify(resultImplicatesMin, formula); - assertThat(resultImplicatesMax.getCoverageType()).isEqualTo(PrimeResult.CoverageType.IMPLICATES_COMPLETE); - assertThat(resultImplicatesMin.getCoverageType()).isEqualTo(PrimeResult.CoverageType.IMPLICATES_COMPLETE); + assertThat(resultImplicatesMax.getCoverageType()).isEqualTo(IMPLICATES_COMPLETE); + assertThat(resultImplicatesMin.getCoverageType()).isEqualTo(IMPLICATES_COMPLETE); assertThat(resultImplicatesMax.getPrimeImplicates()).containsExactlyInAnyOrderElementsOf(resultImplicatesMin.getPrimeImplicates()); } From 18f3c7262e97b0b7bef76e2bb42c642bff8bce4a Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Thu, 1 Aug 2024 22:12:23 +0200 Subject: [PATCH 38/44] Optimization config in advanced simplifier --- .../explanations/smus/SmusComputation.java | 8 +- .../primecomputation/PrimeCompiler.java | 4 +- .../solvers/maxsat/OptimizationConfig.java | 105 +++++++++++++++++- .../simplification/AdvancedSimplifier.java | 62 ++++++----- .../AdvancedSimplifierConfig.java | 50 +++++++-- .../smus/SmusComputationTest.java | 15 ++- .../primecomputation/PrimeCompilerTest.java | 24 ++-- .../AdvancedSimplifierTest.java | 98 ++++++++++++---- 8 files changed, 277 insertions(+), 89 deletions(-) diff --git a/src/main/java/org/logicng/explanations/smus/SmusComputation.java b/src/main/java/org/logicng/explanations/smus/SmusComputation.java index 10cc940d..5de12377 100644 --- a/src/main/java/org/logicng/explanations/smus/SmusComputation.java +++ b/src/main/java/org/logicng/explanations/smus/SmusComputation.java @@ -92,7 +92,7 @@ private SmusComputation() { */ public static

List

computeSmus( final List

propositions, final List additionalConstraints, final FormulaFactory f) { - final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, null, null); + final OptimizationConfig cfg = OptimizationConfig.sat(null); return computeSmus(propositions, additionalConstraints, f, cfg); } @@ -114,7 +114,7 @@ public static

List

computeSmus( final List additionalConstraints, final FormulaFactory f, final OptimizationHandler handler) { - final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, handler, null); + final OptimizationConfig cfg = OptimizationConfig.sat(handler); return computeSmus(propositions, additionalConstraints, f, cfg); } @@ -154,7 +154,7 @@ public static List computeSmusForFormulas( final List formulas, final List additionalConstraints, final FormulaFactory f) { - final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, null, null); + final OptimizationConfig cfg = OptimizationConfig.sat(null); return computeSmusForFormulas(formulas, additionalConstraints, f, cfg); } @@ -171,7 +171,7 @@ public static List computeSmusForFormulas( final List additionalConstraints, final FormulaFactory f, final OptimizationHandler handler) { - final OptimizationConfig cfg = new OptimizationConfig(SAT_OPTIMIZATION, null, handler, null); + final OptimizationConfig cfg = OptimizationConfig.sat(handler); return computeSmusForFormulas(formulas, additionalConstraints, f, cfg); } diff --git a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java index e2aa195e..fde8a8a6 100644 --- a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java +++ b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java @@ -114,7 +114,7 @@ public static PrimeCompiler getWithMaximization() { * @return the prime result */ public PrimeResult compute(final Formula formula, final PrimeResult.CoverageType type) { - return compute(formula, type, new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, null, null)); + return compute(formula, type, OptimizationConfig.sat(null)); } /** @@ -135,7 +135,7 @@ public PrimeResult compute( final Formula formula, final PrimeResult.CoverageType type, final OptimizationHandler handler) { - return compute(formula, type, new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, handler, null)); + return compute(formula, type, OptimizationConfig.sat(handler)); } /** diff --git a/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java index 35c8e1f9..1b4cf7ee 100644 --- a/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java +++ b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java @@ -3,11 +3,26 @@ import org.logicng.formulas.FormulaFactory; import org.logicng.handlers.MaxSATHandler; import org.logicng.handlers.OptimizationHandler; +import org.logicng.handlers.SATHandler; import org.logicng.solvers.MaxSATSolver; import org.logicng.solvers.maxsat.algorithms.MaxSATConfig; import java.util.Objects; +/** + * Configuration for optimization via a SAT or MaxSAT solver. + *

+ * Some algorithms use optimization internally. If they use many incremental + * solving steps, they usually use the SAT solver based + * {@link org.logicng.solvers.functions.OptimizationFunction}. For some cases + * however it can be more performant to use a MaxSAT solver based optimization + * with the drawback of generating the solver again in each step. + *

+ * These algorithms can be configured with this config object. + * + * @version 2.6.0 + * @since 2.6.0 + */ public class OptimizationConfig { public enum OptimizationType { SAT_OPTIMIZATION, @@ -24,7 +39,7 @@ public enum OptimizationType { private final OptimizationHandler optimizationHandler; private final MaxSATHandler maxSATHandler; - public OptimizationConfig( + private OptimizationConfig( final OptimizationType optType, final MaxSATConfig maxConfig, final OptimizationHandler optHandler, @@ -36,22 +51,62 @@ public OptimizationConfig( this.maxSATHandler = maxHandler; } - public OptimizationType getOptimizationType() { - return this.optimizationType; + /** + * Generate a MaxSAT solver based configuration + * @param optType the optimization type (MaxSAT algorithm) + * @param maxConfig the optional MaxSAT solver configuration + * @param maxHandler the optional MaxSAT solver handler + * @return the configuration + */ + public static OptimizationConfig maxsat( + final OptimizationType optType, + final MaxSATConfig maxConfig, + final MaxSATHandler maxHandler + ) { + if (optType == OptimizationType.SAT_OPTIMIZATION) { + throw new IllegalArgumentException("SAT Optimization cannot be parametrized with MaxSat config and handler"); + } + return new OptimizationConfig(optType, maxConfig, null, maxHandler); + } + + /** + * Generate a SAT solver based configuration + * @param optHandler the optional optimization handler + * @return the configuration + */ + public static OptimizationConfig sat(final OptimizationHandler optHandler) { + return new OptimizationConfig(OptimizationType.SAT_OPTIMIZATION, null, optHandler, null); } - public MaxSATConfig getMaxSATConfig() { - return this.maxSATConfig; + /** + * Returns the optimization type. + * @return the optimization type + */ + public OptimizationType getOptimizationType() { + return this.optimizationType; } + /** + * Returns the optional optimization handler. + * @return the optional optimization handler + */ public OptimizationHandler getOptimizationHandler() { return this.optimizationHandler; } + /** + * Returns the optional MaxSAT handler. + * @return the optional MaxSAT handler + */ public MaxSATHandler getMaxSATHandler() { return this.maxSATHandler; } + /** + * Generates a MaxSAT solver with the current configuration. + * @param f the formula factory + * @return the MAxSAT solver + */ public MaxSATSolver genMaxSATSolver(final FormulaFactory f) { switch (this.optimizationType) { case MAXSAT_INCWBO: @@ -71,6 +126,46 @@ public MaxSATSolver genMaxSATSolver(final FormulaFactory f) { } } + /** + * Starts the solver of this config's handler (if present) + */ + public void startHandler() { + if (this.optimizationHandler != null) { + this.optimizationHandler.started(); + } + if (this.maxSATHandler != null) { + this.maxSATHandler.started(); + } + } + + /** + * Return the SAT handler of this config's handler (if present) + * @return the SAT handler + */ + public SATHandler satHandler() { + if (this.optimizationHandler != null) { + return this.optimizationHandler.satHandler(); + } + if (this.maxSATHandler != null) { + return this.maxSATHandler.satHandler(); + } + return null; + } + + /** + * Returns whether this config's handler (if present) was aborted. + * @return whether this config's handler was aborted + */ + public boolean aborted() { + if (this.optimizationHandler != null) { + return this.optimizationHandler.aborted(); + } + if (this.maxSATHandler != null) { + return this.maxSATHandler.aborted(); + } + return false; + } + @Override public boolean equals(final Object object) { if (this == object) { diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java index e5e78f80..594e2e70 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java @@ -28,19 +28,29 @@ package org.logicng.transformations.simplification; +import org.logicng.backbones.Backbone; +import org.logicng.backbones.BackboneGeneration; +import org.logicng.backbones.BackboneType; import org.logicng.configurations.ConfigurationType; +import org.logicng.datastructures.Assignment; +import org.logicng.explanations.smus.SmusComputation; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.FormulaTransformation; import org.logicng.formulas.Literal; import org.logicng.handlers.OptimizationHandler; +import org.logicng.primecomputation.PrimeCompiler; +import org.logicng.primecomputation.PrimeResult; +import org.logicng.solvers.maxsat.OptimizationConfig; import org.logicng.util.FormulaHelper; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; +import java.util.stream.Collectors; /** * An advanced simplifier for formulas. @@ -59,7 +69,7 @@ * * The first and the last two steps can be configured using the {@link AdvancedSimplifierConfig}. Also, the handler and the rating * function can be configured. If no rating function is specified, the {@link DefaultRatingFunction} is chosen. - * @version 2.3.0 + * @version 2.6.0 * @since 2.0.0 */ public final class AdvancedSimplifier implements FormulaTransformation { @@ -113,25 +123,26 @@ public Formula apply(final Formula formula, final boolean cache) { final AdvancedSimplifierConfig config = this.initConfig != null ? this.initConfig : (AdvancedSimplifierConfig) formula.factory().configurationFor(ConfigurationType.ADVANCED_SIMPLIFIER); - //start(config.handler); // TODO activate + final OptimizationConfig cfg = config.optimizationConfig; + cfg.startHandler(); final FormulaFactory f = formula.factory(); Formula simplified = formula; final SortedSet backboneLiterals = new TreeSet<>(); if (config.restrictBackbone) { - //final Backbone backbone = BackboneGeneration // TODO activate - // .compute(Collections.singletonList(formula), formula.variables(), BackboneType.POSITIVE_AND_NEGATIVE, satHandler(config.handler)); - //if (backbone == null || aborted(config.handler)) { - // return null; - //} - //if (!backbone.isSat()) { - // return f.falsum(); - //} - //backboneLiterals.addAll(backbone.getCompleteBackbone()); - //simplified = formula.restrict(new Assignment(backboneLiterals)); + final Backbone backbone = BackboneGeneration + .compute(Collections.singletonList(formula), formula.variables(), BackboneType.POSITIVE_AND_NEGATIVE, cfg.satHandler()); + if (backbone == null || cfg.aborted()) { + return config.returnIntermediateResult ? formula : null; + } + if (!backbone.isSat()) { + return f.falsum(); + } + backboneLiterals.addAll(backbone.getCompleteBackbone()); + simplified = formula.restrict(new Assignment(backboneLiterals)); } final Formula simplifyMinDnf = computeMinDnf(f, simplified, config); if (simplifyMinDnf == null) { - return null; + return config.returnIntermediateResult ? simplified : null; } simplified = simplifyWithRating(simplified, simplifyMinDnf, config); if (config.factorOut) { @@ -149,19 +160,18 @@ public Formula apply(final Formula formula, final boolean cache) { } private Formula computeMinDnf(final FormulaFactory f, final Formula simplified, final AdvancedSimplifierConfig config) { - //final PrimeResult primeResult = //TODO - // PrimeCompiler.getWithMinimization().compute(simplified, PrimeResult.CoverageType.IMPLICANTS_COMPLETE, config.handler); - //if (primeResult == null || aborted(config.handler)) { - // return null; - //} - //final List> primeImplicants = primeResult.getPrimeImplicants(); - //final List minimizedPIs = SmusComputation.computeSmusForFormulas(negateAllLiterals(primeImplicants, f), - // Collections.singletonList(simplified), f, config.handler); - //if (minimizedPIs == null || aborted(config.handler)) { - // return null; - //} - //simplified = f.or(negateAllLiteralsInFormulas(minimizedPIs, f).stream().map(f::and).collect(Collectors.toList())); - return simplified; + final PrimeResult primeResult = + PrimeCompiler.getWithMinimization().compute(simplified, PrimeResult.CoverageType.IMPLICANTS_COMPLETE, config.optimizationConfig); + if (primeResult == null || config.optimizationConfig.aborted()) { + return null; + } + final List> primeImplicants = primeResult.getPrimeImplicants(); + final List minimizedPIs = SmusComputation.computeSmusForFormulas(negateAllLiterals(primeImplicants, f), + Collections.singletonList(simplified), f, config.optimizationConfig); + if (minimizedPIs == null || config.optimizationConfig.aborted()) { + return null; + } + return f.or(negateAllLiteralsInFormulas(minimizedPIs, f).stream().map(f::and).collect(Collectors.toList())); } private List negateAllLiterals(final Collection> literalSets, final FormulaFactory f) { diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java index 83c8d063..cdfada01 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java @@ -28,6 +28,8 @@ package org.logicng.transformations.simplification; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; + import org.logicng.configurations.Configuration; import org.logicng.configurations.ConfigurationType; import org.logicng.handlers.OptimizationHandler; @@ -35,7 +37,7 @@ /** * The configuration object for the {@link AdvancedSimplifier}. - * @version 2.3.0 + * @version 2.6.0 * @since 2.3.0 */ @@ -44,6 +46,7 @@ public class AdvancedSimplifierConfig extends Configuration { boolean restrictBackbone; boolean factorOut; boolean simplifyNegations; + boolean returnIntermediateResult; RatingFunction ratingFunction; OptimizationConfig optimizationConfig; @@ -53,6 +56,7 @@ public String toString() { "restrictBackbone=" + this.restrictBackbone + ", factorOut=" + this.factorOut + ", simplifyNegations=" + this.simplifyNegations + + ", returnIntermediateResult=" + this.returnIntermediateResult + ", ratingFunction=" + this.ratingFunction + ", optimizationConfig=" + this.optimizationConfig + '}'; @@ -67,6 +71,7 @@ private AdvancedSimplifierConfig(final Builder builder) { this.restrictBackbone = builder.restrictBackbone; this.factorOut = builder.factorOut; this.simplifyNegations = builder.simplifyNegations; + this.returnIntermediateResult = builder.returnIntermediateResult; this.ratingFunction = builder.ratingFunction; this.optimizationConfig = builder.optimizationConfig; } @@ -87,15 +92,17 @@ public static class Builder { boolean restrictBackbone = true; boolean factorOut = true; boolean simplifyNegations = true; - private RatingFunction ratingFunction = new DefaultRatingFunction(); - private OptimizationConfig optimizationConfig = null; + boolean returnIntermediateResult = false; + private RatingFunction ratingFunction = DefaultRatingFunction.get(); + private OptimizationConfig optimizationConfig = OptimizationConfig.sat(null); private Builder() { // Initialize only via factory } /** - * Sets the flag for whether the formula should be restricted with the backbone. The default is 'true'. + * Sets the flag for whether the formula should be restricted with the + * backbone. The default is 'true'. * @param restrictBackbone flag for the restriction * @return the current builder */ @@ -105,7 +112,8 @@ public Builder restrictBackbone(final boolean restrictBackbone) { } /** - * Sets the flag for whether the formula should be factorized. The default is 'true'. + * Sets the flag for whether the formula should be factorized. The + * default is 'true'. * @param factorOut flag for the factorisation * @return the current builder */ @@ -115,7 +123,8 @@ public Builder factorOut(final boolean factorOut) { } /** - * Sets the flag for whether negations shall be simplified. The default is 'true'. + * Sets the flag for whether negations shall be simplified. The + * default is 'true'. * @param simplifyNegations flag * @return the current builder */ @@ -125,8 +134,11 @@ public Builder simplifyNegations(final boolean simplifyNegations) { } /** - * Sets the rating function. The aim of the simplification is to minimize the formula with respect to this rating function, - * e.g. finding a formula with a minimal number of symbols when represented as string. The default is the {@code DefaultRatingFunction}. + * Sets the rating function. The aim of the simplification is to + * minimize the formula with respect to this rating function, + * e.g. finding a formula with a minimal number of symbols when + * represented as string. The default is the + * {@code DefaultRatingFunction}. * @param ratingFunction the desired rating function * @return the current builder */ @@ -136,22 +148,40 @@ public Builder ratingFunction(final RatingFunction ratingFunction) { } /** - * Sets the handler to control the computation. The default is 'no handler'. + * Sets the handler to control the computation. The default is + * 'no handler'. * @param handler the optimization handler * @return the current builder * @deprecated use the {@link #optimizationConfig} */ @Deprecated public Builder handler(final OptimizationHandler handler) { - this.optimizationConfig = new OptimizationConfig(OptimizationConfig.OptimizationType.SAT_OPTIMIZATION, null, handler, null); + this.optimizationConfig = OptimizationConfig.sat(handler); return this; } + /** + * Sets the optimization config of the computation. The default is a + * config with a SAT based optimization without a handler. + * @param config the optimization config + * @return the current builder + */ public Builder optimizationConfig(final OptimizationConfig config) { this.optimizationConfig = config; return this; } + /** + * Sets whether the intermediate result should be returned in case of + * a handler abortion. The default is 'false'. + * @param returnIntermediateResult the flag + * @return the current builder + */ + public Builder returnIntermediateResult(final boolean returnIntermediateResult) { + this.returnIntermediateResult = returnIntermediateResult; + return this; + } + /** * Builds the configuration. * @return the configuration. diff --git a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java index bc445360..e4a24068 100644 --- a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java +++ b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java @@ -35,7 +35,6 @@ import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_MSU3; import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_OLL; import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_WBO; -import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -68,13 +67,13 @@ public class SmusComputationTest extends TestWithExampleFormulas { public static Collection configs() { final List configs = new ArrayList<>(); - configs.add(new Object[]{new OptimizationConfig(SAT_OPTIMIZATION, null, null, null), "SAT"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_INCWBO, null, null, null), "INCWBO"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_SU, null, null, null), "LINEAR_SU"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_US, null, null, null), "LINEAR_US"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_MSU3, null, null, null), "MSU3"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_OLL, null, null, null), "OLL"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_WBO, null, null, null), "WBO"}); + configs.add(new Object[]{OptimizationConfig.sat(null), "SAT"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_INCWBO, null, null), "INCWBO"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_SU, null, null), "LINEAR_SU"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_US, null, null), "LINEAR_US"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_MSU3, null, null), "MSU3"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_OLL, null, null), "OLL"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_WBO, null, null), "WBO"}); return configs; } diff --git a/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java b/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java index 78963778..b9530d06 100644 --- a/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java +++ b/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java @@ -78,23 +78,23 @@ public class PrimeCompilerTest extends TestWithExampleFormulas { public static Collection configs() { final List configs = new ArrayList<>(); - configs.add(new Object[]{new OptimizationConfig(SAT_OPTIMIZATION, null, null, null), "SAT"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_INCWBO, null, null, null), "INCWBO"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_SU, null, null, null), "LINEAR_SU"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_US, null, null, null), "LINEAR_US"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_MSU3, null, null, null), "MSU3"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_OLL, null, null, null), "OLL"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_WBO, null, null, null), "WBO"}); + configs.add(new Object[]{OptimizationConfig.sat(null), "SAT"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_INCWBO, null, null), "INCWBO"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_SU, null, null), "LINEAR_SU"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_US, null, null), "LINEAR_US"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_MSU3, null, null), "MSU3"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_OLL, null, null), "OLL"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_WBO, null, null), "WBO"}); return configs; } public static Collection fastConfigs() { final List configs = new ArrayList<>(); - configs.add(new Object[]{new OptimizationConfig(SAT_OPTIMIZATION, null, null, null), "SAT"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_SU, null, null, null), "LINEAR_SU"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_LINEAR_US, null, null, null), "LINEAR_US"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_MSU3, null, null, null), "MSU3"}); - configs.add(new Object[]{new OptimizationConfig(MAXSAT_OLL, null, null, null), "OLL"}); + configs.add(new Object[]{OptimizationConfig.sat(null), "SAT"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_SU, null, null), "LINEAR_SU"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_US, null, null), "LINEAR_US"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_MSU3, null, null), "MSU3"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_OLL, null, null), "OLL"}); return configs; } diff --git a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java index be2b3cad..ec902ca3 100644 --- a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java +++ b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java @@ -29,8 +29,16 @@ package org.logicng.transformations.simplification; import static org.assertj.core.api.Assertions.assertThat; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_INCWBO; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_LINEAR_SU; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_LINEAR_US; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_MSU3; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_OLL; +import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_WBO; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.logicng.LongRunningTag; import org.logicng.RandomTag; import org.logicng.TestWithExampleFormulas; @@ -43,46 +51,80 @@ import org.logicng.io.parsers.ParserException; import org.logicng.io.readers.FormulaReader; import org.logicng.predicates.satisfiability.TautologyPredicate; +import org.logicng.solvers.maxsat.OptimizationConfig; import org.logicng.util.FormulaCornerCases; import org.logicng.util.FormulaRandomizer; import org.logicng.util.FormulaRandomizerConfig; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; /** * Unit Tests for the class {@link AdvancedSimplifier}. - * @version 2.3.0 + * @version 2.6.0 * @since 2.0.0 */ public class AdvancedSimplifierTest extends TestWithExampleFormulas { - private final AdvancedSimplifier simplifier = new AdvancedSimplifier(); + public static Collection configs() { + final List configs = new ArrayList<>(); + configs.add(new Object[]{OptimizationConfig.sat(null), "SAT"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_INCWBO, null, null), "INCWBO"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_SU, null, null), "LINEAR_SU"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_LINEAR_US, null, null), "LINEAR_US"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_MSU3, null, null), "MSU3"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_OLL, null, null), "OLL"}); + configs.add(new Object[]{OptimizationConfig.maxsat(MAXSAT_WBO, null, null), "WBO"}); + return configs; + } - @Test - public void testConstants() { - assertThat(this.f.falsum().transform(this.simplifier)).isEqualTo(this.f.falsum()); - assertThat(this.f.verum().transform(this.simplifier)).isEqualTo(this.f.verum()); + @ParameterizedTest + @MethodSource("configs") + public void testConstants(final OptimizationConfig cfg) { + final AdvancedSimplifier simplifier = new AdvancedSimplifier(AdvancedSimplifierConfig.builder().optimizationConfig(cfg).build()); + assertThat(this.f.falsum().transform(simplifier)).isEqualTo(this.f.falsum()); + assertThat(this.f.verum().transform(simplifier)).isEqualTo(this.f.verum()); } - @Test - public void testCornerCases() { + @ParameterizedTest + @MethodSource("configs") + public void testCornerCases(final OptimizationConfig cfg) { + final AdvancedSimplifier simplifier = new AdvancedSimplifier(AdvancedSimplifierConfig.builder().optimizationConfig(cfg).build()); final FormulaCornerCases cornerCases = new FormulaCornerCases(this.f); - cornerCases.cornerCases().forEach(this::computeAndVerify); + cornerCases.cornerCases().forEach(it -> computeAndVerify(it, simplifier)); } - @Test + @ParameterizedTest + @MethodSource("configs") @RandomTag - public void testRandomized() { + public void testRandomized(final OptimizationConfig cfg) { + final AdvancedSimplifier simplifier = new AdvancedSimplifier(AdvancedSimplifierConfig.builder().optimizationConfig(cfg).build()); for (int i = 0; i < 100; i++) { final FormulaFactory f = new FormulaFactory(); final FormulaRandomizer randomizer = new FormulaRandomizer(f, FormulaRandomizerConfig.builder().numVars(8).weightPbc(2).seed(i * 42).build()); final Formula formula = randomizer.formula(5); - computeAndVerify(formula); + computeAndVerify(formula, simplifier); } } + @ParameterizedTest + @MethodSource("configs") + public void testOriginalFormula(final OptimizationConfig cfg) throws IOException { + final AdvancedSimplifier simplifier = new AdvancedSimplifier(AdvancedSimplifierConfig.builder().optimizationConfig(cfg).build()); + Files.lines(Paths.get("src/test/resources/formulas/simplify_formulas.txt")) + .filter(s -> !s.isEmpty()) + .forEach(s -> { + final FormulaFactory f = new FormulaFactory(); + final Formula formula = parse(f, s); + computeAndVerify(formula, simplifier); + }); + } + @Test public void testTimeoutHandlerSmall() { final List handlers = Arrays.asList( @@ -92,7 +134,8 @@ public void testTimeoutHandlerSmall() { ); final Formula formula = parse(this.f, "a & b | ~c & a"); for (final TimeoutOptimizationHandler handler : handlers) { - testHandler(handler, formula, false); + testHandler(handler, formula, false, false); + testHandler(handler, formula, false, true); } } @@ -105,7 +148,8 @@ public void testTimeoutHandlerLarge() throws IOException, ParserException { ); final Formula formula = FormulaReader.readPseudoBooleanFormula("src/test/resources/formulas/large_formula.txt", this.f); for (final TimeoutOptimizationHandler handler : handlers) { - testHandler(handler, formula, true); + testHandler(handler, formula, true, false); + testHandler(handler, formula, true, true); } } @@ -113,14 +157,16 @@ public void testTimeoutHandlerLarge() throws IOException, ParserException { public void testPrimeCompilerIsCancelled() { final OptimizationHandler handler = new BoundedOptimizationHandler(-1, 0); final Formula formula = parse(this.f, "a&(b|c)"); - testHandler(handler, formula, true); + testHandler(handler, formula, true, false); + testHandler(handler, formula, true, true); } @Test public void testSmusComputationIsCancelled() { final OptimizationHandler handler = new BoundedOptimizationHandler(-1, 5); final Formula formula = parse(this.f, "a&(b|c)"); - testHandler(handler, formula, true); + testHandler(handler, formula, true, false); + testHandler(handler, formula, true, true); } @LongRunningTag @@ -132,7 +178,7 @@ public void testCancellationPoints() { for (int numOptimizationStarts = 1; numOptimizationStarts < 30; numOptimizationStarts++) { for (int numSatHandlerStarts = 1; numSatHandlerStarts < 500; numSatHandlerStarts++) { final OptimizationHandler handler = new BoundedOptimizationHandler(numSatHandlerStarts, numOptimizationStarts); - testHandler(handler, formula, true); + testHandler(handler, formula, true, false); } } } @@ -164,20 +210,28 @@ public void testAdvancedSimplifierConfig() { } } - private void computeAndVerify(final Formula formula) { - final Formula simplified = formula.transform(this.simplifier); + private void computeAndVerify(final Formula formula, final AdvancedSimplifier simplifier) { + final Formula simplified = formula.transform(simplifier); assertThat(formula.factory().equivalence(formula, simplified).holds(new TautologyPredicate(this.f))) .as("Minimized formula is equivalent to original Formula") .isTrue(); } - private void testHandler(final OptimizationHandler handler, final Formula formula, final boolean expAborted) { - final AdvancedSimplifier simplifierWithHandler = new AdvancedSimplifier(AdvancedSimplifierConfig.builder().handler(handler).build()); + private void testHandler(final OptimizationHandler handler, final Formula formula, final boolean expAborted, final boolean expIntermediate) { + final AdvancedSimplifier simplifierWithHandler = new AdvancedSimplifier(AdvancedSimplifierConfig.builder() + .optimizationConfig(OptimizationConfig.sat(handler)) + .returnIntermediateResult(expIntermediate) + .build()); final Formula simplified = formula.transform(simplifierWithHandler); assertThat(handler.aborted()).isEqualTo(expAborted); if (expAborted) { assertThat(handler.aborted()).isTrue(); - assertThat(simplified).isNull(); + if (!expIntermediate) { + assertThat(simplified).isNull(); + } else { + assertThat(simplified).isNotNull(); + assertThat(simplified.isEquivalentTo(formula)).isTrue(); + } } else { assertThat(handler.aborted()).isFalse(); assertThat(simplified).isNotNull(); From 09e61b08866f927a85fe9fc7cf1d24156dd7923e Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Fri, 2 Aug 2024 19:34:36 +0200 Subject: [PATCH 39/44] minor refactoring and improvements --- .../explanations/smus/SmusComputation.java | 75 +++++++++---------- .../primecomputation/PrimeCompiler.java | 2 +- .../solvers/maxsat/OptimizationConfig.java | 15 +++- .../AdvancedSimplifierConfig.java | 2 - 4 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/logicng/explanations/smus/SmusComputation.java b/src/main/java/org/logicng/explanations/smus/SmusComputation.java index 5de12377..4a66ab9c 100644 --- a/src/main/java/org/logicng/explanations/smus/SmusComputation.java +++ b/src/main/java/org/logicng/explanations/smus/SmusComputation.java @@ -32,6 +32,8 @@ import static org.logicng.handlers.Handler.start; import static org.logicng.handlers.OptimizationHandler.satHandler; import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; +import static org.logicng.util.CollectionHelper.difference; +import static org.logicng.util.CollectionHelper.nullSafe; import org.logicng.datastructures.Assignment; import org.logicng.datastructures.Tristate; @@ -52,14 +54,13 @@ import org.logicng.solvers.maxsat.algorithms.MaxSAT; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -100,7 +101,7 @@ public static

List

computeSmus( * Computes the SMUS for the given list of propositions modulo some additional constraint. *

* The SMUS computation can be called with an {@link OptimizationHandler}. The given handler instance will be - * used for every subsequent * {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's + * used for every subsequent {@link org.logicng.solvers.functions.OptimizationFunction} call and the handler's * SAT handler is used for every subsequent SAT call. * @param

the subtype of the propositions * @param propositions the propositions @@ -200,13 +201,8 @@ private static

List

computeSmusSAT( final OptimizationHandler handler) { start(handler); final SATSolver growSolver = MiniSat.miniSat(f); - growSolver.add(additionalConstraints == null ? Collections.singletonList(f.verum()) : additionalConstraints); - final Map propositionMapping = new TreeMap<>(); - for (final P proposition : propositions) { - final Variable selector = f.variable(PROPOSITION_SELECTOR + propositionMapping.size()); - propositionMapping.put(selector, proposition); - growSolver.add(f.equivalence(selector, proposition.formula())); - } + growSolver.add(nullSafe(additionalConstraints)); + final Map propositionMapping = createPropositionsMapping(propositions, growSolver::add, f); final boolean sat = growSolver.sat(satHandler(handler), propositionMapping.keySet()) == Tristate.TRUE; if (sat || aborted(handler)) { return null; @@ -230,26 +226,15 @@ private static

List

computeSmusSAT( private static

List

computeSmusMaxSAT( final List

propositions, - final List addConstraints, + final List additionalConstraints, final FormulaFactory f, final OptimizationConfig config) { final MaxSATHandler handler = config.getMaxSATHandler(); start(handler); - final Collection additionalConstraints = addConstraints == null - ? Collections.singletonList(f.verum()) - : addConstraints; - final List growSolverConstraints = new ArrayList<>(additionalConstraints); - final Map propositionMapping = new TreeMap<>(); - for (final P proposition : propositions) { - final Variable selector = f.variable(PROPOSITION_SELECTOR + propositionMapping.size()); - propositionMapping.put(selector, proposition); - growSolverConstraints.add(f.equivalence(selector, proposition.formula())); - } - final SATSolver satSolver = MiniSat.miniSat(f); - satSolver.add(growSolverConstraints); - final SATHandler satHandler = handler == null ? null : handler.satHandler(); - final boolean sat = satSolver.sat(satHandler, propositionMapping.keySet()) == Tristate.TRUE; - if (sat || aborted(satHandler)) { + final List growSolverConstraints = new ArrayList<>(nullSafe(additionalConstraints)); + final Map propositionMapping = createPropositionsMapping(propositions, growSolverConstraints::add, f); + final boolean sat = sat(growSolverConstraints, propositionMapping.keySet(), handler, f); + if (sat || aborted(handler)) { return null; } final List hSolverConstraints = new ArrayList<>(); @@ -269,6 +254,24 @@ private static

List

computeSmusMaxSAT( } } + private static

Map createPropositionsMapping( + final List

propositions, final Consumer consumer, final FormulaFactory f) { + final Map propositionMapping = new TreeMap<>(); + for (final P proposition : propositions) { + final Variable selector = f.variable(PROPOSITION_SELECTOR + propositionMapping.size()); + propositionMapping.put(selector, proposition); + consumer.accept(f.equivalence(selector, proposition.formula())); + } + return propositionMapping; + } + + private static boolean sat(final List constraints, final Set variables, final MaxSATHandler handler, final FormulaFactory f) { + final SATHandler satHandler = handler == null ? null : handler.satHandler(); + final SATSolver satSolver = MiniSat.miniSat(f); + satSolver.add(constraints); + return satSolver.sat(satHandler, variables) == Tristate.TRUE; + } + private static SortedSet minimumHs( final SATSolver hSolver, final Set variables, final OptimizationHandler handler) { final Assignment minimumHsModel = hSolver.execute(OptimizationFunction.builder() @@ -288,8 +291,9 @@ private static SortedSet minimumHs( for (final Variable v : variables) { maxSatSolver.addSoftFormula(v.negate(), 1); } - final MaxSAT.MaxSATResult result = maxSatSolver.solve(config.getMaxSATHandler()); - if (result == MaxSAT.MaxSATResult.UNDEF) { + final MaxSATHandler handler = config.getMaxSATHandler(); + final MaxSAT.MaxSATResult result = maxSatSolver.solve(handler); + if (result == MaxSAT.MaxSATResult.UNDEF || aborted(handler)) { return null; } return new TreeSet<>(maxSatSolver.model().positiveVariables()); @@ -309,11 +313,8 @@ private static SortedSet grow( if (maxModel == null || aborted(handler)) { return null; } else { - final List maximumSatisfiableSet = maxModel.positiveVariables(); growSolver.loadState(solverState); - final SortedSet minimumCorrectionSet = new TreeSet<>(variables); - maximumSatisfiableSet.forEach(minimumCorrectionSet::remove); - return minimumCorrectionSet; + return difference(variables, maxModel.positiveVariables(), TreeSet::new); } } @@ -329,18 +330,16 @@ private static SortedSet grow( for (final Variable v : variables) { maxSatSolver.addSoftFormula(v, 1); } - final MaxSAT.MaxSATResult result = maxSatSolver.solve(config.getMaxSATHandler()); - if (result == MaxSAT.MaxSATResult.UNDEF) { + final MaxSATHandler handler = config.getMaxSATHandler(); + final MaxSAT.MaxSATResult result = maxSatSolver.solve(handler); + if (result == MaxSAT.MaxSATResult.UNDEF || aborted(handler)) { return null; } final Assignment maxModel = maxSatSolver.model(); if (maxModel == null) { return null; } else { - final List maximumSatisfiableSet = maxModel.positiveVariables(); - final SortedSet minimumCorrectionSet = new TreeSet<>(variables); - maximumSatisfiableSet.forEach(minimumCorrectionSet::remove); - return minimumCorrectionSet; + return difference(variables, maxModel.positiveVariables(), TreeSet::new); } } } diff --git a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java index fde8a8a6..4eab4d82 100644 --- a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java +++ b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java @@ -250,7 +250,7 @@ private Pair>, List>> computeMaxSAT( sub.newVar2oldLit.keySet().forEach(it -> hSolver.addSoftFormula(f.literal(it.name(), this.computeWithMaximization), 1)); final MaxSAT.MaxSATResult result = hSolver.solve(cfg.getMaxSATHandler()); - if (result == MaxSAT.MaxSATResult.UNDEF) { + if (result == MaxSAT.MaxSATResult.UNDEF || aborted(cfg.getMaxSATHandler())) { return null; } final Assignment hModel = hSolver.model(); diff --git a/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java index 1b4cf7ee..5627acb5 100644 --- a/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java +++ b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java @@ -19,7 +19,6 @@ * with the drawback of generating the solver again in each step. *

* These algorithms can be configured with this config object. - * * @version 2.6.0 * @since 2.6.0 */ @@ -53,8 +52,8 @@ private OptimizationConfig( /** * Generate a MaxSAT solver based configuration - * @param optType the optimization type (MaxSAT algorithm) - * @param maxConfig the optional MaxSAT solver configuration + * @param optType the optimization type (MaxSAT algorithm) + * @param maxConfig the optional MaxSAT solver configuration * @param maxHandler the optional MaxSAT solver handler * @return the configuration */ @@ -86,6 +85,14 @@ public OptimizationType getOptimizationType() { return this.optimizationType; } + /** + * Returns the optional MaxSAT configuration + * @return the optional MaxSAT configuration + */ + public MaxSATConfig getMaxSATConfig() { + return this.maxSATConfig; + } + /** * Returns the optional optimization handler. * @return the optional optimization handler @@ -127,7 +134,7 @@ public MaxSATSolver genMaxSATSolver(final FormulaFactory f) { } /** - * Starts the solver of this config's handler (if present) + * Starts this config's handler (if present) */ public void startHandler() { if (this.optimizationHandler != null) { diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java index cdfada01..3f491c05 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java @@ -28,8 +28,6 @@ package org.logicng.transformations.simplification; -import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; - import org.logicng.configurations.Configuration; import org.logicng.configurations.ConfigurationType; import org.logicng.handlers.OptimizationHandler; From b783c194805ea74420c6df6c03c1f04ab462a909 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Fri, 2 Aug 2024 21:04:38 +0200 Subject: [PATCH 40/44] bugfix: added backbone literals to intermediate result in AdvancedSimplifier --- .../simplification/AdvancedSimplifier.java | 11 +++++++---- .../simplification/AdvancedSimplifierTest.java | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java index 594e2e70..c5fe33a3 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java @@ -142,16 +142,14 @@ public Formula apply(final Formula formula, final boolean cache) { } final Formula simplifyMinDnf = computeMinDnf(f, simplified, config); if (simplifyMinDnf == null) { - return config.returnIntermediateResult ? simplified : null; + return config.returnIntermediateResult ? addLiterals(simplified, backboneLiterals) : null; } simplified = simplifyWithRating(simplified, simplifyMinDnf, config); if (config.factorOut) { final Formula factoredOut = simplified.transform(new FactorOutSimplifier(config.ratingFunction)); simplified = simplifyWithRating(simplified, factoredOut, config); } - if (config.restrictBackbone) { - simplified = f.and(f.and(backboneLiterals), simplified); - } + simplified = addLiterals(simplified, backboneLiterals); if (config.simplifyNegations) { final Formula negationSimplified = simplified.transform(NegationSimplifier.get()); simplified = simplifyWithRating(simplified, negationSimplified, config); @@ -159,6 +157,11 @@ public Formula apply(final Formula formula, final boolean cache) { return simplified; } + private static Formula addLiterals(final Formula formula, final SortedSet literals) { + final FormulaFactory f = formula.factory(); + return f.and(f.and(literals), formula); + } + private Formula computeMinDnf(final FormulaFactory f, final Formula simplified, final AdvancedSimplifierConfig config) { final PrimeResult primeResult = PrimeCompiler.getWithMinimization().compute(simplified, PrimeResult.CoverageType.IMPLICANTS_COMPLETE, config.optimizationConfig); diff --git a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java index ec902ca3..64a87dee 100644 --- a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java +++ b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java @@ -35,6 +35,8 @@ import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_MSU3; import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_OLL; import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.MAXSAT_WBO; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -63,6 +65,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * Unit Tests for the class {@link AdvancedSimplifier}. @@ -210,6 +213,17 @@ public void testAdvancedSimplifierConfig() { } } + @Test + public void testBackboneIntermediateResult() { + final FormulaFactory f = new FormulaFactory(); + Formula formula = parse(f, "(a & b) | (a & c)"); + OptimizationHandler optHandler = mock(OptimizationHandler.class); + // abort simplification after successful backbone computation + final AtomicInteger count = new AtomicInteger(0); + when(optHandler.aborted()).then(invocationOnMock -> count.addAndGet(1) > 1); + testHandler(optHandler, formula, true, true); + } + private void computeAndVerify(final Formula formula, final AdvancedSimplifier simplifier) { final Formula simplified = formula.transform(simplifier); assertThat(formula.factory().equivalence(formula, simplified).holds(new TautologyPredicate(this.f))) From c03d34212a9a9b114be9b675e7f399517241e0b8 Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Fri, 2 Aug 2024 21:37:41 +0200 Subject: [PATCH 41/44] added minimalDnfCover config flag in AdvancedSimplifierConfig --- CHANGELOG.md | 6 ++++++ .../simplification/AdvancedSimplifier.java | 16 +++++++++------- .../simplification/AdvancedSimplifierConfig.java | 15 +++++++++++++++ .../simplification/AdvancedSimplifierTest.java | 10 ++++++---- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40ca17f6..43bcfdba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.6.0] - 2024-08-02 + +### Added + +- Added configuration flag `minimalDnfCover` in `AdvancedSimplifierConfig` to set whether the step for computing the minimal DNF cover should be performed. Default is `true`. + ## [2.5.1] - 2024-07-31 ### Changed diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java index c5fe33a3..5e28a285 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java @@ -135,16 +135,18 @@ public Formula apply(final Formula formula, final boolean cache) { return config.returnIntermediateResult ? formula : null; } if (!backbone.isSat()) { - return f.falsum(); + return f.falsum(); } backboneLiterals.addAll(backbone.getCompleteBackbone()); simplified = formula.restrict(new Assignment(backboneLiterals)); } - final Formula simplifyMinDnf = computeMinDnf(f, simplified, config); - if (simplifyMinDnf == null) { - return config.returnIntermediateResult ? addLiterals(simplified, backboneLiterals) : null; + if (config.minimalDnfCover) { + final Formula simplifyMinDnf = computeMinDnf(f, simplified, config); + if (simplifyMinDnf == null) { + return config.returnIntermediateResult ? addLiterals(simplified, backboneLiterals) : null; + } + simplified = simplifyWithRating(simplified, simplifyMinDnf, config); } - simplified = simplifyWithRating(simplified, simplifyMinDnf, config); if (config.factorOut) { final Formula factoredOut = simplified.transform(new FactorOutSimplifier(config.ratingFunction)); simplified = simplifyWithRating(simplified, factoredOut, config); @@ -164,13 +166,13 @@ private static Formula addLiterals(final Formula formula, final SortedSet> primeImplicants = primeResult.getPrimeImplicants(); final List minimizedPIs = SmusComputation.computeSmusForFormulas(negateAllLiterals(primeImplicants, f), - Collections.singletonList(simplified), f, config.optimizationConfig); + Collections.singletonList(simplified), f, config.optimizationConfig); if (minimizedPIs == null || config.optimizationConfig.aborted()) { return null; } diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java index 3f491c05..b9e941c2 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java @@ -42,6 +42,7 @@ public class AdvancedSimplifierConfig extends Configuration { boolean restrictBackbone; + boolean minimalDnfCover; boolean factorOut; boolean simplifyNegations; boolean returnIntermediateResult; @@ -52,6 +53,7 @@ public class AdvancedSimplifierConfig extends Configuration { public String toString() { return "AdvancedSimplifierConfig{" + "restrictBackbone=" + this.restrictBackbone + + ", minimalDnfCover=" + this.minimalDnfCover + ", factorOut=" + this.factorOut + ", simplifyNegations=" + this.simplifyNegations + ", returnIntermediateResult=" + this.returnIntermediateResult + @@ -67,6 +69,7 @@ public String toString() { private AdvancedSimplifierConfig(final Builder builder) { super(ConfigurationType.ADVANCED_SIMPLIFIER); this.restrictBackbone = builder.restrictBackbone; + this.minimalDnfCover = builder.minimalDnfCover; this.factorOut = builder.factorOut; this.simplifyNegations = builder.simplifyNegations; this.returnIntermediateResult = builder.returnIntermediateResult; @@ -88,6 +91,7 @@ public static Builder builder() { public static class Builder { boolean restrictBackbone = true; + boolean minimalDnfCover = true; boolean factorOut = true; boolean simplifyNegations = true; boolean returnIntermediateResult = false; @@ -109,6 +113,17 @@ public Builder restrictBackbone(final boolean restrictBackbone) { return this; } + /** + * Sets the flag for whether a minimal DNF cover should be computed. The + * default is 'true'. + * @param minimalDnfCover flag for the minimal DNF cover computation + * @return the current builder + */ + public Builder minimalDnfCover(final boolean minimalDnfCover) { + this.minimalDnfCover = minimalDnfCover; + return this; + } + /** * Sets the flag for whether the formula should be factorized. The * default is 'true'. diff --git a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java index 64a87dee..1a9905e6 100644 --- a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java +++ b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java @@ -191,11 +191,13 @@ public void testAdvancedSimplifierConfig() { final FormulaFactory f = new FormulaFactory(); final List configs = Arrays.asList( AdvancedSimplifierConfig.builder().build(), - AdvancedSimplifierConfig.builder().restrictBackbone(false).factorOut(false).simplifyNegations(false).build(), + AdvancedSimplifierConfig.builder().restrictBackbone(false).minimalDnfCover(false).factorOut(false).simplifyNegations(false).build(), AdvancedSimplifierConfig.builder().factorOut(false).simplifyNegations(false).build(), AdvancedSimplifierConfig.builder().restrictBackbone(false).simplifyNegations(false).build(), + AdvancedSimplifierConfig.builder().restrictBackbone(false).minimalDnfCover(false).build(), AdvancedSimplifierConfig.builder().restrictBackbone(false).factorOut(false).build(), AdvancedSimplifierConfig.builder().restrictBackbone(false).build(), + AdvancedSimplifierConfig.builder().minimalDnfCover(false).build(), AdvancedSimplifierConfig.builder().factorOut(false).build(), AdvancedSimplifierConfig.builder().simplifyNegations(false).build()); @@ -216,11 +218,11 @@ public void testAdvancedSimplifierConfig() { @Test public void testBackboneIntermediateResult() { final FormulaFactory f = new FormulaFactory(); - Formula formula = parse(f, "(a & b) | (a & c)"); - OptimizationHandler optHandler = mock(OptimizationHandler.class); + final Formula formula = parse(f, "(a & b) | (a & c)"); + final OptimizationHandler optHandler = mock(OptimizationHandler.class); // abort simplification after successful backbone computation final AtomicInteger count = new AtomicInteger(0); - when(optHandler.aborted()).then(invocationOnMock -> count.addAndGet(1) > 1); + when(optHandler.aborted()).then(invocationOnMock -> count.addAndGet(1) > 1); testHandler(optHandler, formula, true, true); } From 84a374cbd9a391289f604e8ff80409ff3d7f354e Mon Sep 17 00:00:00 2001 From: Rouven Walter Date: Fri, 2 Aug 2024 22:28:33 +0200 Subject: [PATCH 42/44] refactoring SmusComputation to avoid redundant code --- .../explanations/smus/SmusComputation.java | 311 ++++++++++-------- 1 file changed, 181 insertions(+), 130 deletions(-) diff --git a/src/main/java/org/logicng/explanations/smus/SmusComputation.java b/src/main/java/org/logicng/explanations/smus/SmusComputation.java index 4a66ab9c..81c024a9 100644 --- a/src/main/java/org/logicng/explanations/smus/SmusComputation.java +++ b/src/main/java/org/logicng/explanations/smus/SmusComputation.java @@ -30,8 +30,6 @@ import static org.logicng.handlers.Handler.aborted; import static org.logicng.handlers.Handler.start; -import static org.logicng.handlers.OptimizationHandler.satHandler; -import static org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType.SAT_OPTIMIZATION; import static org.logicng.util.CollectionHelper.difference; import static org.logicng.util.CollectionHelper.nullSafe; @@ -39,7 +37,9 @@ import org.logicng.datastructures.Tristate; import org.logicng.formulas.Formula; import org.logicng.formulas.FormulaFactory; +import org.logicng.formulas.Literal; import org.logicng.formulas.Variable; +import org.logicng.handlers.Handler; import org.logicng.handlers.MaxSATHandler; import org.logicng.handlers.OptimizationHandler; import org.logicng.handlers.SATHandler; @@ -52,15 +52,16 @@ import org.logicng.solvers.functions.OptimizationFunction; import org.logicng.solvers.maxsat.OptimizationConfig; import org.logicng.solvers.maxsat.algorithms.MaxSAT; +import org.logicng.util.FormulaHelper; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; -import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -137,10 +138,29 @@ public static

List

computeSmus( final List additionalConstraints, final FormulaFactory f, final OptimizationConfig config) { - if (config.getOptimizationType() == SAT_OPTIMIZATION) { - return computeSmusSAT(propositions, additionalConstraints, f, config.getOptimizationHandler()); - } else { - return computeSmusMaxSAT(propositions, additionalConstraints, f, config); + final Handler handler = getHandler(config); + start(handler); + final OptSolver growSolver = OptSolver.create(f, config); + growSolver.addConstraint(nullSafe(additionalConstraints)); + final Map propositionMapping = createPropositionsMapping(propositions, growSolver, f); + final boolean sat = growSolver.sat(propositionMapping.keySet()); + if (sat || growSolver.aborted()) { + return null; + } + final OptSolver hSolver = OptSolver.create(f, config); + while (true) { + final SortedSet h = hSolver.minimize(propositionMapping.keySet()); + if (h == null || aborted(handler)) { + return null; + } + final SortedSet c = grow(growSolver, h, propositionMapping.keySet()); + if (aborted(handler)) { + return null; + } + if (c == null) { + return h.stream().map(propositionMapping::get).collect(Collectors.toList()); + } + hSolver.addConstraint(f.or(c)); } } @@ -194,152 +214,183 @@ public static List computeSmusForFormulas( return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList()); } - private static

List

computeSmusSAT( - final List

propositions, - final List additionalConstraints, - final FormulaFactory f, - final OptimizationHandler handler) { - start(handler); - final SATSolver growSolver = MiniSat.miniSat(f); - growSolver.add(nullSafe(additionalConstraints)); - final Map propositionMapping = createPropositionsMapping(propositions, growSolver::add, f); - final boolean sat = growSolver.sat(satHandler(handler), propositionMapping.keySet()) == Tristate.TRUE; - if (sat || aborted(handler)) { - return null; - } - final SATSolver hSolver = MiniSat.miniSat(f); - while (true) { - final SortedSet h = minimumHs(hSolver, propositionMapping.keySet(), handler); - if (h == null || aborted(handler)) { - return null; - } - final SortedSet c = grow(growSolver, h, propositionMapping.keySet(), handler); - if (aborted(handler)) { - return null; - } - if (c == null) { - return h.stream().map(propositionMapping::get).collect(Collectors.toList()); - } - hSolver.add(f.or(c)); - } - } - - private static

List

computeSmusMaxSAT( - final List

propositions, - final List additionalConstraints, - final FormulaFactory f, - final OptimizationConfig config) { - final MaxSATHandler handler = config.getMaxSATHandler(); - start(handler); - final List growSolverConstraints = new ArrayList<>(nullSafe(additionalConstraints)); - final Map propositionMapping = createPropositionsMapping(propositions, growSolverConstraints::add, f); - final boolean sat = sat(growSolverConstraints, propositionMapping.keySet(), handler, f); - if (sat || aborted(handler)) { - return null; - } - final List hSolverConstraints = new ArrayList<>(); - while (true) { - final SortedSet h = minimumHs(hSolverConstraints, propositionMapping.keySet(), config, f); - if (h == null || aborted(handler)) { - return null; - } - final SortedSet c = grow(growSolverConstraints, h, propositionMapping.keySet(), config, f); - if (aborted(handler)) { - return null; - } - if (c == null) { - return h.stream().map(propositionMapping::get).collect(Collectors.toList()); - } - hSolverConstraints.add(f.or(c)); - } + private static Handler getHandler(final OptimizationConfig config) { + return config.getOptimizationType() == OptimizationConfig.OptimizationType.SAT_OPTIMIZATION + ? config.getOptimizationHandler() + : config.getMaxSATHandler(); } private static

Map createPropositionsMapping( - final List

propositions, final Consumer consumer, final FormulaFactory f) { + final List

propositions, final OptSolver solver, final FormulaFactory f) { final Map propositionMapping = new TreeMap<>(); for (final P proposition : propositions) { final Variable selector = f.variable(PROPOSITION_SELECTOR + propositionMapping.size()); propositionMapping.put(selector, proposition); - consumer.accept(f.equivalence(selector, proposition.formula())); + solver.addConstraint(f.equivalence(selector, proposition.formula())); } return propositionMapping; } - private static boolean sat(final List constraints, final Set variables, final MaxSATHandler handler, final FormulaFactory f) { - final SATHandler satHandler = handler == null ? null : handler.satHandler(); - final SATSolver satSolver = MiniSat.miniSat(f); - satSolver.add(constraints); - return satSolver.sat(satHandler, variables) == Tristate.TRUE; + private static SortedSet grow(final OptSolver growSolver, final SortedSet h, final Set variables) { + growSolver.saveState(); + growSolver.addConstraint(h); + final SortedSet maxModel = growSolver.maximize(variables); + if (maxModel == null) { + return null; + } + growSolver.loadState(); + return difference(variables, maxModel, TreeSet::new); } - private static SortedSet minimumHs( - final SATSolver hSolver, final Set variables, final OptimizationHandler handler) { - final Assignment minimumHsModel = hSolver.execute(OptimizationFunction.builder() - .handler(handler) - .literals(variables) - .minimize().build()); - return aborted(handler) ? null : new TreeSet<>(minimumHsModel.positiveVariables()); - } + private abstract static class OptSolver { + protected final FormulaFactory f; + protected final OptimizationConfig config; - private static SortedSet minimumHs( - final List constraints, - final Set variables, - final OptimizationConfig config, - final FormulaFactory f) { - final MaxSATSolver maxSatSolver = config.genMaxSATSolver(f); - constraints.forEach(maxSatSolver::addHardFormula); - for (final Variable v : variables) { - maxSatSolver.addSoftFormula(v.negate(), 1); + OptSolver(final FormulaFactory f, final OptimizationConfig config) { + this.f = f; + this.config = config; } - final MaxSATHandler handler = config.getMaxSATHandler(); - final MaxSAT.MaxSATResult result = maxSatSolver.solve(handler); - if (result == MaxSAT.MaxSATResult.UNDEF || aborted(handler)) { - return null; + + public static OptSolver create(final FormulaFactory f, final OptimizationConfig config) { + if (config.getOptimizationType() == OptimizationConfig.OptimizationType.SAT_OPTIMIZATION) { + return new SatOptSolver(f, config); + } else { + return new MaxSatOptSolver(f, config); + } + } + + abstract void addConstraint(final Formula formula); + + abstract void addConstraint(final Collection formulas); + + abstract boolean sat(final Collection variables); + + abstract void saveState(); + + abstract void loadState(); + + abstract SortedSet maximize(final Collection targetLiterals); + + SortedSet minimize(final Collection targetLiterals) { + return maximize(FormulaHelper.negateLiterals(targetLiterals, TreeSet::new)); } - return new TreeSet<>(maxSatSolver.model().positiveVariables()); + + abstract boolean aborted(); } - private static SortedSet grow( - final SATSolver growSolver, - final SortedSet h, - final Set variables, - final OptimizationHandler handler) { - final SolverState solverState = growSolver.saveState(); - growSolver.add(h); - final Assignment maxModel = growSolver.execute(OptimizationFunction.builder() - .handler(handler) - .literals(variables) - .maximize().build()); - if (maxModel == null || aborted(handler)) { - return null; - } else { - growSolver.loadState(solverState); - return difference(variables, maxModel.positiveVariables(), TreeSet::new); + private static class SatOptSolver extends OptSolver { + private final MiniSat solver; + private SolverState state; + + SatOptSolver(final FormulaFactory f, final OptimizationConfig config) { + super(f, config); + this.solver = MiniSat.miniSat(f); + this.state = null; + } + + @Override + void addConstraint(final Formula formula) { + this.solver.add(formula); + } + + @Override + void addConstraint(final Collection formulas) { + this.solver.add(formulas); + } + + @Override + boolean sat(final Collection variables) { + final SATHandler satHandler = this.config.getOptimizationHandler() == null ? null : this.config.getOptimizationHandler().satHandler(); + return this.solver.sat(satHandler, variables) == Tristate.TRUE; + } + + @Override + void saveState() { + this.state = this.solver.saveState(); + } + + @Override + void loadState() { + if (this.state != null) { + this.solver.loadState(this.state); + this.state = null; + } + } + + @Override + SortedSet maximize(final Collection targetLiterals) { + final OptimizationFunction optFunction = OptimizationFunction.builder() + .handler(this.config.getOptimizationHandler()) + .literals(targetLiterals) + .maximize().build(); + final Assignment model = this.solver.execute(optFunction); + return model == null || aborted() ? null : new TreeSet<>(model.positiveVariables()); + } + + @Override + boolean aborted() { + return Handler.aborted(this.config.getOptimizationHandler()); } } - private static SortedSet grow( - final List constraints, - final SortedSet h, - final Set variables, - final OptimizationConfig config, - final FormulaFactory f) { - final MaxSATSolver maxSatSolver = config.genMaxSATSolver(f); - constraints.forEach(maxSatSolver::addHardFormula); - h.forEach(maxSatSolver::addHardFormula); - for (final Variable v : variables) { - maxSatSolver.addSoftFormula(v, 1); + private static class MaxSatOptSolver extends OptSolver { + private List constraints; + private int saveIdx; + + public MaxSatOptSolver(final FormulaFactory f, final OptimizationConfig config) { + super(f, config); + this.constraints = new ArrayList<>(); + this.saveIdx = -1; } - final MaxSATHandler handler = config.getMaxSATHandler(); - final MaxSAT.MaxSATResult result = maxSatSolver.solve(handler); - if (result == MaxSAT.MaxSATResult.UNDEF || aborted(handler)) { - return null; + + @Override + void addConstraint(final Formula formula) { + this.constraints.add(formula); } - final Assignment maxModel = maxSatSolver.model(); - if (maxModel == null) { - return null; - } else { - return difference(variables, maxModel.positiveVariables(), TreeSet::new); + + @Override + void addConstraint(final Collection formulas) { + this.constraints.addAll(formulas); + } + + @Override + boolean sat(final Collection variables) { + final SATHandler satHandler = this.config.getMaxSATHandler() == null ? null : this.config.getMaxSATHandler().satHandler(); + final SATSolver satSolver = MiniSat.miniSat(this.f); + satSolver.add(this.constraints); + return satSolver.sat(satHandler, variables) == Tristate.TRUE; + } + + @Override + void saveState() { + this.saveIdx = this.constraints.size(); + } + + @Override + void loadState() { + if (this.saveIdx != -1) { + this.constraints = this.constraints.subList(0, this.saveIdx); + this.saveIdx = -1; + } + } + + @Override + SortedSet maximize(final Collection targetLiterals) { + final MaxSATSolver maxSatSolver = this.config.genMaxSATSolver(this.f); + this.constraints.forEach(maxSatSolver::addHardFormula); + for (final Literal lit : targetLiterals) { + maxSatSolver.addSoftFormula(lit, 1); + } + final MaxSATHandler handler = this.config.getMaxSATHandler(); + final MaxSAT.MaxSATResult result = maxSatSolver.solve(handler); + return result == MaxSAT.MaxSATResult.UNDEF || result == MaxSAT.MaxSATResult.UNSATISFIABLE || aborted() + ? null + : new TreeSet<>(maxSatSolver.model().positiveVariables()); + } + + @Override + boolean aborted() { + return Handler.aborted(this.config.getMaxSATHandler()); } } } From 567a53fe217698186d03ff5bee8166269404ed0c Mon Sep 17 00:00:00 2001 From: Steffen Hildebrandt Date: Mon, 9 Sep 2024 18:15:27 +0200 Subject: [PATCH 43/44] updated changelog and made some fields private --- CHANGELOG.md | 10 +++++++++- .../simplification/AdvancedSimplifierConfig.java | 10 +++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43bcfdba..9b6c3cd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,15 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added -- Added configuration flag `minimalDnfCover` in `AdvancedSimplifierConfig` to set whether the step for computing the minimal DNF cover should be performed. Default is `true`. +- New class `OptimizationConfig` used to configure optimization computations in various algorithms. It allows to configure the following aspects: + - the `optimizationType` (either SAT-based optimization or a MaxSAT algorithm) + - the `maxSATConfig` to further configure the MaxSAT algorithm + - the `optimizationHandler` to use + - the `maxSATHandler` to use +- Added three new configuration options to `AdvancedSimplifierConfig`: + - `minimalDnfCover` determines whether the step for computing the minimal DNF cover should be performed. Default is `true`. + - `returnIntermediateResult` allows to return an intermediate result from the `AdvancedSimplifier` if the computation was aborted by a handler. Default is `false`. + - `optimizationConfig` can be used to configure the algorithms in the simplifier which perform optimizations, also the `OptimizationHandler handler` moved into this config ## [2.5.1] - 2024-07-31 diff --git a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java index b9e941c2..a89733e3 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java @@ -90,11 +90,11 @@ public static Builder builder() { */ public static class Builder { - boolean restrictBackbone = true; - boolean minimalDnfCover = true; - boolean factorOut = true; - boolean simplifyNegations = true; - boolean returnIntermediateResult = false; + private boolean restrictBackbone = true; + private boolean minimalDnfCover = true; + private boolean factorOut = true; + private boolean simplifyNegations = true; + private boolean returnIntermediateResult = false; private RatingFunction ratingFunction = DefaultRatingFunction.get(); private OptimizationConfig optimizationConfig = OptimizationConfig.sat(null); From 6fb3568a3a6b05293f24487d45a3db776e885282 Mon Sep 17 00:00:00 2001 From: Christoph Zengler Date: Mon, 9 Sep 2024 20:30:41 +0200 Subject: [PATCH 44/44] Final 2.6.0 --- CHANGELOG.md | 2 +- README.md | 2 +- pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b6c3cd2..5e21a70e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [2.6.0] - 2024-08-02 +## [2.6.0] - 2024-09-10 ### Added diff --git a/README.md b/README.md index 9bc07c4b..abadb25c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ LogicNG is released in the Maven Central Repository. To include it just add org.logicng logicng - 2.5.1 + 2.6.0 ``` diff --git a/pom.xml b/pom.xml index 00fb5a6b..dfe8c374 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.0.0 org.logicng logicng - 2.6.0-SNAPSHOT + 2.6.0 bundle LogicNG