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 }} 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 }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e9b85fa..5e21a70e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,61 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.6.0] - 2024-09-10 + +### Added + +- 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 + +### 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!) + +- 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. +- 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 + +- UBTree data structure now supports empty sets. +- 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) +- Significant performance improvements in the DTree generation for DNNFs +- Minor performance improvements in some DNF/CNF generating algorithms by using faster `cnf`/`dnf`. + +### Fixed + +- 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 ### Changed @@ -359,4 +414,3 @@ LogicNG uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added - Initial Release of LogicNG - diff --git a/README.md b/README.md index 25518bed..abadb25c 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 @@ -34,7 +34,7 @@ LogicNG is released in the Maven Central Repository. To include it just add org.logicng logicng - 2.4.1 + 2.6.0 ``` 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 @@ - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 46a1fb80..dfe8c374 100644 --- a/pom.xml +++ b/pom.xml @@ -26,36 +26,27 @@ 4.0.0 org.logicng logicng - 2.4.1 + 2.6.0 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 - 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,26 +63,27 @@ 1.8 java - **/LogicNGPropositional*.java,**/LogicNGPseudoBoolean*.java + 5.10.2 + 3.25.3 + + 4.11.0 + 4.9.3 - 5.9.0 - 3.23.1 - 4.7.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 + 1.9.1 @@ -106,22 +98,10 @@ - - 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 + ${version.maven-compiler} @@ -149,6 +129,13 @@ org.apache.maven.plugins maven-source-plugin ${version.maven-source} + + + + LogicNGPropositional* + LogicNGPseudo* + + attach-sources @@ -164,6 +151,9 @@ org.apache.maven.plugins maven-javadoc-plugin ${version.maven-javadoc} + + ${project.build.sourceDirectory} + attach-javadocs @@ -179,12 +169,6 @@ org.jacoco jacoco-maven-plugin ${version.jacoco} - - - **/LogicNGPropositional* - **/LogicNGPseudoBoolean* - - default-prepare-agent @@ -233,36 +217,66 @@ org.eluder.coveralls coveralls-maven-plugin ${version.coveralls} - - - target/generated-sources/antlr - - - org.apache.maven.plugins maven-surefire-plugin ${version.surefire} - false - false - -Xmx2g + ${argLine} -Xmx4g + + + + + + org.antlr + antlr4-maven-plugin + ${version.antlr} + + 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 @@ -385,4 +399,3 @@ - diff --git a/src/main/java/org/logicng/collections/LNGBooleanVector.java b/src/main/java/org/logicng/collections/LNGBooleanVector.java index 363715d1..0cf8c14c 100644 --- a/src/main/java/org/logicng/collections/LNGBooleanVector.java +++ b/src/main/java/org/logicng/collections/LNGBooleanVector.java @@ -88,6 +88,16 @@ public LNGBooleanVector(final boolean... elems) { this.size = elems.length; } + /** + * 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; + } + /** * 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..5f28b027 100644 --- a/src/main/java/org/logicng/collections/LNGIntVector.java +++ b/src/main/java/org/logicng/collections/LNGIntVector.java @@ -88,6 +88,16 @@ public LNGIntVector(final int... elems) { this.size = elems.length; } + /** + * 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; + } + /** * 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..6e05e22d 100644 --- a/src/main/java/org/logicng/collections/LNGLongVector.java +++ b/src/main/java/org/logicng/collections/LNGLongVector.java @@ -88,6 +88,16 @@ public LNGLongVector(final long... elems) { this.size = elems.length; } + /** + * 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; + } + /** * 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/datastructures/ubtrees/UBTree.java b/src/main/java/org/logicng/datastructures/ubtrees/UBTree.java index b9c347ef..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; @@ -41,17 +43,41 @@ * 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; + } + + /** + * 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; } /** @@ -69,7 +95,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 +108,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 +126,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 +139,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 +152,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 +170,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; @@ -159,7 +209,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); } @@ -193,7 +243,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) { diff --git a/src/main/java/org/logicng/explanations/smus/SmusComputation.java b/src/main/java/org/logicng/explanations/smus/SmusComputation.java index b8a10202..81c024a9 100644 --- a/src/main/java/org/logicng/explanations/smus/SmusComputation.java +++ b/src/main/java/org/logicng/explanations/smus/SmusComputation.java @@ -30,22 +30,32 @@ 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.util.CollectionHelper.difference; +import static org.logicng.util.CollectionHelper.nullSafe; import org.logicng.datastructures.Assignment; 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; 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 org.logicng.util.FormulaHelper; -import java.util.Collections; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -60,7 +70,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 +92,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 = OptimizationConfig.sat(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,35 +111,56 @@ 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 = OptimizationConfig.sat(handler); + 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) { + final Handler handler = getHandler(config); 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())); - } - final boolean sat = growSolver.sat(satHandler(handler), propositionMapping.keySet()) == Tristate.TRUE; - if (sat || aborted(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 SATSolver hSolver = MiniSat.miniSat(f); + final OptSolver hSolver = OptSolver.create(f, config); while (true) { - final SortedSet h = minimumHs(hSolver, propositionMapping.keySet(), handler); + final SortedSet h = hSolver.minimize(propositionMapping.keySet()); if (h == null || aborted(handler)) { return null; } - final SortedSet c = grow(growSolver, h, propositionMapping.keySet(), handler); + 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.add(f.or(c)); + hSolver.addConstraint(f.or(c)); } } @@ -137,8 +171,12 @@ public static

List

computeSmus(final List

proposit * @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); + public static List computeSmusForFormulas( + final List formulas, + final List additionalConstraints, + final FormulaFactory f) { + final OptimizationConfig cfg = OptimizationConfig.sat(null); + return computeSmusForFormulas(formulas, additionalConstraints, f, cfg); } /** @@ -149,36 +187,210 @@ public static List computeSmusForFormulas(final List formulas, * @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) { + public static List computeSmusForFormulas( + final List formulas, + final List additionalConstraints, + final FormulaFactory f, + final OptimizationHandler handler) { + final OptimizationConfig cfg = OptimizationConfig.sat(handler); + 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, handler); + final List smus = computeSmus(props, additionalConstraints, f, config); return smus == null ? null : smus.stream().map(Proposition::formula).collect(Collectors.toList()); } - 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 static Handler getHandler(final OptimizationConfig config) { + return config.getOptimizationType() == OptimizationConfig.OptimizationType.SAT_OPTIMIZATION + ? config.getOptimizationHandler() + : config.getMaxSATHandler(); } - 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)) { + private static

Map createPropositionsMapping( + 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); + solver.addConstraint(f.equivalence(selector, proposition.formula())); + } + return propositionMapping; + } + + 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; - } else { - final List maximumSatisfiableSet = maxModel.positiveVariables(); - growSolver.loadState(solverState); - final SortedSet minimumCorrectionSet = new TreeSet<>(variables); - maximumSatisfiableSet.forEach(minimumCorrectionSet::remove); - return minimumCorrectionSet; + } + growSolver.loadState(); + return difference(variables, maxModel, TreeSet::new); + } + + private abstract static class OptSolver { + protected final FormulaFactory f; + protected final OptimizationConfig config; + + OptSolver(final FormulaFactory f, final OptimizationConfig config) { + this.f = f; + this.config = config; + } + + 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)); + } + + abstract boolean aborted(); + } + + 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 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; + } + + @Override + void addConstraint(final Formula formula) { + this.constraints.add(formula); + } + + @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()); } } } diff --git a/src/main/java/org/logicng/formulas/FormulaFactory.java b/src/main/java/org/logicng/formulas/FormulaFactory.java index 664df73c..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; @@ -80,7 +78,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 { @@ -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); } /** @@ -802,6 +798,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 +940,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); @@ -1258,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/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/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/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/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/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java b/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java index 9b0f0e0a..1b2f964b 100644 --- a/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java +++ b/src/main/java/org/logicng/knowledgecompilation/dnnf/datastructures/Dnnf.java @@ -37,8 +37,8 @@ /** * A DNNF - Decomposable Negation Normal Form. - * @version 2.0.0 - * @since 2.5.0 + * @version 2.5.0 + * @since 2.0.0 */ public final class Dnnf { 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++; } } 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/main/java/org/logicng/primecomputation/PrimeCompiler.java b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java index a3e433af..4eab4d82 100644 --- a/src/main/java/org/logicng/primecomputation/PrimeCompiler.java +++ b/src/main/java/org/logicng/primecomputation/PrimeCompiler.java @@ -39,10 +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.sat.MiniSatConfig; +import org.logicng.solvers.maxsat.OptimizationConfig; +import org.logicng.solvers.maxsat.OptimizationConfig.OptimizationType; +import org.logicng.solvers.maxsat.algorithms.MaxSAT; import org.logicng.transformations.LiteralSubstitution; import org.logicng.util.FormulaHelper; import org.logicng.util.Pair; @@ -69,7 +73,7 @@ * {@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 { @@ -110,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, null); + return compute(formula, type, OptimizationConfig.sat(null)); } /** @@ -127,12 +131,41 @@ public PrimeResult compute(final Formula formula, final PrimeResult.CoverageType * @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, final OptimizationHandler handler) { - start(handler); + public PrimeResult compute( + final Formula formula, + final PrimeResult.CoverageType type, + final OptimizationHandler handler) { + return compute(formula, type, OptimizationConfig.sat(handler)); + } + + /** + * 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 + * @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 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( @@ -141,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<>(); @@ -167,7 +203,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; } @@ -192,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 || aborted(cfg.getMaxSATHandler())) { + 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/MiniSat.java b/src/main/java/org/logicng/solvers/MiniSat.java index 5b4e8f00..112a2862 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/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 diff --git a/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java b/src/main/java/org/logicng/solvers/datastructures/LNGBoundedIntQueue.java index 80db3aee..83c2b343 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; } + 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; + 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; } + public LNGIntVector getElems() { + return this.elems; + } + + public int getFirst() { + return this.first; + } + + public int getLast() { + return this.last; + } + + public long getSumOfQueue() { + return this.sumOfQueue; + } + + public int getMaxSize() { + return this.maxSize; + } + + public 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..63a1199e 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; } + 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; + 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; } + public LNGLongVector getElems() { + return this.elems; + } + + public int getFirst() { + return this.first; + } + + public int getLast() { + return this.last; + } + + public long getSumOfQueue() { + return this.sumOfQueue; + } + + public int getMaxSize() { + return this.maxSize; + } + + public 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..cfbb2a8a 100644 --- a/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java +++ b/src/main/java/org/logicng/solvers/datastructures/LNGHeap.java @@ -69,6 +69,18 @@ public LNGHeap(final MiniSatStyleSolver solver) { this.indices = new LNGIntVector(1000); } + /** + * 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; + } + /** * Returns the left position on the heap for a given position. * @param pos the position @@ -252,6 +264,14 @@ private void percolateDown(final int pos) { this.indices.set(y, p); } + public LNGIntVector getHeap() { + return this.heap; + } + + public 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..acc4c633 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; } + 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; + 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; } + public 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..249290b9 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; } + 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; + 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/maxsat/OptimizationConfig.java b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java new file mode 100644 index 00000000..5627acb5 --- /dev/null +++ b/src/main/java/org/logicng/solvers/maxsat/OptimizationConfig.java @@ -0,0 +1,205 @@ +package org.logicng.solvers.maxsat; + +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, + 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; + + private 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; + } + + /** + * 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); + } + + /** + * Returns the optimization type. + * @return the optimization type + */ + 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 + */ + 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: + 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); + } + } + + /** + * Starts 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) { + 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/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/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/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/MiniSatConfig.java b/src/main/java/org/logicng/solvers/sat/MiniSatConfig.java index 691fc9a1..f60a9211 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()); @@ -346,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 */ 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/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 f7fb6896..9407b236 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.clause(term) : f.term(term)); } - return ubTree; + return cnf ? f.cnf(terms) : f.dnf(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/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java index 7d57439c..5e28a285 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifier.java @@ -28,10 +28,6 @@ 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; @@ -45,6 +41,7 @@ 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; @@ -72,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 { @@ -126,15 +123,16 @@ 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); + 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 - .compute(Collections.singletonList(formula), formula.variables(), BackboneType.POSITIVE_AND_NEGATIVE, satHandler(config.handler)); - if (backbone == null || aborted(config.handler)) { - return null; + .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(); @@ -142,18 +140,18 @@ public Formula apply(final Formula formula, final boolean cache) { backboneLiterals.addAll(backbone.getCompleteBackbone()); simplified = formula.restrict(new Assignment(backboneLiterals)); } - final Formula simplifyMinDnf = computeMinDnf(f, simplified, config); - if (simplifyMinDnf == null) { - return 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); } - 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); @@ -161,20 +159,24 @@ public Formula apply(final Formula formula, final boolean cache) { return simplified; } - private Formula computeMinDnf(final FormulaFactory f, Formula simplified, final AdvancedSimplifierConfig config) { + 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.handler); - if (primeResult == null || aborted(config.handler)) { + 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.handler); - if (minimizedPIs == null || aborted(config.handler)) { + Collections.singletonList(simplified), f, config.optimizationConfig); + if (minimizedPIs == null || config.optimizationConfig.aborted()) { return null; } - simplified = f.or(negateAllLiteralsInFormulas(minimizedPIs, f).stream().map(f::and).collect(Collectors.toList())); - return simplified; + 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 f3f1af55..a89733e3 100644 --- a/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java +++ b/src/main/java/org/logicng/transformations/simplification/AdvancedSimplifierConfig.java @@ -31,29 +31,34 @@ 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}. - * @version 2.3.0 + * @version 2.6.0 * @since 2.3.0 */ public class AdvancedSimplifierConfig extends Configuration { boolean restrictBackbone; + boolean minimalDnfCover; boolean factorOut; boolean simplifyNegations; + boolean returnIntermediateResult; RatingFunction ratingFunction; - OptimizationHandler handler; + OptimizationConfig optimizationConfig; @Override public String toString() { return "AdvancedSimplifierConfig{" + "restrictBackbone=" + this.restrictBackbone + + ", minimalDnfCover=" + this.minimalDnfCover + ", factorOut=" + this.factorOut + ", simplifyNegations=" + this.simplifyNegations + + ", returnIntermediateResult=" + this.returnIntermediateResult + ", ratingFunction=" + this.ratingFunction + - ", handler=" + this.handler + + ", optimizationConfig=" + this.optimizationConfig + '}'; } @@ -64,10 +69,12 @@ 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; this.ratingFunction = builder.ratingFunction; - this.handler = builder.handler; + this.optimizationConfig = builder.optimizationConfig; } /** @@ -83,18 +90,21 @@ public static Builder builder() { */ public static class Builder { - boolean restrictBackbone = true; - boolean factorOut = true; - boolean simplifyNegations = true; - private RatingFunction ratingFunction = new DefaultRatingFunction(); - private OptimizationHandler handler = null; + 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); 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 */ @@ -104,7 +114,19 @@ 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 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'. * @param factorOut flag for the factorisation * @return the current builder */ @@ -114,7 +136,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 */ @@ -124,8 +147,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 */ @@ -135,12 +161,37 @@ 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.handler = handler; + 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; } 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/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/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/datastructures/ubtrees/UBTreeTest.java b/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java index 3bb02d6e..9540af75 100644 --- a/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java +++ b/src/test/java/org/logicng/datastructures/ubtrees/UBTreeTest.java @@ -28,26 +28,49 @@ 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; /** * Unit tests for {@link UBTree}. - * @version 2.0.0 + * @version 2.5.0 * @since 1.5.0 */ 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<>(); + 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 +88,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 +100,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 +147,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 +180,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 +237,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 +270,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 +327,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 +411,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 +420,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) { - return new TreeSet<>(Arrays.asList(elements)); + private static SortedSet set(final String... elements) { + return new TreeSet<>(asList(elements)); } } 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..e4a24068 100644 --- a/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java +++ b/src/test/java/org/logicng/explanations/smus/SmusComputationTest.java @@ -29,8 +29,16 @@ 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 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,200 +48,225 @@ 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() throws ParserException { + 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; + } + + @ParameterizedTest + @MethodSource("configs") + public void testFromPaper(final OptimizationConfig cfg) { 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")); + 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() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testWithAdditionalConstraint(final OptimizationConfig cfg) { 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, cfg); + assertThat(result).containsExactlyInAnyOrder(parse(this.f, "~n"), parse(this.f, "~l")); } - @Test - public void testSatisfiable() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testSatisfiable(final OptimizationConfig cfg) { 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, cfg); assertThat(result).isNull(); } - @Test - public void testUnsatisfiableAdditionalConstraints() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testUnsatisfiableAdditionalConstraints(final OptimizationConfig cfg) { 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, cfg); assertThat(result).isEmpty(); } - @Test - public void testTrivialUnsatFormula() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testTrivialUnsatFormula(final OptimizationConfig cfg) { 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, cfg); assertThat(result).containsExactly(this.f.falsum()); } - @Test - public void testUnsatFormula() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testUnsatFormula(final OptimizationConfig cfg) { 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, cfg); + assertThat(result).containsExactly(parse(this.f, "(a<=>b)&(~a<=>b)")); } - @Test - public void testShorterConflict() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testShorterConflict(final OptimizationConfig cfg) { 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")); + 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() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testCompleteConflict(final OptimizationConfig cfg) { 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); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f, cfg); assertThat(result).containsExactlyInAnyOrderElementsOf(input); } - @Test - public void testLongConflictWithShortcut() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testLongConflictWithShortcut(final OptimizationConfig cfg) { 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")); + 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"), + parse(this.f, "m|~n"), + parse(this.f, "n|s")); } - @Test - public void testManyConflicts() throws ParserException { + @ParameterizedTest + @MethodSource("configs") + public void testManyConflicts(final OptimizationConfig cfg) { 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")); + final List result = SmusComputation.computeSmusForFormulas(input, Collections.emptyList(), this.f, cfg); + 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 +274,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 +299,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/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/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/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(); } } 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 2a10bfe7..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; @@ -69,17 +68,22 @@ 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() { 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) @@ -87,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) @@ -95,20 +99,20 @@ 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); - 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( @@ -117,14 +121,14 @@ 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 - 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); @@ -132,7 +136,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( @@ -140,6 +144,56 @@ public void testSwappingMultipleBdds() throws ParserException { new BDDInnerNode(this.A, BDDConstant.getFalsumNode(this.f), BDDConstant.getVerumNode(this.f)))); } + @Test + public void testReorderingAndFormulaGeneration() { + final List order = this.f.variables("a", "b", "c", "d", "e", "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); + final BDD bdd1 = BDDFactory.build(formula1, kernel); + final BDD bdd2 = BDDFactory.build(formula2, kernel); + kernel.addAllVariablesAsBlock(); + kernel.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() { + final List order = this.f.variables("a", "b", "c", "d", "e", "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(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(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(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(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 public void testRandomReorderingQuick() { testRandomReordering(25, 30, false); @@ -182,7 +236,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))) @@ -196,7 +250,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(); @@ -206,26 +260,25 @@ 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); } } 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(); } } @@ -235,7 +288,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); @@ -255,7 +308,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; @@ -264,7 +317,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); } } 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/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; + } + } } diff --git a/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfModelEnumerationTest.java b/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfModelEnumerationTest.java index 03a09a14..d9775c9e 100644 --- a/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfModelEnumerationTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfModelEnumerationTest.java @@ -15,6 +15,7 @@ import org.logicng.formulas.Variable; import org.logicng.handlers.NumberOfModelsHandler; import org.logicng.io.parsers.ParserException; +import org.logicng.io.parsers.PropositionalParser; import org.logicng.knowledgecompilation.dnnf.datastructures.Dnnf; import org.logicng.knowledgecompilation.dnnf.functions.DnnfModelEnumerationFunction; import org.logicng.solvers.MiniSat; @@ -38,7 +39,7 @@ public class DnnfModelEnumerationTest extends TestWithExampleFormulas { @Test public void testCornerCases() throws ParserException, IOException { - final Formula contradiction = this.f.parse("(A | B) & ~A & ~B"); + final Formula contradiction = new PropositionalParser(f).parse("(A | B) & ~A & ~B"); compareModels(this.f.verum(), Collections.emptyList(), 1); compareModels(this.A, Collections.emptyList(), 1); compareModels(this.AND1, Collections.emptyList(), 1); diff --git a/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfProjectionFunctionTest.java b/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfProjectionFunctionTest.java index e5706bc4..fce61114 100644 --- a/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfProjectionFunctionTest.java +++ b/src/test/java/org/logicng/knowledgecompilation/dnnf/DnnfProjectionFunctionTest.java @@ -7,6 +7,7 @@ import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.Variable; import org.logicng.io.parsers.ParserException; +import org.logicng.io.parsers.PropositionalParser; import org.logicng.knowledgecompilation.dnnf.datastructures.Dnnf; import org.logicng.knowledgecompilation.dnnf.functions.DnnfProjectionFunction; import org.logicng.util.CollectionHelper; @@ -21,8 +22,9 @@ public class DnnfProjectionFunctionTest { @Test public void test() throws ParserException { final FormulaFactory f = new FormulaFactory(); - final Formula formula = f.parse("((A1 | ~A2 & A3) & (~B1 & B2 | ~B3 | B4) | (~A1 | A2 | A4 & ~A5) & B1) " + - "& ((C1 & C2 | ~C1 & C3 | C4) & (D1 | D2 | D3) | (~C1 | ~C2) & (D1 | D2 & D3))"); + final PropositionalParser p = new PropositionalParser(f); + final Formula formula = p.parse("((A1 | ~A2 & A3) & (~B1 & B2 | ~B3 | B4) | (~A1 | A2 | A4 & ~A5) & B1) " + + "& ((C1 & C2 | ~C1 & C3 | C4) & (D1 | D2 | D3) | (~C1 | ~C2) & (D1 | D2 & D3))"); final Dnnf dnnf = new Dnnf(formula.variables(), formula); final Dnnf projectAll = dnnf.execute(new DnnfProjectionFunction(formula.variables())); @@ -33,17 +35,17 @@ public void test() throws ParserException { final SortedSet elimA1Vars = CollectionHelper.difference(formula.variables(), Collections.singletonList(f.variable("A1")), TreeSet::new); final Dnnf elimA1 = dnnf.execute(new DnnfProjectionFunction(elimA1Vars)); - assertThat(elimA1).isEqualTo(new Dnnf(elimA1Vars, f.parse("(~B1 & B2 | ~B3 | B4 | B1) " + - "& ((C1 & C2 | ~C1 & C3 | C4) & (D1 | D2 | D3) | (~C1 | ~C2) & (D1 | D2 & D3))"))); + assertThat(elimA1).isEqualTo(new Dnnf(elimA1Vars, p.parse("(~B1 & B2 | ~B3 | B4 | B1) " + + "& ((C1 & C2 | ~C1 & C3 | C4) & (D1 | D2 | D3) | (~C1 | ~C2) & (D1 | D2 & D3))"))); final SortedSet elimA2C1Vars = CollectionHelper.difference(formula.variables(), Arrays.asList(f.variable("A2"), f.variable("C1")), TreeSet::new); final Dnnf elimA2C1 = dnnf.execute(new DnnfProjectionFunction(elimA2C1Vars)); - assertThat(elimA2C1).isEqualTo(new Dnnf(elimA2C1Vars, f.parse("((A1 | A3) & (~B1 & B2 | ~B3 | B4) | B1) " + - "& ((C2 | C3 | C4) & (D1 | D2 | D3) | (D1 | D2 & D3))"))); + assertThat(elimA2C1).isEqualTo(new Dnnf(elimA2C1Vars, p.parse("((A1 | A3) & (~B1 & B2 | ~B3 | B4) | B1) " + + "& ((C2 | C3 | C4) & (D1 | D2 | D3) | (D1 | D2 & D3))"))); final SortedSet elimA3B3C4D2Vars = CollectionHelper.difference(formula.variables(), Arrays.asList(f.variable("A3"), f.variable("B3"), f.variable("C4"), f.variable("D2")), TreeSet::new); final Dnnf elimA3B3C4D2 = dnnf.execute(new DnnfProjectionFunction(elimA3B3C4D2Vars)); - assertThat(elimA3B3C4D2).isEqualTo(new Dnnf(elimA3B3C4D2Vars, f.parse("((A1 | ~A2) | (~A1 | A2 | A4 & ~A5) & B1)"))); + assertThat(elimA3B3C4D2).isEqualTo(new Dnnf(elimA3B3C4D2Vars, p.parse("((A1 | ~A2) | (~A1 | A2 | A4 & ~A5) & B1)"))); } } 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 f735a2f4..178f6dcb 100644 --- a/src/test/java/org/logicng/modelcounting/ModelCounterTest.java +++ b/src/test/java/org/logicng/modelcounting/ModelCounterTest.java @@ -41,7 +41,8 @@ import org.logicng.formulas.FormulaFactory; import org.logicng.formulas.PBConstraint; import org.logicng.formulas.Variable; -import org.logicng.io.parsers.ParserException; +import org.logicng.handlers.DnnfCompilationHandler; +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 +52,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; @@ -74,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 @@ -91,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."); @@ -164,6 +166,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 +261,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; + } + } } 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..b9530d06 100644 --- a/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java +++ b/src/test/java/org/logicng/primecomputation/PrimeCompilerTest.java @@ -29,9 +29,19 @@ package org.logicng.primecomputation; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +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; @@ -44,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; @@ -54,94 +65,117 @@ 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[]{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 testCornerCases() { + public static Collection fastConfigs() { + final List configs = new ArrayList<>(); + 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; + } + + @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 -> { - 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, IMPLICANTS_COMPLETE , cfg); + verify(resultImplicantsMin, formula); + final PrimeResult resultImplicatesMin = PrimeCompiler.getWithMinimization().compute(formula, IMPLICATES_COMPLETE, cfg); + 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), - 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), 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,12 +183,12 @@ 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), - 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), @@ -169,13 +203,13 @@ 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), - 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++) { @@ -186,21 +220,21 @@ public void testCancellationPoints() throws IOException, ParserException { } } - 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()); } 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/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" + 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..1a9905e6 100644 --- a/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java +++ b/src/test/java/org/logicng/transformations/simplification/AdvancedSimplifierTest.java @@ -29,8 +29,18 @@ 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 static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; 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,61 +53,97 @@ 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; +import java.util.concurrent.atomic.AtomicInteger; /** * 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() 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); + testHandler(handler, formula, false, false); + testHandler(handler, formula, false, true); } } @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), @@ -105,34 +151,37 @@ public void testTimeoutHandlerLarge() throws ParserException, IOException { ); 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); } } @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)"); - testHandler(handler, formula, true); + final Formula formula = parse(this.f, "a&(b|c)"); + testHandler(handler, formula, true, false); + testHandler(handler, formula, true, 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)"); - testHandler(handler, formula, true); + final Formula formula = parse(this.f, "a&(b|c)"); + testHandler(handler, formula, true, false); + testHandler(handler, formula, true, 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++) { final OptimizationHandler handler = new BoundedOptimizationHandler(numSatHandlerStarts, numOptimizationStarts); - testHandler(handler, formula, true); + testHandler(handler, formula, true, false); } } } @@ -142,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()); @@ -164,20 +215,39 @@ public void testAdvancedSimplifierConfig() { } } - private void computeAndVerify(final Formula formula) { - final Formula simplified = formula.transform(this.simplifier); + @Test + public void testBackboneIntermediateResult() { + final FormulaFactory f = new FormulaFactory(); + 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); + 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))) .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(); 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