diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1902bcbfe..6e9b76d03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ jobs: strategy: matrix: # We test against Java releases: - # - greater than 7 + # - greater than or equal to 11 # AND # - with LTS and in "Premier Support" phase # OR @@ -15,12 +15,12 @@ jobs: # https://blogs.oracle.com/java-platform-group/oracle-jdk-releases-for-java-11-and-later # https://www.oracle.com/technetwork/java/java-se-support-roadmap.html java: - # LTS and in "Premier Support" as of 2019-03 (until 2022-03) - - 8 # LTS and in "Premier Support" as of 2019-03 (until 2023-09) - 11 # LTS as of 2021-11 (until 2029) - 17 + # Not succeeded as of 2022-12 + - 19 os: [ubuntu, windows] env: # We only post coverage data for exactly one build to coveralls. @@ -40,7 +40,7 @@ jobs: # See https://github.com/marketplace/actions/gradle-wrapper-validation - uses: gradle/wrapper-validation-action@v1 # See https://github.com/marketplace/actions/setup-java-jdk - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: java-version: ${{ matrix.java }} distribution: 'temurin' @@ -52,7 +52,7 @@ jobs: if: matrix.os == env.MAIN_OS && matrix.java == env.MAIN_JAVA continue-on-error: true with: - arguments: jacocoTestReport coveralls + arguments: jacocoAggregatedTestReport coveralls env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - uses: codecov/codecov-action@v1 diff --git a/README.md b/README.md index 6e5147a2c..0c3bb9412 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ possibilities to interface with the ecosystem built around the Java Virtual Mach ## Getting Started -Download a current version of `alpha.jar` from [Releases](https://github.com/alpha-asp/Alpha/releases). +Download a current version of the distribution jar (`alpha-cli-app-${version}-bundled.jar`) from [Releases](https://github.com/alpha-asp/Alpha/releases) and save it as `alpha.jar` for convenience. Running Alpha is as simple as running any other JAR: @@ -52,19 +52,19 @@ Alpha uses the [Gradle build automation system](https://gradle.org). Executing $ ./gradlew build ``` -will automatically fetch all dependencies (declared in [`build.gradle`](build.gradle)) and compile the project. +will automatically fetch all dependencies (declared in [`build.gradle.kts`](build.gradle.kts)) and compile the project. -Artifacts generated will be placed in `build/`. Most notably you'll find files ready for distribution at -`build/distributions/`. They contain archives which in turn contain a `bin/` directory with scripts to run Alpha on Linux +Artifacts generated will be placed in the `build/` subfolder of the respective module. Most notably you'll find files ready for distribution at +`alpha-cli-app/build/distributions/`. They contain archives which in turn contain a `bin/` directory with scripts to run Alpha on Linux and Windows. If you want to generate a JAR file to be run standalone, execute ```bash -$ ./gradlew bundledJar +$ ./gradlew alpha-cli-app:bundledJar ``` -and pick up `build/libs/alpha-bundled.jar`. +and pick up `alpha-cli-app/build/libs/alpha-cli-app-${version}-bundled.jar`. ### A Note on IDEs diff --git a/RELEASE.md b/RELEASE.md index 400d3cff6..5d922b0b6 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -2,64 +2,70 @@ This document explains how to build and release Alpha. -First, decide which revision (= Git commit) of Alpha you want to release. This revision should be on `master` -and ideally ahead of any previously released revisions. We denote the Git commit hash of the revision to be -released as `$rev` (it is a reference to a commit, so it could be the name of a branch, say, `master` or just -a hash like `cafebabe`). - -You probably have already checked out this version, but if you haven't, do so now: +The regular release workflow for Alpha assumes that a release will always be based on the latest commit in the `master` branch. In order to release Alpha, first checkout the `master` branch and make sure you're up to date: ```bash -$ git checkout $rev +$ git checkout master +$ git pull ``` -Now is the time to make sure the revision you are about to release actually works fine. Run tests, try it out -manually, maybe go paranoid and `./gradlew clean` everything and try again. Only continue if you are happy with -the revision you are about to release, and avoid list minute fixes. +Now is the time to make sure the revision you are about to release actually works. Build it using `./gradlew clean build`, potentially do some manual tests, play around a bit, maybe go paranoid and `./gradlew clean build` everything once more. Only continue if you are happy with the state you are about to release, and avoid last minute fixes. -Next, give `$rev` a name, by tagging it. The naming convention for tags is -[Semantic Versioning 2](http://semver.org/spec/v2.0.0.html). **Read through the specification of Semantic -Versioning carefully, before releasing anything. If in doubt, read it again and seek advice.** +The actual release process consists of following steps: +- Create a release tag using gradle release plugin. +- From the tag created by gradle release plugin, create a release on github. -Make sure the version you want to release does not collide and fits with any -[tags already present on GitHub](https://github.com/alpha-asp/Alpha/tags). We denote the version to be released -as `$version` (it looks like "v0.1.0", "v1.0.0-beta", note it starts with the letter "v"). +#### Creating a release tag using Gradle Release Plugin -```bash -$ git tag $version -``` +Before running the release plugin, decide on a release version identifier and the next development version. Version identifiers must confirm to [Semantic Versioning 2](http://semver.org/spec/v2.0.0.html). **Read through the specification of Semantic Versioning carefully, before releasing anything. If in doubt, read it again and seek advice.** Also, make sure the version you want to release does not collide with any [tag already present on GitHub](https://github.com/alpha-asp/Alpha/tags). We denote the version to be released as `$version` (it looks like "0.1.0", "1.0.0-beta"). -Now you push this tag to GitHub: +The next development version (denoted `$nextVersion`) is the version you expect to be the next release version. Note that it isn't set in stone since actual release versions are set during the release process. For example, if your release version is `0.9.0`, your next version could be `0.10.0` or `1.0.0`. + +To create a release tag and set the correct versions in the `gradle.properties` file, call the gradle release plugin: ```bash -$ git push --tags +$ ./gradlew release -Prelease.useAutomaticVersion=true -Prelease.releaseVersion=$version -Prelease.newVersion=$nextVersion-SNAPSHOT ``` +**Make sure you add the `-SNAPSHOT` qualifier to the next version!** This is the version that will be put into `gradle.properties` in the `master` branch after creating the release tag, i.e. subsequent builds of `master` (e.g. nightly builds from CI workflows) will have this version. + +The release plugin automatically pushes all changes it makes in the repository. After running it, make sure: +- `gradle.properties` in `master` has the new `SNAPSHOT` version. +- On github, you can see a new tag with the same name as your release version. +- When you check out the tag, `gradle.properties` contains the correct version, i.e. the tag name. Navigate to (Releases)[https://github.com/alpha-asp/Alpha/releases] and press "Draft a new release"). Fill in `$version` as the name of your tag, and change the Release Title to `$version`. Feel free to write a release note (we currently have no policy in place for release notes). If `$version` is below 1 or you are releasing a preview version, check the box. -Now, let's generate two distribution packages of Alpha for convenience. You will attach two files to the release on -GitHub. `alpha.jar`, a self-contained and executbale JAR and `alpha.zip` which contains Alpha as JAR file, dependencies -as JAR files and two scripts to run Alpha on Unix-like and Windows respectively. +Now, let's generate some distribution packages of Alpha for convenience. You will attach the following files to the release on GitHub: +- `alpha-cli-app-$version-bundled.jar: A "fat-jar" containingthe Alpha CLI applications along with all dependencies in one jar file. +- Distribution zip- and tar-archives for the CLI application: Zip- and tar-versions of an archive with Alpha, all dependencies, and launcher scripts for windows and UNIX-like systems. +- A zip- and tar-archive of the source code for Alpha. -To generate `alpha.jar`: +To generate these artifacts, check out your release tag: + +```bash +$ git checkout $version +``` + +To generate the "fat-jar": ```bash $ ./gradlew alpha-cli-app:bundledJar -$ cp alpha-cli-app/build/libs/alpha-cli*-bundled.jar alpha.jar ``` -To generate `alpha.zip`: +The jar file can be found in `./alpha-cli-app/build/libs/alpha-cli-app-$version-bundled.jar` + +To generate distribution archives: ```bash -$ ./gradlew alpha-cli-app:distZip -$ cp alpha-cli-app/build/distributions/*.zip alpha.zip +$ ./gradlew alpha-cli-app:distZip && ./gradlew alpha-cli-app:distTar ``` -Attach the two files to the release on GitHub, then publish the release. Lastly, check that everything is fine, -e.g. that the tag/version really points at the revision you wanted to rlease and that `alpha.zip` and `alpha.jar -downloaded from GitHub do what they are supposed to do. +The finished archives are located in `./alpha-cli-app/build/distributions/`. +Last `./gradlew clean` the project to get rid of all build artifacts, then create a `sources.zip` (using e.g. `zip -r sources.zip .`) and a `sources.tar.gz` (using e.g. `tar -czf /tmp/sources.tar.gz .`) + +Attach the generated files to the release on GitHub, then publish the release. Last but not least, check that everything is fine, i.e. the files - when downloaded from the github release - do what they're supposed to. Optionally, archive the release on Zenodo. If you do so, add the new identifier to `CITATION.cff`. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/Alpha.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/Alpha.java index 60dd0a236..74ef89dac 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/Alpha.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/Alpha.java @@ -1,9 +1,11 @@ package at.ac.tuwien.kr.alpha.api; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Path; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Stream; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; @@ -11,6 +13,8 @@ import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestResult; /** * Main API entry point for the Alpha ASP system. Provides facilities for parsing, normalizing and solving ASP programs. @@ -24,18 +28,18 @@ public interface Alpha { * * @param cfg and {@link InputConfig} specifying program sources (strings, files) as well as config metadata (e.g. literate program, * external atoms, etc) - * @return an {@link ASPCore2Program} representing the parsed ASP code from all sources referenced in the given {@link InputConfig} + * @return an {@link InputProgram} representing the parsed ASP code from all sources referenced in the given {@link InputConfig} * @throws IOException in case one or more program sources (e.g. files) cannot be read, or parsing fails */ InputProgram readProgram(InputConfig cfg) throws IOException; /** - * Reads and parses an {@link ASPCore2Program} from a list of {@link String}s representing paths. + * Reads and parses an {@link InputProgram} from a list of {@link String}s representing paths. * * @param literate flag indicating whether ASP code should be treated as "literate". * @param externals Custom {@link PredicateInterpretation}s for user-defined external atoms * @param paths a list of {@link String}s representing paths containing all sources from which ASP code should be read - * @return an {@link ASPCore2Program} representing the parsed ASP code from all given path strings + * @return an {@link InputProgram} representing the parsed ASP code from all given path strings * @throws IOException in case one or more program sources cannot be read, or parsing fails */ InputProgram readProgramFiles(boolean literate, Map externals, List paths) throws IOException; @@ -46,12 +50,12 @@ public interface Alpha { InputProgram readProgramFiles(boolean literate, Map externals, Path... paths) throws IOException; /** - * Parses a given String into an {@link ASPCore2Program}, using a map of custom {@link PredicateInterpretation}s to resolve external atoms + * Parses a given String into an {@link InputProgram}, using a map of custom {@link PredicateInterpretation}s to resolve external atoms * in ASP code. * * @param aspString a string representing a valid ASP-Core2 program * @param externals a map of custom {@link PredicateInterpretation}s against which external atoms in the given code are resolved - * @return an {@link ASPCore2Program} representing the parsed ASP code + * @return an {@link InputProgram} representing the parsed ASP code */ InputProgram readProgramString(String aspString, Map externals); @@ -61,7 +65,17 @@ public interface Alpha { InputProgram readProgramString(String aspString); /** - * Prepares a {@link DebugSolvingContext} for the given {@link ASPCore2Program} to debug program preprocessing. + * Parses an ASP program from an input stream. + */ + InputProgram readProgramStream(InputStream is) throws IOException; + + /** + * Parses an ASP program from an input stream. + */ + InputProgram readProgramStream(InputStream is, Map externals) throws IOException; + + /** + * Prepares a {@link DebugSolvingContext} for the given {@link InputProgram} to debug program preprocessing. * * @return a {@link DebugSolvingContext} holding debug information for the given program */ @@ -75,7 +89,7 @@ public interface Alpha { DebugSolvingContext prepareDebugSolve(final NormalProgram program); /** - * Prepares a {@link DebugSolvingContext} for the given {@link ASPCore2Program} to debug program preprocessing. + * Prepares a {@link DebugSolvingContext} for the given {@link InputProgram} to debug program preprocessing. * * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. * @return a {@link DebugSolvingContext} holding debug information for the given program @@ -91,22 +105,25 @@ public interface Alpha { DebugSolvingContext prepareDebugSolve(final NormalProgram program, java.util.function.Predicate filter); /** - * Solves the given {@link ASPCore2Program}. + * Solves the given {@link InputProgram}. + * * @param program an input program * @return a {@link Stream} of {@link AnswerSet}s of the given program */ Stream solve(InputProgram program); /** - * Solves the given {@link ASPCore2Program}. + * Solves the given {@link InputProgram}. + * * @param program an input program - * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. + * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. * @return a {@link Stream} of {@link AnswerSet}s of the given program */ Stream solve(InputProgram program, java.util.function.Predicate filter); /** * Solves the given {@link NormalProgram}. + * * @param program an input program * @return a {@link Stream} of {@link AnswerSet}s of the given program */ @@ -114,36 +131,54 @@ public interface Alpha { /** * Solves the given {@link NormalProgram}. + * * @param program an input program - * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. + * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. * @return a {@link Stream} of {@link AnswerSet}s of the given program */ Stream solve(NormalProgram program, java.util.function.Predicate filter); /** - * Normalizes a program, i.e. rewrites all syntax constructs not natively supported by Alphas back-end into semantically equivalent ASP code. + * Normalizes a program, i.e. rewrites all syntax constructs not natively supported by Alphas back-end into semantically equivalent ASP + * code. * See {@link NormalProgram}, - * @param program An {@link ASPCore2Program} to normalize + * + * @param program An {@link InputProgram} to normalize * @return a {@link NormalProgram} that is a semantic equivalent to the given input program */ NormalProgram normalizeProgram(InputProgram program); /** - * Constructs a @{link Solver} pre-loaded with the given {@link ASPCore2Program} from which {@link AnswerSet}s can be obtained via {@link Solver#stream()}. + * Constructs a @{link Solver} pre-loaded with the given {@link InputProgram} from which {@link AnswerSet}s can be obtained via + * {@link Solver#stream()}. * * @param program the program to solve - * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. + * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. * @return a {@link Solver} pre-loaded withthe given program */ Solver prepareSolverFor(InputProgram program, java.util.function.Predicate filter); /** - * Constructs a @{link Solver} pre-loaded with the given {@link NormalProgram} from which {@link AnswerSet}s can be obtained via {@link Solver#stream()}. + * Constructs a @{link Solver} pre-loaded with the given {@link NormalProgram} from which {@link AnswerSet}s can be obtained via + * {@link Solver#stream()}. * * @param program the program to solve - * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. + * @param filter a {@link java.util.function.Predicate} against which {@link Predicate}s of answer sets are tested. * @return a {@link Solver} pre-loaded withthe given program */ Solver prepareSolverFor(NormalProgram program, java.util.function.Predicate filter); + /** + * Reifies, i.e. re-expresses as a set of ASP facts, the given input program. + * + * @param program an ASP program to reify + * @return a set of {@link BasicAtom}s encoding the given program + */ + Set reify(InputProgram program); + + /** + * Runs all test cases of the given program. + */ + TestResult test(InputProgram program); + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/AnswerSet.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/AnswerSet.java index 748e1a781..8b80fc9ef 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/AnswerSet.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/AnswerSet.java @@ -1,10 +1,13 @@ package at.ac.tuwien.kr.alpha.api; -import java.util.List; -import java.util.SortedSet; - import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AtomQuery; + +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; /** * API representation of an answer set, i.e. a set of atoms that is a model of an ASP program. @@ -29,7 +32,17 @@ public interface AnswerSet extends Comparable { boolean isEmpty(); /** - * List {@link Atom}s in this answer set satisfying the given {@link AnswerSetQuery}. + * List {@link Atom}s in this answer set satisfying the given {@link AtomQuery}. */ - List query(AnswerSetQuery query); + List query(AtomQuery query); + + default Set asFacts() { + return getPredicates().stream() + .map(this::getPredicateInstances) + .reduce(new TreeSet(), (left, right) -> { + left.addAll(right); + return left; + }); + } + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/AnswerSetQuery.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/AnswerSetQuery.java deleted file mode 100644 index dcd015a21..000000000 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/AnswerSetQuery.java +++ /dev/null @@ -1,82 +0,0 @@ -package at.ac.tuwien.kr.alpha.api; - -import java.util.List; - -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; - -/** - * A {@link java.util.function.Predicate} testing {@link Atom}s in order to query {@link AnswerSet}s for {@link Atom}s satisfying a specific - * query. - * - * Copyright (c) 2021, the Alpha Team. - */ -public interface AnswerSetQuery extends java.util.function.Predicate { - - /** - * Adds a filter predicate to apply on terms at the given index position. - * - * @param termIdx the term index on which to apply the new filter - * @param filter a filter predicate - * @return this answer set query withthe given filter added - */ - AnswerSetQuery withFilter(int termIdx, java.util.function.Predicate filter); - - /** - * Convenience method - adds a filter to match names of symbolic constants against a string. - * - * @param termIdx - * @param str - * @return - */ - AnswerSetQuery withConstantEquals(int termIdx, String str); - - /** - * Convenience method - adds a filter to match values of constant terms against a string. - * - * @param termIdx - * @param str - * @return - */ - AnswerSetQuery withStringEquals(int termIdx, String str); - - /** - * Convenience method - adds a filter to check for function terms with a given function symbol and arity. - * - * @param termIdx - * @param funcSymbol - * @param funcArity - * @return - */ - AnswerSetQuery withFunctionTerm(int termIdx, String funcSymbol, int funcArity); - - /** - * Convenience method - adds a filter to check whether a term is equal to a given term. - * - * @param termIdx - * @param otherTerm - * @return - */ - AnswerSetQuery withTermEquals(int termIdx, Term otherTerm); - - /** - * Applies this query to an atom. Filters are worked off in - * order of ascending term index in a conjunctive fashion, i.e. for an atom - * to match the query, all of its terms must satisfy all filters on these - * terms - * - * @param atom the atom to which to apply the query - * @return true iff the atom satisfies the query - */ - @Override - boolean test(Atom atom); - - /** - * Applies this query to an {@link AnswerSet}. - * - * @param as - * @return - */ - List applyTo(AnswerSet as); - -} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/ComparisonOperator.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/ComparisonOperator.java index 7b8343b8e..cc896ba5a 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/ComparisonOperator.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/ComparisonOperator.java @@ -2,7 +2,7 @@ import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; /** * A comparison operator that can be used in {@link InputProgram}s. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/common/fixedinterpretations/PredicateInterpretation.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/common/fixedinterpretations/PredicateInterpretation.java index 655fff135..bbe8680bf 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/common/fixedinterpretations/PredicateInterpretation.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/common/fixedinterpretations/PredicateInterpretation.java @@ -30,8 +30,8 @@ import java.util.List; import java.util.Set; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import static java.util.Collections.*; diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/AggregateRewritingConfig.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/AggregateRewritingConfig.java index 6c72fbe62..908b2b3cb 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/AggregateRewritingConfig.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/AggregateRewritingConfig.java @@ -5,7 +5,7 @@ /** * Configuration structure controlling how {@link AggregateLiteral}s are compiled during program normalization in - * {@link Alpha#normalizeProgram(at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program)}. + * {@link Alpha#normalizeProgram(at.ac.tuwien.kr.alpha.api.programs.InputProgram)}. * * Copyright (c) 2021, the Alpha Team. */ diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/InputConfig.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/InputConfig.java index 5ce30a2bb..3a951a81f 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/InputConfig.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/InputConfig.java @@ -26,6 +26,8 @@ public class InputConfig { public static final String DEFAULT_PREPROC_TARGET_FILE = "input.preproc.asp"; public static final boolean DEFAULT_WRITE_XLSX = false; public static final String DEFAULT_XLSX_OUTFILE_PATH = "alphaAnswerSet"; // current directory, files named "alphaAnswerSet.{num}.{ext}" + public static final boolean DEFAULT_REIFY_INPUT = false; + public static final boolean DEFAULT_RUN_TESTS = false; private List aspStrings = new ArrayList<>(); private List files = new ArrayList<>(); @@ -37,11 +39,13 @@ public class InputConfig { private String compgraphPath = InputConfig.DEFAULT_COMPGRAPH_TARGET_FILE; private String normalizedPath = InputConfig.DEFAULT_NORMALIZED_TARGET_FILE; private String preprocessedPath = InputConfig.DEFAULT_PREPROC_TARGET_FILE; - - private Map predicateMethods = new HashMap<>(); private boolean writeAnswerSetsAsXlsx = InputConfig.DEFAULT_WRITE_XLSX; private String answerSetFileOutputPath; + private boolean reifyInput = InputConfig.DEFAULT_REIFY_INPUT; + private boolean runTests = InputConfig.DEFAULT_RUN_TESTS; + private Map predicateMethods = new HashMap<>(); + public static InputConfig forString(String str) { InputConfig retVal = new InputConfig(); retVal.aspStrings.add(str); @@ -209,4 +213,20 @@ public void setDebugPreprocessing(boolean debugPreprocessing) { this.debugPreprocessing = debugPreprocessing; } + public boolean isReifyInput() { + return reifyInput; + } + + public void setReifyInput(boolean reifyInput) { + this.reifyInput = reifyInput; + } + + public boolean isRunTests() { + return runTests; + } + + public void setRunTests(boolean runTests) { + this.runTests = runTests; + } + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/SystemConfig.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/SystemConfig.java index e5c94fefd..25c79b348 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/SystemConfig.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/SystemConfig.java @@ -44,6 +44,7 @@ public class SystemConfig { // initializing from those values in order to have the values accessible in // contexts where no AlphaConfig instance exists (e.g. argument parsing from // command line) + public static final boolean DEFAULT_ACCEPT_EVOLOG = true; public static final String DEFAULT_SOLVER_NAME = "default"; public static final String DEFAULT_NOGOOD_STORE_NAME = "alphaRoaming"; public static final Heuristic DEFAULT_BRANCHING_HEURISTIC = Heuristic.VSIDS; @@ -55,7 +56,6 @@ public class SystemConfig { public static final boolean DEFAULT_DEBUG_INTERNAL_CHECKS = false; public static final boolean DEFAULT_SORT_ANSWER_SETS = false; public static final List DEFAULT_REPLAY_CHOICES = Collections.emptyList(); - public static final boolean DEFAULT_STRATIFIED_EVALUATION = true; public static final boolean DEFAULT_DISABLE_NOGOOD_DELETION = false; public static final String DEFAULT_GROUNDER_TOLERANCE_CONSTRAINTS = GrounderHeuristicsConfiguration.STRICT_STRING; public static final String DEFAULT_GROUNDER_TOLERANCE_RULES = GrounderHeuristicsConfiguration.STRICT_STRING; @@ -63,6 +63,7 @@ public class SystemConfig { public static final String DEFAULT_ATOM_SEPARATOR = ", "; public static final AggregateRewritingConfig DEFAULT_AGGREGATE_REWRITING_CONFIG = new AggregateRewritingConfig(); + private boolean acceptEvologPrograms = DEFAULT_ACCEPT_EVOLOG; private String solverName = DEFAULT_SOLVER_NAME; private String nogoodStoreName = DEFAULT_NOGOOD_STORE_NAME; private long seed = DEFAULT_SEED; @@ -74,7 +75,6 @@ public class SystemConfig { private boolean disableJustificationSearch = DEFAULT_DISABLE_JUSTIFICATION_SEARCH; private boolean sortAnswerSets = DEFAULT_SORT_ANSWER_SETS; private List replayChoices = DEFAULT_REPLAY_CHOICES; - private boolean evaluateStratifiedPart = DEFAULT_STRATIFIED_EVALUATION; private boolean disableNoGoodDeletion = DEFAULT_DISABLE_NOGOOD_DELETION; private String grounderToleranceConstraints = DEFAULT_GROUNDER_TOLERANCE_CONSTRAINTS; private String grounderToleranceRules = DEFAULT_GROUNDER_TOLERANCE_RULES; @@ -197,14 +197,6 @@ public void setReplayChoices(String replayChoices) { this.replayChoices = Arrays.stream(replayChoices.split(",")).map(String::trim).map(Integer::valueOf).collect(Collectors.toList()); } - public boolean isEvaluateStratifiedPart() { - return this.evaluateStratifiedPart; - } - - public void setEvaluateStratifiedPart(boolean evaluateStratifiedPart) { - this.evaluateStratifiedPart = evaluateStratifiedPart; - } - public boolean isDisableNoGoodDeletion() { return this.disableNoGoodDeletion; } @@ -253,4 +245,12 @@ public void setAggregateRewritingConfig(AggregateRewritingConfig aggregateRewrit this.aggregateRewritingConfig = aggregateRewritingConfig; } + public boolean isAcceptEvologPrograms() { + return this.acceptEvologPrograms; + } + + public void setAcceptEvologPrograms(boolean acceptEvologPrograms) { + this.acceptEvologPrograms = acceptEvologPrograms; + } + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/grounder/Substitution.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/grounder/Substitution.java index 3bc416b54..7a9d5a3c3 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/grounder/Substitution.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/grounder/Substitution.java @@ -2,8 +2,8 @@ import java.util.TreeMap; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; /** * A mapping from {@link VariableTerm}s to {@link Term}s used during grounding to represent ground instances of terms, literals and rules. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/InputProgram.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/InputProgram.java index c7be5bd2f..7c3df5bf8 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/InputProgram.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/InputProgram.java @@ -1,9 +1,16 @@ package at.ac.tuwien.kr.alpha.api.programs; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; + +import java.util.List; -// TODO javadoc public interface InputProgram extends Program> { + /** + * The test cases associated with this program. + */ + List getTestCases(); + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/NormalProgram.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/NormalProgram.java index 92734afab..c6eff6bea 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/NormalProgram.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/NormalProgram.java @@ -1,6 +1,6 @@ package at.ac.tuwien.kr.alpha.api.programs; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; /** * A {@link Program} consisting only of facts and {@link NormalRule}s, i.e. no disjunctive- or choice-rules, and no aggregates in rule bodies. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/Program.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/Program.java index 2e8c0f528..eeb251945 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/Program.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/Program.java @@ -3,8 +3,8 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; /** * An ASP program as accepted by Alpha. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/actions/Action.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/actions/Action.java new file mode 100644 index 000000000..240a3b232 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/actions/Action.java @@ -0,0 +1,22 @@ +package at.ac.tuwien.kr.alpha.api.programs.actions; + +import at.ac.tuwien.kr.alpha.api.programs.terms.ActionResultTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; + +import java.util.List; + +/** + * An action that gets executed as part of an action rule in an evolog program firing. + * + * Copyright (c) 2021, the Alpha Team. + */ +@FunctionalInterface +public interface Action { + + /** + * @param input a list of (ground) terms constituting the input of the action + * @return a function term representing the result of executing the action + */ + ActionResultTerm execute(List input); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/AggregateAtom.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/AggregateAtom.java index 4dae7148c..bd5127cf2 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/AggregateAtom.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/AggregateAtom.java @@ -5,8 +5,8 @@ import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; /** * An {@link Atom} representing a comparison over an aggregate function, for example '13 < #sum{ X : p(X) }'. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/Atom.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/Atom.java index c5cffbbfd..8d014fd04 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/Atom.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/Atom.java @@ -6,8 +6,8 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; /** * An Atom is the common super-interface of all representations of ASP atoms used by Alpha. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/AtomQuery.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/AtomQuery.java new file mode 100644 index 000000000..2545d274d --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/AtomQuery.java @@ -0,0 +1,68 @@ +package at.ac.tuwien.kr.alpha.api.programs.atoms; + +import java.util.List; + +import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; + +/** + * A query for ASP atoms matching a set of filter predicates. + */ +public interface AtomQuery extends java.util.function.Predicate { + + /** + * Adds a new filter to this AtomQuery. + * For an atom a(t1, ..., tn), the term at index termIdx will be tested against the given filter predicate. + * + * @param termIdx the index of the term to test + * @param filter the test predicate to use on terms + * @return this AtomQuery with the additional filter added + */ + public AtomQuery withFilter(int termIdx, java.util.function.Predicate filter); + + /** + * Convenience method - adds a filter to match names of symbolic constants against a string. + * + * @param termIdx + * @param str + * @return + */ + public AtomQuery withConstantEquals(int termIdx, String str); + + /** + * Convenience method - adds a filter to match values of constant terms against a string. + * + * @param termIdx + * @param str + * @return + */ + public AtomQuery withStringEquals(int termIdx, String str); + + /** + * Convenience method - adds a filter to check for function terms with a given function symbol and arity. + * + * @param termIdx + * @param funcSymbol + * @param funcArity + * @return + */ + public AtomQuery withFunctionTerm(int termIdx, String funcSymbol, int funcArity); + + /** + * Convenience method - adds a filter to check whether a term is equal to a given term. + * + * @param termIdx + * @param otherTerm + * @return + */ + public AtomQuery withTermEquals(int termIdx, Term otherTerm); + + /** + * Applies this query to an {@link AnswerSet}. + * + * @param as + * @return + */ + public List applyTo(AnswerSet as); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ExternalAtom.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ExternalAtom.java index 42b4f110e..d4b2f946c 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ExternalAtom.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ExternalAtom.java @@ -4,7 +4,7 @@ import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.programs.VariableNormalizableAtom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; /** * An external atom, i.e. an {@link Atom} that is interpreted by calling a linked Java-Method. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/ComparisonLiteral.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/ComparisonLiteral.java index 01b7d6075..5abf83c95 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/ComparisonLiteral.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/ComparisonLiteral.java @@ -1,6 +1,6 @@ package at.ac.tuwien.kr.alpha.api.programs.literals; -public interface ComparisonLiteral extends Literal, FixedInterpretationLiteral { +public interface ComparisonLiteral extends FixedInterpretationLiteral { boolean isLeftOrRightAssigning(); diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/Literal.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/Literal.java index 13b4dac0c..4824480e9 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/Literal.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/Literal.java @@ -6,8 +6,8 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; /** * A literal according to the ASP Core 2 Standard. @@ -17,6 +17,7 @@ */ // TODO go through implementations and pull out stuff that can be default-implemented here public interface Literal { + Atom getAtom(); boolean isNegated(); diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/NormalRule.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/NormalRule.java new file mode 100644 index 000000000..92bdc6776 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/NormalRule.java @@ -0,0 +1,19 @@ +package at.ac.tuwien.kr.alpha.api.programs.rules; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; + +/** + * A {@link Rule} with a {@link NormalHead}. + * + * Copyright (c) 2021, the Alpha Team. + */ +public interface NormalRule extends Rule { + + default BasicAtom getHeadAtom() { + return this.isConstraint() ? null : this.getHead().getAtom(); + } + + boolean isGround(); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/Rule.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/Rule.java similarity index 72% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/Rule.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/Rule.java index 4f3013a86..b9a319bbc 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/Rule.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/Rule.java @@ -1,14 +1,15 @@ -package at.ac.tuwien.kr.alpha.api.rules; +package at.ac.tuwien.kr.alpha.api.programs.rules; import java.util.Set; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; /** * A rule as defined in the ASP Core 2 Standard. * - * @param the type of rule head (e.g. choice, normal, disjunctive) supported by a specific rule. + * @param the type of rule head (e.g. choice, normal, disjunctive) supported + * by a specific rule. * Copyright (c) 2021, the Alpha Team. */ public interface Rule { @@ -22,4 +23,5 @@ public interface Rule { Set getPositiveBody(); Set getNegativeBody(); + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/RuleInstantiator.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/RuleInstantiator.java new file mode 100644 index 000000000..7a36f19db --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/RuleInstantiator.java @@ -0,0 +1,11 @@ +package at.ac.tuwien.kr.alpha.api.programs.rules; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.InstantiableHead; + +public interface RuleInstantiator { + + BasicAtom instantiate(InstantiableHead ruleHead, Substitution substitution); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/ActionHead.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/ActionHead.java new file mode 100644 index 000000000..9956ccee8 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/ActionHead.java @@ -0,0 +1,16 @@ +package at.ac.tuwien.kr.alpha.api.programs.rules.heads; + +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; + +import java.util.List; + +public interface ActionHead extends NormalHead { + + String getActionName(); + + List getActionInputTerms(); + + VariableTerm getActionOutputTerm(); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/ChoiceHead.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/ChoiceHead.java similarity index 85% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/ChoiceHead.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/ChoiceHead.java index 2adf05d2c..c9d7011af 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/ChoiceHead.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/ChoiceHead.java @@ -1,11 +1,11 @@ -package at.ac.tuwien.kr.alpha.api.rules.heads; +package at.ac.tuwien.kr.alpha.api.programs.rules.heads; import java.util.List; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; /** * A choice head as defined by the ASP Core 2 Standard. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/DisjunctiveHead.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/DisjunctiveHead.java similarity index 81% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/DisjunctiveHead.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/DisjunctiveHead.java index 24d19172f..f2237833e 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/DisjunctiveHead.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/DisjunctiveHead.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.rules.heads; +package at.ac.tuwien.kr.alpha.api.programs.rules.heads; /** * Deprecated - A disjunctive head (see ASP Core 2 Standard). Should be removed since disjunction is not actually supported by Alpha. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/Head.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/Head.java similarity index 65% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/Head.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/Head.java index 4fb9e365b..20cef5933 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/Head.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/Head.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.rules.heads; +package at.ac.tuwien.kr.alpha.api.programs.rules.heads; /** * The head of an ASP rule. @@ -6,4 +6,5 @@ * Copyright (c) 2021, the Alpha Team. */ public interface Head { + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/InstantiableHead.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/InstantiableHead.java new file mode 100644 index 000000000..32dcca689 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/InstantiableHead.java @@ -0,0 +1,11 @@ +package at.ac.tuwien.kr.alpha.api.programs.rules.heads; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.rules.RuleInstantiator; + +public interface InstantiableHead extends Head { + + BasicAtom instantiate(RuleInstantiator instantiator, Substitution substitution); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/NormalHead.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/NormalHead.java similarity index 70% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/NormalHead.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/NormalHead.java index 64c335807..b8b9269f4 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/heads/NormalHead.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/NormalHead.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.rules.heads; +package at.ac.tuwien.kr.alpha.api.programs.rules.heads; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; @@ -7,7 +7,7 @@ * * Copyright (c) 2021, the Alpha Team. */ -public interface NormalHead extends Head { +public interface NormalHead extends InstantiableHead { BasicAtom getAtom(); diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ActionResultTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ActionResultTerm.java new file mode 100644 index 000000000..5436abf0f --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ActionResultTerm.java @@ -0,0 +1,30 @@ +package at.ac.tuwien.kr.alpha.api.programs.terms; + +/** + * A term representing the result of an evolog action (i.e. result of action function application). + * Action result terms are function terms with symbol "success" or "error" depending on whether the corresponding action was sucessful. + * There is always one argument which is either some term representing the actual function result or an error message, respectively. + */ +public interface ActionResultTerm extends FunctionTerm { + + public static final String SUCCESS_SYMBOL = "success"; + public static final String ERROR_SYMBOL = "error"; + + /** + * True if the action that generated this result was successful (i.e. executed normally). + */ + boolean isSuccess(); + + /** + * True if the action that generated this result failed (i.e. threw an error in execution). + */ + boolean isError(); + + /** + * Gets the actual value wrapped in this result. + * Either a term representing the action return value or a string term representing an error + * message.s + */ + T getValue(); + +} \ No newline at end of file diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ArithmeticOperator.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ArithmeticOperator.java similarity index 94% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ArithmeticOperator.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ArithmeticOperator.java index 33be0a5e9..9203e9d33 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ArithmeticOperator.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ArithmeticOperator.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.terms; +package at.ac.tuwien.kr.alpha.api.programs.terms; import com.google.common.math.IntMath; diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ArithmeticTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ArithmeticTerm.java similarity index 84% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ArithmeticTerm.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ArithmeticTerm.java index 8f0551d89..ce58b8028 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ArithmeticTerm.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ArithmeticTerm.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.terms; +package at.ac.tuwien.kr.alpha.api.programs.terms; /** * A {@link Term} that is a binary arithmetic expression. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ConstantTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ConstantTerm.java similarity index 84% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ConstantTerm.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ConstantTerm.java index bc41438d0..0c43dfb5d 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/ConstantTerm.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/ConstantTerm.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.terms; +package at.ac.tuwien.kr.alpha.api.programs.terms; /** * A term consisting of a constant symbol. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/FunctionTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/FunctionTerm.java similarity index 81% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/FunctionTerm.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/FunctionTerm.java index a524ca619..88cb6a2c5 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/FunctionTerm.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/FunctionTerm.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.terms; +package at.ac.tuwien.kr.alpha.api.programs.terms; import java.util.List; diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/IntervalTerm.java similarity index 84% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/IntervalTerm.java index 3e3a7f394..ddb071f06 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/IntervalTerm.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.terms; +package at.ac.tuwien.kr.alpha.api.programs.terms; /** * A term representing an interval of integers. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/Term.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/Term.java similarity index 94% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/Term.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/Term.java index 4ed768155..840f6ee3b 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/Term.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/Term.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.terms; +package at.ac.tuwien.kr.alpha.api.programs.terms; import java.util.Map; import java.util.Set; diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/VariableTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/VariableTerm.java similarity index 75% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/VariableTerm.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/VariableTerm.java index d735ed942..eee71fcfb 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/VariableTerm.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/terms/VariableTerm.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.terms; +package at.ac.tuwien.kr.alpha.api.programs.terms; /** * A term representing a variable symbol in ASP programs. diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/Assertion.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/Assertion.java new file mode 100644 index 000000000..4acf1e5f8 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/Assertion.java @@ -0,0 +1,29 @@ +package at.ac.tuwien.kr.alpha.api.programs.tests; + +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; + +public interface Assertion { + + enum Mode { + FOR_ALL("forAll"), + FOR_SOME("forSome"); + + private final String text; + + Mode(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + + } + + Mode getMode(); + + InputProgram getVerifier(); + + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/TestCase.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/TestCase.java new file mode 100644 index 000000000..0f148dcca --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/TestCase.java @@ -0,0 +1,19 @@ +package at.ac.tuwien.kr.alpha.api.programs.tests; + +import java.util.List; +import java.util.Set; +import java.util.function.IntPredicate; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; + +public interface TestCase { + + String getName(); + + IntPredicate getAnswerSetCountVerifier(); + + Set getInput(); + + List getAssertions(); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/TestResult.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/TestResult.java new file mode 100644 index 000000000..b7d0bff65 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/TestResult.java @@ -0,0 +1,32 @@ +package at.ac.tuwien.kr.alpha.api.programs.tests; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public interface TestResult { + + List getTestCaseResults(); + + default boolean isSuccess() { + return getTestCaseResults().stream().allMatch(TestCaseResult::isSuccess); + } + + interface TestCaseResult { + + String getTestCaseName(); + + Optional answerSetCountVerificationResult(); + + int getAssertionsPassed(); + + int getAssertionsFailed(); + + Map> getAssertionErrors(); + + default boolean isSuccess() { + return answerSetCountVerificationResult().isEmpty() && getAssertionsFailed() == 0; + } + + } +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/NormalRule.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/NormalRule.java deleted file mode 100644 index 5a5c995c6..000000000 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/rules/NormalRule.java +++ /dev/null @@ -1,15 +0,0 @@ -package at.ac.tuwien.kr.alpha.api.rules; - -import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; - -/** - * A {@link Rule} with a {@link NormalHead}. - * - * Copyright (c) 2021, the Alpha Team. - */ -public interface NormalRule extends Rule { - - BasicAtom getHeadAtom(); - -} diff --git a/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/Main.java b/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/Main.java index 4fd32e07e..94a8eb285 100644 --- a/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/Main.java +++ b/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/Main.java @@ -33,11 +33,16 @@ import java.io.IOException; import java.io.PrintStream; import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import at.ac.tuwien.kr.alpha.api.programs.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestResult; import org.apache.commons.cli.ParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,6 +60,7 @@ import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.analysis.ComponentGraph; import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.util.AnswerSetFormatter; import at.ac.tuwien.kr.alpha.app.ComponentGraphWriter; import at.ac.tuwien.kr.alpha.app.DependencyGraphWriter; @@ -92,20 +98,34 @@ public static void main(String[] args) { } InputConfig inputCfg = cfg.getInputConfig(); - Solver solver; - if (inputCfg.isDebugPreprocessing()) { - DebugSolvingContext dbgCtx = alpha.prepareDebugSolve(program); - Main.writeNormalProgram(dbgCtx.getNormalizedProgram(), inputCfg.getNormalizedPath()); - Main.writeNormalProgram(dbgCtx.getPreprocessedProgram(), inputCfg.getPreprocessedPath()); - Main.writeDependencyGraph(dbgCtx.getDependencyGraph(), inputCfg.getDepgraphPath()); - Main.writeComponentGraph(dbgCtx.getComponentGraph(), inputCfg.getCompgraphPath()); - solver = dbgCtx.getSolver(); + + // Note: We might potentially want to get the reified program as an AnswerSet and + // apply all the formatting we can do on answer sets also on reified programs. + if (inputCfg.isReifyInput()) { + Set reified = alpha.reify(program); + for (BasicAtom atom : reified) { + System.out.println(atom + "."); + } + } else if (inputCfg.isRunTests()) { + TestResult result = alpha.test(program); + printTestResult(result); } else { - solver = alpha.prepareSolverFor(program, inputCfg.getFilter()); + Solver solver; + if (inputCfg.isDebugPreprocessing()) { + DebugSolvingContext dbgCtx = alpha.prepareDebugSolve(program); + Main.writeNormalProgram(dbgCtx.getNormalizedProgram(), inputCfg.getNormalizedPath()); + Main.writeNormalProgram(dbgCtx.getPreprocessedProgram(), inputCfg.getPreprocessedPath()); + Main.writeDependencyGraph(dbgCtx.getDependencyGraph(), inputCfg.getDepgraphPath()); + Main.writeComponentGraph(dbgCtx.getComponentGraph(), inputCfg.getCompgraphPath()); + solver = dbgCtx.getSolver(); + } else { + solver = alpha.prepareSolverFor(program, inputCfg.getFilter()); + } + Main.computeAndConsumeAnswerSets(solver, cfg); } - Main.computeAndConsumeAnswerSets(solver, cfg); } + /** * Writes the given {@link DependencyGraph} to the destination passed as the second parameter * @@ -155,6 +175,30 @@ private static void writeNormalProgram(NormalProgram prg, String path) { } } + private static void printTestResult(TestResult result) { + if (result.isSuccess()) { + System.out.println("TEST SUCCESSFUL"); + } else { + System.out.println("TESTS FAILED!"); + } + for (TestResult.TestCaseResult tcResult : result.getTestCaseResults()) { + System.out.println("Test case: " + tcResult.getTestCaseName() + " " + (tcResult.isSuccess() ? "PASSED" : "FAILED") + + ", assertions passed: " + tcResult.getAssertionsPassed() + + ", assertions failed: " + tcResult.getAssertionsFailed()); + if (!tcResult.isSuccess()) { + System.out.println("Assertion failures:"); + if (tcResult.answerSetCountVerificationResult().isPresent()) { + System.out.println(tcResult.answerSetCountVerificationResult().get()); + } + for (Map.Entry> assertionError : tcResult.getAssertionErrors().entrySet()) { + for (String errMsg : assertionError.getValue()) { + System.out.println("Assertion failed: " + assertionError.getKey() + ", error = " + errMsg); + } + } + } + } + } + private static void computeAndConsumeAnswerSets(Solver solver, AlphaConfig alphaCfg) { SystemConfig sysCfg = alphaCfg.getSystemConfig(); InputConfig inputCfg = alphaCfg.getInputConfig(); diff --git a/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParser.java b/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParser.java index b8a27f880..25c0cda34 100644 --- a/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParser.java +++ b/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParser.java @@ -88,6 +88,8 @@ public class CommandLineParser { .desc("write files for normalized and preprocessed programs, also emit dependency- and component graphs as (graphviz) dot files").build(); private static final Option OPT_WRITE_XSLX = Option.builder("wx").longOpt("write-xlsx").hasArg(true).argName("path").type(String.class) .desc("Write answer sets to excel files, i.e. xlsx workbooks (one workbook per answer set)").build(); + private static final Option OPT_REIFY = Option.builder("reify").longOpt("reifyProgram").hasArg(false).desc("Reifies, i.e. encodes as ASP facts, the given program.").build(); + private static final Option OPT_RUN_TESTS = Option.builder("t").longOpt("run-tests").hasArg(false).desc("Runs all unit tests of the given ASP Program").build(); // general system-wide config private static final Option OPT_SOLVER = Option.builder("s").longOpt("solver").hasArg(true).argName("solver") @@ -122,9 +124,6 @@ public class CommandLineParser { private static final Option OPT_AGGREGATES_NO_NEGATIVE_INTEGERS = Option.builder("dni").longOpt("disableNegativeIntegers") .desc("use simplified encodings without netagive integer support for #sum aggregates (default: " + !AggregateRewritingConfig.DEFAULT_SUPPORT_NEGATIVE_INTEGERS + ")") .build(); - private static final Option OPT_NO_EVAL_STRATIFIED = Option.builder("dse").longOpt("disableStratifiedEvaluation") - .desc("Disable stratified evaluation") - .build(); private static final Option OPT_NO_NOGOOD_DELETION = Option.builder("dnd").longOpt("disableNoGoodDeletion") .desc("disable the deletion of (learned, little active) nogoods (default: " + SystemConfig.DEFAULT_DISABLE_NOGOOD_DELETION + ")") @@ -162,6 +161,8 @@ public class CommandLineParser { CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_ASPSTRING); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_DEBUG_PREPROCESSING); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_WRITE_XSLX); + CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_REIFY); + CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_RUN_TESTS); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_SOLVER); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NOGOOD_STORE); @@ -177,7 +178,6 @@ public class CommandLineParser { CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_AGGREGATES_NO_SORTING_GRID); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_AGGREGATES_NO_NEGATIVE_INTEGERS); - CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NO_EVAL_STRATIFIED); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NO_NOGOOD_DELETION); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_TOLERANCE_CONSTRAINTS); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_TOLERANCE_RULES); @@ -232,7 +232,6 @@ private void initializeGlobalOptionHandlers() { this.globalOptionHandlers.put(CommandLineParser.OPT_NO_JUSTIFICATION.getOpt(), this::handleNoJustification); this.globalOptionHandlers.put(CommandLineParser.OPT_AGGREGATES_NO_SORTING_GRID.getOpt(), this::handleDisableSortingGrid); this.globalOptionHandlers.put(CommandLineParser.OPT_AGGREGATES_NO_NEGATIVE_INTEGERS.getOpt(), this::handleDisableNegativeSumElements); - this.globalOptionHandlers.put(CommandLineParser.OPT_NO_EVAL_STRATIFIED.getOpt(), this::handleDisableStratifedEval); this.globalOptionHandlers.put(CommandLineParser.OPT_NO_NOGOOD_DELETION.getOpt(), this::handleNoNoGoodDeletion); this.globalOptionHandlers.put(CommandLineParser.OPT_GROUNDER_TOLERANCE_CONSTRAINTS.getOpt(), this::handleGrounderToleranceConstraints); this.globalOptionHandlers.put(CommandLineParser.OPT_GROUNDER_TOLERANCE_RULES.getOpt(), this::handleGrounderToleranceRules); @@ -248,6 +247,8 @@ private void initializeInputOptionHandlers() { this.inputOptionHandlers.put(CommandLineParser.OPT_LITERATE.getOpt(), this::handleLiterate); this.inputOptionHandlers.put(CommandLineParser.OPT_DEBUG_PREPROCESSING.getOpt(), this::handleDebugPreprocessing); this.inputOptionHandlers.put(CommandLineParser.OPT_WRITE_XSLX.getOpt(), this::handleWriteXlsx); + this.inputOptionHandlers.put(CommandLineParser.OPT_REIFY.getOpt(), this::handleReify); + this.inputOptionHandlers.put(CommandLineParser.OPT_RUN_TESTS.getOpt(), this::handleRunTests); } public AlphaConfig parseCommandLine(String[] args) throws ParseException { @@ -349,10 +350,6 @@ private void handleSort(Option opt, SystemConfig cfg) { cfg.setSortAnswerSets(true); } - private void handleDeterministic(Option opt, SystemConfig cfg) { - cfg.setSeed(0); - } - private void handleSeed(Option opt, SystemConfig cfg) { String optVal = opt.getValue(); long seed; @@ -411,6 +408,14 @@ private void handleWriteXlsx(Option opt, InputConfig cfg) { cfg.setAnswerSetFileOutputPath(outputPath); } + private void handleReify(Option opt, InputConfig cfg) { + cfg.setReifyInput(true); + } + + private void handleRunTests(Option opt, InputConfig cfg) { + cfg.setRunTests(true); + } + private void handleStats(Option opt, SystemConfig cfg) { cfg.setPrintStats(true); } @@ -422,15 +427,11 @@ private void handleNoJustification(Option opt, SystemConfig cfg) { private void handleDisableSortingGrid(Option opt, SystemConfig cfg) { cfg.getAggregateRewritingConfig().setUseSortingGridEncoding(false); } - + private void handleDisableNegativeSumElements(Option opt, SystemConfig cfg) { cfg.getAggregateRewritingConfig().setSupportNegativeValuesInSums(false); } - private void handleDisableStratifedEval(Option opt, SystemConfig cfg) { - cfg.setEvaluateStratifiedPart(false); - } - private void handleDebugPreprocessing(Option opt, InputConfig cfg) { cfg.setDebugPreprocessing(true); } @@ -456,5 +457,5 @@ private void handleGrounderNoInstanceRemoval(Option opt, SystemConfig cfg) { private void handleAtomSeparator(Option opt, SystemConfig cfg) { cfg.setAtomSeparator(StringEscapeUtils.unescapeJava(opt.getValue(SystemConfig.DEFAULT_ATOM_SEPARATOR))); } - + } diff --git a/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapper.java b/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapper.java index 4fc5e81ee..8b7278921 100644 --- a/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapper.java +++ b/alpha-cli-app/src/main/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapper.java @@ -43,7 +43,7 @@ import at.ac.tuwien.kr.alpha.api.mapper.AnswerSetToObjectMapper; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; /** * Implementation of {@link AnswerSetToObjectMapper} that generates an office open xml workbook ("excel file") from a given answer set. diff --git a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParserTest.java b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParserTest.java index f77f6527e..91a2855b9 100644 --- a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParserTest.java +++ b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/config/CommandLineParserTest.java @@ -28,7 +28,6 @@ package at.ac.tuwien.kr.alpha.app.config; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -160,20 +159,6 @@ public void noInstanceRemoval() throws ParseException { assertTrue(alphaConfig.getSystemConfig().isGrounderAccumulatorEnabled()); } - @Test - public void disableStratifiedEval() throws ParseException { - CommandLineParser parser = new CommandLineParser(DEFAULT_COMMAND_LINE, DEFAULT_ABORT_ACTION); - AlphaConfig ctx = parser.parseCommandLine(new String[]{"-i", "someFile.asp", "-i", "someOtherFile.asp", "-dse"}); - assertFalse(ctx.getSystemConfig().isEvaluateStratifiedPart()); - } - - @Test - public void disableStratifiedEvalLongOpt() throws ParseException { - CommandLineParser parser = new CommandLineParser(DEFAULT_COMMAND_LINE, DEFAULT_ABORT_ACTION); - AlphaConfig ctx = parser.parseCommandLine(new String[]{"-i", "someFile.asp", "-i", "someOtherFile.asp", "--disableStratifiedEvaluation"}); - assertFalse(ctx.getSystemConfig().isEvaluateStratifiedPart()); - } - @Test public void atomSeparator() throws ParseException { CommandLineParser parser = new CommandLineParser(DEFAULT_COMMAND_LINE, DEFAULT_ABORT_ACTION); diff --git a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapperTest.java b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapperTest.java index 75a2d7cb6..3b156426d 100644 --- a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapperTest.java +++ b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/mappers/AnswerSetToWorkbookMapperTest.java @@ -19,7 +19,7 @@ import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; // TODO This is a functional test and should not be run with standard unit tests diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSetBuilder.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSetBuilder.java index ca8d6db68..68dabf24a 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSetBuilder.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSetBuilder.java @@ -13,9 +13,9 @@ import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; public class AnswerSetBuilder { private boolean firstInstance = true; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSets.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSets.java index 0587e51d8..6b22bbaaf 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSets.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/AnswerSets.java @@ -19,4 +19,8 @@ public static AnswerSet newAnswerSet(SortedSet predicates, Map query(AnswerSetQuery query) { + public List query(AtomQuery query) { return query.applyTo(this); } } \ No newline at end of file diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/AbstractComparisonOperator.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/AbstractComparisonOperator.java index 2ea96c01f..b13098d12 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/AbstractComparisonOperator.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/AbstractComparisonOperator.java @@ -4,7 +4,7 @@ import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; abstract class AbstractComparisonOperator implements ComparisonOperator { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/ComparisonOperators.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/ComparisonOperators.java index 1b851da26..bb66df705 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/ComparisonOperators.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/comparisons/ComparisonOperators.java @@ -1,7 +1,7 @@ package at.ac.tuwien.kr.alpha.commons.comparisons; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; public class ComparisonOperators { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibrary.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibrary.java index 14142ed62..03682d772 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibrary.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibrary.java @@ -27,13 +27,17 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import at.ac.tuwien.kr.alpha.api.externals.Predicate; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; /** * Collection of methods that can be used as external atoms from ASP programs. @@ -47,6 +51,8 @@ */ public final class AspStandardLibrary { + private static final Logger LOGGER = LoggerFactory.getLogger(AspStandardLibrary.class); + private AspStandardLibrary() { throw new AssertionError(this.getClass().getSimpleName() + " is a non-instantiable utility class!"); } @@ -211,4 +217,47 @@ public static Set>> stringConcat(String s1, String s2) return Collections.singleton(Terms.asTermList(s1 + s2)); } + /** + * Converts the given string to an integer + */ + @Predicate(name = "string_parse_integer") + public static Set>> stringParseInteger(String str) { + try { + return Collections.singleton(Collections.singletonList(Terms.newConstant(Integer.valueOf(str)))); + } catch (NumberFormatException ex) { + LOGGER.warn("Not a valid integer value: {}", str); + return Collections.emptySet(); + } + } + + @Predicate(name = "string_is_empty") + public static boolean isStringEmpty(String str) { + return str.isEmpty(); + } + + @Predicate(name = "string_substring") + public static Set>> substringOfString(String str, int startIdx, int endIdx) { + try { + return Collections.singleton(Collections.singletonList(Terms.newConstant(str.substring(startIdx, endIdx)))); + } catch (StringIndexOutOfBoundsException ex) { + LOGGER.warn("Invalid range for substring: {}, start {}, end {}", str, startIdx, endIdx); + return Collections.emptySet(); + } + } + + @Predicate(name = "str_x_xs") + public static Set>> stringHeadRemainder(String str) { + List> xXs = new ArrayList<>(); + if (str.isEmpty()) { + return Collections.emptySet(); + } else if (str.length() == 1) { + xXs.add(Terms.newConstant(str)); + xXs.add(Terms.newConstant("")); + } else { + xXs.add(Terms.newConstant(str.substring(0, 1))); + xXs.add(Terms.newConstant(str.substring(1, str.length()))); + } + return Collections.singleton(xXs); + } + } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BinaryPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BinaryPredicateInterpretation.java index 22150b49f..5f506a2f8 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BinaryPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BinaryPredicateInterpretation.java @@ -29,7 +29,7 @@ import java.util.List; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; public class BinaryPredicateInterpretation extends NonBindingPredicateInterpretation { private final java.util.function.BiPredicate predicate; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BindingMethodPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BindingMethodPredicateInterpretation.java index a12c6f44d..c10cbdee5 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BindingMethodPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BindingMethodPredicateInterpretation.java @@ -36,8 +36,8 @@ import java.util.Set; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.BindingPredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; public class BindingMethodPredicateInterpretation implements BindingPredicateInterpretation { private final Method method; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/Externals.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/Externals.java index 386c8c983..52066fd09 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/Externals.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/Externals.java @@ -25,25 +25,18 @@ */ package at.ac.tuwien.kr.alpha.commons.externals; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.reflections.Reflections; -import org.reflections.scanners.MethodAnnotationsScanner; - import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.externals.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.reflections.Reflections; +import org.reflections.scanners.MethodAnnotationsScanner; + +import java.lang.reflect.Method; +import java.util.*; public final class Externals { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/IntPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/IntPredicateInterpretation.java index 36d0a06bc..c0ceaa262 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/IntPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/IntPredicateInterpretation.java @@ -29,7 +29,7 @@ import java.util.List; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; public class IntPredicateInterpretation extends NonBindingPredicateInterpretation { private final java.util.function.IntPredicate predicate; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/LongPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/LongPredicateInterpretation.java index e7978f3c8..fd3182200 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/LongPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/LongPredicateInterpretation.java @@ -29,7 +29,7 @@ import java.util.List; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; public class LongPredicateInterpretation extends NonBindingPredicateInterpretation { private final java.util.function.LongPredicate predicate; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/MethodPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/MethodPredicateInterpretation.java index c4aaacbdc..d1abdc97a 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/MethodPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/MethodPredicateInterpretation.java @@ -29,7 +29,7 @@ import org.apache.commons.lang3.ClassUtils; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/NonBindingPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/NonBindingPredicateInterpretation.java index 7a065aa7c..af7c3c899 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/NonBindingPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/NonBindingPredicateInterpretation.java @@ -28,8 +28,8 @@ package at.ac.tuwien.kr.alpha.commons.externals; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import java.util.ArrayList; import java.util.List; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/PredicateInterpretationImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/PredicateInterpretationImpl.java index 8e52bfacb..5ff6c5cfe 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/PredicateInterpretationImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/PredicateInterpretationImpl.java @@ -1,11 +1,12 @@ package at.ac.tuwien.kr.alpha.commons.externals; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; + import java.util.List; import java.util.Set; -import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; // TODO this looks like a duplicate public interface PredicateInterpretationImpl extends PredicateInterpretation { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/SuppliedPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/SuppliedPredicateInterpretation.java index 1efa81425..b0da2a4d1 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/SuppliedPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/SuppliedPredicateInterpretation.java @@ -28,8 +28,8 @@ package at.ac.tuwien.kr.alpha.commons.externals; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.BindingPredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import java.util.List; import java.util.Set; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/UnaryPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/UnaryPredicateInterpretation.java index 10611bcdc..7c7f0a5da 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/UnaryPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/UnaryPredicateInterpretation.java @@ -29,7 +29,7 @@ import java.util.List; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; public class UnaryPredicateInterpretation extends NonBindingPredicateInterpretation { private final java.util.function.Predicate predicate; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AbstractProgram.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/AbstractProgram.java similarity index 77% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AbstractProgram.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/AbstractProgram.java index 31a3617af..0851167b1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AbstractProgram.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/AbstractProgram.java @@ -1,14 +1,14 @@ -package at.ac.tuwien.kr.alpha.core.programs; - -import java.util.Collections; -import java.util.List; +package at.ac.tuwien.kr.alpha.commons.programs; import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; import at.ac.tuwien.kr.alpha.commons.util.Util; +import java.util.Collections; +import java.util.List; + /** * The parent type for all kinds of programs. Defines a program's basic structure (facts + rules + inlineDirectives) * @@ -40,14 +40,13 @@ public InlineDirectives getInlineDirectives() { return inlineDirectives; } + @Override public String toString() { final String ls = System.lineSeparator(); - final String result = facts.isEmpty() ? "" : Util.join("", facts, "." + ls, "." + ls); - if (rules.isEmpty()) { - return result; - } - return Util.join(result, rules, ls, ls); + final String factString = facts.isEmpty() ? "" : Util.join("", facts, "." + ls, "." + ls); + final String ruleString = rules.isEmpty() ? "" : Util.join("", rules, ls, ls); + return factString + ruleString; } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/InlineDirectivesImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InlineDirectivesImpl.java similarity index 90% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/InlineDirectivesImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InlineDirectivesImpl.java index c04de330c..be34d2022 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/InlineDirectivesImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InlineDirectivesImpl.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.core.parser; +package at.ac.tuwien.kr.alpha.commons.programs; import java.util.LinkedHashMap; import java.util.Map; @@ -9,7 +9,7 @@ * Stores directives appearing in the ASP program. Each directive starts with # and ends with . * Copyright (c) 2017 - 2021, the Alpha Team. */ -public class InlineDirectivesImpl implements InlineDirectives { +class InlineDirectivesImpl implements InlineDirectives { private final LinkedHashMap directives = new LinkedHashMap<>(); diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InputProgramImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InputProgramImpl.java new file mode 100644 index 000000000..64c3c5a3c --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InputProgramImpl.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2019, the Alpha Team. + * All rights reserved. + *

+ * Additional changes made by Siemens. + *

+ * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *

+ * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + *

+ * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package at.ac.tuwien.kr.alpha.commons.programs; + +import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; +import at.ac.tuwien.kr.alpha.commons.util.Util; + +import java.util.Collections; +import java.util.List; + +/** + * Alpha-internal representation of an ASP program, i.e., a set of ASP rules. + *

+ * Copyright (c) 2017-2019, the Alpha Team. + */ +// TODO rename this to InputProgramImpl or some such +class InputProgramImpl extends AbstractProgram> implements InputProgram { + + static final InputProgramImpl EMPTY = new InputProgramImpl(Collections.emptyList(), Collections.emptyList(), new InlineDirectivesImpl(), Collections.emptyList()); + + private final List testCases; + + InputProgramImpl(List> rules, List facts, InlineDirectives inlineDirectives, List testCases) { + super(rules, facts, inlineDirectives); + this.testCases = testCases; + } + + @Override + public List getTestCases() { + return testCases; + } + + @Override + public String toString() { + String ls = System.lineSeparator(); + final String testsString = testCases.isEmpty() ? "" : Util.join("", testCases, ls, ls); + return super.toString() + testsString; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/NormalProgramImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/NormalProgramImpl.java new file mode 100644 index 000000000..8bbfc4365 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/NormalProgramImpl.java @@ -0,0 +1,21 @@ +package at.ac.tuwien.kr.alpha.commons.programs; + +import java.util.List; + +import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; +import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; + +/** + * A program that only contains NormalRules. + * + * Copyright (c) 2019, the Alpha Team. + */ +class NormalProgramImpl extends AbstractProgram implements NormalProgram { + + NormalProgramImpl(List rules, List facts, InlineDirectives inlineDirectives) { + super(rules, facts, inlineDirectives); + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/Programs.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/Programs.java new file mode 100644 index 000000000..0a10b61d7 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/Programs.java @@ -0,0 +1,129 @@ +package at.ac.tuwien.kr.alpha.commons.programs; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; +import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; + +public final class Programs { + + private Programs() { + throw new AssertionError("Cannot instantiate utility class!"); + } + + public static InputProgram emptyProgram() { + return InputProgramImpl.EMPTY; + } + + // TODO rename method + public static InputProgram newInputProgram(List> rules, List facts, InlineDirectives inlineDirectives, List testCases) { + return new InputProgramImpl(rules, facts, inlineDirectives, testCases); + } + + // TODO rename method + public static InputProgram newInputProgram(List> rules, List facts, InlineDirectives inlineDirectives) { + return new InputProgramImpl(rules, facts, inlineDirectives, Collections.emptyList()); + } + + public static InputProgramBuilder builder() { + return new InputProgramBuilder(); + } + + public static InputProgramBuilder builder(InputProgram program) { + return new InputProgramBuilder(program); + } + + public static NormalProgram newNormalProgram(List rules, List facts, InlineDirectives inlineDirectives) { + return new NormalProgramImpl(rules, facts, inlineDirectives); + } + + public static NormalProgram toNormalProgram(InputProgram inputProgram) { + List normalRules = new ArrayList<>(); + for (Rule r : inputProgram.getRules()) { + normalRules.add(Rules.toNormalRule(r)); + } + return new NormalProgramImpl(normalRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + } + + public static InlineDirectives newInlineDirectives() { + return new InlineDirectivesImpl(); + } + + /** + * Builder for more complex program construction scenarios, ensuring that an {@link InputProgramImpl} is immutable + */ + // TODO maybe rename + public static class InputProgramBuilder { + + private List> rules = new ArrayList<>(); + private List facts = new ArrayList<>(); + private InlineDirectives inlineDirectives = new InlineDirectivesImpl(); + + private List testCases = new ArrayList<>(); + + public InputProgramBuilder(InputProgram prog) { + this.addRules(prog.getRules()); + this.addFacts(prog.getFacts()); + this.addInlineDirectives(prog.getInlineDirectives()); + this.addTestCases(prog.getTestCases()); + } + + public InputProgramBuilder() { + + } + + public InputProgramBuilder addRules(List> rules) { + this.rules.addAll(rules); + return this; + } + + public InputProgramBuilder addRule(Rule r) { + this.rules.add(r); + return this; + } + + public InputProgramBuilder addFacts(List facts) { + this.facts.addAll(facts); + return this; + } + + public InputProgramBuilder addFact(Atom fact) { + this.facts.add(fact); + return this; + } + + public InputProgramBuilder addInlineDirectives(InlineDirectives inlineDirectives) { + this.inlineDirectives.accumulate(inlineDirectives); + return this; + } + + public InputProgramBuilder addTestCase(TestCase testCase) { + this.testCases.add(testCase); + return this; + } + + public InputProgramBuilder addTestCases(List testCases) { + this.testCases.addAll(testCases); + return this; + } + + public InputProgramBuilder accumulate(InputProgram prog) { + return this.addRules(prog.getRules()).addFacts(prog.getFacts()).addInlineDirectives(prog.getInlineDirectives()).addTestCases(prog.getTestCases()); + } + + public InputProgram build() { + return Programs.newInputProgram(this.rules, this.facts, this.inlineDirectives, this.testCases); + } + + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/AbstractAtom.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AbstractAtom.java similarity index 93% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/AbstractAtom.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AbstractAtom.java index f55611a0f..4a54b90f4 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/AbstractAtom.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AbstractAtom.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.atoms; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import java.util.List; import java.util.Set; @@ -34,9 +34,9 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; /** * An Atom is the common superclass of all representations of ASP atoms used by Alpha. diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/AggregateAtomImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AggregateAtomImpl.java similarity index 97% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/AggregateAtomImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AggregateAtomImpl.java index 964728e57..206bf9782 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/AggregateAtomImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AggregateAtomImpl.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.atoms; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import static at.ac.tuwien.kr.alpha.commons.util.Util.join; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; @@ -40,9 +40,9 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; class AggregateAtomImpl extends AbstractAtom implements AggregateAtom { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/AnswerSetQueryImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AtomQueryImpl.java similarity index 75% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/AnswerSetQueryImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AtomQueryImpl.java index ccb89f6c5..7ba031a80 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/AnswerSetQueryImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AtomQueryImpl.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.util; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import java.util.Collections; import java.util.HashMap; @@ -7,45 +7,49 @@ import java.util.stream.Collectors; import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.AnswerSetQuery; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AtomQuery; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.Predicates; /** * A query for ASP atoms matching a set of filter predicates. */ -public final class AnswerSetQueryImpl implements AnswerSetQuery { +final class AtomQueryImpl implements AtomQuery { private final Predicate predicate; private Map> filters = new HashMap<>(); - private AnswerSetQueryImpl(Predicate pred) { + private AtomQueryImpl(Predicate pred) { this.predicate = pred; } /** - * Creates a new AnswerSetQuery that will match all atoms that are instances of the given {@link Predicate}. + * Creates a new AtomQuery that will match all atoms that are instances of the given {@link Predicate}. * * @param predicate the predicate to match against - * @return a new AnswerSetQuery matching against the given predicate + * @return a new AtomQuery matching against the given predicate */ - public static AnswerSetQueryImpl forPredicate(Predicate predicate) { - return new AnswerSetQueryImpl(predicate); + static AtomQuery forPredicate(Predicate predicate) { + return new AtomQueryImpl(predicate); + } + + static AtomQuery forPredicate(String name, int arity) { + return forPredicate(Predicates.getPredicate(name, arity)); } /** - * Adds a new filter to this AnswerSetQuery. + * Adds a new filter to this AtomQuery. * For an atom a(t1, ..., tn), the term at index termIdx will be tested against the given filter predicate. * * @param termIdx the index of the term to test * @param filter the test predicate to use on terms - * @return this AnswerSetQuery with the additional filter added + * @return this AtomQuery with the additional filter added */ - @Override - public AnswerSetQueryImpl withFilter(int termIdx, java.util.function.Predicate filter) { + public AtomQuery withFilter(int termIdx, java.util.function.Predicate filter) { if (termIdx >= this.predicate.getArity()) { throw new IndexOutOfBoundsException( "Predicate " + this.predicate.getName() + " has arity " + this.predicate.getArity() + ", term index " + termIdx + " is invalid!"); @@ -66,9 +70,8 @@ public AnswerSetQueryImpl withFilter(int termIdx, java.util.function.Predicate { if (!(term instanceof ConstantTerm)) { return false; @@ -99,8 +101,7 @@ public AnswerSetQueryImpl withStringEquals(int termIdx, String str) { * @param funcArity * @return */ - @Override - public AnswerSetQueryImpl withFunctionTerm(int termIdx, String funcSymbol, int funcArity) { + public AtomQuery withFunctionTerm(int termIdx, String funcSymbol, int funcArity) { java.util.function.Predicate isFunction = (term) -> { if (!(term instanceof FunctionTerm)) { return false; @@ -124,8 +125,7 @@ public AnswerSetQueryImpl withFunctionTerm(int termIdx, String funcSymbol, int f * @param otherTerm * @return */ - @Override - public AnswerSetQueryImpl withTermEquals(int termIdx, Term otherTerm) { + public AtomQuery withTermEquals(int termIdx, Term otherTerm) { java.util.function.Predicate isEqual = (term) -> { return term.equals(otherTerm); }; @@ -162,7 +162,6 @@ public boolean test(Atom atom) { * @param as * @return */ - @Override public List applyTo(AnswerSet as) { if (!as.getPredicates().contains(this.predicate)) { return Collections.emptyList(); @@ -172,7 +171,7 @@ public List applyTo(AnswerSet as) { private static java.util.function.Predicate constantTermEquals(final String str) { java.util.function.Predicate equalsGivenString = (t) -> { - return AnswerSetQueryImpl.constantTermEquals(t, str); + return AtomQueryImpl.constantTermEquals(t, str); }; return equalsGivenString; } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/Atoms.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/Atoms.java similarity index 83% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/Atoms.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/Atoms.java index ed7b95ddc..8658c58d1 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/Atoms.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/Atoms.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.atoms; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import java.util.Arrays; import java.util.Collections; @@ -10,12 +10,13 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateElement; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AtomQuery; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.commons.atoms.AggregateAtomImpl.AggregateElementImpl; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.AggregateAtomImpl.AggregateElementImpl; public final class Atoms { @@ -62,4 +63,12 @@ public static ExternalAtom newExternalAtom(Predicate predicate, PredicateInterpr return new ExternalAtomImpl(predicate, interpretation, input, output); } + public static AtomQuery query(Predicate predicate) { + return AtomQueryImpl.forPredicate(predicate); + } + + public static AtomQuery query(String predicateName, int predicateArity) { + return AtomQueryImpl.forPredicate(predicateName, predicateArity); + } + } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/BasicAtomImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImpl.java similarity index 95% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/BasicAtomImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImpl.java index 6b7cc57e5..ebe1c8266 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/BasicAtomImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImpl.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.atoms; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import java.util.Arrays; import java.util.Collections; @@ -37,9 +37,9 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; /** diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/ComparisonAtomImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ComparisonAtomImpl.java similarity index 94% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/ComparisonAtomImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ComparisonAtomImpl.java index 52d063427..1d4a9fd3a 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/ComparisonAtomImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ComparisonAtomImpl.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.atoms; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import java.util.Arrays; import java.util.List; @@ -37,9 +37,9 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; /** * Represents a builtin comparison atom according to the standard. diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/ExternalAtomImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImpl.java similarity index 96% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/ExternalAtomImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImpl.java index e5e5ef5e6..79cddde75 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/atoms/ExternalAtomImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImpl.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.atoms; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import java.util.Collections; import java.util.List; @@ -38,9 +38,9 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ExternalLiteral; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; class ExternalAtomImpl extends AbstractAtom implements ExternalAtom { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/AbstractLiteral.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/AbstractLiteral.java similarity index 95% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/AbstractLiteral.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/AbstractLiteral.java index 8d96711b1..76686365a 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/AbstractLiteral.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/AbstractLiteral.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.literals; +package at.ac.tuwien.kr.alpha.commons.programs.literals; import java.util.List; import java.util.Set; @@ -36,8 +36,8 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; /** * A potentially negated {@link AbstractAtom} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/AggregateLiteralImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/AggregateLiteralImpl.java similarity index 90% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/AggregateLiteralImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/AggregateLiteralImpl.java index 082d5cf5d..b5cdfb799 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/AggregateLiteralImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/AggregateLiteralImpl.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.literals; +package at.ac.tuwien.kr.alpha.commons.programs.literals; import java.util.HashSet; import java.util.Set; @@ -7,10 +7,10 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.AbstractAtom; /** * Copyright (c) 2018, the Alpha Team. diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/BasicLiteralImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/BasicLiteralImpl.java similarity index 93% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/BasicLiteralImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/BasicLiteralImpl.java index 4f0479d1f..3635d0b51 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/BasicLiteralImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/BasicLiteralImpl.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.literals; +package at.ac.tuwien.kr.alpha.commons.programs.literals; import java.util.Collections; import java.util.HashSet; @@ -35,9 +35,9 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.AbstractAtom; /** * Contains a potentially negated {@link BasicAtomImpl}. diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/ComparisonLiteralImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ComparisonLiteralImpl.java similarity index 95% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/ComparisonLiteralImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ComparisonLiteralImpl.java index cad9d1121..820de3e3f 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/ComparisonLiteralImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ComparisonLiteralImpl.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.literals; +package at.ac.tuwien.kr.alpha.commons.programs.literals; import java.util.Collections; import java.util.HashSet; @@ -38,13 +38,13 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; /** * Contains a potentially negated {@link ComparisonAtomImpl}. diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/ExternalLiteralImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java similarity index 96% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/ExternalLiteralImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java index bcd1b7e0a..c2d87b3e6 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/ExternalLiteralImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.literals; +package at.ac.tuwien.kr.alpha.commons.programs.literals; import java.util.ArrayList; import java.util.Collections; @@ -37,10 +37,10 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ExternalLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.AbstractAtom; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; /** diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/Literals.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/Literals.java similarity index 95% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/Literals.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/Literals.java index a7ec8a770..82b91f24b 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/literals/Literals.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/Literals.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.literals; +package at.ac.tuwien.kr.alpha.commons.programs.literals; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/reification/ReificationContext.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/reification/ReificationContext.java new file mode 100644 index 000000000..a5034ef9a --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/reification/ReificationContext.java @@ -0,0 +1,54 @@ +package at.ac.tuwien.kr.alpha.commons.programs.reification; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.util.IdGenerator; + +class ReificationContext implements IdGenerator> { + + private final IdGenerator> idGenerator; + private final Map> predicateTable = new HashMap<>(); + + private final Set reifiedItems = new LinkedHashSet<>(); + + ReificationContext(IdGenerator> idGenerator) { + this.idGenerator = idGenerator; + } + + ConstantTerm computePredicateId(Predicate predicate) { + return predicateTable.computeIfAbsent(predicate, (pred) -> idGenerator.getNextId()); + } + + @Override + public ConstantTerm getNextId() { + return idGenerator.getNextId(); + } + + void addAtom(BasicAtom item) { + reifiedItems.add(item); + } + + private Set generatePredicateAtoms() { + Set predicateAtoms = new LinkedHashSet<>(); + for (Map.Entry> entry : predicateTable.entrySet()) { + predicateAtoms.add(Atoms.newBasicAtom(Reifier.PREDICATE, entry.getValue(), Terms.newConstant(entry.getKey().getName()), + Terms.newConstant(entry.getKey().getArity()))); + } + return predicateAtoms; + } + + Set computeReifiedProgram() { + Set reifiedProgram = new LinkedHashSet<>(reifiedItems); + reifiedProgram.addAll(generatePredicateAtoms()); + return reifiedProgram; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/reification/Reifier.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/reification/Reifier.java new file mode 100644 index 000000000..c21c7e0cb --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/reification/Reifier.java @@ -0,0 +1,448 @@ +package at.ac.tuwien.kr.alpha.commons.programs.reification; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import at.ac.tuwien.kr.alpha.api.ComparisonOperator; +import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateElement; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead.ChoiceElement; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.util.IdGenerator; +import at.ac.tuwien.kr.alpha.commons.util.Util; + +// TODO add support for action rules +public class Reifier { + + // Predicates describing rules. + static final Predicate RULE = Predicates.getPredicate("rule", 1); + static final Predicate CONSTRAINT = Predicates.getPredicate("constraint", 1); + static final Predicate RULE_HEAD = Predicates.getPredicate("rule_head", 2); + static final Predicate RULE_NUM_BODY_LITERALS = Predicates.getPredicate("rule_numBodyLiterals", 2); + static final Predicate RULE_BODY_LITERAL = Predicates.getPredicate("rule_bodyLiteral", 2); + + // Predicates describing facts. + static final Predicate FACT = Predicates.getPredicate("fact", 1); + + // Predicates describing heads. + static final Predicate HEAD_TYPE = Predicates.getPredicate("head_type", 2); + + // Predicates describing normal heads. + static final Predicate NORMAL_HEAD_ATOM = Predicates.getPredicate("normalHead_atom", 2); + + // Predicates describing choice heads. + static final Predicate CHOICE_HEAD_LOWER_BOUND = Predicates.getPredicate("choiceHead_lowerBound", 2); + static final Predicate CHOICE_HEAD_UPPER_BOUND = Predicates.getPredicate("choiceHead_upperBound", 2); + static final Predicate CHOICE_HEAD_NUM_ELEMENTS = Predicates.getPredicate("choiceHead_numElements", 2); + static final Predicate CHOICE_HEAD_ELEMENT = Predicates.getPredicate("choiceHead_element", 2); + static final Predicate CHOICE_ELEMENT_ATOM = Predicates.getPredicate("choiceElement_atom", 2); + static final Predicate CHOICE_ELEMENT_NUM_CONDITION_LITERALS = Predicates.getPredicate("choiceElement_numConditionLiterals", 2); + static final Predicate CHOICE_ELEMENT_CONDITION_LITERAL = Predicates.getPredicate("choiceElement_conditionLiteral", 2); + + // Predicates describing literals. + static final Predicate LITERAL_POLARITY = Predicates.getPredicate("literal_polarity", 2); + static final Predicate LITERAL_ATOM = Predicates.getPredicate("literal_atom", 2); + + // Predicates describing predicates. + static final Predicate PREDICATE = Predicates.getPredicate("predicate", 3); + + // Predicates describing atoms. + static final Predicate ATOM_TYPE = Predicates.getPredicate("atom_type", 2); + + // Predicates describing basic atoms. + static final Predicate BASIC_ATOM_PREDICATE = Predicates.getPredicate("basicAtom_predicate", 2); + static final Predicate BASIC_ATOM_NUM_TERMS = Predicates.getPredicate("basicAtom_numTerms", 2); + static final Predicate BASIC_ATOM_TERM = Predicates.getPredicate("basicAtom_term", 3); + + // Predicates describing comparison atoms. + static final Predicate COMPARISON_ATOM_LEFT = Predicates.getPredicate("comparisonAtom_leftTerm", 2); + static final Predicate COMPARISON_ATOM_RIGHT = Predicates.getPredicate("comparisonAtom_rightTerm", 2); + static final Predicate COMPARISON_ATOM_OPERATOR = Predicates.getPredicate("comparisonAtom_operator", 2); + + // Predicates describing external atoms. + static final Predicate EXTERNAL_ATOM_NAME = Predicates.getPredicate("externalAtom_name", 2); + static final Predicate EXTERNAL_ATOM_NUM_INPUT_TERMS = Predicates.getPredicate("externalAtom_numInputTerms", 2); + static final Predicate EXTERNAL_ATOM_INPUT_TERM = Predicates.getPredicate("externalAtom_inputTerm", 3); + static final Predicate EXTERNAL_ATOM_NUM_OUTPUT_TERMS = Predicates.getPredicate("externalAtom_numOutputTerms", 2); + static final Predicate EXTERNAL_ATOM_OUTPUT_TERM = Predicates.getPredicate("externalAtom_outputTerm", 3); + + // Predicates describing aggregate atoms. + static final Predicate AGGREGATE_ATOM_LEFT_TERM = Predicates.getPredicate("aggregateAtom_leftHandTerm", 2); + static final Predicate AGGREGATE_ATOM_LEFT_OPERATOR = Predicates.getPredicate("aggregateAtom_leftHandOperator", 2); + static final Predicate AGGREGATE_ATOM_RIGHT_TERM = Predicates.getPredicate("aggregateAtom_rightHandTerm", 2); + static final Predicate AGGREGATE_ATOM_RIGHT_OPERATOR = Predicates.getPredicate("aggregateAtom_rightHandOperator", 2); + static final Predicate AGGREGATE_ATOM_AGGREGATE_FUNCTION = Predicates.getPredicate("aggregateAtom_aggregateFunction", 2); + static final Predicate AGGREGATE_ATOM_NUM_AGGREGATE_ELEMENTS = Predicates.getPredicate("aggregateAtom_numAggregateElements", 2); + static final Predicate AGGREGATE_ATOM_AGGREGATE_ELEMENT = Predicates.getPredicate("aggregateAtom_aggregateElement", 2); + + // Predicates describing aggregate elements. + static final Predicate AGGREGATE_ELEMENT_NUM_TERMS = Predicates.getPredicate("aggregateElement_numTerms", 2); + static final Predicate AGGREGATE_ELEMENT_TERM = Predicates.getPredicate("aggregateElement_term", 3); + static final Predicate AGGREGATE_ELEMENT_NUM_LITERALS = Predicates.getPredicate("aggregateElement_numLiterals", 2); + static final Predicate AGGREGATE_ELEMENT_LITERAL = Predicates.getPredicate("aggregateElement_literal", 2); + + // Predicates describing terms. + static final Predicate TERM_TYPE = Predicates.getPredicate("term_type", 2); + + // Predicates describing constant terms. + static final Predicate CONSTANT_TERM_TYPE = Predicates.getPredicate("constantTerm_type", 2); + static final Predicate CONSTANT_TERM_VALUE = Predicates.getPredicate("constantTerm_value", 2); + + // Predicates describing variable terms. + static final Predicate VARIABLE_TERM_SYMBOL = Predicates.getPredicate("variableTerm_symbol", 2); + + // Predicates describing arithmetic terms. + static final Predicate ARITHMETIC_TERM_LEFT = Predicates.getPredicate("arithmeticTerm_leftTerm", 2); + static final Predicate ARITHMETIC_TERM_RIGHT = Predicates.getPredicate("arithmeticTerm_rightTerm", 2); + static final Predicate ARITHMETIC_TERM_OPERATOR = Predicates.getPredicate("arithmeticTerm_operator", 2); + + // Predicates describing function terms. + static final Predicate FUNCTION_TERM_SYMBOL = Predicates.getPredicate("functionTerm_symbol", 2); + static final Predicate FUNCTION_TERM_NUM_ARGUMENTS = Predicates.getPredicate("functionTerm_numArguments", 2); + static final Predicate FUNCTION_TERM_ARGUMENT = Predicates.getPredicate("functionTerm_argumentTerm", 3); + + // Predicates describing interval terms + static final Predicate INTERVAL_TERM_LOWER = Predicates.getPredicate("intervalTerm_lower", 2); + static final Predicate INTERVAL_TERM_UPPER = Predicates.getPredicate("intervalTerm_Upper", 2); + + // Predicates describing InlineDirectives + static final Predicate INLINE_DIRECTIVE = Predicates.getPredicate("inlineDirective", 2); + + // Constants describing head types. + static final ConstantTerm HEAD_TYPE_NORMAL = Terms.newSymbolicConstant("normal"); + static final ConstantTerm HEAD_TYPE_CHOICE = Terms.newSymbolicConstant("choice"); + + // Constants describing literal polaritites. + static final ConstantTerm LITERAL_POLARITY_POSITIVE = Terms.newSymbolicConstant("pos"); + static final ConstantTerm LITERAL_POLARITY_NEGATIVE = Terms.newSymbolicConstant("neg"); + + // Constants describing atom types. + static final ConstantTerm ATOM_TYPE_BASIC = Terms.newSymbolicConstant("basic"); + static final ConstantTerm ATOM_TYPE_COMPARISON = Terms.newSymbolicConstant("comparison"); + static final ConstantTerm ATOM_TYPE_EXTERNAL = Terms.newSymbolicConstant("external"); + static final ConstantTerm ATOM_TYPE_AGGREGATE = Terms.newSymbolicConstant("aggregate"); + + // Constants describing comparison operators. + static final ConstantTerm CMP_OP_EQ = Terms.newSymbolicConstant("eq"); + static final ConstantTerm CMP_OP_NE = Terms.newSymbolicConstant("ne"); + static final ConstantTerm CMP_OP_LE = Terms.newSymbolicConstant("le"); + static final ConstantTerm CMP_OP_LT = Terms.newSymbolicConstant("lt"); + static final ConstantTerm CMP_OP_GE = Terms.newSymbolicConstant("ge"); + static final ConstantTerm CMP_OP_GT = Terms.newSymbolicConstant("gt"); + + // Constants describing aggregate functions. + static final ConstantTerm AGGREGATE_FUNCTION_COUNT = Terms.newSymbolicConstant("count"); + static final ConstantTerm AGGREGATE_FUNCTION_SUM = Terms.newSymbolicConstant("sum"); + static final ConstantTerm AGGREGATE_FUNCTION_MIN = Terms.newSymbolicConstant("min"); + static final ConstantTerm AGGREGATE_FUNCTION_MAX = Terms.newSymbolicConstant("max"); + + // Constants describing term types. + static final ConstantTerm TERM_TYPE_CONSTANT = Terms.newSymbolicConstant("constant"); + static final ConstantTerm TERM_TYPE_VARIABLE = Terms.newSymbolicConstant("variable"); + static final ConstantTerm TERM_TYPE_ARITHMETIC = Terms.newSymbolicConstant("arithmetic"); + static final ConstantTerm TERM_TYPE_FUNCTION = Terms.newSymbolicConstant("function"); + static final ConstantTerm TERM_TYPE_INTERVAL = Terms.newSymbolicConstant("interval"); + + private static final Map> CMP_OPS = new HashMap<>(); + private static final Map> AGG_FUNCS = new HashMap<>(); + private static final Map, String> TERM_TYPES = new HashMap<>(); + + static { + CMP_OPS.put(ComparisonOperators.EQ, CMP_OP_EQ); + CMP_OPS.put(ComparisonOperators.NE, CMP_OP_NE); + CMP_OPS.put(ComparisonOperators.LE, CMP_OP_LE); + CMP_OPS.put(ComparisonOperators.LT, CMP_OP_LT); + CMP_OPS.put(ComparisonOperators.GE, CMP_OP_GE); + CMP_OPS.put(ComparisonOperators.GT, CMP_OP_GT); + + AGG_FUNCS.put(AggregateFunctionSymbol.COUNT, AGGREGATE_FUNCTION_COUNT); + AGG_FUNCS.put(AggregateFunctionSymbol.SUM, AGGREGATE_FUNCTION_SUM); + AGG_FUNCS.put(AggregateFunctionSymbol.MIN, AGGREGATE_FUNCTION_MIN); + AGG_FUNCS.put(AggregateFunctionSymbol.MAX, AGGREGATE_FUNCTION_MAX); + + TERM_TYPES.put(String.class, "string"); + TERM_TYPES.put(Integer.class, "integer"); + } + + private final Supplier>> idGeneratorProvider; + + public Reifier(Supplier>> idGeneratorProvider) { + this.idGeneratorProvider = idGeneratorProvider; + } + + public Set reifyProgram(InputProgram program) { + ReificationContext ctx = new ReificationContext(idGeneratorProvider.get()); + reifyDirectives(ctx, program.getInlineDirectives()); + for (Atom fact : program.getFacts()) { + ConstantTerm factId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(FACT, factId)); + reifyAtom(ctx, factId, fact); + } + for (Rule rule : program.getRules()) { + reifyRule(ctx, rule); + } + return ctx.computeReifiedProgram(); + } + + /** + * Generates atoms of form inlineDirective("", ""). + */ + void reifyDirectives(ReificationContext ctx, InlineDirectives directives) { + for (Map.Entry entry : directives.getDirectives().entrySet()) { + ctx.addAtom(Atoms.newBasicAtom(INLINE_DIRECTIVE, Terms.newConstant(entry.getKey().name()), Terms.newConstant(entry.getValue()))); + } + } + + void reifyRule(ReificationContext ctx, Rule rule) { + ConstantTerm ruleId = ctx.getNextId(); + if (rule.isConstraint()) { + ctx.addAtom(Atoms.newBasicAtom(CONSTRAINT, ruleId)); + } else { + ctx.addAtom(Atoms.newBasicAtom(RULE, ruleId)); + reifyHead(ctx, ruleId, rule.getHead()); + } + ctx.addAtom(Atoms.newBasicAtom(RULE_NUM_BODY_LITERALS, ruleId, Terms.newConstant(rule.getBody().size()))); + for (Literal lit : rule.getBody()) { + ConstantTerm literalId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(RULE_BODY_LITERAL, ruleId, literalId)); + reifyLiteral(ctx, literalId, lit); + } + } + + void reifyHead(ReificationContext ctx, ConstantTerm ruleId, Head head) { + ConstantTerm headId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(RULE_HEAD, ruleId, headId)); + if (head instanceof NormalHead) { + reifyNormalHead(ctx, headId, (NormalHead) head); + } else if (head instanceof ChoiceHead) { + reifyChoiceHead(ctx, headId, (ChoiceHead) head); + } else { + throw Util.oops("Head type " + head.getClass().getSimpleName() + " cannot be reified!"); + } + } + + void reifyNormalHead(ReificationContext ctx, ConstantTerm headId, NormalHead head) { + ctx.addAtom(Atoms.newBasicAtom(HEAD_TYPE, headId, HEAD_TYPE_NORMAL)); + ConstantTerm atomId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(NORMAL_HEAD_ATOM, headId, atomId)); + reifyAtom(ctx, atomId, head.getAtom()); + } + + void reifyChoiceHead(ReificationContext ctx, ConstantTerm headId, ChoiceHead head) { + ctx.addAtom(Atoms.newBasicAtom(HEAD_TYPE, headId, HEAD_TYPE_CHOICE)); + if (head.getLowerBound() != null) { + ctx.addAtom(Atoms.newBasicAtom(CHOICE_HEAD_LOWER_BOUND, headId, head.getLowerBound())); + } + if (head.getUpperBound() != null) { + ctx.addAtom(Atoms.newBasicAtom(CHOICE_HEAD_UPPER_BOUND, headId, head.getUpperBound())); + } + ctx.addAtom(Atoms.newBasicAtom(CHOICE_HEAD_NUM_ELEMENTS, headId, Terms.newConstant(head.getChoiceElements().size()))); + for (ChoiceElement element : head.getChoiceElements()) { + reifyChoiceElement(ctx, headId, element); + } + } + + void reifyChoiceElement(ReificationContext ctx, ConstantTerm headId, ChoiceElement element) { + ConstantTerm elementId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(CHOICE_HEAD_ELEMENT, headId, elementId)); + ConstantTerm atomId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(CHOICE_ELEMENT_ATOM, elementId, atomId)); + reifyAtom(ctx, atomId, element.getChoiceAtom()); + ctx.addAtom(Atoms.newBasicAtom(CHOICE_ELEMENT_NUM_CONDITION_LITERALS, elementId, Terms.newConstant(element.getConditionLiterals().size()))); + for (Literal lit : element.getConditionLiterals()) { + ConstantTerm literalId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(CHOICE_ELEMENT_CONDITION_LITERAL, elementId, literalId)); + reifyLiteral(ctx, literalId, lit); + } + } + + void reifyLiteral(ReificationContext ctx, ConstantTerm literalId, Literal lit) { + ctx.addAtom(Atoms.newBasicAtom(LITERAL_POLARITY, literalId, lit.isNegated() ? LITERAL_POLARITY_NEGATIVE : LITERAL_POLARITY_POSITIVE)); + ConstantTerm atomId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(LITERAL_ATOM, literalId, atomId)); + reifyAtom(ctx, atomId, lit.getAtom()); + } + + void reifyAtom(ReificationContext ctx, ConstantTerm atomId, Atom atom) { + if (atom instanceof BasicAtom) { + reifyBasicAtom(ctx, atomId, (BasicAtom) atom); + } else if (atom instanceof ComparisonAtom) { + reifyComparisonAtom(ctx, atomId, (ComparisonAtom) atom); + } else if (atom instanceof ExternalAtom) { + reifyExternalAtom(ctx, atomId, (ExternalAtom) atom); + } else if (atom instanceof AggregateAtom) { + reifyAggregateAtom(ctx, atomId, (AggregateAtom) atom); + } else { + throw Util.oops("Atom type " + atom.getClass().getSimpleName() + " cannot be reified!"); + } + } + + void reifyBasicAtom(ReificationContext ctx, ConstantTerm atomId, BasicAtom atom) { + ctx.addAtom(Atoms.newBasicAtom(ATOM_TYPE, atomId, ATOM_TYPE_BASIC)); + ConstantTerm predicateId = ctx.computePredicateId(atom.getPredicate()); + ctx.addAtom(Atoms.newBasicAtom(BASIC_ATOM_PREDICATE, atomId, predicateId)); + ctx.addAtom(Atoms.newBasicAtom(BASIC_ATOM_NUM_TERMS, atomId, Terms.newConstant(atom.getTerms().size()))); + for (int i = 0; i < atom.getTerms().size(); i++) { + ConstantTerm termId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(BASIC_ATOM_TERM, atomId, Terms.newConstant(i), termId)); + reifyTerm(ctx, termId, atom.getTerms().get(i)); + } + } + + void reifyComparisonAtom(ReificationContext ctx, ConstantTerm atomId, ComparisonAtom atom) { + ctx.addAtom(Atoms.newBasicAtom(ATOM_TYPE, atomId, ATOM_TYPE_COMPARISON)); + ConstantTerm leftTermId = ctx.getNextId(); + ConstantTerm rightTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(COMPARISON_ATOM_LEFT, atomId, leftTermId)); + ctx.addAtom(Atoms.newBasicAtom(COMPARISON_ATOM_RIGHT, atomId, rightTermId)); + if (!CMP_OPS.containsKey(atom.getOperator())) { + throw Util.oops("Cannot reifiy comparison operator " + atom.getOperator()); + } + ctx.addAtom(Atoms.newBasicAtom(COMPARISON_ATOM_OPERATOR, atomId, CMP_OPS.get(atom.getOperator()))); + reifyTerm(ctx, leftTermId, atom.getTerms().get(0)); + reifyTerm(ctx, rightTermId, atom.getTerms().get(1)); + } + + void reifyExternalAtom(ReificationContext ctx, ConstantTerm atomId, ExternalAtom atom) { + ctx.addAtom(Atoms.newBasicAtom(ATOM_TYPE, atomId, ATOM_TYPE_EXTERNAL)); + ctx.addAtom(Atoms.newBasicAtom(EXTERNAL_ATOM_NAME, atomId, Terms.newConstant(atom.getPredicate().getName()))); + ctx.addAtom(Atoms.newBasicAtom(EXTERNAL_ATOM_NUM_INPUT_TERMS, atomId, Terms.newConstant(atom.getInput().size()))); + for (int i = 0; i < atom.getInput().size(); i++) { + ConstantTerm inTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(EXTERNAL_ATOM_INPUT_TERM, atomId, Terms.newConstant(i), inTermId)); + reifyTerm(ctx, inTermId, atom.getInput().get(i)); + } + ctx.addAtom(Atoms.newBasicAtom(EXTERNAL_ATOM_NUM_OUTPUT_TERMS, atomId, Terms.newConstant(atom.getOutput().size()))); + for (int i = 0; i < atom.getOutput().size(); i++) { + ConstantTerm outTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(EXTERNAL_ATOM_OUTPUT_TERM, atomId, Terms.newConstant(i), outTermId)); + reifyTerm(ctx, outTermId, atom.getOutput().get(i)); + } + } + + void reifyAggregateAtom(ReificationContext ctx, ConstantTerm atomId, AggregateAtom atom) { + ctx.addAtom(Atoms.newBasicAtom(ATOM_TYPE, atomId, ATOM_TYPE_AGGREGATE)); + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ATOM_AGGREGATE_FUNCTION, atomId, AGG_FUNCS.get(atom.getAggregateFunction()))); + if (atom.getLowerBoundOperator() != null) { + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ATOM_LEFT_OPERATOR, atomId, CMP_OPS.get(atom.getLowerBoundOperator()))); + ConstantTerm leftTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ATOM_LEFT_TERM, atomId, leftTermId)); + } + if (atom.getUpperBoundOperator() != null) { + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ATOM_RIGHT_OPERATOR, atomId, CMP_OPS.get(atom.getUpperBoundOperator()))); + ConstantTerm rightTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ATOM_RIGHT_TERM, atomId, rightTermId)); + } + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ATOM_NUM_AGGREGATE_ELEMENTS, atomId, Terms.newConstant(atom.getAggregateElements().size()))); + for (AggregateElement element : atom.getAggregateElements()) { + ConstantTerm elementId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ATOM_AGGREGATE_ELEMENT, atomId, elementId)); + reifyAggregateElement(ctx, elementId, element); + } + } + + void reifyAggregateElement(ReificationContext ctx, ConstantTerm elementId, AggregateElement element) { + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ELEMENT_NUM_TERMS, elementId, Terms.newConstant(element.getElementTerms().size()))); + for (int i = 0; i < element.getElementTerms().size(); i++) { + ConstantTerm termId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ELEMENT_TERM, elementId, Terms.newConstant(i), termId)); + reifyTerm(ctx, termId, element.getElementTerms().get(i)); + } + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ELEMENT_NUM_LITERALS, elementId, Terms.newConstant(element.getElementLiterals().size()))); + for (Literal lit : element.getElementLiterals()) { + ConstantTerm literalId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(AGGREGATE_ELEMENT_LITERAL, elementId, literalId)); + reifyLiteral(ctx, literalId, lit); + } + } + + void reifyTerm(ReificationContext ctx, ConstantTerm termId, Term term) { + if (term instanceof ConstantTerm) { + reifyConstantTerm(ctx, termId, (ConstantTerm) term); + } else if (term instanceof VariableTerm) { + reifyVariableTerm(ctx, termId, (VariableTerm) term); + } else if (term instanceof ArithmeticTerm) { + reifyArithmeticTerm(ctx, termId, (ArithmeticTerm) term); + } else if (term instanceof FunctionTerm) { + reifyFunctionTerm(ctx, termId, (FunctionTerm) term); + } else if (term instanceof IntervalTerm) { + reifyIntervalTerm(ctx, termId, (IntervalTerm) term); + } else { + throw Util.oops("Cannot reify term of type " + term.getClass().getSimpleName()); + } + } + + void reifyConstantTerm(ReificationContext ctx, ConstantTerm termId, ConstantTerm term) { + String termType; + if (term.isSymbolic()) { + termType = "symbol"; + } else { + termType = TERM_TYPES.getOrDefault(term.getObject().getClass(), "object(" + term.getObject().getClass().getName() + ")"); + } + ctx.addAtom(Atoms.newBasicAtom(TERM_TYPE, termId, TERM_TYPE_CONSTANT)); + ctx.addAtom(Atoms.newBasicAtom(CONSTANT_TERM_TYPE, termId, Terms.newConstant(termType))); + ctx.addAtom(Atoms.newBasicAtom(CONSTANT_TERM_VALUE, termId, Terms.newConstant(term.getObject().toString().replace("\"", "\\\"")))); + } + + void reifyVariableTerm(ReificationContext ctx, ConstantTerm termId, VariableTerm term) { + ctx.addAtom(Atoms.newBasicAtom(TERM_TYPE, termId, TERM_TYPE_VARIABLE)); + ctx.addAtom(Atoms.newBasicAtom(VARIABLE_TERM_SYMBOL, termId, Terms.newConstant(term.toString()))); + } + + void reifyArithmeticTerm(ReificationContext ctx, ConstantTerm termId, ArithmeticTerm term) { + ctx.addAtom(Atoms.newBasicAtom(TERM_TYPE, termId, TERM_TYPE_ARITHMETIC)); + ConstantTerm leftTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(ARITHMETIC_TERM_LEFT, termId, leftTermId)); + reifyTerm(ctx, leftTermId, term.getLeftOperand()); + ConstantTerm rightTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(ARITHMETIC_TERM_RIGHT, termId, rightTermId)); + reifyTerm(ctx, rightTermId, term.getRightOperand()); + ctx.addAtom(Atoms.newBasicAtom(ARITHMETIC_TERM_OPERATOR, termId, Terms.newConstant(term.getOperator().toString()))); + } + + void reifyFunctionTerm(ReificationContext ctx, ConstantTerm termId, FunctionTerm term) { + ctx.addAtom(Atoms.newBasicAtom(TERM_TYPE, termId, TERM_TYPE_FUNCTION)); + ctx.addAtom(Atoms.newBasicAtom(FUNCTION_TERM_SYMBOL, termId, Terms.newConstant(term.getSymbol()))); + ctx.addAtom(Atoms.newBasicAtom(FUNCTION_TERM_NUM_ARGUMENTS, termId, Terms.newConstant(term.getTerms().size()))); + for (int i = 0; i < term.getTerms().size(); i++) { + ConstantTerm argTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(FUNCTION_TERM_ARGUMENT, termId, Terms.newConstant(i), argTermId)); + reifyTerm(ctx, argTermId, term.getTerms().get(i)); + } + } + + void reifyIntervalTerm(ReificationContext ctx, ConstantTerm termId, IntervalTerm term) { + ctx.addAtom(Atoms.newBasicAtom(TERM_TYPE, termId, TERM_TYPE_INTERVAL)); + ConstantTerm lowerTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(INTERVAL_TERM_LOWER, termId, lowerTermId)); + reifyTerm(ctx, lowerTermId, term.getLowerBound()); + ConstantTerm upperTermId = ctx.getNextId(); + ctx.addAtom(Atoms.newBasicAtom(INTERVAL_TERM_UPPER, termId, upperTermId)); + reifyTerm(ctx, upperTermId, term.getUpperBound()); + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/AbstractRule.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/AbstractRule.java similarity index 93% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/AbstractRule.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/AbstractRule.java index dad66bc2d..c243d840b 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/AbstractRule.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/AbstractRule.java @@ -1,19 +1,16 @@ -package at.ac.tuwien.kr.alpha.core.rules; +package at.ac.tuwien.kr.alpha.commons.programs.rules; + +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.commons.util.Util; +import org.apache.commons.collections4.SetUtils; -import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; -import java.util.List; import java.util.Objects; import java.util.Set; -import org.apache.commons.collections4.SetUtils; - -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.commons.util.Util; - /** * An abstract representation of a rule with a specific type of @{link Head} (type parameter H) * @@ -27,7 +24,7 @@ public abstract class AbstractRule implements Rule { private final Set bodyLiteralsPositive; private final Set bodyLiteralsNegative; - public AbstractRule(H head, List body) { + public AbstractRule(H head, Set body) { this.head = head; Set positiveBody = new LinkedHashSet<>(); Set negativeBody = new LinkedHashSet<>(); @@ -48,10 +45,6 @@ public AbstractRule(H head, List body) { + "Notice: A rule is considered safe if all variables occurring in negative literals, builtin atoms, and the head of the rule also occur in some positive literal."); } } - - public AbstractRule(H head, Set body) { - this(head, new ArrayList<>(body)); - } /** * Checks whether a rule is safe. The actual safety condition may vary over the next improvements. Currently, a rule is @@ -60,7 +53,7 @@ public AbstractRule(H head, Set body) { * * @return true if this rule is safe. */ - private boolean isSafe() { + boolean isSafe() { // TODO: do the real check. // Note that - once a proper safety check is implemented - that check should probably be specific for each rule // implementation, therefore this method should be "protected abstract" here and implemented in each subclass. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/BasicRule.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/BasicRule.java similarity index 75% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/BasicRule.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/BasicRule.java index 1c218769a..77aac0ea3 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/BasicRule.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/BasicRule.java @@ -25,28 +25,21 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.core.rules; - -import java.util.Arrays; -import java.util.List; +package at.ac.tuwien.kr.alpha.commons.programs.rules; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; + +import java.util.Set; /** * Represents a non-ground rule or a constraint. A {@link BasicRule} has a general {@link Head}, meaning both choice heads and disjunctive * heads are permissible. - * This implementation represents a rule after being parsed from a given ASP program, but before being transformed into a - * {@link NormalRuleImpl}. */ -public class BasicRule extends AbstractRule implements Rule { +class BasicRule extends AbstractRule { - public BasicRule(Head head, List body) { + BasicRule(Head head, Set body) { super(head, body); } - public BasicRule(Head head, Literal... body) { - this(head, Arrays.asList(body)); - } } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/NormalRuleImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/NormalRuleImpl.java new file mode 100644 index 000000000..acd5ee0d5 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/NormalRuleImpl.java @@ -0,0 +1,34 @@ +package at.ac.tuwien.kr.alpha.commons.programs.rules; + +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; + +import java.util.Set; + +/** + * A rule that has a normal head, i.e. just one head atom, no disjunction or choice heads allowed. + * Currently, any constructs such as aggregates, intervals, etc. in the rule body are allowed. + * + * Copyright (c) 2019, the Alpha Team. + */ +class NormalRuleImpl extends AbstractRule implements NormalRule { + + NormalRuleImpl(NormalHead head, Set body) { + super(head, body); + } + + @Override + public boolean isGround() { + if (!isConstraint() && !this.getHead().isGround()) { + return false; + } + for (Literal bodyElement : this.getBody()) { + if (!bodyElement.isGround()) { + return false; + } + } + return true; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/Rules.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/Rules.java new file mode 100644 index 000000000..9a19b54bc --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/Rules.java @@ -0,0 +1,50 @@ +package at.ac.tuwien.kr.alpha.commons.programs.rules; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.commons.util.Util; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +public final class Rules { + + private Rules() { + throw new AssertionError("Cannot instantiate utility class!"); + } + + public static Rule newRule(Head head, Set body) { + return new BasicRule(head, body); + } + + public static Rule newRule(Head head, Literal... body) { + Set bodyLst = new LinkedHashSet<>(Arrays.asList(body)); + return new BasicRule(head, bodyLst); + } + + public static NormalRule newNormalRule(NormalHead head, Set body) { + return new NormalRuleImpl(head, body); + } + + public static NormalRule newNormalRule(NormalHead head, Literal... body) { + Set bodyLst = new LinkedHashSet<>(Arrays.asList(body)); + return new NormalRuleImpl(head, bodyLst); + } + + public static NormalRule toNormalRule(Rule rule) { + BasicAtom headAtom = null; + if (!rule.isConstraint()) { + if (!(rule.getHead() instanceof NormalHead)) { + throw Util.oops("Trying to construct a NormalRule from rule with non-normal head! Head type is: " + rule.getHead().getClass().getSimpleName()); + } + + } + return newNormalRule(rule.isConstraint() ? null : (NormalHead) rule.getHead(), new LinkedHashSet<>(rule.getBody())); + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/ActionHeadImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/ActionHeadImpl.java new file mode 100644 index 000000000..4d41d044a --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/ActionHeadImpl.java @@ -0,0 +1,63 @@ +package at.ac.tuwien.kr.alpha.commons.programs.rules.heads; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.rules.RuleInstantiator; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ActionHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.List; + +class ActionHeadImpl implements ActionHead { + + private final BasicAtom atom; + private final String actionName; + private final List actionInputTerms; + private final VariableTerm actionOutputTerm; + + ActionHeadImpl(BasicAtom atom, String actionName, List actionInputTerms, VariableTerm actionOutputTerm) { + this.atom = atom; + this.actionName = actionName; + this.actionInputTerms = Collections.unmodifiableList(actionInputTerms); + this.actionOutputTerm = actionOutputTerm; + } + + @Override + public BasicAtom getAtom() { + return atom; + } + + @Override + public boolean isGround() { + // TODO: an action head is conceptually a basic one with an (interpreted) function term + return false; + } + + @Override + public BasicAtom instantiate(RuleInstantiator instantiator, Substitution substitution) { + return instantiator.instantiate(this, substitution); + } + + @Override + public String getActionName() { + return actionName; + } + + @Override + public List getActionInputTerms() { + return actionInputTerms; + } + + @Override + public VariableTerm getActionOutputTerm() { + return actionOutputTerm; + } + + public String toString() { + return atom.toString() + " : @" + actionName + "(" + StringUtils.join(actionInputTerms, ", ") + ") = " + actionOutputTerm; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/ChoiceHeadImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/ChoiceHeadImpl.java similarity index 95% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/ChoiceHeadImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/ChoiceHeadImpl.java index 7c81d7357..5af548b01 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/ChoiceHeadImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/ChoiceHeadImpl.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.rules.heads; +package at.ac.tuwien.kr.alpha.commons.programs.rules.heads; import static at.ac.tuwien.kr.alpha.commons.util.Util.join; @@ -7,8 +7,8 @@ import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; /** * Represents the head of a choice rule. diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/DisjunctiveHeadImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/DisjunctiveHeadImpl.java similarity index 91% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/DisjunctiveHeadImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/DisjunctiveHeadImpl.java index bc33e8f17..d463d8b4f 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/DisjunctiveHeadImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/DisjunctiveHeadImpl.java @@ -1,11 +1,11 @@ -package at.ac.tuwien.kr.alpha.commons.rules.heads; +package at.ac.tuwien.kr.alpha.commons.programs.rules.heads; import static at.ac.tuwien.kr.alpha.commons.util.Util.join; import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.heads.DisjunctiveHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.DisjunctiveHead; /** * Copyright (c) 2017, the Alpha Team. diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/Heads.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/Heads.java similarity index 52% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/Heads.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/Heads.java index 9e529a7e7..d2d271258 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/Heads.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/Heads.java @@ -1,15 +1,17 @@ -package at.ac.tuwien.kr.alpha.commons.rules.heads; - -import java.util.List; +package at.ac.tuwien.kr.alpha.commons.programs.rules.heads; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead.ChoiceElement; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.commons.rules.heads.ChoiceHeadImpl.ChoiceElementImpl; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ActionHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead.ChoiceElement; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.ChoiceHeadImpl.ChoiceElementImpl; + +import java.util.List; public final class Heads { @@ -29,5 +31,9 @@ public static ChoiceHead newChoiceHead(List choiceElements, Term public static ChoiceElement newChoiceElement(BasicAtom choiceAtom, List conditionLiterals) { return new ChoiceElementImpl(choiceAtom, conditionLiterals); } + + public static ActionHead newActionHead(BasicAtom atom, String actionName, List actionInputTerms, VariableTerm actionResult) { + return new ActionHeadImpl(atom, actionName, actionInputTerms, actionResult); + } } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/NormalHeadImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/NormalHeadImpl.java similarity index 74% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/NormalHeadImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/NormalHeadImpl.java index 2cdfc4404..1422d8e75 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/rules/heads/NormalHeadImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/NormalHeadImpl.java @@ -1,7 +1,9 @@ -package at.ac.tuwien.kr.alpha.commons.rules.heads; +package at.ac.tuwien.kr.alpha.commons.programs.rules.heads; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.RuleInstantiator; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; /** * Represents a normal head, i.e., a head that is an Atom. @@ -26,6 +28,11 @@ public BasicAtom getAtom() { return atom; } + @Override + public BasicAtom instantiate(RuleInstantiator instantiator, Substitution substitution) { + return instantiator.instantiate(this, substitution); + } + @Override public String toString() { return atom.toString(); diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/AbstractActionResultTerm.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/AbstractActionResultTerm.java new file mode 100644 index 000000000..1eacea528 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/AbstractActionResultTerm.java @@ -0,0 +1,26 @@ +package at.ac.tuwien.kr.alpha.commons.programs.terms; + +import at.ac.tuwien.kr.alpha.api.programs.terms.ActionResultTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; + +import java.util.Collections; + +abstract class AbstractActionResultTerm extends FunctionTermImpl implements ActionResultTerm { + + AbstractActionResultTerm(String symbol, T value) { + super(symbol, Collections.singletonList(value)); + } + + public abstract boolean isSuccess(); + + public boolean isError() { + return !isSuccess(); + } + + // Note: Unchecked cast is ok, we permit only instances of T as constructor arguments. + @SuppressWarnings("unchecked") + public T getValue() { + return (T) getTerms().get(0); + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/AbstractTerm.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/AbstractTerm.java similarity index 91% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/AbstractTerm.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/AbstractTerm.java index 5db258d85..f9d1c3d7d 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/AbstractTerm.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/AbstractTerm.java @@ -1,14 +1,14 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import java.util.HashMap; import java.util.Map; import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; //@formatter:off /** diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ActionErrorTerm.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ActionErrorTerm.java new file mode 100644 index 000000000..40815fe80 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ActionErrorTerm.java @@ -0,0 +1,24 @@ +package at.ac.tuwien.kr.alpha.commons.programs.terms; + +import at.ac.tuwien.kr.alpha.api.programs.terms.ActionResultTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.commons.util.Interner; + +class ActionErrorTerm extends AbstractActionResultTerm> { + + private static final Interner INTERNER = new Interner<>(); + + ActionErrorTerm(ConstantTerm value) { + super(ActionResultTerm.ERROR_SYMBOL, value); + } + + public static ActionErrorTerm getInstance(ConstantTerm term) { + return INTERNER.intern(new ActionErrorTerm(term)); + } + + @Override + public boolean isSuccess() { + return false; + } + +} \ No newline at end of file diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ActionSuccessTerm.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ActionSuccessTerm.java new file mode 100644 index 000000000..c5a2fde14 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ActionSuccessTerm.java @@ -0,0 +1,25 @@ +package at.ac.tuwien.kr.alpha.commons.programs.terms; + +import at.ac.tuwien.kr.alpha.api.programs.terms.ActionResultTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.util.Interner; + +class ActionSuccessTerm extends AbstractActionResultTerm { + + private static final Interner> INTERNER = new Interner<>(); + + ActionSuccessTerm(T value) { + super(ActionResultTerm.SUCCESS_SYMBOL, value); + } + + @SuppressWarnings("unchecked") + public static ActionSuccessTerm getInstance(T term) { + return (ActionSuccessTerm) INTERNER.intern(new ActionSuccessTerm<>(term)); + } + + @Override + public boolean isSuccess() { + return true; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/ArithmeticTermImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ArithmeticTermImpl.java similarity index 95% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/ArithmeticTermImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ArithmeticTermImpl.java index fd2b780aa..8df7a76e8 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/ArithmeticTermImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ArithmeticTermImpl.java @@ -25,16 +25,16 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import java.util.LinkedHashSet; import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticOperator; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.util.Interner; /** diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/ConstantTermImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ConstantTermImpl.java similarity index 94% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/ConstantTermImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ConstantTermImpl.java index 4dcaec598..11e163d54 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/ConstantTermImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/ConstantTermImpl.java @@ -1,12 +1,12 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import java.util.Collections; import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.util.Interner; /** diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/FunctionTermImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/FunctionTermImpl.java similarity index 80% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/FunctionTermImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/FunctionTermImpl.java index 14b8535de..d993a0915 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/FunctionTermImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/FunctionTermImpl.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import java.util.ArrayList; import java.util.Arrays; @@ -8,9 +8,9 @@ import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.util.Interner; import at.ac.tuwien.kr.alpha.commons.util.Util; @@ -18,13 +18,14 @@ * Copyright (c) 2016-2017, the Alpha Team. */ class FunctionTermImpl extends AbstractTerm implements FunctionTerm { + private static final Interner INTERNER = new Interner<>(); private final String symbol; private final List terms; private final boolean ground; - private FunctionTermImpl(String symbol, List terms) { + FunctionTermImpl(String symbol, List terms) { if (symbol == null) { throw new IllegalArgumentException(); } @@ -97,16 +98,19 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (o == null) { + return false; + } + if (!(o instanceof FunctionTerm)) { return false; } - FunctionTermImpl that = (FunctionTermImpl) o; + FunctionTerm that = (FunctionTerm) o; - if (!symbol.equals(that.symbol)) { + if (!symbol.equals(that.getSymbol())) { return false; } - return terms.equals(that.terms); + return terms.equals(that.getTerms()); } @Override @@ -120,24 +124,24 @@ public int compareTo(Term o) { return 0; } - if (!(o instanceof FunctionTermImpl)) { + if (!(o instanceof FunctionTerm)) { return super.compareTo(o); } - FunctionTermImpl other = (FunctionTermImpl) o; + FunctionTerm other = (FunctionTerm) o; - if (terms.size() != other.terms.size()) { - return terms.size() - other.terms.size(); + if (terms.size() != other.getTerms().size()) { + return terms.size() - other.getTerms().size(); } - int result = symbol.compareTo(other.symbol); + int result = symbol.compareTo(other.getSymbol()); if (result != 0) { return result; } for (int i = 0; i < terms.size(); i++) { - result = terms.get(i).compareTo(other.terms.get(i)); + result = terms.get(i).compareTo(other.getTerms().get(i)); if (result != 0) { return result; } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/IntervalTermImpl.java similarity index 92% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/IntervalTermImpl.java index eb14b44f7..f91af0c40 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/IntervalTermImpl.java @@ -1,12 +1,12 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import java.util.LinkedHashSet; import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.util.Interner; /** diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/Terms.java similarity index 90% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/Terms.java index c651a70aa..7d0ac9971 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/Terms.java @@ -1,19 +1,13 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import java.util.ArrayList; import java.util.List; import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.*; +import at.ac.tuwien.kr.alpha.commons.programs.terms.ArithmeticTermImpl.MinusTerm; import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; -import at.ac.tuwien.kr.alpha.commons.terms.ArithmeticTermImpl.MinusTerm; /** * Convenience methods for {@link Term}s. The methods provided here are an @@ -70,6 +64,15 @@ public static IntervalTerm newIntervalTerm(Term lowerBound, Term upperBound) { return IntervalTermImpl.getInstance(lowerBound, upperBound); } + public static ActionResultTerm actionSuccess(T value) { + return ActionSuccessTerm.getInstance(value); + } + + public static ActionResultTerm> actionError(String errMsg) { + return ActionErrorTerm.getInstance(Terms.newConstant(errMsg)); + } + + @SafeVarargs public static > List> asTermList(T... values) { List> retVal = new ArrayList<>(); diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/VariableTermImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/VariableTermImpl.java similarity index 94% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/VariableTermImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/VariableTermImpl.java index 5e892b480..221c83aa4 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/VariableTermImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/VariableTermImpl.java @@ -1,11 +1,11 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import java.util.Collections; import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; import at.ac.tuwien.kr.alpha.commons.util.Interner; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/AssertionImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/AssertionImpl.java new file mode 100644 index 000000000..a62753c8e --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/AssertionImpl.java @@ -0,0 +1,31 @@ +package at.ac.tuwien.kr.alpha.commons.programs.tests; + +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.tests.Assertion; + +class AssertionImpl implements Assertion { + + private final Mode mode; + private final InputProgram verifier; + + AssertionImpl(final Mode mode, final InputProgram verifier) { + this.mode = mode; + this.verifier = verifier; + } + + @Override + public Mode getMode() { + return mode; + } + + @Override + public InputProgram getVerifier() { + return verifier; + } + + @Override + public String toString() { + return "assert" + mode.toString() + " {" + System.lineSeparator() + verifier.toString() + "}"; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/TestCaseImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/TestCaseImpl.java new file mode 100644 index 000000000..765db2c81 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/TestCaseImpl.java @@ -0,0 +1,53 @@ +package at.ac.tuwien.kr.alpha.commons.programs.tests; + +import java.util.List; +import java.util.Set; +import java.util.function.IntPredicate; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; +import at.ac.tuwien.kr.alpha.commons.util.Util; + +class TestCaseImpl implements TestCase { + + private final String name; + private final IntPredicate answerSetCountVerifier; + private final Set input; + private final List assertions; + + TestCaseImpl(final String name, final IntPredicate answerSetCountVerifier, final Set input, final List assertions) { + this.name = name; + this.answerSetCountVerifier = answerSetCountVerifier; + this.input = input; + this.assertions = assertions; + } + + @Override + public String getName() { + return name; + } + + @Override + public IntPredicate getAnswerSetCountVerifier() { + return answerSetCountVerifier; + } + + @Override + public Set getInput() { + return input; + } + + @Override + public List getAssertions() { + return assertions; + } + + public String toString() { + String ls = System.lineSeparator(); + String inputString = input.isEmpty() ? "" : Util.join("{", input, ls, "}"); + String assertionsString = assertions.isEmpty() ? "" : Util.join(ls, assertions, ls, ls); + return "#test " + name + "(expect: " + answerSetCountVerifier.toString() + ") { " + ls + "given " + inputString + assertionsString + "}"; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/Tests.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/Tests.java new file mode 100644 index 000000000..a750dc7c4 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/tests/Tests.java @@ -0,0 +1,90 @@ +package at.ac.tuwien.kr.alpha.commons.programs.tests; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.IntPredicate; + +import at.ac.tuwien.kr.alpha.api.ComparisonOperator; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestResult; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; + +public final class Tests { + + private Tests() { + throw new AssertionError("Cannot instantiate utility class!"); + } + + public static TestCase newTestCase(final String name, final IntPredicate answerSetCountVerifier, final Set input, final List assertions) { + return new TestCaseImpl(name, answerSetCountVerifier, input, assertions); + } + + public static Assertion newAssertion(final Assertion.Mode mode, final InputProgram verifier) { + return new AssertionImpl(mode, verifier); + } + + public static IntPredicate newIsUnsatCondition() { + return new IntPredicate() { + @Override + public boolean test(int value) { + return value == 0; + } + + @Override + public String toString() { + return "unsat"; + } + + }; + } + + public static IntPredicate newAnswerSetCountCondition(ComparisonOperator cmpOp, int number) { + return new IntPredicate() { + @Override + public boolean test(int value) { + return cmpOp.compare(Terms.newConstant(value), Terms.newConstant(number)); + } + + @Override + public String toString() { + return cmpOp.toString() + " " + Integer.toString(number); + } + + }; + } + + public static TestResult.TestCaseResult newTestCaseResult(String testCaseName, Optional answerSetCountResult, int assertionsPassed, int assertionsFailed, Map> assertionErrors) { + return new TestResult.TestCaseResult() { + @Override + public String getTestCaseName() { + return testCaseName; + } + + @Override + public Optional answerSetCountVerificationResult() { + return answerSetCountResult; + } + + @Override + public int getAssertionsPassed() { + return assertionsPassed; + } + + @Override + public int getAssertionsFailed() { + return assertionsFailed; + } + + @Override + public Map> getAssertionErrors() { + return assertionErrors; + } + }; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/BasicSubstitution.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/BasicSubstitution.java index df8d26d6a..72d79ee53 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/BasicSubstitution.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/BasicSubstitution.java @@ -27,21 +27,21 @@ */ package at.ac.tuwien.kr.alpha.commons.substitutions; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.util.Util; + import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeMap; -import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.util.Util; - public class BasicSubstitution implements at.ac.tuwien.kr.alpha.api.grounder.Substitution { public static final Substitution EMPTY_SUBSTITUTION = new BasicSubstitution() { @@ -193,7 +193,7 @@ public boolean isEmpty() { @Override public boolean isVariableSet(VariableTerm variable) { - return substitution.get(variable) != null; + return substitution.containsKey(variable); } public Set getMappedVariables() { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Instance.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Instance.java index aa707ff36..dca9d526c 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Instance.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Instance.java @@ -6,7 +6,7 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.util.Util; /** diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Unifier.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Unifier.java index 06033cf51..90889b3ce 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Unifier.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/substitutions/Unifier.java @@ -10,8 +10,8 @@ import java.util.TreeMap; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; /** * A variable substitution allowing variables to occur on the right-hand side. Chains of variable substitutions are diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/IdGenerator.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/IdGenerator.java new file mode 100644 index 000000000..526dee3d9 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/IdGenerator.java @@ -0,0 +1,14 @@ +package at.ac.tuwien.kr.alpha.commons.util; + +/** + * A generator of (per instance) unique values that can be used for uniquely identifying internal variables, etc. + */ +@FunctionalInterface +public interface IdGenerator { + + /** + * Retrieves the next identifier value from the internal sequence of this id generator. + */ + T getNextId(); + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/IntIdGenerator.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/IntIdGenerator.java index df044d1b7..f807609d3 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/IntIdGenerator.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/util/IntIdGenerator.java @@ -6,7 +6,7 @@ * Generates unique, sequential integers starting at 0, i.e., it maintains a counter that is incremented for each getNextId(). * Copyright (c) 2016, the Alpha Team. */ -public class IntIdGenerator { +public class IntIdGenerator implements IdGenerator { private int highestId; public IntIdGenerator() { @@ -17,7 +17,7 @@ public IntIdGenerator(int initial) { this.highestId = initial; } - public int getNextId() { + public Integer getNextId() { if (highestId == Integer.MAX_VALUE) { throw oops("Ran out of IDs (integer overflow)"); } diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/BasicAnswerSetTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/BasicAnswerSetTest.java index 5c1de5dcf..fff2ef4e3 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/BasicAnswerSetTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/BasicAnswerSetTest.java @@ -16,9 +16,9 @@ import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; /** * Copyright (c) 2016, the Alpha Team. diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibraryTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibraryTest.java index 75efaa200..2569c8f3e 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibraryTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibraryTest.java @@ -6,11 +6,12 @@ import java.util.List; import java.util.Set; +import java.util.function.Function; import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; public class AspStandardLibraryTest { @@ -104,4 +105,50 @@ public void stringConcat() { assertEquals(Terms.newConstant("Foobar"), concat); } + @Test + public void stringParseValidInteger() { + Set>> result = AspStandardLibrary.stringParseInteger("123"); + assertEquals(1, result.size()); + List> intTerms = result.stream().findFirst().get(); + assertEquals(1, intTerms.size()); + Integer value = intTerms.get(0).getObject(); + assertEquals(123, value); + } + + @Test + public void stringParseInvalidInteger() { + assertTrue(AspStandardLibrary.stringParseInteger("bla").isEmpty()); + } + + @Test + public void stringEmpty() { + assertTrue(AspStandardLibrary.isStringEmpty("")); + assertFalse(AspStandardLibrary.isStringEmpty("bla")); + } + + @Test + public void substringValidRange() { + Set>> result = AspStandardLibrary.substringOfString("hahaha", 1, 4); + assertEquals(1, result.size()); + List> terms = result.stream().findFirst().get(); + assertEquals(1, terms.size()); + String substr = terms.get(0).getObject(); + assertEquals("aha", substr); + } + + @Test + public void substringInvalidRange() { + assertTrue(AspStandardLibrary.substringOfString("foo", 1, 0).isEmpty()); + } + + @Test + public void stringGetHead() { + Function>>, String> extractString = (set) -> { + return set.stream().findFirst().get().get(0).getObject(); + }; + assertTrue(AspStandardLibrary.stringHeadRemainder("").isEmpty()); + assertEquals("x", extractString.apply(AspStandardLibrary.stringHeadRemainder("x"))); + assertEquals("x", extractString.apply(AspStandardLibrary.stringHeadRemainder("xy"))); + } + } diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/atoms/BasicAtomImplTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImplTest.java similarity index 85% rename from alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/atoms/BasicAtomImplTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImplTest.java index 275aa413e..a500b850a 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/atoms/BasicAtomImplTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImplTest.java @@ -1,14 +1,11 @@ -package at.ac.tuwien.kr.alpha.commons.atoms; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; /** * Test for basic functionality of various implementations of {@link Atom}. @@ -56,12 +53,12 @@ public void testAreBasicAtomsEqual() { Terms.newFunctionTerm("r", Terms.newConstant("bla"), Terms.newVariable("BLUBB"))); assertEquals(a7, a8); - assertFalse(a1.equals(a3)); - assertFalse(a3.equals(a1)); - assertFalse(a1.equals(a5)); - assertFalse(a5.equals(a1)); - assertFalse(a1.equals(a7)); - assertFalse(a7.equals(a1)); + assertNotEquals(a1, a3); + assertNotEquals(a3, a1); + assertNotEquals(a1, a5); + assertNotEquals(a5, a1); + assertNotEquals(a1, a7); + assertNotEquals(a7, a1); } } diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/atoms/ExternalAtomImplTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImplTest.java similarity index 82% rename from alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/atoms/ExternalAtomImplTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImplTest.java index d762709b5..9365625f6 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/atoms/ExternalAtomImplTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImplTest.java @@ -1,27 +1,18 @@ -package at.ac.tuwien.kr.alpha.commons.atoms; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.junit.jupiter.api.Test; +package at.ac.tuwien.kr.alpha.commons.programs.atoms; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.externals.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.externals.Externals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; public class ExternalAtomImplTest { @@ -83,9 +74,9 @@ public void testAreExternalAtomsEqual() { assertEquals(ext1, ext2); assertEquals(ext2, ext1); - assertFalse(ext1.equals(null)); - assertFalse(ext1.equals("bla")); - assertTrue(ext1.hashCode() == ext2.hashCode()); + assertNotEquals(null, ext1); + assertNotEquals("bla", ext1); + assertEquals(ext1.hashCode(), ext2.hashCode()); } @Test diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/literals/LiteralBindingNonBindingVariablesTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/literals/LiteralBindingNonBindingVariablesTest.java similarity index 88% rename from alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/literals/LiteralBindingNonBindingVariablesTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/literals/LiteralBindingNonBindingVariablesTest.java index e60887fed..8bd512135 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/literals/LiteralBindingNonBindingVariablesTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/literals/LiteralBindingNonBindingVariablesTest.java @@ -23,29 +23,25 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.literals; +package at.ac.tuwien.kr.alpha.commons.programs.literals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; import at.ac.tuwien.kr.alpha.commons.externals.IntPredicateInterpretation; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; /** * Tests the behaviour of {@link Literal#getBindingVariables()} and {@link Literal#getNonBindingVariables()} @@ -58,7 +54,7 @@ public class LiteralBindingNonBindingVariablesTest { public void testPositiveBasicLiteral() { // literal := q(X, Y) Literal literal = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("q", 2), Terms.newVariable("X"), Terms.newVariable("Y")), true); - assertEquals(false, literal.isNegated()); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "X", "Y"); expectVariables(literal.getNonBindingVariables()); } @@ -67,7 +63,7 @@ public void testPositiveBasicLiteral() { public void testNegativeBasicLiteral() { // literal := not r(X, Y) Literal literal = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("r", 2), Terms.newVariable("X"), Terms.newVariable("Y")), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "X", "Y"); } @@ -76,7 +72,7 @@ public void testNegativeBasicLiteral() { public void testPositiveComparisonLiteral_EQ_LeftAssigning() { // literal := Y = 5 Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.EQ), true); - assertEquals(false, literal.isNegated()); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @@ -85,7 +81,7 @@ public void testPositiveComparisonLiteral_EQ_LeftAssigning() { public void testNegativeComparisonLiteral_EQ_LeftAssigning() { // literal := not Y = 5 Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.EQ), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } @@ -94,7 +90,7 @@ public void testNegativeComparisonLiteral_EQ_LeftAssigning() { public void testPositiveComparisonLiteral_EQ_RightAssigning() { // literal := 5 = Y Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.EQ), true); - assertEquals(false, literal.isNegated()); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @@ -103,7 +99,7 @@ public void testPositiveComparisonLiteral_EQ_RightAssigning() { public void testNegativeComparisonLiteral_EQ_RightAssigning() { // literal := 5 = Y Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.EQ), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } @@ -112,7 +108,7 @@ public void testNegativeComparisonLiteral_EQ_RightAssigning() { public void testNegativeComparisonLiteral_EQ_Bidirectional() { // literal := not X = Y Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("X"), Terms.newVariable("Y"), ComparisonOperators.EQ), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "X", "Y"); } @@ -121,7 +117,7 @@ public void testNegativeComparisonLiteral_EQ_Bidirectional() { public void testPositiveComparisonLiteral_NEQ_LeftAssigning() { // literal := Y != 5 Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.NE), true); - assertEquals(false, literal.isNegated()); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } @@ -130,7 +126,7 @@ public void testPositiveComparisonLiteral_NEQ_LeftAssigning() { public void testNegativeComparisonLiteral_NEQ_LeftAssigning() { // literal := not Y != 5 Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.NE), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @@ -139,7 +135,7 @@ public void testNegativeComparisonLiteral_NEQ_LeftAssigning() { public void testPositiveComparisonLiteral_NEQ_RightAssigning() { // literal := 5 != Y Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.NE), true); - assertEquals(false, literal.isNegated()); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } @@ -148,7 +144,7 @@ public void testPositiveComparisonLiteral_NEQ_RightAssigning() { public void testNegativeComparisonLiteral_NEQ_RightAssigning() { // literal := not 5 != Y Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.NE), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @@ -157,7 +153,7 @@ public void testNegativeComparisonLiteral_NEQ_RightAssigning() { public void testPositiveComparisonLiteral_NEQ_Bidirectional() { // literal := X != Y Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("X"), Terms.newVariable("Y"), ComparisonOperators.NE), true); - assertEquals(false, literal.isNegated()); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "X", "Y"); } @@ -167,7 +163,7 @@ public void testPositiveComparisonLiteral_NEQ_Bidirectional() { public void testNegativeComparisonLiteral_NEQ_Bidirectional() { // literal := not X != Y Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("X"), Terms.newVariable("Y"), ComparisonOperators.NE), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables(), "X", "Y"); expectVariables(literal.getNonBindingVariables()); } @@ -180,7 +176,7 @@ public void testPositiveExternalLiteral() { extInput.add(Terms.newVariable("Y")); extOutput.add(Terms.newVariable("X")); Literal literal = Literals.fromAtom(Atoms.newExternalAtom(Predicates.getPredicate("ext", 2), new IntPredicateInterpretation(i -> i > 0), extInput, extOutput), true); - assertEquals(false, literal.isNegated()); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "X"); expectVariables(literal.getNonBindingVariables(), "Y"); } @@ -193,7 +189,7 @@ public void testNegativeExternalLiteral() { extInput.add(Terms.newVariable("Y")); extOutput.add(Terms.newVariable("X")); Literal literal = Literals.fromAtom(Atoms.newExternalAtom(Predicates.getPredicate("ext", 2), new IntPredicateInterpretation(i -> i > 0), extInput, extOutput), false); - assertEquals(true, literal.isNegated()); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "X", "Y"); } diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermTest.java similarity index 93% rename from alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermTest.java index ebb36c0b8..32c44da2d 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermTest.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -13,12 +13,12 @@ import org.junit.jupiter.api.Test; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticOperator; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; /** diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermsTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermsTest.java similarity index 56% rename from alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermsTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermsTest.java index 4c4600dc8..50e5afb51 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermsTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermsTest.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -6,7 +6,8 @@ import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; public class TermsTest { @@ -30,4 +31,15 @@ public void stringsAsTermList() { assertEquals("\"blubb\"", terms.get(1).toString()); } + /** + * Reproduction test for an error observed while testing evolog actions. + */ + @Test + public void functionTermVsActionSuccessTermHash() { + FunctionTerm funcTerm = Terms.newFunctionTerm("success", Terms.newFunctionTerm("stream", Terms.newConstant("outputStream_2"))); + FunctionTerm actionSuccessTerm = Terms.actionSuccess(Terms.newFunctionTerm("stream", Terms.newConstant("outputStream_2"))); + assertEquals(funcTerm, actionSuccessTerm); + assertEquals(funcTerm.hashCode(), actionSuccessTerm.hashCode()); + } + } diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TestMinusTerm.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TestMinusTerm.java similarity index 86% rename from alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TestMinusTerm.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TestMinusTerm.java index ea7a02728..71132647c 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TestMinusTerm.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TestMinusTerm.java @@ -23,16 +23,16 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.commons.terms; +package at.ac.tuwien.kr.alpha.commons.programs.terms; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.Term.RenameCounter; -import at.ac.tuwien.kr.alpha.commons.terms.AbstractTerm.RenameCounterImpl; -import at.ac.tuwien.kr.alpha.commons.terms.ArithmeticTermImpl.MinusTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term.RenameCounter; +import at.ac.tuwien.kr.alpha.commons.programs.terms.AbstractTerm.RenameCounterImpl; +import at.ac.tuwien.kr.alpha.commons.programs.terms.ArithmeticTermImpl.MinusTerm; /** * Tests {@link MinusTerm} diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/AnswerSetQueryTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/AtomQueryTest.java similarity index 81% rename from alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/AnswerSetQueryTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/AtomQueryTest.java index cc81e6af9..b7dcc1859 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/AnswerSetQueryTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/AtomQueryTest.java @@ -14,15 +14,16 @@ import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AtomQuery; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; import at.ac.tuwien.kr.alpha.commons.AnswerSets; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; -public class AnswerSetQueryTest { +public class AtomQueryTest { @Test public void matchPredicate() { @@ -35,7 +36,7 @@ public void matchPredicate() { .symbolicInstance("x"); //@formatter:on AnswerSet as = bld.build(); - List queryResult = as.query(AnswerSetQueryImpl.forPredicate(Predicates.getPredicate("p", 1))); + List queryResult = as.query(Atoms.query(Predicates.getPredicate("p", 1))); assertEquals(2, queryResult.size()); for (Atom a : queryResult) { assertTrue(a.getPredicate().equals(Predicates.getPredicate("p", 1))); @@ -49,8 +50,7 @@ public void matchSymbolicConstant() { .symbolicInstance("a") .instance("a"); AnswerSet as = bld.build(); - AnswerSetQueryImpl constantQuery = AnswerSetQueryImpl - .forPredicate(Predicates.getPredicate("p", 1)) + AtomQuery constantQuery = Atoms.query(Predicates.getPredicate("p", 1)) .withConstantEquals(0, "a"); List queryResult = as.query(constantQuery); assertEquals(1, queryResult.size()); @@ -63,8 +63,7 @@ public void matchString() { .symbolicInstance("a") .instance("a"); AnswerSet as = bld.build(); - AnswerSetQueryImpl stringQuery = AnswerSetQueryImpl - .forPredicate(Predicates.getPredicate("p", 1)) + AtomQuery stringQuery = Atoms.query(Predicates.getPredicate("p", 1)) .withStringEquals(0, "a"); List queryResult = as.query(stringQuery); assertEquals(1, queryResult.size()); @@ -84,7 +83,7 @@ public void matchEvenIntegers() { String strValue = ((ConstantTerm) term).getObject().toString(); return strValue.matches("[0-9]+"); }; - AnswerSetQueryImpl evenIntegers = AnswerSetQueryImpl.forPredicate(Predicates.getPredicate("p", 1)) + AtomQuery evenIntegers = Atoms.query(Predicates.getPredicate("p", 1)) .withFilter(0, isInteger.and( (term) -> Integer.valueOf(((ConstantTerm) term).getObject().toString()) % 2 == 0)); List queryResult = as.query(evenIntegers); @@ -114,11 +113,11 @@ public void matchXWithFuncTerm() { ps.add(a5); instances.put(p, ps); AnswerSet as = AnswerSets.newAnswerSet(predicates, instances); - AnswerSetQueryImpl query = AnswerSetQueryImpl.forPredicate(Predicates.getPredicate("p", 2)).withConstantEquals(0, "x").withFunctionTerm(1, "f", 1); + AtomQuery query = Atoms.query(Predicates.getPredicate("p", 2)).withConstantEquals(0, "x").withFunctionTerm(1, "f", 1); List queryResult = as.query(query); assertEquals(2, queryResult.size()); } - + @Test public void matchTerm() { AnswerSetBuilder bld = new AnswerSetBuilder(); @@ -126,8 +125,8 @@ public void matchTerm() { .instance(1).instance(2).instance(3).instance(4).instance(5) .instance("bla").symbolicInstance("blubb"); AnswerSet as = bld.build(); - - AnswerSetQueryImpl equalTerm = AnswerSetQueryImpl.forPredicate(Predicates.getPredicate("p", 1)).withTermEquals(0, Terms.newConstant(1)); + + AtomQuery equalTerm = Atoms.query(Predicates.getPredicate("p", 1)).withTermEquals(0, Terms.newConstant(1)); List queryResult = as.query(equalTerm); assertEquals(1, queryResult.size()); Atom retrievedAtom = queryResult.get(0); diff --git a/alpha-core/.gitignore b/alpha-core/.gitignore index 84c048a73..c07308f42 100644 --- a/alpha-core/.gitignore +++ b/alpha-core/.gitignore @@ -1 +1,2 @@ /build/ +/src/main/gen/ diff --git a/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPCore2.g4 b/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPCore2.g4 index 4f80be1a2..bbd952cad 100644 --- a/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPCore2.g4 +++ b/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPCore2.g4 @@ -20,7 +20,9 @@ statement : head DOT # statement_fact | WCONS body? DOT SQUARE_OPEN weight_at_level SQUARE_CLOSE # statement_weightConstraint | directive # statement_directive; // NOT Core2 syntax. -head : disjunction | choice; +head : disjunction | choice | action; + +action: classical_literal COLON AT ID SQUARE_OPEN terms SQUARE_CLOSE EQUAL variable_term; // NOT Core2 syntax body : ( naf_literal | aggregate ) (COMMA body)?; @@ -46,7 +48,11 @@ naf_literals : naf_literal (COMMA naf_literals)?; naf_literal : NAF? (external_atom | classical_literal | builtin_atom); -classical_literal : MINUS? ID (PAREN_OPEN terms PAREN_CLOSE)?; +id : ID | TEST_EXPECT | TEST_UNSAT | TEST_GIVEN | TEST_ASSERT_ALL | TEST_ASSERT_SOME | DIRECTIVE_ENUM | DIRECTIVE_TEST; + +basic_atom : id (PAREN_OPEN terms PAREN_CLOSE)?; + +classical_literal : MINUS? basic_atom; builtin_atom : term binop term; @@ -54,8 +60,8 @@ binop : EQUAL | UNEQUAL | LESS | GREATER | LESS_OR_EQ | GREATER_OR_EQ; terms : term (COMMA terms)?; -term : ID # term_const - | ID (PAREN_OPEN terms? PAREN_CLOSE) # term_func +term : id # term_const + | id (PAREN_OPEN terms? PAREN_CLOSE) # term_func | numeral # term_number | QUOTED_STRING # term_string | VARIABLE # term_variable @@ -75,20 +81,34 @@ interval : lower = interval_bound DOT DOT upper = interval_bound; // NOT Core2 s interval_bound : numeral | VARIABLE; -external_atom : MINUS? AMPERSAND ID (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; // NOT Core2 syntax. +external_atom : MINUS? AMPERSAND id (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; // NOT Core2 syntax. -directive : directive_enumeration; // NOT Core2 syntax, allows solver specific directives. Further directives shall be added here. +directive : directive_enumeration | directive_test; // NOT Core2 syntax, allows solver specific directives. Further directives shall be added here. -directive_enumeration : SHARP 'enumeration_predicate_is' ID DOT; // NOT Core2 syntax, used for aggregate translation. +directive_enumeration : SHARP DIRECTIVE_ENUM id DOT; // NOT Core2 syntax, used for aggregate translation. + +// Alpha-specific language extension: Unit Tests (-> https://github.com/alpha-asp/Alpha/issues/237) +directive_test : SHARP DIRECTIVE_TEST id PAREN_OPEN test_satisfiability_condition PAREN_CLOSE CURLY_OPEN test_input test_assert* CURLY_CLOSE; basic_terms : basic_term (COMMA basic_terms)? ; basic_term : ground_term | variable_term; -ground_term : /*SYMBOLIC_CONSTANT*/ ID | QUOTED_STRING | numeral; +ground_term : /*SYMBOLIC_CONSTANT*/ id | QUOTED_STRING | numeral; variable_term : VARIABLE | ANONYMOUS_VARIABLE; answer_set : CURLY_OPEN classical_literal? (COMMA classical_literal)* CURLY_CLOSE; -answer_sets: answer_set* EOF; \ No newline at end of file +answer_sets : answer_set* EOF; + +test_satisfiability_condition : TEST_EXPECT COLON (TEST_UNSAT | (binop? NUMBER)); + +test_input : TEST_GIVEN CURLY_OPEN (basic_atom DOT)* CURLY_CLOSE; + +test_assert : test_assert_all | test_assert_some; + +test_assert_all : TEST_ASSERT_ALL CURLY_OPEN statements? CURLY_CLOSE; + +test_assert_some : TEST_ASSERT_SOME CURLY_OPEN statements? CURLY_CLOSE; + diff --git a/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPLexer.g4 b/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPLexer.g4 index a900ca342..1e5582d82 100644 --- a/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPLexer.g4 +++ b/alpha-core/src/main/antlr/at/ac/tuwien/kr/alpha/core/antlr/ASPLexer.g4 @@ -40,6 +40,16 @@ AGGREGATE_MAX : '#max'; AGGREGATE_MIN : '#min'; AGGREGATE_SUM : '#sum'; +DIRECTIVE_ENUM : 'enumeration_predicate_is'; + +DIRECTIVE_TEST : 'test'; +TEST_EXPECT : 'expect'; +TEST_UNSAT : 'unsat'; +TEST_GIVEN : 'given'; +TEST_ASSERT_ALL : 'assertForAll'; +TEST_ASSERT_SOME : 'assertForSome'; + + ID : ('a'..'z') ( 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' )*; VARIABLE : ('A'..'Z') ( 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' )*; NUMBER : '0' | ('1'..'9') ('0'..'9')*; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/AbstractActionImplementationProvider.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/AbstractActionImplementationProvider.java new file mode 100644 index 000000000..c23352dbd --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/AbstractActionImplementationProvider.java @@ -0,0 +1,214 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; +import at.ac.tuwien.kr.alpha.api.programs.actions.Action; +import at.ac.tuwien.kr.alpha.api.programs.terms.ActionResultTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; + +import java.io.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class AbstractActionImplementationProvider implements ActionImplementationProvider { + + private final IntIdGenerator idGenerator = new IntIdGenerator(); + private final Map supportedActions = new HashMap<>(); + + private ConstantTerm stdoutHandle; + private ConstantTerm stdinHandle; + + public AbstractActionImplementationProvider() { + registerAction("fileOutputStream", this::openFileOutputStreamAction); + registerAction("streamWrite", this::outputStreamWriteAction); + registerAction("outputStreamClose", this::outputStreamCloseAction); + registerAction("fileInputStream", this::openFileInputStreamAction); + registerAction("streamReadLine", this::inputStreamReadLineAction); + registerAction("inputStreamClose", this::inputStreamCloseAction); + } + + /** + * Returns a map of all actions supported by this implementation provider. + */ + @Override + public final Map getSupportedActions() { + return supportedActions; + } + + /** + * Returns a predicate interpretation specifying an external that takes no arguments + * and returns a reference to the standard system output stream (stdout). + */ + @Override + public final PredicateInterpretation getStdoutTerm() { + if (stdoutHandle == null) { + stdoutHandle = Terms.newConstant(new OutputStreamHandle(idGenerator.getNextId(), getStdoutStream())); + } + return (trms) -> { + if (!trms.isEmpty()) { + throw new IllegalArgumentException("Invalid method call! Expected term list to be empty!"); + } + return Collections.singleton(Collections.singletonList(stdoutHandle)); + }; + } + + /** + * Returns a predicate interpretation specifying an external that takes no arguments + * and returns a reference to the standard system input stream (stdin). + */ + @Override + public final PredicateInterpretation getStdinTerm() { + if (stdinHandle == null) { + stdinHandle = Terms.newConstant(new InputStreamHandle(idGenerator.getNextId(), + new BufferedReader(new InputStreamReader(getStdinStream())))); + } + return (trms) -> { + if (!trms.isEmpty()) { + throw new IllegalArgumentException("Invalid method call! Expected term list to be empty!"); + } + return Collections.singleton(Collections.singletonList(stdinHandle)); + }; + } + + protected final void registerAction(String name, Action action) { + supportedActions.put(name, action); + } + + private ActionResultTerm openFileOutputStreamAction(List input) { + if (input.size() != 1) { + return Terms.actionError("Incorrect input size!"); + } + Term inTerm = input.get(0); + if (!(inTerm instanceof ConstantTerm)) { + return Terms.actionError("Input must be a string constant!"); + } + ConstantTerm inConst = (ConstantTerm) inTerm; + if (!(inConst.getObject() instanceof String) || inConst.isSymbolic()) { + return Terms.actionError("Input must be a string constant!"); + } + String path = (String) inConst.getObject(); + try { + OutputStreamHandle streamHandle = new OutputStreamHandle(idGenerator.getNextId(), getFileOutputStream(path)); + return Terms.actionSuccess(Terms.newFunctionTerm("stream", Terms.newConstant(streamHandle))); + } catch (IOException e) { + return Terms.actionError("File not found: " + path); + } + } + + @SuppressWarnings("unchecked") + private ActionResultTerm> outputStreamWriteAction(List input) { + if (input.size() != 2) { + return Terms.actionError("Incorrect input size!"); + } + if (!(input.get(0) instanceof ConstantTerm) || !(((ConstantTerm) input.get(0)).getObject() instanceof OutputStreamHandle)) { + return Terms.actionError("First input term must be an output stream handle!"); + } + OutputStreamHandle dstHandle = ((ConstantTerm) input.get(0)).getObject(); + if (!(input.get(1) instanceof ConstantTerm) || !(((ConstantTerm) input.get(1)).getObject() instanceof String) + || ((ConstantTerm) input.get(1)).isSymbolic()) { + return Terms.actionError("Second input term must be a string constant!"); + } + String str = ((ConstantTerm) input.get(1)).getObject(); + // TODO this needs some built-in conversion function + byte[] data = str.getBytes(); + OutputStream dst = dstHandle.getStream(); + try { + dst.write(data); + return Terms.actionSuccess(Terms.newSymbolicConstant("ok")); + } catch (IOException ex) { + return Terms.actionError("Error writing data: " + ex.getMessage()); + } + } + + @SuppressWarnings("unchecked") + private ActionResultTerm> outputStreamCloseAction(List input) { + if (input.size() != 1) { + return Terms.actionError("Incorrect input size!"); + } + if (!(input.get(0) instanceof ConstantTerm) || !(((ConstantTerm) input.get(0)).getObject() instanceof OutputStreamHandle)) { + return Terms.actionError("First input term must be an output stream handle!"); + } + OutputStreamHandle handle = ((ConstantTerm) input.get(0)).getObject(); + try { + handle.getStream().close(); + return Terms.actionSuccess(Terms.newSymbolicConstant("ok")); + } catch (IOException ex) { + return Terms.actionError("Error closing stream: " + ex.getMessage()); + } + } + + private ActionResultTerm openFileInputStreamAction(List input) { + if (input.size() != 1) { + return Terms.actionError("Incorrect input size!"); + } + Term inTerm = input.get(0); + if (!(inTerm instanceof ConstantTerm)) { + return Terms.actionError("Input must be a string constant!"); + } + ConstantTerm inConst = (ConstantTerm) inTerm; + if (!(inConst.getObject() instanceof String) || inConst.isSymbolic()) { + return Terms.actionError("Input must be a string constant!"); + } + String path = (String) inConst.getObject(); + try { + InputStreamHandle streamHandle = new InputStreamHandle(idGenerator.getNextId(), new BufferedReader(new InputStreamReader(getInputStream(path)))); + return Terms.actionSuccess(Terms.newFunctionTerm("stream", Terms.newConstant(streamHandle))); + } catch (IOException ex) { + return Terms.actionError("Error opening input stream: " + ex.getMessage()); + } + } + + @SuppressWarnings("unchecked") + private ActionResultTerm inputStreamReadLineAction(List input) { + if (input.size() != 1) { + return Terms.actionError("Incorrect input size!"); + } + if (!(input.get(0) instanceof ConstantTerm) || !(((ConstantTerm) input.get(0)).getObject() instanceof InputStreamHandle)) { + return Terms.actionError("First input term must be an input stream handle!"); + } + InputStreamHandle handle = ((ConstantTerm) input.get(0)).getObject(); + try { + String line = handle.getStream().readLine(); + ConstantTerm lineTerm; + if (line == null) { + // we reached EOF + lineTerm = Terms.newSymbolicConstant("eof"); + } else { + lineTerm = Terms.newConstant(line); + } + return Terms.actionSuccess(Terms.newFunctionTerm("line", lineTerm)); + } catch (IOException ex) { + return Terms.actionError("Error reading data"); + } + } + + @SuppressWarnings("unchecked") + private ActionResultTerm inputStreamCloseAction(List input) { + if (input.size() != 1) { + return Terms.actionError("Incorrect input size!"); + } + if (!(input.get(0) instanceof ConstantTerm) || !(((ConstantTerm) input.get(0)).getObject() instanceof InputStreamHandle)) { + return Terms.actionError("First input term must be an input stream handle!"); + } + InputStreamHandle handle = ((ConstantTerm) input.get(0)).getObject(); + try { + handle.getStream().close(); + return Terms.actionSuccess(Terms.newFunctionTerm("closeResult", Terms.newSymbolicConstant("ok"))); + } catch (IOException ex) { + return Terms.actionError("Error writing data: " + ex.getMessage()); + } + } + + protected abstract OutputStream getStdoutStream(); + + protected abstract InputStream getStdinStream(); + + protected abstract OutputStream getFileOutputStream(String path) throws IOException; + + protected abstract InputStream getInputStream(String path) throws IOException; + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionExecutionService.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionExecutionService.java new file mode 100644 index 000000000..ef5d8daa6 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionExecutionService.java @@ -0,0 +1,12 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; + +import java.util.List; + +public interface ActionExecutionService { + + ActionWitness execute(String actionName, int sourceRuleId, Substitution sourceRuleInstance, List inputTerms); + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionExecutionServiceImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionExecutionServiceImpl.java new file mode 100644 index 000000000..4067e2182 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionExecutionServiceImpl.java @@ -0,0 +1,99 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.actions.Action; + +public class ActionExecutionServiceImpl implements ActionExecutionService { + + private final ActionImplementationProvider actionProvider; + private final Map actionRecord = new HashMap<>(); + + public ActionExecutionServiceImpl(ActionImplementationProvider implementationProvider) { + this.actionProvider = implementationProvider; + } + + @Override + public ActionWitness execute(String actionName, int sourceRuleId, Substitution sourceRuleInstance, List inputTerms) { + ActionInput actInput = new ActionInput(actionName, sourceRuleId, sourceRuleInstance, inputTerms); + return actionRecord.computeIfAbsent(actInput, this::execute); + } + + private ActionWitness execute(ActionInput input) { + Action action = actionProvider.getSupportedActions().get(input.name); + FunctionTerm result = action.execute(input.inputTerms); + return new ActionWitness(input.sourceRule, input.instance, input.name, input.inputTerms, result); + } + + private static class ActionInput { + + private final String name; + private final int sourceRule; + private final Substitution instance; + private final List inputTerms; + + public ActionInput(String name, int sourceRule, Substitution instance, List inputTerms) { + this.name = name; + this.sourceRule = sourceRule; + this.instance = instance; + this.inputTerms = inputTerms; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((inputTerms == null) ? 0 : inputTerms.hashCode()); + result = prime * result + ((instance == null) ? 0 : instance.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + sourceRule; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ActionInput other = (ActionInput) obj; + if (inputTerms == null) { + if (other.inputTerms != null) { + return false; + } + } else if (!inputTerms.equals(other.inputTerms)) { + return false; + } + if (instance == null) { + if (other.instance != null) { + return false; + } + } else if (!instance.equals(other.instance)) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (sourceRule != other.sourceRule) { + return false; + } + return true; + } + + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionImplementationProvider.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionImplementationProvider.java new file mode 100644 index 000000000..53157b7da --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionImplementationProvider.java @@ -0,0 +1,30 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import java.util.Map; + +import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; +import at.ac.tuwien.kr.alpha.api.programs.actions.Action; + +/** + * Interface for types providing action implementations. + */ +public interface ActionImplementationProvider { + + /** + * Returns a map of all actions supported by this implementation provider. + */ + Map getSupportedActions(); + + /** + * Returns a predicate interpretation specifying an external that takes no arguments + * and returns a reference to the standard system output stream (stdout). + */ + PredicateInterpretation getStdoutTerm(); + + /** + * Returns a predicate interpretation specifying an external that takes no arguments + * and returns a reference to the standard system input stream (stdin). + */ + PredicateInterpretation getStdinTerm(); + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionWitness.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionWitness.java new file mode 100644 index 000000000..265780719 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionWitness.java @@ -0,0 +1,44 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; + +import java.util.List; + +public class ActionWitness { + + private final int ruleId; + private final Substitution groundSubstitution; + private final String actionName; + private final List actionInput; + private final Term actionResult; + + public ActionWitness(int ruleId, Substitution groundSubstitution, String actionName, List actionInput, Term actionResult) { + this.ruleId = ruleId; + this.groundSubstitution = groundSubstitution; + this.actionName = actionName; + this.actionInput = actionInput; + this.actionResult = actionResult; + } + + public int getRuleId() { + return ruleId; + } + + public Substitution getGroundSubstitution() { + return groundSubstitution; + } + + public String getActionName() { + return actionName; + } + + public List getActionInput() { + return actionInput; + } + + public Term getActionResult() { + return actionResult; + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/DefaultActionImplementationProvider.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/DefaultActionImplementationProvider.java new file mode 100644 index 000000000..c6d9a26eb --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/DefaultActionImplementationProvider.java @@ -0,0 +1,32 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +public class DefaultActionImplementationProvider extends AbstractActionImplementationProvider { + + @Override + protected OutputStream getStdoutStream() { + return System.out; + } + + @Override + protected InputStream getStdinStream() { + return System.in; + } + + @Override + protected OutputStream getFileOutputStream(String path) throws IOException { + return Files.newOutputStream(Paths.get(path), StandardOpenOption.APPEND); + } + + @Override + protected InputStream getInputStream(String path) throws IOException { + return Files.newInputStream(Paths.get(path)); + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/InputStreamHandle.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/InputStreamHandle.java new file mode 100644 index 000000000..9692e555b --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/InputStreamHandle.java @@ -0,0 +1,49 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import java.io.BufferedReader; + +public class InputStreamHandle implements Comparable { + + private final int id; + private final BufferedReader stream; + + public InputStreamHandle(int id, BufferedReader stream) { + this.id = id; + this.stream = stream; + } + + public int getId() { + return id; + } + + public BufferedReader getStream() { + return stream; + } + + @Override + public String toString() { + return "inputStream_" + id; + } + + @Override + public int compareTo(InputStreamHandle other) { + return this.id - other.id; + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } else if (!(o instanceof InputStreamHandle)) { + return false; + } + InputStreamHandle other = (InputStreamHandle) o; + return this.id == other.id; + } + + @Override + public int hashCode() { + return this.id; + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/OutputStreamHandle.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/OutputStreamHandle.java new file mode 100644 index 000000000..272fee029 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/OutputStreamHandle.java @@ -0,0 +1,52 @@ +package at.ac.tuwien.kr.alpha.core.actions; + +import java.io.OutputStream; + +// TODO change this to wrap a PrintStream +// TODO we have a problem when parsing answer sets from strings for testing - currently no praseable string representation +// TODO of a ConstantTerm or some such +public class OutputStreamHandle implements Comparable { + + private final int id; + private final OutputStream stream; + + public OutputStreamHandle(int id, OutputStream stream) { + this.id = id; + this.stream = stream; + } + + public int getId() { + return id; + } + + public OutputStream getStream() { + return stream; + } + + @Override + public String toString() { + return "outputStream_" + id; + } + + @Override + public int compareTo(OutputStreamHandle other) { + return this.id - other.id; + } + + @Override + public boolean equals(Object o) { + if (o == null) { + return false; + } else if (!(o instanceof OutputStreamHandle)) { + return false; + } + OutputStreamHandle other = (OutputStreamHandle) o; + return this.id == other.id; + } + + @Override + public int hashCode() { + return this.id; + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/RuleAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/RuleAtom.java deleted file mode 100644 index 605bc8dfb..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/RuleAtom.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2016-2018, the Alpha Team. - * All rights reserved. - * - * Additional changes made by Siemens. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2) Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package at.ac.tuwien.kr.alpha.core.atoms; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; - -/** - * Atoms corresponding to rule bodies use this predicate, first term is rule number, - * second is a term containing variable substitutions. - */ -public class RuleAtom implements Atom { - public static final Predicate PREDICATE = Predicates.getPredicate("_R_", 2, true, true); - - private final List> terms; - - private RuleAtom(List> terms) { - if (terms.size() != 2) { - throw new IllegalArgumentException(); - } - - this.terms = terms; - } - - public RuleAtom(CompiledRule nonGroundRule, Substitution substitution) { - this(Arrays.asList( - Terms.newConstant(Integer.toString(nonGroundRule.getRuleId())), - Terms.newConstant(substitution.toString()))); - } - - @Override - public Predicate getPredicate() { - return PREDICATE; - } - - @Override - public List getTerms() { - return Arrays.asList(terms.get(0), terms.get(1)); - } - - @Override - public boolean isGround() { - // NOTE: Both terms are ConstantTerms, which are ground by definition. - return true; - } - - @Override - public Literal toLiteral(boolean positive) { - throw new UnsupportedOperationException("RuleAtom cannot be literalized"); - } - - @Override - public Atom substitute(Substitution substitution) { - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - RuleAtom that = (RuleAtom) o; - - return terms.equals(that.terms); - } - - @Override - public int hashCode() { - return 31 * PREDICATE.hashCode() + terms.hashCode(); - } - - @Override - public String toString() { - return PREDICATE.getName() + "(" + terms.get(0) + "," + terms.get(1) + ')'; - } - - @Override - public Atom withTerms(List terms) { - throw new UnsupportedOperationException("RuleAtoms do not support setting of terms!"); - } - - @Override - public Set getOccurringVariables() { - // RuleAtom has 2 terms which are both constants - return Collections.emptySet(); - } - - @Override - public Atom renameVariables(String newVariablePrefix) { - throw new UnsupportedOperationException("RuleAtom does not have any variables to rename!"); - } -} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/Assignment.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/Assignment.java index 47ae1790a..961323c41 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/Assignment.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/Assignment.java @@ -27,8 +27,8 @@ */ package at.ac.tuwien.kr.alpha.core.common; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isNegated; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isNegated; import java.util.Set; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStore.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStore.java index eeaa2f024..446d64e56 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStore.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStore.java @@ -27,8 +27,8 @@ */ package at.ac.tuwien.kr.alpha.core.common; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isNegated; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isNegated; import java.util.Iterator; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStoreImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStoreImpl.java index 4f9cf9a55..646a172a1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStoreImpl.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStoreImpl.java @@ -37,7 +37,7 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; import at.ac.tuwien.kr.alpha.commons.util.Util; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.solver.AtomCounter; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java index 3575669ba..826cf380e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java @@ -27,23 +27,23 @@ */ package at.ac.tuwien.kr.alpha.core.common; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isNegated; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.negateLiteral; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.positiveLiteral; -import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.INTERNAL; -import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.LEARNT; -import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.STATIC; -import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.SUPPORT; +import at.ac.tuwien.kr.alpha.commons.util.Util; +import at.ac.tuwien.kr.alpha.core.solver.Antecedent; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.stream.IntStream; -import at.ac.tuwien.kr.alpha.commons.util.Util; -import at.ac.tuwien.kr.alpha.core.solver.Antecedent; +import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.INTERNAL; +import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.LEARNT; +import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.STATIC; +import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.SUPPORT; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isNegated; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isPositive; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.negateLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.positiveLiteral; public class NoGood implements NoGoodInterface, Comparable { public static final int HEAD = 0; @@ -163,6 +163,11 @@ public void bumpActivity() { @Override public void decreaseActivity() { } + + @Override + public String toString() { + return NoGood.this + "(unwatched)"; + } }; } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/depgraph/DependencyGraphImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/depgraph/DependencyGraphImpl.java index e2e2200af..a58120ac6 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/depgraph/DependencyGraphImpl.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/depgraph/DependencyGraphImpl.java @@ -41,7 +41,7 @@ import at.ac.tuwien.kr.alpha.api.programs.literals.FixedInterpretationLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; /** * Internal representation of an {@link at.ac.tuwien.kr.alpha.core.programs.InternalProgram}'s dependency graph. The dependency graph tracks dependencies diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/BridgedGrounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/BridgedGrounder.java index 406ced3b0..8ebf24cb7 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/BridgedGrounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/BridgedGrounder.java @@ -8,7 +8,7 @@ import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; public abstract class BridgedGrounder extends AbstractGrounder { protected final Bridge[] bridges; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceRecorder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceRecorder.java index 19b012b41..375bf6410 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceRecorder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceRecorder.java @@ -28,18 +28,18 @@ package at.ac.tuwien.kr.alpha.core.grounder; import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import java.util.*; -import static at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom.off; -import static at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom.on; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.*; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.ChoiceAtom.off; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.ChoiceAtom.on; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.*; import static java.util.Collections.emptyList; public class ChoiceRecorder { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java index 508f25cbe..e68bbc67b 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java @@ -5,12 +5,12 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; /** * Helper functions to evaluate facts potentially containing intervals. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Grounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Grounder.java index 2c697f955..d6cdecbb9 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Grounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Grounder.java @@ -33,10 +33,10 @@ import org.apache.commons.lang3.tuple.Pair; import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.IntIterator; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; public interface Grounder { /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorage.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorage.java index 2be5302a5..5c7d62cdb 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorage.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorage.java @@ -38,7 +38,7 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; /** @@ -112,7 +112,8 @@ public void removeIndexPosition(int position) { * @return true if the instance is already contained in the storage. */ public boolean containsInstance(Instance instance) { - return instances.contains(instance); + boolean contains = instances.contains(instance); + return contains; // TODO remove extra variable, debugging only } public void addInstance(Instance instance) { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounder.java index 4d695d6af..f978b5677 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounder.java @@ -28,7 +28,7 @@ package at.ac.tuwien.kr.alpha.core.grounder; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import java.util.ArrayList; import java.util.Collection; @@ -54,14 +54,12 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.AnswerSets; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; import at.ac.tuwien.kr.alpha.commons.util.Util; -import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.IntIterator; @@ -75,7 +73,9 @@ import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.atoms.ChoiceAtom; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; /** * A semi-naive grounder. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGenerator.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGenerator.java index 3d97e7fa6..1b06cdec3 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGenerator.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGenerator.java @@ -27,9 +27,9 @@ */ package at.ac.tuwien.kr.alpha.core.grounder; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.negateLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.negateLiteral; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -46,12 +46,12 @@ import at.ac.tuwien.kr.alpha.api.programs.literals.FixedInterpretationLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.core.atoms.EnumerationAtom; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.NoGood; import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.atoms.EnumerationAtom; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; /** * Class to generate ground NoGoods out of non-ground rules and grounding substitutions. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java index d64388123..3a993736e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java @@ -5,7 +5,7 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.core.common.Assignment; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; /** * Copyright (c) 2017, the Alpha Team. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingInfoImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingInfoImpl.java index 7ec5430f3..9ea901c8e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingInfoImpl.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingInfoImpl.java @@ -39,8 +39,8 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; /** * Provides the grounder with information on the order to ground the literals in the body of a rule. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingOrderImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingOrderImpl.java index bd7c8ffa1..0f72c8f3c 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingOrderImpl.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingOrderImpl.java @@ -29,7 +29,7 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; /** * A grounding order computed by {@link RuleGroundingInfoImpl} for a specific {@link InternalRule} and a specific starting literal. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java index ab2647942..4da06621f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java @@ -32,10 +32,10 @@ import java.util.Set; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/bridges/Bridge.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/bridges/Bridge.java index 2d0beedb2..b835551a1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/bridges/Bridge.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/bridges/Bridge.java @@ -3,7 +3,7 @@ import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; import java.util.Collection; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/AbstractLiteralInstantiationStrategy.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/AbstractLiteralInstantiationStrategy.java index 9547b94dd..88e4c772d 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/AbstractLiteralInstantiationStrategy.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/AbstractLiteralInstantiationStrategy.java @@ -33,7 +33,7 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationResult.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationResult.java index 6d2506543..b8773af6a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationResult.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationResult.java @@ -35,7 +35,7 @@ import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; import at.ac.tuwien.kr.alpha.core.grounder.Grounder; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; /** * Representation of the result of instantiating, i.e. finding ground instances for a literal, as performed by diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiator.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiator.java index e6fead4c6..68d3839fc 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiator.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiator.java @@ -37,8 +37,8 @@ import at.ac.tuwien.kr.alpha.api.programs.literals.FixedInterpretationLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.core.atoms.EnumerationLiteral; -import at.ac.tuwien.kr.alpha.core.atoms.IntervalLiteral; +import at.ac.tuwien.kr.alpha.core.programs.atoms.EnumerationLiteral; +import at.ac.tuwien.kr.alpha.core.programs.atoms.IntervalLiteral; /** * Provides ground instantiations for literals. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java index cb12167db..751f68599 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java @@ -21,17 +21,17 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.grounder.Unification; import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ParseTreeVisitor.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ParseTreeVisitor.java index 53e19ab0e..6bdb979cf 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ParseTreeVisitor.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ParseTreeVisitor.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016-2018, the Alpha Team. + * Copyright (c) 2016-2023, the Alpha Team. * All rights reserved. *

* Additional changes made by Siemens. @@ -27,55 +27,40 @@ */ package at.ac.tuwien.kr.alpha.core.parser; -import static java.util.Collections.emptyList; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; - -import org.antlr.v4.runtime.RuleContext; -import org.antlr.v4.runtime.tree.TerminalNode; - import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; -import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.*; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead.ChoiceElement; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead.ChoiceElement; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.*; +import at.ac.tuwien.kr.alpha.api.programs.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; import at.ac.tuwien.kr.alpha.commons.AnswerSets; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.tests.Tests; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2BaseVisitor; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import org.antlr.v4.runtime.RuleContext; +import org.antlr.v4.runtime.tree.TerminalNode; + +import java.util.*; +import java.util.function.IntPredicate; /** * Copyright (c) 2016-2018, the Alpha Team. @@ -84,9 +69,16 @@ public class ParseTreeVisitor extends ASPCore2BaseVisitor { private final Map externals; private final boolean acceptVariables; - private InputProgramImpl.Builder programBuilder; private InlineDirectives inlineDirectives; + /* + * Since verifiers for tests are ASP programs in themselves, we need to parse nested programs. + * Therefore, have a stack onto which we "park" a program builder for the outer scope (i.e. main program) + * while we parse the inner scope (i.e. test verifier). + */ + private InputProgramBuilder currentLevelProgramBuilder; + private Stack programBuilders = new Stack<>(); + public ParseTreeVisitor(Map externals) { this(externals, true); } @@ -160,13 +152,13 @@ public InputProgram visitProgram(ASPCore2Parser.ProgramContext ctx) { } if (ctx.statements() == null) { - return InputProgramImpl.EMPTY; + return Programs.emptyProgram(); } - inlineDirectives = new InlineDirectivesImpl(); - programBuilder = InputProgramImpl.builder(); + inlineDirectives = Programs.newInlineDirectives(); + currentLevelProgramBuilder = Programs.builder(); visitStatements(ctx.statements()); - programBuilder.addInlineDirectives(inlineDirectives); - return programBuilder.build(); + currentLevelProgramBuilder.addInlineDirectives(inlineDirectives); + return currentLevelProgramBuilder.build(); } @Override @@ -183,10 +175,10 @@ public Object visitStatement_fact(ASPCore2Parser.Statement_factContext ctx) { // head DOT Head head = visitHead(ctx.head()); if (head instanceof NormalHead) { - programBuilder.addFact(((NormalHead) head).getAtom()); + currentLevelProgramBuilder.addFact(((NormalHead) head).getAtom()); } else { // Treat facts with choice or disjunction in the head like a rule. - programBuilder.addRule(new BasicRule(head, emptyList())); + currentLevelProgramBuilder.addRule(Rules.newRule(head, Collections.emptySet())); } return null; } @@ -194,14 +186,14 @@ public Object visitStatement_fact(ASPCore2Parser.Statement_factContext ctx) { @Override public Object visitStatement_constraint(ASPCore2Parser.Statement_constraintContext ctx) { // CONS body DOT - programBuilder.addRule(new BasicRule(null, visitBody(ctx.body()))); + currentLevelProgramBuilder.addRule(Rules.newRule(null, visitBody(ctx.body()))); return null; } @Override public Object visitStatement_rule(ASPCore2Parser.Statement_ruleContext ctx) { // head CONS body DOT - programBuilder.addRule(new BasicRule(visitHead(ctx.head()), visitBody(ctx.body()))); + currentLevelProgramBuilder.addRule(Rules.newRule(visitHead(ctx.head()), visitBody(ctx.body()))); return null; } @@ -230,11 +222,15 @@ public Head visitDisjunction(ASPCore2Parser.DisjunctionContext ctx) { @Override public Head visitHead(ASPCore2Parser.HeadContext ctx) { - // head : disjunction | choice; + // head : disjunction | choice | action; if (ctx.choice() != null) { return visitChoice(ctx.choice()); + } else if (ctx.action() != null) { + return visitAction(ctx.action()); + } else if (ctx.disjunction() != null) { + return visitDisjunction(ctx.disjunction()); } - return visitDisjunction(ctx.disjunction()); + throw notSupported(ctx); } @Override @@ -255,6 +251,15 @@ public Head visitChoice(ASPCore2Parser.ChoiceContext ctx) { return Heads.newChoiceHead(visitChoice_elements(ctx.choice_elements()), lt, lop, ut, uop); } + @Override + public Head visitAction(ASPCore2Parser.ActionContext ctx) { + BasicAtom atom = visitClassical_literal(ctx.classical_literal()); + VariableTerm actionResultTerm = visitVariable_term(ctx.variable_term()); + String actionId = ctx.ID().getText(); + List actionInputTerms = visitTerms(ctx.terms()); + return Heads.newActionHead(atom, actionId, actionInputTerms, actionResultTerm); + } + @Override public List visitChoice_elements(ASPCore2Parser.Choice_elementsContext ctx) { // choice_elements : choice_element (SEMICOLON choice_elements)?; @@ -294,19 +299,39 @@ public List visitNaf_literals(ASPCore2Parser.Naf_literalsContext ctx) { @Override public Object visitDirective_enumeration(ASPCore2Parser.Directive_enumerationContext ctx) { - // directive_enumeration : SHARP 'enum_predicate_is' ID DOT; - inlineDirectives.addDirective(InlineDirectives.DIRECTIVE.enum_predicate_is, ctx.ID().getText()); + // directive_enumeration : DIRECTIVE_ENUM id DOT; + inlineDirectives.addDirective(InlineDirectives.DIRECTIVE.enum_predicate_is, visitId(ctx.id())); + return null; + } + + @Override + public Object visitDirective_test(ASPCore2Parser.Directive_testContext ctx) { + // directive_test : DIRECTIVE_TEST id PAREN_OPEN test_satisfiability_condition PAREN_CLOSE CURLY_OPEN test_input test_assert* CURLY_CLOSE; + String name = visitId(ctx.id()); + IntPredicate answerSetCountVerifier = visitTest_satisfiability_condition(ctx.test_satisfiability_condition()); + Set input = visitTest_input(ctx.test_input()); + List assertions; + if (ctx.test_assert() == null) { + assertions = Collections.emptyList(); + } else { + assertions = new ArrayList<>(); + for (ASPCore2Parser.Test_assertContext assertionCtx : ctx.test_assert()) { + assertions.add(visitTest_assert(assertionCtx)); + } + } + TestCase testCase = Tests.newTestCase(name, answerSetCountVerifier, input, assertions); + currentLevelProgramBuilder.addTestCase(testCase); return null; } @Override - public List visitBody(ASPCore2Parser.BodyContext ctx) { + public Set visitBody(ASPCore2Parser.BodyContext ctx) { // body : ( naf_literal | aggregate ) (COMMA body)?; if (ctx == null) { - return emptyList(); + return Collections.emptySet(); } - final List literals = new ArrayList<>(); + final Set literals = new LinkedHashSet<>(); do { if (ctx.naf_literal() != null) { literals.add(visitNaf_literal(ctx.naf_literal())); @@ -382,10 +407,10 @@ public Term visitBasic_term(ASPCore2Parser.Basic_termContext ctx) { @Override public Term visitGround_term(ASPCore2Parser.Ground_termContext ctx) { - // ground_term : ID | QUOTED_STRING | numeral; - if (ctx.ID() != null) { - // ID - return Terms.newSymbolicConstant(ctx.ID().getText()); + // ground_term : id | QUOTED_STRING | numeral; + if (ctx.id() != null) { + // id + return Terms.newSymbolicConstant(visitId(ctx.id())); } else if (ctx.QUOTED_STRING() != null) { // QUOTED_STRING String quotedString = ctx.QUOTED_STRING().getText(); @@ -397,7 +422,7 @@ public Term visitGround_term(ASPCore2Parser.Ground_termContext ctx) { } @Override - public Term visitVariable_term(ASPCore2Parser.Variable_termContext ctx) { + public VariableTerm visitVariable_term(ASPCore2Parser.Variable_termContext ctx) { // variable_term : VARIABLE | ANONYMOUS_VARIABLE; if (ctx.VARIABLE() != null) { return Terms.newVariable(ctx.VARIABLE().getText()); @@ -465,22 +490,33 @@ public Literal visitNaf_literal(ASPCore2Parser.Naf_literalContext ctx) { throw notSupported(ctx); } + @Override + public String visitId(ASPCore2Parser.IdContext ctx) { + // id : ID | TEST_EXPECT | TEST_UNSAT | TEST_GIVEN | TEST_ASSERT_ALL | TEST_ASSERT_SOME; + return ctx.getText(); + } + + @Override + public BasicAtom visitBasic_atom(ASPCore2Parser.Basic_atomContext ctx) { + // basic_atom : ID (PAREN_OPEN terms PAREN_CLOSE)?; + List terms = visitTerms(ctx.terms()); + return Atoms.newBasicAtom(Predicates.getPredicate(visitId(ctx.id()), terms.size()), terms); + } + @Override public BasicAtom visitClassical_literal(ASPCore2Parser.Classical_literalContext ctx) { - // classical_literal : MINUS? ID (PAREN_OPEN terms PAREN_CLOSE)?; + // classical_literal : MINUS? basic_atom; if (ctx.MINUS() != null) { throw notSupported(ctx); } - - final List terms = visitTerms(ctx.terms()); - return Atoms.newBasicAtom(Predicates.getPredicate(ctx.ID().getText(), terms.size()), terms); + return visitBasic_atom(ctx.basic_atom()); } @Override public List visitTerms(ASPCore2Parser.TermsContext ctx) { // terms : term (COMMA terms)?; if (ctx == null) { - return emptyList(); + return Collections.emptyList(); } final List terms = new ArrayList<>(); @@ -506,7 +542,7 @@ public Integer visitNumeral(ASPCore2Parser.NumeralContext ctx) { @Override public ConstantTerm visitTerm_const(ASPCore2Parser.Term_constContext ctx) { - return Terms.newSymbolicConstant(ctx.ID().getText()); + return Terms.newSymbolicConstant(visitId(ctx.id())); } @Override @@ -517,7 +553,7 @@ public ConstantTerm visitTerm_string(ASPCore2Parser.Term_stringContext c @Override public FunctionTerm visitTerm_func(ASPCore2Parser.Term_funcContext ctx) { - return Terms.newFunctionTerm(ctx.ID().getText(), visitTerms(ctx.terms())); + return Terms.newFunctionTerm(visitId(ctx.id()), visitTerms(ctx.terms())); } @Override @@ -543,13 +579,13 @@ public Term visitTerm_parenthesisedTerm(ASPCore2Parser.Term_parenthesisedTermCon @Override public ExternalAtom visitExternal_atom(ASPCore2Parser.External_atomContext ctx) { - // external_atom : AMPERSAND ID (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; + // external_atom : AMPERSAND id (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; if (ctx.MINUS() != null) { throw notSupported(ctx); } - final String predicateName = ctx.ID().getText(); + final String predicateName = visitId(ctx.id()); final PredicateInterpretation interpretation = externals.get(predicateName); if (interpretation == null) { @@ -617,4 +653,71 @@ public Object visitTerm_bitxorArithTerm(ASPCore2Parser.Term_bitxorArithTermConte // | term BITXOR term return Terms.newArithmeticTerm((Term) visit(ctx.term(0)), ArithmeticOperator.BITXOR, (Term) visit(ctx.term(1))); } + + public IntPredicate visitTest_satisfiability_condition(ASPCore2Parser.Test_satisfiability_conditionContext ctx) { + // 'expect' COLON ('unsat' | (binop? NUMBER)); + if (ctx.binop() == null && ctx.NUMBER() == null) { + // 'unsat' + return Tests.newIsUnsatCondition(); + } else { + // binop? NUMBER + int num = Integer.valueOf(ctx.NUMBER().getText()); + if (ctx.binop() == null) { + return Tests.newAnswerSetCountCondition(ComparisonOperators.EQ, num); + } else { + ComparisonOperator op = visitBinop(ctx.binop()); + return Tests.newAnswerSetCountCondition(op, num); + } + } + } + + @Override + public Set visitTest_input(ASPCore2Parser.Test_inputContext ctx) { + if (ctx.basic_atom() == null) { + return Collections.emptySet(); + } + Set result = new LinkedHashSet<>(); + for (ASPCore2Parser.Basic_atomContext atomCtx : ctx.basic_atom()) { + result.add(visitBasic_atom(atomCtx)); + } + return result; + } + + public Assertion visitTest_assert(ASPCore2Parser.Test_assertContext ctx) { + if (ctx.test_assert_all() != null) { + return visitTest_assert_all(ctx.test_assert_all()); + } else if (ctx.test_assert_some() != null) { + return visitTest_assert_some(ctx.test_assert_some()); + } else { + throw new IllegalArgumentException("Unsupported assertion mode at: " + ctx.getText()); + } + } + + @Override + public Assertion visitTest_assert_all(ASPCore2Parser.Test_assert_allContext ctx) { + // 'assert' 'for' 'all' CURLY_OPEN statements? CURLY_CLOSE; + return visitTestVerifier(Assertion.Mode.FOR_ALL, ctx.statements()); + } + + @Override + public Assertion visitTest_assert_some(ASPCore2Parser.Test_assert_someContext ctx) { + // 'assert' 'for' 'some' CURLY_OPEN statements? CURLY_CLOSE; + return visitTestVerifier(Assertion.Mode.FOR_SOME, ctx.statements()); + } + + public Assertion visitTestVerifier(Assertion.Mode assertionMode, ASPCore2Parser.StatementsContext ctx) { + if (ctx == null) { // empty verifier for a test case is OK + return Tests.newAssertion(assertionMode, Programs.emptyProgram()); + } + List stmts = ctx.statement(); + programBuilders.push(currentLevelProgramBuilder); + currentLevelProgramBuilder = new InputProgramBuilder(); + for (ASPCore2Parser.StatementContext stmtCtx : stmts) { + visit(stmtCtx); + } + InputProgram verifier = currentLevelProgramBuilder.build(); + currentLevelProgramBuilder = programBuilders.pop(); + return Tests.newAssertion(assertionMode, verifier); + } + } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramParserImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramParserImpl.java index e67cfaa4a..4c4d418ce 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramParserImpl.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramParserImpl.java @@ -7,6 +7,10 @@ import java.util.HashMap; import java.util.Map; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.core.actions.ActionImplementationProvider; +import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Lexer; +import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; @@ -17,12 +21,10 @@ import org.antlr.v4.runtime.misc.ParseCancellationException; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; import at.ac.tuwien.kr.alpha.commons.externals.Externals; -import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Lexer; -import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; public class ProgramParserImpl implements ProgramParser { @@ -36,6 +38,12 @@ public ProgramParserImpl(Map externals) { this(); this.preloadedExternals.putAll(externals); } + + public ProgramParserImpl(ActionImplementationProvider actionImplementationProvider, Map externals) { + this(externals); + this.preloadedExternals.put("stdin", actionImplementationProvider.getStdinTerm()); + this.preloadedExternals.put("stdout", actionImplementationProvider.getStdoutTerm()); + } @Override public InputProgram parse(String s) { @@ -142,7 +150,7 @@ public InputProgram parse(Path programPath, Map @Override public InputProgram parse(Map externalPredicateDefinitions, Path... programSources) throws IOException { - InputProgramImpl.Builder bld = InputProgramImpl.builder(); + InputProgramBuilder bld = Programs.builder(); for (Path src : programSources) { bld.accumulate(parse(src, externalPredicateDefinitions)); } @@ -151,7 +159,7 @@ public InputProgram parse(Map externalPredicate @Override public InputProgram parse(Iterable programSources, Map externalPredicateDefinitions) throws IOException { - InputProgramImpl.Builder bld = InputProgramImpl.builder(); + InputProgramBuilder bld = Programs.builder(); for (Path src : programSources) { bld.accumulate(parse(src, externalPredicateDefinitions)); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramPartParser.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramPartParser.java index bc2690666..b115e4cd9 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramPartParser.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/parser/ProgramPartParser.java @@ -38,14 +38,15 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Lexer; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; /** - * A parser that, in contrast to {@link ProgramParserImpl}, does not parse full programs but only program parts like + * A parser that, in contrast to {@link at.ac.tuwien.kr.alpha.api.programs.ProgramParser}, does not parse full programs but only program parts like * atoms, terms and such. */ +// TODO adapt this and create evolog version public class ProgramPartParser { private final ParseTreeVisitor visitor = new ParseTreeVisitor(Collections.emptyMap(), true); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AnalyzedProgram.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AnalyzedProgram.java index c6e68c7ee..e3dd5336e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AnalyzedProgram.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/AnalyzedProgram.java @@ -11,7 +11,7 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.core.depgraph.ComponentGraphImpl; import at.ac.tuwien.kr.alpha.core.depgraph.StronglyConnectedComponentsAlgorithm; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/CompiledProgram.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/CompiledProgram.java index ab307bb67..83cb2e255 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/CompiledProgram.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/CompiledProgram.java @@ -6,7 +6,7 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.Program; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; public interface CompiledProgram extends Program { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InputProgramImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InputProgramImpl.java deleted file mode 100644 index 3ab39a124..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InputProgramImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2019, the Alpha Team. - * All rights reserved. - *

- * Additional changes made by Siemens. - *

- * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - *

- * 1) Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - *

- * 2) Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package at.ac.tuwien.kr.alpha.core.programs; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import at.ac.tuwien.kr.alpha.api.programs.InputProgram; -import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl; - -/** - * Alpha-internal representation of an ASP program, i.e., a set of ASP rules. - *

- * Copyright (c) 2017-2019, the Alpha Team. - */ -public class InputProgramImpl extends AbstractProgram> implements InputProgram { - - public static final InputProgramImpl EMPTY = new InputProgramImpl(Collections.emptyList(), Collections.emptyList(), new InlineDirectivesImpl()); - - public InputProgramImpl(List> rules, List facts, InlineDirectives inlineDirectives) { - super(rules, facts, inlineDirectives); - } - - public InputProgramImpl() { - super(new ArrayList<>(), new ArrayList<>(), new InlineDirectivesImpl()); - } - - public static Builder builder() { - return new Builder(); - } - - public static Builder builder(InputProgram prog) { - return new Builder(prog); - } - - /** - * Builder for more complex program construction scenarios, ensuring that an {@link InputProgramImpl} is immutable - */ - public static class Builder { - - private List> rules = new ArrayList<>(); - private List facts = new ArrayList<>(); - private InlineDirectives inlineDirectives = new InlineDirectivesImpl(); - - public Builder(InputProgram prog) { - this.addRules(prog.getRules()); - this.addFacts(prog.getFacts()); - this.addInlineDirectives(prog.getInlineDirectives()); - } - - public Builder() { - - } - - public Builder addRules(List> rules) { - this.rules.addAll(rules); - return this; - } - - public Builder addRule(Rule r) { - this.rules.add(r); - return this; - } - - public Builder addFacts(List facts) { - this.facts.addAll(facts); - return this; - } - - public Builder addFact(Atom fact) { - this.facts.add(fact); - return this; - } - - public Builder addInlineDirectives(InlineDirectives inlineDirectives) { - this.inlineDirectives.accumulate(inlineDirectives); - return this; - } - - public Builder accumulate(InputProgram prog) { - return this.addRules(prog.getRules()).addFacts(prog.getFacts()).addInlineDirectives(prog.getInlineDirectives()); - } - - public InputProgram build() { - return new InputProgramImpl(this.rules, this.facts, this.inlineDirectives); - } - } - -} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InternalProgram.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InternalProgram.java index bca2f97cc..afd2236ab 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InternalProgram.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InternalProgram.java @@ -12,14 +12,16 @@ import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.commons.programs.AbstractProgram; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; import at.ac.tuwien.kr.alpha.core.grounder.FactIntervalEvaluator; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; /** * A program in the internal representation needed for grounder and solver, i.e.: rules must have normal heads, all @@ -102,9 +104,9 @@ public Map getRulesById() { public NormalProgram toNormalProgram() { List normalRules = new ArrayList<>(); for (CompiledRule rule : getRules()) { - normalRules.add(new NormalRuleImpl(rule.getHead(), new ArrayList<>(rule.getBody()))); + normalRules.add(Rules.newNormalRule(rule.getHead(), new LinkedHashSet<>(rule.getBody()))); } - return new NormalProgramImpl(normalRules, getFacts(), getInlineDirectives()); + return Programs.newNormalProgram(normalRules, getFacts(), getInlineDirectives()); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/NormalProgramImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/NormalProgramImpl.java deleted file mode 100644 index ad65431e0..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/NormalProgramImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.programs; - -import java.util.ArrayList; -import java.util.List; - -import at.ac.tuwien.kr.alpha.api.programs.InputProgram; -import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; -import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; - -/** - * A program that only contains NormalRules. - * - * Copyright (c) 2019, the Alpha Team. - */ -public class NormalProgramImpl extends AbstractProgram implements NormalProgram { - - public NormalProgramImpl(List rules, List facts, InlineDirectives inlineDirectives) { - super(rules, facts, inlineDirectives); - } - - public static NormalProgramImpl fromInputProgram(InputProgram inputProgram) { - List normalRules = new ArrayList<>(); - for (Rule r : inputProgram.getRules()) { - normalRules.add(NormalRuleImpl.fromBasicRule(r)); - } - return new NormalProgramImpl(normalRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); - } - -} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/Programs.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/Programs.java deleted file mode 100644 index e3f184886..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/Programs.java +++ /dev/null @@ -1,24 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.programs; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; - -import org.antlr.v4.runtime.CharStreams; - -import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.programs.InputProgram; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; - -public class Programs { - - private Programs() { - throw new AssertionError("This is a pure utility class and should therefore not be instantiated!"); - } - - public static InputProgram fromInputStream(InputStream is, Map externals) throws IOException { - ProgramParserImpl parser = new ProgramParserImpl(); - return parser.parse(CharStreams.fromStream(is), externals); - } - -} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/ChoiceAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/ChoiceAtom.java similarity index 93% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/ChoiceAtom.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/ChoiceAtom.java index 5c6af0bde..3fc3c74c0 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/ChoiceAtom.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/ChoiceAtom.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.core.atoms; +package at.ac.tuwien.kr.alpha.core.programs.atoms; import java.util.Collections; import java.util.List; @@ -35,11 +35,11 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; public class ChoiceAtom implements Atom { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/EnumerationAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationAtom.java similarity index 95% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/EnumerationAtom.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationAtom.java index d66f1989a..97b9865fc 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/EnumerationAtom.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationAtom.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.core.atoms; +package at.ac.tuwien.kr.alpha.core.programs.atoms; import java.util.ArrayList; import java.util.HashMap; @@ -9,12 +9,12 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/EnumerationLiteral.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationLiteral.java similarity index 85% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/EnumerationLiteral.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationLiteral.java index f45e5032d..d66d45055 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/EnumerationLiteral.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationLiteral.java @@ -1,13 +1,13 @@ -package at.ac.tuwien.kr.alpha.core.atoms; +package at.ac.tuwien.kr.alpha.core.programs.atoms; import java.util.Collections; import java.util.HashSet; import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.literals.AbstractLiteral; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.literals.AbstractLiteral; /** * Copyright (c) 2018, the Alpha Team. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/IntervalAtom.java similarity index 93% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalAtom.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/IntervalAtom.java index f9d39be68..bea9fc62c 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalAtom.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/IntervalAtom.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.core.atoms; +package at.ac.tuwien.kr.alpha.core.programs.atoms; import java.util.Arrays; import java.util.List; @@ -34,11 +34,11 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.VariableNormalizableAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.AbstractAtom; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.AbstractAtom; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/IntervalLiteral.java similarity index 92% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/IntervalLiteral.java index a0d762bf2..84f4d145d 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/IntervalLiteral.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.core.atoms; +package at.ac.tuwien.kr.alpha.core.programs.atoms; import java.util.ArrayList; import java.util.Collections; @@ -36,13 +36,13 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.literals.FixedInterpretationLiteral; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.literals.AbstractLiteral; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.literals.AbstractLiteral; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/Literals.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/Literals.java similarity index 98% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/Literals.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/Literals.java index 8c34bb1b0..5409bce4a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/Literals.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/Literals.java @@ -25,7 +25,7 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.core.atoms; +package at.ac.tuwien.kr.alpha.core.programs.atoms; /** * Provides methods to convert atoms to literals and vice versa, diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtom.java new file mode 100644 index 000000000..cd39b2976 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtom.java @@ -0,0 +1,199 @@ +/** + * Copyright (c) 2016-2018, the Alpha Team. + * All rights reserved. + * + * Additional changes made by Siemens. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package at.ac.tuwien.kr.alpha.core.programs.atoms; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; + +/** + * Atoms corresponding to rule bodies use this predicate, its only term is a Java object linking to the non-ground rule and grounding substitution. + */ +public class RuleAtom implements Atom { + public static final Predicate PREDICATE = Predicates.getPredicate("_R_", 1, true, true); + + private final List> terms; + + public static class RuleAtomData implements Comparable { + private final CompiledRule nonGroundRule; + private final Substitution substitution; + private final int substitutionHash; + + RuleAtomData(CompiledRule nonGroundRule, Substitution substitution) { + this.nonGroundRule = nonGroundRule; + this.substitution = substitution; + this.substitutionHash = substitution.hashCode(); + } + + @Override + public int compareTo(RuleAtomData other) { + if (nonGroundRule.getRuleId() != other.nonGroundRule.getRuleId()) { + return Integer.compare(nonGroundRule.getRuleId(), other.nonGroundRule.getRuleId()); + } + if (substitution.getSubstitution().size() != other.getSubstitution().getSubstitution().size()) { + throw oops("RuleAtoms over the same rule have different-sized substitutions."); + } + // Note: Since Substitutions are backed by TreeMaps, their variables can be iterated in the same order. + Iterator> iteratorThis = substitution.getSubstitution().entrySet().iterator(); + Iterator> iteratorOther = other.getSubstitution().getSubstitution().entrySet().iterator(); + while (iteratorThis.hasNext()) { + Map.Entry thisNextEntry = iteratorThis.next(); + Map.Entry otherNextEntry = iteratorOther.next(); + VariableTerm thisVariable = thisNextEntry.getKey(); + VariableTerm otherVariable = otherNextEntry.getKey(); + if (thisVariable != otherVariable) { + throw oops("Comparing substitutions for the same non-ground rule whose variables differ: " + thisVariable + " != " + otherVariable); + } + int compare = thisNextEntry.getValue().compareTo(otherNextEntry.getValue()); + if (compare != 0) { + return compare; + } + } + return 0; + } + + public CompiledRule getNonGroundRule() { + return nonGroundRule; + } + + public Substitution getSubstitution() { + return substitution; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + RuleAtomData that = (RuleAtomData) o; + if (!nonGroundRule.equals(that.nonGroundRule) || substitutionHash != that.substitutionHash) { + return false; + } + return getSubstitution().equals(that.getSubstitution()); + } + + @Override + public int hashCode() { + return 31 * getNonGroundRule().hashCode() + substitutionHash; + } + + @Override + public String toString() { + return "ruleId=" + nonGroundRule.getRuleId() + ":substitution=" + substitution.toString(); + } + } + + public RuleAtom(CompiledRule nonGroundRule, Substitution substitution) { + this.terms = Collections.singletonList(Terms.newConstant(new RuleAtomData(nonGroundRule, substitution))); + } + + @Override + public Predicate getPredicate() { + return PREDICATE; + } + + @Override + public List getTerms() { + return Collections.singletonList(terms.get(0)); + } + + @Override + public boolean isGround() { + // NOTE: single term is a ConstantTerm, which is ground by definition. + return true; + } + + @Override + public Literal toLiteral(boolean positive) { + throw new UnsupportedOperationException("RuleAtom cannot be literalized"); + } + + @Override + public Atom substitute(Substitution substitution) { + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + RuleAtom that = (RuleAtom) o; + + return terms.equals(that.terms); + } + + @Override + public int hashCode() { + return 31 * PREDICATE.hashCode() + terms.hashCode(); + } + + @Override + public String toString() { + return PREDICATE.getName() + "(" + terms.get(0) + ')'; + } + + @Override + public Atom withTerms(List terms) { + throw new UnsupportedOperationException("RuleAtoms do not support setting of terms!"); + } + + @Override + public Set getOccurringVariables() { + // RuleAtom has 2 terms which are both constants + return Collections.emptySet(); + } + + @Override + public Atom renameVariables(String newVariablePrefix) { + throw new UnsupportedOperationException("RuleAtom does not have any variables to rename!"); + } +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/CompiledRule.java similarity index 75% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/CompiledRule.java index b15dfbc41..633a4c5c8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/CompiledRule.java @@ -1,9 +1,9 @@ -package at.ac.tuwien.kr.alpha.core.rules; +package at.ac.tuwien.kr.alpha.core.programs.rules; import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfo; public interface CompiledRule extends NormalRule { @@ -16,5 +16,4 @@ public interface CompiledRule extends NormalRule { CompiledRule renameVariables(String str); - boolean isGround(); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/InternalRule.java similarity index 73% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java rename to alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/InternalRule.java index 3283ac64f..c6bbf7239 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/InternalRule.java @@ -25,32 +25,35 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.core.rules; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import com.google.common.annotations.VisibleForTesting; +package at.ac.tuwien.kr.alpha.core.programs.rules; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.rules.AbstractRule; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfoImpl; +import com.google.common.annotations.VisibleForTesting; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; /** * Represents a normal rule or a constraint for the semi-naive grounder. * A normal rule has no head atom if it represents a constraint, otherwise it has one atom in its head. + * + * {@link InternalRule}s are assumed to be uniquely identified by an ID. */ -public class InternalRule extends NormalRuleImpl implements CompiledRule { +public class InternalRule extends AbstractRule implements CompiledRule { private static final IntIdGenerator ID_GENERATOR = new IntIdGenerator(); @@ -60,11 +63,13 @@ public class InternalRule extends NormalRuleImpl implements CompiledRule { private final RuleGroundingInfoImpl groundingOrders; - public InternalRule(NormalHead head, Literal... body) { - this(head, Arrays.asList(body)); - } - - public InternalRule(NormalHead head, List body) { + /** + * Creates a new {@link InternalRule} with the given head plus body and a fresh identifier. + * Note that no check is done whether head and body already occur in another {@link InternalRule}. + * @param head the head of the rule. + * @param body the list of body literals of the rule. + */ + public InternalRule(NormalHead head, Set body) { super(head, body); if (body.isEmpty()) { throw new IllegalArgumentException( @@ -98,18 +103,19 @@ public static void resetIdGenerator() { } public static CompiledRule fromNormalRule(Rule rule) { - return new InternalRule(rule.isConstraint() ? null : Heads.newNormalHead(rule.getHead().getAtom()), new ArrayList<>(rule.getBody())); + return new InternalRule(rule.isConstraint() ? null : rule.getHead(), new LinkedHashSet<>(rule.getBody())); } /** * Returns a new Rule that is equal to this one except that all variables are renamed to have the newVariablePostfix * appended. - * + * * @param newVariablePostfix * @return */ @Override public InternalRule renameVariables(String newVariablePostfix) { + // TODO handle action heads! List occurringVariables = new ArrayList<>(); BasicAtom headAtom = this.getHeadAtom(); occurringVariables.addAll(headAtom.getOccurringVariables()); @@ -122,10 +128,12 @@ public InternalRule renameVariables(String newVariablePostfix) { variableReplacement.put(occurringVariable, Terms.newVariable(newVariableName)); } BasicAtom renamedHeadAtom = headAtom.substitute(variableReplacement); - ArrayList renamedBody = new ArrayList<>(this.getBody().size()); + Set renamedBody = new LinkedHashSet<>(this.getBody().size()); for (Literal literal : this.getBody()) { renamedBody.add(literal.substitute(variableReplacement)); } + // TODO action heads! + // TODO we want to pull renameVariables down to atom, term, etc level return new InternalRule(Heads.newNormalHead(renamedHeadAtom), renamedBody); } @@ -148,4 +156,34 @@ public int getRuleId() { return this.ruleId; } + public boolean isGround() { + if (!isConstraint() && !getHead().isGround()) { + return false; + } + for (Literal bodyElement : getBody()) { + if (!bodyElement.isGround()) { + return false; + } + } + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InternalRule that = (InternalRule) o; + return getRuleId() == that.getRuleId(); + } + + @Override + public int hashCode() { + return Integer.hashCode(getRuleId()); + } + } + diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewriting.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewriting.java index 259d410a9..d7111f098 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewriting.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewriting.java @@ -1,28 +1,31 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; import at.ac.tuwien.kr.alpha.commons.util.Util; -import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; /** * Transforms rules such that arithmetic terms only occur in comparison predicates. @@ -32,8 +35,12 @@ * Copyright (c) 2020-2021, the Alpha Team. */ public class ArithmeticTermsRewriting extends ProgramTransformation { - private static final String ARITHMETIC_VARIABLES_PREFIX = "_A"; - private int numArithmeticVariables; + /** + private int numArithmeticVariables; + * The prefix with which to begin names of internal variables created by this transformation. + */ + private final String generatedVariablesPrefix = "_A"; + private final IntIdGenerator variableNumberGenerator = new IntIdGenerator(); @Override public NormalProgram apply(NormalProgram inputProgram) { @@ -52,23 +59,25 @@ public NormalProgram apply(NormalProgram inputProgram) { return inputProgram; } // Create new program with rewritten rules. - return new NormalProgramImpl(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return Programs.newNormalProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); } /** - * Takes a normal rule and rewrites it such that {@link ArithmeticTerm}s only appear inside {@link at.ac.tuwien.kr.alpha.common.atoms.ComparisonLiteral}s. + * Takes a normal rule and rewrites it such that {@link ArithmeticTerm}s only appear inside + * {@link at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral}s. * * @param inputProgramRule the rule to rewrite. * @return the rewritten rule. Note that a new {@link NormalRule} is returned for every call of this method. */ private NormalRule rewriteRule(NormalRule inputProgramRule) { - numArithmeticVariables = 0; // Reset number of introduced variables for each rule. + variableNumberGenerator.resetGenerator(); // Reset number of introduced variables for each rule. NormalHead rewrittenHead = null; - List rewrittenBodyLiterals = new ArrayList<>(); + Set rewrittenBodyLiterals = new LinkedHashSet<>(); // Rewrite head. if (!inputProgramRule.isConstraint()) { BasicAtom headAtom = inputProgramRule.getHeadAtom(); if (containsArithmeticTermsToRewrite(headAtom)) { + // TODO handle action heads rewrittenHead = Heads.newNormalHead((BasicAtom) rewriteAtom(headAtom, rewrittenBodyLiterals)); } else { rewrittenHead = inputProgramRule.getHead(); @@ -83,14 +92,16 @@ private NormalRule rewriteRule(NormalRule inputProgramRule) { } rewrittenBodyLiterals.add(rewriteAtom(literal.getAtom(), rewrittenBodyLiterals).toLiteral(!literal.isNegated())); } - return new NormalRuleImpl(rewrittenHead, rewrittenBodyLiterals); + return Rules.newNormalRule(rewrittenHead, rewrittenBodyLiterals); } /** - * Checks whether a normal rule contains an {@link ArithmeticTerm} outside of a {@link at.ac.tuwien.kr.alpha.common.atoms.ComparisonLiteral}. + * Checks whether a normal rule contains an {@link ArithmeticTerm} outside of a + * {@link at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral}. * * @param inputProgramRule the rule to check for presence of arithmetic terms outside comparison literals. - * @return true if the inputProgramRule contains an {@link ArithmeticTerm} outside of a {@link at.ac.tuwien.kr.alpha.common.atoms.ComparisonLiteral}. + * @return true if the inputProgramRule contains an {@link ArithmeticTerm} outside of a + * {@link at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral}. */ private boolean containsArithmeticTermsToRewrite(NormalRule inputProgramRule) { if (!inputProgramRule.isConstraint()) { @@ -108,14 +119,14 @@ private boolean containsArithmeticTermsToRewrite(NormalRule inputProgramRule) { return false; } - private Term rewriteArithmeticSubterms(Term term, List bodyLiterals) { + private Term rewriteArithmeticSubterms(Term term, Set bodyLiterals) { // Keep term as-is if it contains no ArithmeticTerm. if (!containsArithmeticTerm(term)) { return term; } // Switch on term type. if (term instanceof ArithmeticTerm) { - VariableTerm replacementVariable = Terms.newVariable(ARITHMETIC_VARIABLES_PREFIX + numArithmeticVariables++); + VariableTerm replacementVariable = Terms.newVariable(generatedVariablesPrefix + variableNumberGenerator.getNextId()); bodyLiterals.add(Atoms.newComparisonAtom(replacementVariable, term, ComparisonOperators.EQ).toLiteral()); return replacementVariable; } else if (term instanceof VariableTerm || term instanceof ConstantTerm) { @@ -132,7 +143,7 @@ private Term rewriteArithmeticSubterms(Term term, List bodyLiterals) { } } - private Atom rewriteAtom(Atom atomToRewrite, List bodyLiterals) { + private Atom rewriteAtom(Atom atomToRewrite, Set bodyLiterals) { if (atomToRewrite instanceof ComparisonAtom) { throw Util.oops("Trying to rewrite ComparisonAtom."); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ChoiceHeadToNormal.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ChoiceHeadToNormal.java index 746b43313..3b167ac9f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ChoiceHeadToNormal.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ChoiceHeadToNormal.java @@ -27,26 +27,25 @@ */ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.*; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead.ChoiceElement; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead.ChoiceElement; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; /** * Copyright (c) 2017-2021, the Alpha Team. @@ -57,7 +56,7 @@ public class ChoiceHeadToNormal extends ProgramTransformation> additionalRules = new ArrayList<>(); List> srcRules = new ArrayList<>(inputProgram.getRules()); @@ -103,13 +102,13 @@ public InputProgram apply(InputProgram inputProgram) { BasicAtom negHead = Atoms.newBasicAtom(negPredicate, headTerms); // Construct two guessing rules. - List guessingRuleBodyWithNegHead = new ArrayList<>(ruleBody); + Set guessingRuleBodyWithNegHead = new LinkedHashSet<>(ruleBody); guessingRuleBodyWithNegHead.add(Atoms.newBasicAtom(head.getPredicate(), head.getTerms()).toLiteral(false)); - additionalRules.add(new BasicRule(Heads.newNormalHead(negHead), guessingRuleBodyWithNegHead)); + additionalRules.add(Rules.newRule(Heads.newNormalHead(negHead), guessingRuleBodyWithNegHead)); - List guessingRuleBodyWithHead = new ArrayList<>(ruleBody); + Set guessingRuleBodyWithHead = new LinkedHashSet<>(ruleBody); guessingRuleBodyWithHead.add(Atoms.newBasicAtom(negPredicate, headTerms).toLiteral(false)); - additionalRules.add(new BasicRule(Heads.newNormalHead(head), guessingRuleBodyWithHead)); + additionalRules.add(Rules.newRule(Heads.newNormalHead(head), guessingRuleBodyWithHead)); // TODO: when cardinality constraints are possible, process the boundaries by adding a constraint with a cardinality check. } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/EnumerationRewriting.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/EnumerationRewriting.java index f9498270e..803af1879 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/EnumerationRewriting.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/EnumerationRewriting.java @@ -1,27 +1,24 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +import java.util.*; +import at.ac.tuwien.kr.alpha.api.programs.InlineDirectives; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.core.atoms.EnumerationAtom; -import at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.util.Util; +import at.ac.tuwien.kr.alpha.core.programs.atoms.EnumerationAtom; /** * Rewrites the ordinary atom whose name is given in the input program by the enumeration directive #enum_atom_is into @@ -35,14 +32,14 @@ public class EnumerationRewriting extends ProgramTransformation srcFacts, Predicate enumPredicate) { for (Atom fact : srcFacts) { if (fact.getPredicate().equals(enumPredicate)) { - throw oops("Atom declared as enumeration atom by directive occurs in a fact: " + fact); + throw Util.oops("Atom declared as enumeration atom by directive occurs in a fact: " + fact); } } } @@ -64,12 +61,12 @@ private List> rewriteRules(List> srcRules, Predicate enumP List> rewrittenRules = new ArrayList<>(); for (Rule rule : srcRules) { if (rule.getHead() != null && !(rule.getHead() instanceof NormalHead)) { - throw oops("Encountered rule whose head is not normal: " + rule); + throw Util.oops("Encountered rule whose head is not normal: " + rule); } if (rule.getHead() != null && ((NormalHead) rule.getHead()).getAtom().getPredicate().equals(enumPredicate)) { - throw oops("Atom declared as enumeration atom by directive occurs in head of the rule: " + rule); + throw Util.oops("Atom declared as enumeration atom by directive occurs in head of the rule: " + rule); } - List modifiedBodyLiterals = new ArrayList<>(rule.getBody()); + Set modifiedBodyLiterals = new LinkedHashSet<>(rule.getBody()); Iterator rit = modifiedBodyLiterals.iterator(); LinkedList rewrittenLiterals = new LinkedList<>(); while (rit.hasNext()) { @@ -89,7 +86,7 @@ private List> rewriteRules(List> srcRules, Predicate enumP rewrittenLiterals.add(new EnumerationAtom(enumIdTerm, valueTerm, indexTerm).toLiteral()); } modifiedBodyLiterals.addAll(rewrittenLiterals); - rewrittenRules.add(new BasicRule(rule.getHead(), modifiedBodyLiterals)); + rewrittenRules.add(Rules.newRule(rule.getHead(), modifiedBodyLiterals)); } return rewrittenRules; } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/IntervalTermToIntervalAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/IntervalTermToIntervalAtom.java index 013aaab5d..ef73eec08 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/IntervalTermToIntervalAtom.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/IntervalTermToIntervalAtom.java @@ -27,10 +27,7 @@ */ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; @@ -38,17 +35,17 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.atoms.IntervalAtom; -import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.core.programs.atoms.IntervalAtom; /** * Rewrites all interval terms in a rule into a new variable and an IntervalAtom. @@ -68,7 +65,7 @@ private static NormalRule rewriteIntervalSpecifications(NormalRule rule) { // Collect all intervals and replace them with variables. Map intervalReplacements = new LinkedHashMap<>(); - List rewrittenBody = new ArrayList<>(); + Set rewrittenBody = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { Literal rewrittenLiteral = rewriteLiteral(literal, intervalReplacements); @@ -78,6 +75,7 @@ private static NormalRule rewriteIntervalSpecifications(NormalRule rule) { } // Note that this cast is safe: NormalHead can only have a BasicAtom, so literalizing and getting back the Atom destroys type information, // but should never yield anything other than a BasicAtom + // TODO handle action headS! NormalHead rewrittenHead = rule.isConstraint() ? null : Heads.newNormalHead((BasicAtom) rewriteLiteral(rule.getHead().getAtom().toLiteral(), intervalReplacements).getAtom()); @@ -90,7 +88,7 @@ private static NormalRule rewriteIntervalSpecifications(NormalRule rule) { for (Map.Entry interval : intervalReplacements.entrySet()) { rewrittenBody.add(new IntervalAtom(interval.getValue(), interval.getKey()).toLiteral()); } - return new NormalRuleImpl(rewrittenHead, rewrittenBody); + return Rules.newNormalRule(rewrittenHead, rewrittenBody); } /** @@ -182,6 +180,6 @@ public NormalProgram apply(NormalProgram inputProgram) { if (!didChange) { return inputProgram; } - return new NormalProgramImpl(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return Programs.newNormalProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/NormalizeProgramTransformation.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/NormalizeProgramTransformation.java index 341c46eb1..d3b5c9cc8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/NormalizeProgramTransformation.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/NormalizeProgramTransformation.java @@ -1,11 +1,10 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import java.util.function.Supplier; - +import at.ac.tuwien.kr.alpha.api.config.AggregateRewritingConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; -import at.ac.tuwien.kr.alpha.core.atoms.EnumerationAtom; -import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.core.programs.atoms.EnumerationAtom; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewriting; /** @@ -15,10 +14,10 @@ */ public class NormalizeProgramTransformation extends ProgramTransformation { - private final Supplier aggregateRewritingFactory; + private final AggregateRewritingConfig aggregateRewritingCfg; - public NormalizeProgramTransformation(Supplier aggregateRewritingFactory) { - this.aggregateRewritingFactory = aggregateRewritingFactory; + public NormalizeProgramTransformation(AggregateRewritingConfig aggregateCfg) { + this.aggregateRewritingCfg = aggregateCfg; } @Override @@ -29,13 +28,13 @@ public NormalProgram apply(InputProgram inputProgram) { // Transform choice rules. tmpPrg = new ChoiceHeadToNormal().apply(tmpPrg); // Transform aggregates. - tmpPrg = aggregateRewritingFactory.get().apply(tmpPrg); + tmpPrg = new AggregateRewriting(aggregateRewritingCfg.isUseSortingGridEncoding(), aggregateRewritingCfg.isSupportNegativeValuesInSums()).apply(tmpPrg); // Transform enumeration atoms. tmpPrg = new EnumerationRewriting().apply(tmpPrg); EnumerationAtom.resetEnumerations(); // Construct the normal program. - NormalProgram retVal = NormalProgramImpl.fromInputProgram(tmpPrg); + NormalProgram retVal = Programs.toNormalProgram(tmpPrg); // Transform intervals. retVal = new IntervalTermToIntervalAtom().apply(retVal); // Rewrite ArithmeticTerms. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/PredicateInternalizer.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/PredicateInternalizer.java index 9deb24b06..5095da814 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/PredicateInternalizer.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/PredicateInternalizer.java @@ -1,22 +1,23 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import java.util.ArrayList; -import java.util.List; - import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; + +import java.util.LinkedHashSet; +import java.util.Set; /** * @@ -27,7 +28,7 @@ public class PredicateInternalizer { public static InputProgram makePrefixedPredicatesInternal(InputProgram program, String prefix) { - InputProgramImpl.Builder prgBuilder = InputProgramImpl.builder(); + InputProgramBuilder prgBuilder = Programs.builder(); for (Atom atom : program.getFacts()) { if (atom.getPredicate().getName().startsWith(prefix)) { prgBuilder.addFact(PredicateInternalizer.makePredicateInternal((BasicAtom) atom)); @@ -55,7 +56,7 @@ public static Rule makePrefixedPredicatesInternal(Rule rule, String newHead = head; } } - List newBody = new ArrayList<>(); + Set newBody = new LinkedHashSet<>(); for (Literal bodyElement : rule.getBody()) { // Only rewrite BasicAtoms. if (bodyElement instanceof BasicLiteral) { @@ -69,7 +70,7 @@ public static Rule makePrefixedPredicatesInternal(Rule rule, String newBody.add(bodyElement); } } - return new BasicRule(newHead, newBody); + return Rules.newRule(newHead, newBody); } private static BasicAtom makePredicateInternal(BasicAtom atom) { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformation.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformation.java index 0b7d4e7f1..5fc28c50a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformation.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformation.java @@ -1,7 +1,7 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; import at.ac.tuwien.kr.alpha.api.programs.Program; -import at.ac.tuwien.kr.alpha.api.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; /** * Copyright (c) 2017-2019, the Alpha Team. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluation.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluation.java index 2c3105134..07bf0036e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluation.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluation.java @@ -11,6 +11,15 @@ import java.util.Set; import java.util.Stack; +import at.ac.tuwien.kr.alpha.api.programs.rules.RuleInstantiator; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ActionHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.InstantiableHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; import org.apache.commons.collections4.SetUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.slf4j.Logger; @@ -21,10 +30,13 @@ import at.ac.tuwien.kr.alpha.api.programs.analysis.ComponentGraph; import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; +import at.ac.tuwien.kr.alpha.core.actions.ActionExecutionService; +import at.ac.tuwien.kr.alpha.core.actions.ActionWitness; import at.ac.tuwien.kr.alpha.core.depgraph.StratificationAlgorithm; import at.ac.tuwien.kr.alpha.core.grounder.IndexedInstanceStorage; import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfo; @@ -36,14 +48,13 @@ import at.ac.tuwien.kr.alpha.core.grounder.instantiation.WorkingMemoryBasedInstantiationStrategy; import at.ac.tuwien.kr.alpha.core.programs.AnalyzedProgram; import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; /** * Evaluates the stratifiable part of a given (analyzed) ASP program. - * + * * Copyright (c) 2019-2020, the Alpha Team. */ -public class StratifiedEvaluation extends ProgramTransformation { +public class StratifiedEvaluation extends ProgramTransformation implements RuleInstantiator { private static final Logger LOGGER = LoggerFactory.getLogger(StratifiedEvaluation.class); @@ -56,6 +67,13 @@ public class StratifiedEvaluation extends ProgramTransformation solvedRuleIds = new HashSet<>(); // Set of rules that have been completely evaluated. private LiteralInstantiator literalInstantiator; + private ActionExecutionService actionExecutionService; + private final boolean generateActionWitnesses; + + public StratifiedEvaluation(ActionExecutionService actionExecutionService, boolean generateActionWitnesses) { + this.actionExecutionService = actionExecutionService; + this.generateActionWitnesses = generateActionWitnesses; + } @Override // Note: ideally this returns a "PartiallyEvaluatedProgram" such that the grounder can directly use the working @@ -84,7 +102,7 @@ public InternalProgram apply(AnalyzedProgram inputProgram) { // Set up set of facts to which we'll add everything derived during stratified evaluation. outputFacts = new HashSet<>(inputProgram.getFacts()); - + // Set up literal instantiator. literalInstantiator = new LiteralInstantiator(new WorkingMemoryBasedInstantiationStrategy(workingMemory)); @@ -229,7 +247,7 @@ private List calculateSatisfyingSubstitutionsForRule(CompiledRule * Use this to find initial substitutions for a starting literal when grounding a rule. * In order to avoid finding the same ground instantiations of rules again, only look at * modifiedInLastEvaluationRun to obtain instances. - * + * * @param lit the literal to substitute. * @return valid ground substitutions for the literal based on the recently added instances (i.e. instances derived in * the last evaluation run). @@ -259,7 +277,7 @@ private List calcSubstitutionsWithGroundingOrder(RuleGroundingOrde substitutionStack.push((ArrayList) startingSubstitutions); } else { substitutionStack.push(new ArrayList<>(startingSubstitutions)); // Copy startingSubstitutions into ArrayList. Note: mostly happens for empty or - // singleton lists. + // singleton lists. } int currentOrderPosition = 0; List fullSubstitutions = new ArrayList<>(); @@ -284,7 +302,7 @@ private List calcSubstitutionsWithGroundingOrder(RuleGroundingOrde } // Take one substitution from the top-list of the stack and try extending it. Substitution currentSubstitution = currentSubstitutions.remove(currentSubstitutions.size() - 1); // Work on last element (removing last element is - // O(1) for ArrayList). + // O(1) for ArrayList). LiteralInstantiationResult currentLiteralResult = literalInstantiator.instantiateLiteral(currentLiteral, currentSubstitution); if (currentLiteralResult.getType() == LiteralInstantiationResult.Type.CONTINUE) { // The currentSubstitution could be extended, push the extensions on the stack and continue working on them. @@ -301,7 +319,13 @@ private List calcSubstitutionsWithGroundingOrder(RuleGroundingOrde } private void fireRule(CompiledRule rule, Substitution substitution) { - Atom newAtom = rule.getHeadAtom().substitute(substitution); + // BasicAtom newAtom = this.instantiate(rule.getHead(), substitution); + BasicAtom newAtom; + if (rule.getHead() instanceof ActionHead) { + newAtom = instantiateActionHead((ActionHead) rule.getHead(), substitution, rule); + } else { + newAtom = instantiateNormalHead(rule.getHead(), substitution); + } if (!newAtom.isGround()) { throw new IllegalStateException("Trying to fire rule " + rule.toString() + " with incompatible substitution " + substitution.toString()); } @@ -309,6 +333,64 @@ private void fireRule(CompiledRule rule, Substitution substitution) { workingMemory.addInstance(newAtom, true); } + @Override + public BasicAtom instantiate(InstantiableHead ruleHead, Substitution substitution) { + return ruleHead.instantiate(this, substitution); + } + + // FIXME should be dispatched via visitor pattern + public BasicAtom instantiateNormalHead(NormalHead head, Substitution substitution) { + return head.getAtom().substitute(substitution); + } + + // FIXME should be dispatched via visitor pattern + public BasicAtom instantiateActionHead(ActionHead head, Substitution substitution, CompiledRule rule) { + List actionInput = head.getActionInputTerms(); + List substitutedInput = new ArrayList<>(); + // Substitute all variables in action input so that all input terms are ground. + for (Term inputTerm : actionInput) { + substitutedInput.add(inputTerm.substitute(substitution)); + } + // Delegate action execution to respective backend. + ActionWitness witness = actionExecutionService.execute(head.getActionName(), rule.getRuleId(), substitution, substitutedInput); + // If the according debug flag is set, convert witness to atom and add to facts. + if (generateActionWitnesses) { + BasicAtom witnessAtom = buildActionWitnessAtom(witness, rule); + // Note that this is a rather "sneaky" side-effect, + // but seems like overkill to do this structurally proper just for a debug feature. + workingMemory.addInstance(witnessAtom, true); + } + // We have an action result. Add it to the substitution as the substitute for the variable bound to the action so we're able to obtain the + // ground BasicAtom derived by the rule + substitution.put(head.getActionOutputTerm(), witness.getActionResult()); + return head.getAtom().substitute(substitution); + } + + private BasicAtom buildActionWitnessAtom(ActionWitness witness, CompiledRule rule) { + // Note that this methods should only ever be used for debugging! + // While action witnesses are used as a semantic concept in the evolog specification, + // they normally only exist implicitly. + + // Construct state term: create function terms from ground body literals. + List functionalizedBody = new ArrayList<>(); + for (Literal lit : rule.getBody()) { + Literal groundLit = lit.substitute(witness.getGroundSubstitution()); + FunctionTerm functionalizedLiteral = Terms.newFunctionTerm(groundLit.getPredicate().getName(), groundLit.getTerms()); + functionalizedBody.add(functionalizedLiteral); + } + FunctionTerm stateTerm = Terms.newFunctionTerm("state", functionalizedBody); + + // Construct input term: wrap action input terms into one function term. + FunctionTerm inputTerm = Terms.newFunctionTerm("input", witness.getActionInput()); + + // Return witness atom: put state and input terms together. + return Atoms.newBasicAtom(Predicates.getPredicate("action_witness", 4), + Terms.newConstant(witness.getActionName()), + stateTerm, + inputTerm, + witness.getActionResult()); + } + private ComponentEvaluationInfo getRulesToEvaluate(ComponentGraph.SCComponent comp) { Set nonRecursiveRules = new HashSet<>(); Set recursiveRules = new HashSet<>(); @@ -352,7 +434,7 @@ private ComponentEvaluationInfo getRulesToEvaluate(ComponentGraph.SCComponent co * dependency chain within that component, and non-recursive rules, i.e. rules where all body predicates occur in lower * strata. The reason for this grouping is that, when evaluating rules within a component, non-recursive rules only need * to be evaluated once, while recursive rules need to be evaluated until a fixed-point has been reached. - * + * * Copyright (c) 2020, the Alpha Team. */ private class ComponentEvaluationInfo { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/VariableEqualityRemoval.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/VariableEqualityRemoval.java index 11f361cd4..1ca5eb985 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/VariableEqualityRemoval.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/VariableEqualityRemoval.java @@ -27,30 +27,23 @@ */ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.DisjunctiveHead; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ActionHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.DisjunctiveHead; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; /** * Removes variable equalities from rules by replacing one variable with the other. @@ -65,7 +58,7 @@ public InputProgram apply(InputProgram inputProgram) { for (Rule rule : inputProgram.getRules()) { rewrittenRules.add(findAndReplaceVariableEquality(rule)); } - return new InputProgramImpl(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return Programs.newInputProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); } private Rule findAndReplaceVariableEquality(Rule rule) { @@ -112,11 +105,20 @@ private Rule findAndReplaceVariableEquality(Rule rule) { return rule; } - List rewrittenBody = new ArrayList<>(rule.getBody()); + Set rewrittenBody = new LinkedHashSet<>(rule.getBody()); if (!rule.isConstraint() && rule.getHead() instanceof DisjunctiveHead) { throw new UnsupportedOperationException("VariableEqualityRemoval cannot be applied to rule with DisjunctiveHead, yet."); } - NormalHead rewrittenHead = rule.isConstraint() ? null : Heads.newNormalHead(((NormalHead)rule.getHead()).getAtom()); + // TODO can this be done nicer? + NormalHead rewrittenHead = null; + if (!rule.isConstraint()) { + if (rule.getHead() instanceof ActionHead) { + ActionHead actHead = (ActionHead) rule.getHead(); + rewrittenHead = Heads.newActionHead(actHead.getAtom(), actHead.getActionName(), actHead.getActionInputTerms(), actHead.getActionOutputTerm()); + } else { + rewrittenHead = Heads.newNormalHead(((NormalHead) rule.getHead()).getAtom()); + } + } // Use substitution for actual replacement. Unifier replacementSubstitution = new Unifier(); @@ -149,6 +151,6 @@ private Rule findAndReplaceVariableEquality(Rule rule) { headAtom.getTerms().set(i, replaced); } } - return new BasicRule(rewrittenHead, rewrittenBody); + return Rules.newRule(rewrittenHead, rewrittenBody); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateLiteralSplitting.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateLiteralSplitting.java index 457d41daa..ed55537b0 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateLiteralSplitting.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateLiteralSplitting.java @@ -1,8 +1,6 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -10,11 +8,11 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; /** * Splits aggregate literals with both "lower" and "upper" bound operators into literals with only one operator each. @@ -66,17 +64,17 @@ private static List> splitAggregatesInRule(Rule sourceRule) { } } // Second, compute rule bodies of splitting result. - List commonBody = new ArrayList<>(commonBodyLiterals); + Set commonBody = new LinkedHashSet<>(commonBodyLiterals); commonBody.addAll(twoLiteralsSplitAggregates); - List> rewrittenBodies = new ArrayList<>(); + List> rewrittenBodies = new ArrayList<>(); rewrittenBodies.add(commonBody); // Initialize list of rules with the common body. // For n twoRulesSplitAggregates we need 2^n rules, so // for each of the n pairs in twoRulesSplitAggregates we duplicate the list of rewritten bodies. for (ImmutablePair ruleSplitAggregate : twoRulesSplitAggregates) { int numBodiesBeforeDuplication = rewrittenBodies.size(); for (int i = 0; i < numBodiesBeforeDuplication; i++) { - List originalBody = rewrittenBodies.get(i); - List duplicatedBody = new ArrayList<>(originalBody); + Set originalBody = rewrittenBodies.get(i); + Set duplicatedBody = new LinkedHashSet<>(originalBody); // Extend bodies of original and duplicate with splitting results. originalBody.add(ruleSplitAggregate.left); duplicatedBody.add(ruleSplitAggregate.right); @@ -85,8 +83,8 @@ private static List> splitAggregatesInRule(Rule sourceRule) { } // Third, turn computed bodies into rules again. List> rewrittenRules = new ArrayList<>(); - for (List rewrittenBody : rewrittenBodies) { - rewrittenRules.add(new BasicRule(sourceRule.getHead(), rewrittenBody)); + for (Set rewrittenBody : rewrittenBodies) { + rewrittenRules.add(Rules.newRule(sourceRule.getHead(), rewrittenBody)); } return rewrittenRules; } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalization.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalization.java index 66d93a737..8235c1364 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalization.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalization.java @@ -1,29 +1,26 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; -import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticOperator; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; /** - * Transforms an {@link InputProgram} such that, for all aggregate (body-)literals, only the comparison operators "=" + * Transforms an {@link at.ac.tuwien.kr.alpha.api.programs.InputProgram} such that, for all aggregate (body-)literals, only the comparison operators "=" * and "<=" are used. * * Rewriting of "#count" and "#sum" aggregates is done using the following equivalences: @@ -42,7 +39,7 @@ * Note that input programs must only contain aggregate literals of form TERM OP #aggr{...} or #aggr{...} OP TERM, * i.e. with only * a left or right term and operator (but not both). When preprocessing programs, apply this transformation AFTER - * {@link at.ac.tuwien.kr.alpha.grounder.transformation.aggregates.AggregateLiteralSplitting}. + * {@link AggregateLiteralSplitting}. * * Copyright (c) 2020-2021, the Alpha Team. */ @@ -53,11 +50,11 @@ private AggregateOperatorNormalization() { } public static Rule normalize(Rule rule) { - List rewrittenBody = new ArrayList<>(); + Set rewrittenBody = new LinkedHashSet<>(); for (Literal lit : rule.getBody()) { rewrittenBody.addAll(rewriteLiteral(lit)); } - return new BasicRule(rule.getHead(), rewrittenBody); + return Rules.newRule(rule.getHead(), rewrittenBody); } private static List rewriteLiteral(Literal lit) { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewriting.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewriting.java index da9352b3a..48d4747c9 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewriting.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewriting.java @@ -1,29 +1,24 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang3.tuple.ImmutablePair; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; import at.ac.tuwien.kr.alpha.core.programs.transformation.ProgramTransformation; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewritingContext.AggregateInfo; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders.AbstractAggregateEncoder; -import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders.CountEncoder; -import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders.MinMaxEncoder; -import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders.SumEncoder; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders.AggregateEncoders; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import java.util.*; /** * Rewrites {@link AggregateLiteral}s in programs to semantically equivalent, aggregate-free sub-programs. @@ -49,14 +44,13 @@ public class AggregateRewriting extends ProgramTransformation, Set> aggToRewrite : ctx.getAggregateFunctionsToRewrite() @@ -138,7 +132,7 @@ private AbstractAggregateEncoder getEncoderForAggregateFunction(AggregateFunctio private static List> rewriteRulesWithAggregates(AggregateRewritingContext ctx) { List> rewrittenRules = new ArrayList<>(); for (Rule rule : ctx.getRulesWithAggregates()) { - List rewrittenBody = new ArrayList<>(); + Set rewrittenBody = new LinkedHashSet<>(); for (Literal lit : rule.getBody()) { if (lit instanceof AggregateLiteral) { AggregateInfo aggregateInfo = ctx.getAggregateInfo((AggregateLiteral) lit); @@ -147,7 +141,7 @@ private static List> rewriteRulesWithAggregates(AggregateRewritingCon rewrittenBody.add(lit); } } - rewrittenRules.add(new BasicRule(rule.getHead(), rewrittenBody)); + rewrittenRules.add(Rules.newRule(rule.getHead(), rewrittenBody)); } return rewrittenRules; } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingContext.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingContext.java index fa704b3ab..a1742b71d 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingContext.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingContext.java @@ -1,19 +1,5 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates; -import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.stringtemplate.v4.ST; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; @@ -21,13 +7,19 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.stringtemplate.v4.ST; + +import java.util.*; + +import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; /** * Holds all information about aggregate literals that need to be rewritten within a program. diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingRuleAnalysis.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingRuleAnalysis.java index fd97d61be..9647fa444 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingRuleAnalysis.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingRuleAnalysis.java @@ -1,23 +1,16 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.collections4.SetUtils; - import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import org.apache.commons.collections4.SetUtils; + +import java.util.*; /** * Analyses a rule and records occurring aggregates and for each aggregate its global variables and its dependencies on diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AbstractAggregateEncoder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AbstractAggregateEncoder.java index e609c3984..92a09f658 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AbstractAggregateEncoder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AbstractAggregateEncoder.java @@ -1,11 +1,5 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import org.apache.commons.collections4.ListUtils; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; @@ -13,19 +7,26 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.programs.transformation.PredicateInternalizer; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewritingContext.AggregateInfo; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.SetUtils; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; /** * Abstract base class for aggregate encoders. An aggregate encoder provides an encoding for a given aggregate literal, @@ -52,7 +53,7 @@ protected AbstractAggregateEncoder(AggregateFunctionSymbol aggregateFunctionToEn * @return all rules encoding the given aggregates as an {@link InputProgram}. */ public InputProgram encodeAggregateLiterals(Set aggregatesToEncode) { - InputProgramImpl.Builder programBuilder = InputProgramImpl.builder(); + InputProgramBuilder programBuilder = Programs.builder(); for (AggregateInfo aggregateInfo : aggregatesToEncode) { programBuilder.accumulate(encodeAggregateLiteral(aggregateInfo)); } @@ -82,7 +83,7 @@ public InputProgram encodeAggregateLiteral(AggregateInfo aggregateToEncode) { Rule elementRule = encodeAggregateElement(aggregateToEncode, elementToEncode); elementEncodingRules.add(PredicateInternalizer.makePrefixedPredicatesInternal(elementRule, aggregateId)); } - return new InputProgramImpl(ListUtils.union(literalEncoding.getRules(), elementEncodingRules), literalEncoding.getFacts(), new InlineDirectivesImpl()); + return Programs.newInputProgram(ListUtils.union(literalEncoding.getRules(), elementEncodingRules), literalEncoding.getFacts(), Programs.newInlineDirectives()); } /** @@ -104,8 +105,8 @@ public InputProgram encodeAggregateLiteral(AggregateInfo aggregateToEncode) { */ protected Rule encodeAggregateElement(AggregateInfo aggregateInfo, AggregateElement element) { BasicAtom headAtom = buildElementRuleHead(aggregateInfo.getId(), element, aggregateInfo.getAggregateArguments()); - return new BasicRule(Heads.newNormalHead(headAtom), - ListUtils.union(element.getElementLiterals(), new ArrayList<>(aggregateInfo.getDependencies()))); + return Rules.newRule(Heads.newNormalHead(headAtom), + SetUtils.union(new LinkedHashSet<>(element.getElementLiterals()), new LinkedHashSet<>(aggregateInfo.getDependencies()))); } /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AggregateEncoderFactory.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AggregateEncoderFactory.java deleted file mode 100644 index cb3d1152a..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AggregateEncoderFactory.java +++ /dev/null @@ -1,44 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; - -import java.util.function.Supplier; - -import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; -import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; - -public class AggregateEncoderFactory { - - private final Supplier parserFactory; - private final boolean useSortingGridEncoding; - private final boolean supportNegativeSumElements; - - public AggregateEncoderFactory(Supplier parserFactory, boolean useSortingGridEncoding, boolean supportNegativeSumElements) { - this.parserFactory = parserFactory; - this.useSortingGridEncoding = useSortingGridEncoding; - this.supportNegativeSumElements = supportNegativeSumElements; - } - - public CountEncoder newCountEqualsEncoder() { - return CountEncoder.buildCountEqualsEncoder(parserFactory.get()); - } - - public CountEncoder newCountLessOrEqualEncoder() { - return CountEncoder.buildCountLessOrEqualEncoder(parserFactory.get(), useSortingGridEncoding); - } - - public SumEncoder newSumEqualsEncoder() { - return SumEncoder.buildSumEqualsEncoder(parserFactory.get(), supportNegativeSumElements); - } - - public SumEncoder newSumLessOrEqualEncoder() { - return SumEncoder.buildSumLessOrEqualEncoder(parserFactory.get(), supportNegativeSumElements); - } - - public MinMaxEncoder newMinEncoder() { - return new MinMaxEncoder(AggregateFunctionSymbol.MIN); - } - - public MinMaxEncoder newMaxEncoder() { - return new MinMaxEncoder(AggregateFunctionSymbol.MAX); - } - -} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AggregateEncoders.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AggregateEncoders.java new file mode 100644 index 000000000..a22ecb65e --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AggregateEncoders.java @@ -0,0 +1,35 @@ +package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; + +public final class AggregateEncoders { + + private AggregateEncoders() { + throw new AssertionError("Cannot instantiate utility class!"); + } + + public static CountEncoder newCountEqualsEncoder() { + return CountEncoder.buildCountEqualsEncoder(); + } + + public static CountEncoder newCountLessOrEqualEncoder(boolean useSortingGridEncoding) { + return CountEncoder.buildCountLessOrEqualEncoder(useSortingGridEncoding); + } + + public static SumEncoder newSumEqualsEncoder(boolean supportNegativeSumElements) { + return SumEncoder.buildSumEqualsEncoder(supportNegativeSumElements); + } + + public static SumEncoder newSumLessOrEqualEncoder(boolean supportNegativeSumElements) { + return SumEncoder.buildSumLessOrEqualEncoder(supportNegativeSumElements); + } + + public static MinMaxEncoder newMinEncoder() { + return new MinMaxEncoder(AggregateFunctionSymbol.MIN); + } + + public static MinMaxEncoder newMaxEncoder() { + return new MinMaxEncoder(AggregateFunctionSymbol.MAX); + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/CountEncoder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/CountEncoder.java index be64efabd..dceca1dcf 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/CountEncoder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/CountEncoder.java @@ -1,13 +1,11 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; -import org.stringtemplate.v4.ST; -import org.stringtemplate.v4.STGroup; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; -import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; import at.ac.tuwien.kr.alpha.commons.util.Util; +import org.stringtemplate.v4.ST; +import org.stringtemplate.v4.STGroup; public final class CountEncoder extends StringtemplateBasedAggregateEncoder { @@ -18,16 +16,16 @@ public final class CountEncoder extends StringtemplateBasedAggregateEncoder { private static final ST CNT_EQ_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("cnt_eq"); private static final ST CNT_LE_COUNTING_GRID_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("cnt_le_counting_grid"); - private CountEncoder(ProgramParser parser, ComparisonOperator acceptedOperator, ST encodingTemplate) { - super(parser, AggregateFunctionSymbol.COUNT, acceptedOperator, encodingTemplate); + private CountEncoder(ComparisonOperator acceptedOperator, ST encodingTemplate) { + super(AggregateFunctionSymbol.COUNT, acceptedOperator, encodingTemplate); } - static CountEncoder buildCountLessOrEqualEncoder(ProgramParser parser, boolean useSortingGrid) { - return new CountEncoder(parser, ComparisonOperators.LE, useSortingGrid ? CNT_LE_SORTING_GRID_TEMPLATE : CNT_LE_COUNTING_GRID_TEMPLATE); + static CountEncoder buildCountLessOrEqualEncoder(boolean useSortingGrid) { + return new CountEncoder(ComparisonOperators.LE, useSortingGrid ? CNT_LE_SORTING_GRID_TEMPLATE : CNT_LE_COUNTING_GRID_TEMPLATE); } - static CountEncoder buildCountEqualsEncoder(ProgramParser parser) { - return new CountEncoder(parser, ComparisonOperators.EQ, CNT_EQ_TEMPLATE); + static CountEncoder buildCountEqualsEncoder() { + return new CountEncoder(ComparisonOperators.EQ, CNT_EQ_TEMPLATE); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/MinMaxEncoder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/MinMaxEncoder.java index 316d1ad5c..0f8b5d9da 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/MinMaxEncoder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/MinMaxEncoder.java @@ -1,11 +1,5 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.collections4.SetUtils; -import org.stringtemplate.v4.ST; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; @@ -16,20 +10,28 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewritingContext.AggregateInfo; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import org.apache.commons.collections4.SetUtils; +import org.stringtemplate.v4.ST; + +import java.util.LinkedHashSet; +import java.util.Set; public class MinMaxEncoder extends AbstractAggregateEncoder { @@ -109,7 +111,7 @@ protected InputProgram encodeAggregateResult(AggregateInfo aggregateToEncode) { */ NormalHead resultRuleHead = Heads.newNormalHead( Atoms.newBasicAtom(Predicates.getPredicate(resultName, 2), aggregateToEncode.getAggregateArguments(), atom.getLowerBoundTerm())); - List resultRuleBody = new ArrayList<>(); + Set resultRuleBody = new LinkedHashSet<>(); VariableTerm aggregateValue = Terms.newVariable("_AGG_VAL"); ComparisonLiteral aggregateValueComparison = Literals.fromAtom(Atoms.newComparisonAtom(atom.getLowerBoundTerm(), aggregateValue, cmpOp), true); Literal aggregateResult = Atoms.newBasicAtom(Predicates.getPredicate( @@ -118,8 +120,8 @@ protected InputProgram encodeAggregateResult(AggregateInfo aggregateToEncode) { resultRuleBody.add(aggregateResult); resultRuleBody.add(aggregateValueComparison); resultRuleBody.addAll(aggregateToEncode.getDependencies()); - InputProgramImpl.Builder bld = InputProgramImpl.builder(parser.parse(encodingTemplate.render())); - BasicRule resultRule = new BasicRule(resultRuleHead, resultRuleBody); + InputProgramBuilder bld = Programs.builder(parser.parse(encodingTemplate.render())); + Rule resultRule = Rules.newRule(resultRuleHead, resultRuleBody); bld.addRule(resultRule); return bld.build(); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/StringtemplateBasedAggregateEncoder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/StringtemplateBasedAggregateEncoder.java index c025a6d55..94fa889c8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/StringtemplateBasedAggregateEncoder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/StringtemplateBasedAggregateEncoder.java @@ -1,28 +1,27 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; -import java.util.ArrayList; -import java.util.Collections; - -import org.apache.commons.collections4.ListUtils; -import org.stringtemplate.v4.ST; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import at.ac.tuwien.kr.alpha.core.programs.transformation.EnumerationRewriting; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewritingContext.AggregateInfo; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; +import org.apache.commons.collections4.ListUtils; +import org.stringtemplate.v4.ST; + +import java.util.Collections; +import java.util.LinkedHashSet; /** * Abstract base class for aggregate encoders making use of stringtemplates in their rewriting workflow. @@ -36,14 +35,13 @@ */ public abstract class StringtemplateBasedAggregateEncoder extends AbstractAggregateEncoder { - private final ProgramParser parser; + private final ProgramParser parser = new ProgramParserImpl(); private final ST encodingTemplate; private final boolean needsBoundRule; - protected StringtemplateBasedAggregateEncoder(ProgramParser parser, AggregateFunctionSymbol aggregateFunctionToEncode, ComparisonOperator acceptedOperator, ST encodingTemplate) { + protected StringtemplateBasedAggregateEncoder(AggregateFunctionSymbol aggregateFunctionToEncode, ComparisonOperator acceptedOperator, ST encodingTemplate) { super(aggregateFunctionToEncode, Collections.singleton(acceptedOperator)); this.encodingTemplate = encodingTemplate; - this.parser = parser; if (acceptedOperator.equals(ComparisonOperators.EQ)) { this.needsBoundRule = false; } else if (acceptedOperator.equals(ComparisonOperators.LE)) { @@ -85,8 +83,8 @@ protected InputProgram encodeAggregateResult(AggregateInfo aggregateToEncode) { InputProgram coreEncoding = new EnumerationRewriting().apply(parser.parse(coreEncodingAsp)); // Add the programatically created bound rule and return - return new InputProgramImpl(ListUtils.union(coreEncoding.getRules(), Collections.singletonList(boundRule)), coreEncoding.getFacts(), - new InlineDirectivesImpl()); + return Programs.newInputProgram(ListUtils.union(coreEncoding.getRules(), Collections.singletonList(boundRule)), coreEncoding.getFacts(), + Programs.newInlineDirectives()); } private String getBoundPredicateName(String aggregateId) { @@ -96,13 +94,13 @@ private String getBoundPredicateName(String aggregateId) { private Rule buildZeroBoundRule(AggregateInfo aggregateToEncode) { BasicAtom bound = Atoms.newBasicAtom(Predicates.getPredicate(getBoundPredicateName(aggregateToEncode.getId()), 2), aggregateToEncode.getAggregateArguments(), Terms.newConstant(0)); - return new BasicRule(Heads.newNormalHead(bound), new ArrayList<>(aggregateToEncode.getDependencies())); + return Rules.newRule(Heads.newNormalHead(bound), new LinkedHashSet<>(aggregateToEncode.getDependencies())); } private Rule buildBoundRule(AggregateInfo aggregateToEncode) { BasicAtom bound = Atoms.newBasicAtom(Predicates.getPredicate(getBoundPredicateName(aggregateToEncode.getId()), 2), aggregateToEncode.getAggregateArguments(), aggregateToEncode.getLiteral().getAtom().getLowerBoundTerm()); - return new BasicRule(Heads.newNormalHead(bound), new ArrayList<>(aggregateToEncode.getDependencies())); + return Rules.newRule(Heads.newNormalHead(bound), new LinkedHashSet<>(aggregateToEncode.getDependencies())); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/SumEncoder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/SumEncoder.java index 95d9737a3..c184d2dce 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/SumEncoder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/SumEncoder.java @@ -1,21 +1,19 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; -import org.stringtemplate.v4.ST; -import org.stringtemplate.v4.STGroup; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateElement; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; +import org.stringtemplate.v4.ST; +import org.stringtemplate.v4.STGroup; /** * Aggregate encoder handling sum aggregates. @@ -33,16 +31,16 @@ public final class SumEncoder extends StringtemplateBasedAggregateEncoder { private static final ST NON_NEG_ELEMENTS_SUM_LE_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("sum_le_no_negative_elements"); private static final ST NON_NEG_ELEMENTS_SUM_EQ_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("sum_eq_no_negative_elements"); - private SumEncoder(ProgramParser parser, ComparisonOperator acceptedOperator, ST encodingTemplate) { - super(parser, AggregateFunctionSymbol.SUM, acceptedOperator, encodingTemplate); + private SumEncoder(ComparisonOperator acceptedOperator, ST encodingTemplate) { + super(AggregateFunctionSymbol.SUM, acceptedOperator, encodingTemplate); } - public static SumEncoder buildSumLessOrEqualEncoder(ProgramParser parser, boolean supportNegativeIntegers) { - return new SumEncoder(parser, ComparisonOperators.LE, supportNegativeIntegers ? SUM_LE_TEMPLATE : NON_NEG_ELEMENTS_SUM_LE_TEMPLATE); + static SumEncoder buildSumLessOrEqualEncoder(boolean supportNegativeIntegers) { + return new SumEncoder(ComparisonOperators.LE, supportNegativeIntegers ? SUM_LE_TEMPLATE : NON_NEG_ELEMENTS_SUM_LE_TEMPLATE); } - public static SumEncoder buildSumEqualsEncoder(ProgramParser parser, boolean supportNegativeIntegers) { - return new SumEncoder(parser, ComparisonOperators.EQ, supportNegativeIntegers ? SUM_EQ_TEMPLATE : NON_NEG_ELEMENTS_SUM_EQ_TEMPLATE); + static SumEncoder buildSumEqualsEncoder(boolean supportNegativeIntegers) { + return new SumEncoder(ComparisonOperators.EQ, supportNegativeIntegers ? SUM_EQ_TEMPLATE : NON_NEG_ELEMENTS_SUM_EQ_TEMPLATE); } /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRules.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRules.java new file mode 100644 index 000000000..a3f81eefa --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRules.java @@ -0,0 +1,29 @@ +package at.ac.tuwien.kr.alpha.core.rules; + +import java.util.LinkedHashSet; +import java.util.Set; + +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; + +public final class CompiledRules { + + private CompiledRules() { + throw new AssertionError("Cannot instantiate utility class!"); + } + + public static CompiledRule newCompiledRule(NormalHead head, Set body) { + return new InternalRule(head, body); + } + + public static CompiledRule newCompiledRule(NormalHead head, Literal... body) { + Set bodySet = new LinkedHashSet<>(); + for (Literal lit : body) { + bodySet.add(lit); + } + return CompiledRules.newCompiledRule(head, bodySet); + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/NormalRuleImpl.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/NormalRuleImpl.java deleted file mode 100644 index 5283a6a6d..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/NormalRuleImpl.java +++ /dev/null @@ -1,60 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.rules; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.util.Util; - -/** - * A rule that has a normal head, i.e. just one head atom, no disjunction or choice heads allowed. - * Currently, any constructs such as aggregates, intervals, etc. in the rule body are allowed. - * - * Copyright (c) 2019, the Alpha Team. - */ -public class NormalRuleImpl extends AbstractRule implements NormalRule { - - public NormalRuleImpl(NormalHead head, List body) { - super(head, body); - } - - public NormalRuleImpl(NormalHead head, Set body) { - super(head, body); - } - - public static NormalRuleImpl fromBasicRule(Rule rule) { - BasicAtom headAtom = null; - if (!rule.isConstraint()) { - if (!(rule.getHead() instanceof NormalHead)) { - throw Util.oops("Trying to construct a NormalRule from rule with non-normal head! Head type is: " + rule.getHead().getClass().getSimpleName()); - } - headAtom = ((NormalHead) rule.getHead()).getAtom(); - } - return new NormalRuleImpl(headAtom != null ? Heads.newNormalHead(headAtom) : null, new ArrayList<>(rule.getBody())); - } - - public boolean isGround() { - if (!isConstraint() && !this.getHead().isGround()) { - return false; - } - for (Literal bodyElement : this.getBody()) { - if (!bodyElement.isGround()) { - return false; - } - } - return true; - } - - @Override - public BasicAtom getHeadAtom() { - return this.isConstraint() ? null : this.getHead().getAtom(); - } - -} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/Rules.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/Rules.java deleted file mode 100644 index 7666ba84a..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/Rules.java +++ /dev/null @@ -1,28 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.rules; - -import java.util.ArrayList; -import java.util.List; - -import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; - -public final class Rules { - - private Rules() { - throw new AssertionError("Cannot instantiate utility class!"); - } - - public static Rule newRule(BasicAtom headAtom, Literal... body) { - NormalHead head = Heads.newNormalHead(headAtom); - List bodyLiterals = new ArrayList<>(); - for (Literal lit : body) { - bodyLiterals.add(lit); - } - return new BasicRule(head, bodyLiterals); - } - -} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/Choice.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/Choice.java index 10b398dda..8c50ee903 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/Choice.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/Choice.java @@ -27,8 +27,8 @@ */ package at.ac.tuwien.kr.alpha.core.solver; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isPositive; class Choice { private final int atom; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManager.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManager.java index 8e800b953..0fb5e754e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManager.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManager.java @@ -28,7 +28,7 @@ package at.ac.tuwien.kr.alpha.core.solver; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; import java.util.ArrayList; import java.util.Collections; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/DefaultSolver.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/DefaultSolver.java index b66ff1e01..f8bf444d1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/DefaultSolver.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/DefaultSolver.java @@ -28,9 +28,9 @@ package at.ac.tuwien.kr.alpha.core.solver; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToNegatedLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToNegatedLiteral; import static at.ac.tuwien.kr.alpha.core.solver.NoGoodStore.LBD_NO_VALUE; import static at.ac.tuwien.kr.alpha.core.solver.heuristics.BranchingHeuristic.DEFAULT_CHOICE_LITERAL; import static at.ac.tuwien.kr.alpha.core.solver.learning.GroundConflictNoGoodLearner.ConflictAnalysisResult.UNSAT; @@ -56,20 +56,19 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.NoGood; import at.ac.tuwien.kr.alpha.core.grounder.Grounder; import at.ac.tuwien.kr.alpha.core.grounder.ProgramAnalyzingGrounder; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; import at.ac.tuwien.kr.alpha.core.solver.heuristics.BranchingHeuristic; import at.ac.tuwien.kr.alpha.core.solver.heuristics.BranchingHeuristicFactory; import at.ac.tuwien.kr.alpha.core.solver.heuristics.ChainedBranchingHeuristics; import at.ac.tuwien.kr.alpha.core.solver.heuristics.HeuristicsConfiguration; import at.ac.tuwien.kr.alpha.core.solver.heuristics.NaiveHeuristic; import at.ac.tuwien.kr.alpha.core.solver.learning.GroundConflictNoGoodLearner; -import at.ac.tuwien.kr.alpha.core.util.Substitutions; /** * The new default solver employed in Alpha. @@ -377,11 +376,10 @@ private boolean treatConflictAfterClosing(Antecedent violatedNoGood) { continue; } // For RuleAtoms in toJustify the corresponding ground body contains BasicAtoms that have been assigned FALSE in the closing. - // First, translate RuleAtom back to NonGroundRule + Substitution. - String ruleId = (String) ((ConstantTerm)atom.getTerms().get(0)).getObject(); - CompiledRule nonGroundRule = analyzingGrounder.getNonGroundRule(Integer.parseInt(ruleId)); - String substitution = (String) ((ConstantTerm)atom.getTerms().get(1)).getObject(); - Substitution groundingSubstitution = Substitutions.fromString(substitution); + // First, get NonGroundRule + Substitution, stored in the RuleAtom's single term. + RuleAtom.RuleAtomData ruleAtomData = (RuleAtom.RuleAtomData) ((ConstantTerm)(atom.getTerms().get(0))).getObject(); + Substitution groundingSubstitution = ruleAtomData.getSubstitution(); + CompiledRule nonGroundRule = ruleAtomData.getNonGroundRule(); // Find ground literals in the body that have been assigned false and justify those. for (Literal bodyLiteral : nonGroundRule.getBody()) { Atom groundAtom = bodyLiteral.getAtom().substitute(groundingSubstitution); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/LearnedNoGoodDeletion.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/LearnedNoGoodDeletion.java index f77211baa..d9f47d421 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/LearnedNoGoodDeletion.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/LearnedNoGoodDeletion.java @@ -5,7 +5,7 @@ import at.ac.tuwien.kr.alpha.core.common.Assignment; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import java.util.ArrayList; import java.util.Collections; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveNoGoodStore.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveNoGoodStore.java index 7eb8bc6a2..2d19b7f88 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveNoGoodStore.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveNoGoodStore.java @@ -34,10 +34,12 @@ import java.util.HashMap; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.*; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.*; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.*; public class NaiveNoGoodStore implements NoGoodStore { + + @SuppressWarnings("unused") private static final Logger LOGGER = LoggerFactory.getLogger(NaiveNoGoodStore.class); private HashMap delegate = new HashMap<>(); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveSolver.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveSolver.java index 12507f071..3da723e59 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveSolver.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NaiveSolver.java @@ -27,9 +27,9 @@ */ package at.ac.tuwien.kr.alpha.core.solver; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isNegated; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isNegated; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isPositive; import static java.lang.Math.abs; import java.util.ArrayList; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java index 8b4d1977e..8785ac209 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java @@ -44,12 +44,12 @@ import static at.ac.tuwien.kr.alpha.commons.util.Util.arrayGrowthSize; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isNegated; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.literalToString; import static at.ac.tuwien.kr.alpha.core.common.NoGood.HEAD; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isNegated; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isPositive; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.literalToString; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.FALSE; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.MBT; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.TRUE; @@ -774,7 +774,7 @@ public int size() { @Override public String toString() { - return "BinaryWatchList(" + forLiteral + ")"; + return "BinaryWatchList(" + literalToString(forLiteral) + ")"; } @Override diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java index 929b904f3..47e037d87 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java @@ -27,14 +27,12 @@ */ package at.ac.tuwien.kr.alpha.core.solver; -import static at.ac.tuwien.kr.alpha.commons.util.Util.arrayGrowthSize; -import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; -import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.FALSE; -import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.MBT; -import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.TRUE; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.core.common.Assignment; +import at.ac.tuwien.kr.alpha.core.common.AtomStore; +import at.ac.tuwien.kr.alpha.core.common.IntIterator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; @@ -42,13 +40,14 @@ import java.util.List; import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.core.common.Assignment; -import at.ac.tuwien.kr.alpha.core.common.AtomStore; -import at.ac.tuwien.kr.alpha.core.common.IntIterator; +import static at.ac.tuwien.kr.alpha.commons.util.Util.arrayGrowthSize; +import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isPositive; +import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.FALSE; +import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.MBT; +import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.TRUE; /** * An implementation of Assignment using a trail (of literals) and arrays as underlying structures for storing @@ -72,7 +71,11 @@ public void bumpActivity() { @Override public void decreaseActivity() { + } + @Override + public String toString() { + return "ClosingIndicatorAntecedent"; } }; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WatchedNoGood.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WatchedNoGood.java index 50fde0e88..12f0c128a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WatchedNoGood.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WatchedNoGood.java @@ -33,7 +33,7 @@ import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.literalToString; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.literalToString; public final class WatchedNoGood implements NoGoodInterface, Antecedent { private int activity; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WritableAssignment.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WritableAssignment.java index 6ee85f3f7..f17d76277 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WritableAssignment.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/WritableAssignment.java @@ -27,8 +27,8 @@ */ package at.ac.tuwien.kr.alpha.core.solver; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isPositive; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.NoGood; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaActiveRuleHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaActiveRuleHeuristic.java index f42aa1ee9..aae77b02d 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaActiveRuleHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaActiveRuleHeuristic.java @@ -29,7 +29,7 @@ import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.heuristics.activity.BodyActivityProviderFactory.BodyActivityType; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import java.util.Random; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMin.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMin.java index 0581e6cca..ff1c65c7f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMin.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMin.java @@ -25,9 +25,9 @@ */ package at.ac.tuwien.kr.alpha.core.solver.heuristics; -import at.ac.tuwien.kr.alpha.core.atoms.Literals; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; import at.ac.tuwien.kr.alpha.core.solver.learning.GroundConflictNoGoodLearner.ConflictAnalysisResult; @@ -38,8 +38,8 @@ import java.util.*; import java.util.stream.Stream; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.FALSE; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.TRUE; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMinLiteral.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMinLiteral.java index b523480bf..8a46227f6 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMinLiteral.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BerkMinLiteral.java @@ -31,7 +31,7 @@ import at.ac.tuwien.kr.alpha.core.common.NoGood; import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import java.util.Deque; import java.util.LinkedList; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BranchingHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BranchingHeuristic.java index 2e0bb219d..91a7524d1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BranchingHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/BranchingHeuristic.java @@ -28,7 +28,7 @@ import at.ac.tuwien.kr.alpha.core.common.NoGood; import at.ac.tuwien.kr.alpha.core.solver.learning.GroundConflictNoGoodLearner; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; import java.util.Collection; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/DependencyDrivenHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/DependencyDrivenHeuristic.java index 7d594fbcf..cd63b9a5c 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/DependencyDrivenHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/DependencyDrivenHeuristic.java @@ -25,9 +25,9 @@ */ package at.ac.tuwien.kr.alpha.core.solver.heuristics; -import at.ac.tuwien.kr.alpha.core.atoms.Literals; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; import at.ac.tuwien.kr.alpha.core.solver.heuristics.activity.BodyActivityProvider; @@ -44,7 +44,7 @@ import java.util.function.Predicate; import java.util.stream.Stream; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.*; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.*; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.FALSE; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.TRUE; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenHeuristic.java index 9243c3589..4ebba14b3 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenHeuristic.java @@ -30,7 +30,7 @@ import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.heuristics.activity.BodyActivityProviderFactory.BodyActivityType; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import java.util.HashSet; import java.util.Random; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtoms.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtoms.java index 94421084f..e73b40417 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtoms.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtoms.java @@ -35,7 +35,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import java.util.Arrays; import java.util.Collection; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveChoicePoints.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveChoicePoints.java index 24644e69b..17b09f1ac 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveChoicePoints.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveChoicePoints.java @@ -35,7 +35,7 @@ import java.util.Set; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; /** * Extends {@code HeapOfActiveAtoms} by a mechanism that, diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/NaiveHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/NaiveHeuristic.java index d77a7349f..73aaa986f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/NaiveHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/NaiveHeuristic.java @@ -31,7 +31,7 @@ import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.learning.GroundConflictNoGoodLearner.ConflictAnalysisResult; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; import java.util.Collection; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristic.java index e2b2f3e2a..58d34938f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristic.java @@ -25,8 +25,8 @@ */ package at.ac.tuwien.kr.alpha.core.solver.heuristics; -import at.ac.tuwien.kr.alpha.core.atoms.Literals; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.learning.GroundConflictNoGoodLearner.ConflictAnalysisResult; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDS.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDS.java index bb29d6e14..62286638c 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDS.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDS.java @@ -26,9 +26,9 @@ package at.ac.tuwien.kr.alpha.core.solver.heuristics; import static at.ac.tuwien.kr.alpha.commons.util.Util.arrayGrowthSize; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.isPositive; import java.util.ArrayList; import java.util.Arrays; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/activity/BodyActivityProvider.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/activity/BodyActivityProvider.java index ff4503f9e..33b3257cc 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/activity/BodyActivityProvider.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/activity/BodyActivityProvider.java @@ -27,7 +27,7 @@ import org.apache.commons.collections4.MultiValuedMap; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import java.util.Map; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearner.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearner.java index 3224be049..68bb54701 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearner.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearner.java @@ -41,7 +41,7 @@ import java.util.stream.IntStream; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.*; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.*; import static at.ac.tuwien.kr.alpha.core.solver.NoGoodStore.LBD_NO_VALUE; /** diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/util/Substitutions.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/util/Substitutions.java deleted file mode 100644 index 40470cf09..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/util/Substitutions.java +++ /dev/null @@ -1,31 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.util; - -import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.parser.ProgramPartParser; - -public final class Substitutions { - - private static final ProgramPartParser PROGRAM_PART_PARSER = new ProgramPartParser(); - - private Substitutions() { - throw new AssertionError("Cannot instantiate utility class!"); - } - - public static Substitution fromString(String str) { - String bare = str.substring(1, str.length() - 1); - String[] assignments = bare.split(","); - BasicSubstitution ret = new BasicSubstitution(); - for (String assignment : assignments) { - String[] keyVal = assignment.split("->"); - VariableTerm variable = Terms.newVariable(keyVal[0]); - Term assignedTerm = PROGRAM_PART_PARSER.parseTerm(keyVal[1]); - ret.put(variable, assignedTerm); - } - return ret; - } - -} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/NoGoodTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/NoGoodTest.java index e448d058f..26b91aae7 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/NoGoodTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/NoGoodTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.core.atoms.Literals; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; public class NoGoodTest { /** diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/ProgramTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/ProgramTest.java index 0557fe2c4..71b6aef05 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/ProgramTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/ProgramTest.java @@ -25,45 +25,24 @@ */ package at.ac.tuwien.kr.alpha.core.common; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.ArrayList; -import java.util.List; - +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.programs.InputProgram; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.Rules; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ProgramTest { @Test public void testToString() { - InputProgram program; - // rule := q(X) :- p(X). - List body = new ArrayList<>(); - body.add(Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newVariable("X")), true)); - Rule rule = Rules.newRule( - Atoms.newBasicAtom(Predicates.getPredicate("q", 1), Terms.newVariable("X")), - Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newVariable("X")).toLiteral()); - List facts = new ArrayList<>(); - facts.add(Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newSymbolicConstant("a"))); - facts.add(Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newSymbolicConstant("b"))); - // program := p(a). p(b). q(X) :- p(X). - program = InputProgramImpl.builder().addFacts(facts).addRule(rule).build(); + InputProgram parsedProgram = new ProgramParserImpl().parse( + "p(a)." + System.lineSeparator() + + "q(X) :- p(X)." + System.lineSeparator() + + "p(b)."); assertEquals( "p(a)." + System.lineSeparator() + "p(b)." + System.lineSeparator() + "q(X) :- p(X)." + System.lineSeparator(), - program.toString()); + parsedProgram.toString()); } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/RuleTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/RuleTest.java index 9359bb09c..2f2b41740 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/RuleTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/RuleTest.java @@ -1,76 +1,46 @@ package at.ac.tuwien.kr.alpha.core.common; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; -import at.ac.tuwien.kr.alpha.core.rules.Rules; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; /** - * Copyright (c) 2018 - 2021, the Alpha Team. + * Copyright (c) 2018, the Alpha Team. */ public class RuleTest { + private final ProgramParserImpl parser = new ProgramParserImpl(); + @Test public void renameVariables() { - // rule := p(X,Y) :- a, f(Z) = 1, q(X,g(Y),Z), dom(A). - BasicAtom headAtom = Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")); - BasicAtom bodyAtom1 = Atoms.newBasicAtom(Predicates.getPredicate("a", 0)); - ComparisonAtom bodyAtom2 = Atoms.newComparisonAtom(Terms.newFunctionTerm("f", Terms.newVariable("Z")), Terms.newConstant(1), ComparisonOperators.EQ); - BasicAtom bodyAtom3 = Atoms.newBasicAtom(Predicates.getPredicate("q", 3), - Terms.newVariable("X"), Terms.newFunctionTerm("g", Terms.newVariable("Y")), Terms.newVariable("Z")); - BasicAtom bodyAtom4 = Atoms.newBasicAtom(Predicates.getPredicate("dom", 1), Terms.newVariable("A")); - CompiledRule rule = InternalRule.fromNormalRule(NormalRuleImpl.fromBasicRule( - Rules.newRule(headAtom, bodyAtom1.toLiteral(), bodyAtom2.toLiteral(), bodyAtom3.toLiteral(), bodyAtom4.toLiteral()))); - - // ruleWithRenamedVars := p(X_13, Y_13) :- a, f(Z_13) = 1, q(X_13, g(Y_13), Z_13), dom(A_13). - BasicAtom headAtomRenamed = Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X_13"), Terms.newVariable("Y_13")); - BasicAtom bodyAtom1Renamed = Atoms.newBasicAtom(Predicates.getPredicate("a", 0)); - ComparisonAtom bodyAtom2Renamed = Atoms.newComparisonAtom(Terms.newFunctionTerm("f", Terms.newVariable("Z_13")), Terms.newConstant(1), - ComparisonOperators.EQ); - BasicAtom bodyAtom3Renamed = Atoms.newBasicAtom(Predicates.getPredicate("q", 3), - Terms.newVariable("X_13"), Terms.newFunctionTerm("g", Terms.newVariable("Y_13")), Terms.newVariable("Z_13")); - BasicAtom bodyAtom4Renamed = Atoms.newBasicAtom(Predicates.getPredicate("dom", 1), Terms.newVariable("A_13")); - CompiledRule ruleWithRenamedVars = InternalRule.fromNormalRule(NormalRuleImpl.fromBasicRule( - Rules.newRule(headAtomRenamed, bodyAtom1Renamed.toLiteral(), bodyAtom2Renamed.toLiteral(), bodyAtom3Renamed.toLiteral(), - bodyAtom4Renamed.toLiteral()))); - - assertEquals(ruleWithRenamedVars, rule.renameVariables("_13")); + String originalRule = "p(X,Y) :- a, f(Z) = 1, q(X,g(Y),Z), dom(A)."; + Rule rule = parser.parse(originalRule).getRules().get(0); + CompiledRule normalRule = InternalRule.fromNormalRule(Rules.toNormalRule(rule)); + CompiledRule renamedRule = normalRule.renameVariables("_13"); + Rule expectedRenamedRule = parser.parse("p(X_13, Y_13) :- a, f(Z_13) = 1, q(X_13, g(Y_13), Z_13), dom(A_13).").getRules().get(0); + CompiledRule expectedRenamedNormalRule = InternalRule.fromNormalRule(Rules.toNormalRule(expectedRenamedRule)); + assertEquals(expectedRenamedNormalRule.toString(), renamedRule.toString()); } @Test public void testRulesEqual() { - // r1 := p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X). - Rule r1 = Rules.newRule(Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")), - Atoms.newBasicAtom(Predicates.getPredicate("bla", 1), Terms.newVariable("X")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("blub", 1), Terms.newVariable("Y")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("foo", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("bar", 1), Terms.newVariable("X")).toLiteral(false)); - // r2 := p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X). - Rule r2 = Rules.newRule(Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")), - Atoms.newBasicAtom(Predicates.getPredicate("bla", 1), Terms.newVariable("X")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("blub", 1), Terms.newVariable("Y")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("foo", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("bar", 1), Terms.newVariable("X")).toLiteral(false)); - // r3 := p(X, Y) :- bla(X), blub(X), foo(X, X), not bar(X). - Rule r3 = Rules.newRule(Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")), - Atoms.newBasicAtom(Predicates.getPredicate("bla", 1), Terms.newVariable("X")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("blub", 1), Terms.newVariable("X")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("foo", 2), Terms.newVariable("X"), Terms.newVariable("X")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("bar", 1), Terms.newVariable("X")).toLiteral(false)); + InputProgram p1 = parser.parse("p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X)."); + Rule r1 = p1.getRules().get(0); + InputProgram p2 = parser.parse("p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X)."); + Rule r2 = p2.getRules().get(0); + InputProgram p3 = parser.parse("p(X, Y) :- bla(X), blub(X), foo(X, X), not bar(X)."); + Rule r3 = p3.getRules().get(0); assertTrue(r1.equals(r2)); assertTrue(r2.equals(r1)); assertTrue(r1.hashCode() == r2.hashCode()); @@ -82,4 +52,4 @@ public void testRulesEqual() { assertTrue(r2.hashCode() != r3.hashCode()); } -} +} \ No newline at end of file diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithBasicProgram.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithBasicProgram.java index 7950b90dd..a298cb6eb 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithBasicProgram.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithBasicProgram.java @@ -1,19 +1,19 @@ /** * Copyright (c) 2016-2019, the Alpha Team. * All rights reserved. - * + * * Additional changes made by Siemens. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1) Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2) Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -44,6 +44,9 @@ import java.util.TreeSet; import java.util.stream.Stream; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -54,17 +57,13 @@ import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; import at.ac.tuwien.kr.alpha.commons.AnswerSets; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.IntIterator; import at.ac.tuwien.kr.alpha.core.common.NoGood; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRules; /** * Represents a small ASP program {@code { c :- a, b. a. b. }}. @@ -73,20 +72,20 @@ */ public class GrounderMockWithBasicProgram implements Grounder { public static final Set EXPECTED = new HashSet<>(singletonList(new AnswerSetBuilder() - .predicate("a") - .predicate("b") - .predicate("c") - .build() + .predicate("a") + .predicate("b") + .predicate("c") + .build() )); private static final int FACT_A = 11; // { -a } private static final int FACT_B = 12; // { -b } private static final int RULE_B = 13; // { -_br1, a, b } private static final int RULE_H = 14; // { -c, _br1 } private static final Map NOGOODS = Stream.of( - entry(FACT_A, headFirst(fromOldLiterals(-1))), - entry(FACT_B, headFirst(fromOldLiterals(-2))), - entry(RULE_B, headFirst(fromOldLiterals(-3, 1, 2))), - entry(RULE_H, headFirst(fromOldLiterals(-4, 3))) + entry(FACT_A, headFirst(fromOldLiterals(-1))), + entry(FACT_B, headFirst(fromOldLiterals(-2))), + entry(RULE_B, headFirst(fromOldLiterals(-3, 1, 2))), + entry(RULE_H, headFirst(fromOldLiterals(-4, 3))) ).collect(entriesToMap()); private final AtomStore atomStore; private final java.util.function.Predicate filter; @@ -94,8 +93,8 @@ public class GrounderMockWithBasicProgram implements Grounder { private static Atom atomAA = Atoms.newBasicAtom(Predicates.getPredicate("a", 0)); private static Atom atomBB = Atoms.newBasicAtom(Predicates.getPredicate("b", 0)); private static BasicAtom atomCC = Atoms.newBasicAtom(Predicates.getPredicate("c", 0)); - private static BasicRule ruleABC = new BasicRule(Heads.newNormalHead(atomCC), Arrays.asList(atomAA.toLiteral(), atomBB.toLiteral())); - private static Atom rule1 = new RuleAtom(InternalRule.fromNormalRule(NormalRuleImpl.fromBasicRule(ruleABC)), new BasicSubstitution()); + private static CompiledRule ruleABC = CompiledRules.newCompiledRule(Heads.newNormalHead(atomCC), atomAA.toLiteral(), atomBB.toLiteral()); + private static Atom rule1 = new RuleAtom(ruleABC, new BasicSubstitution()); private Set returnedNogoods = new HashSet<>(); public GrounderMockWithBasicProgram(AtomStore atomStore) { @@ -171,7 +170,7 @@ public Map getNoGoods(Assignment assignment) { public Pair, Map> getChoiceAtoms() { return new ImmutablePair<>(new HashMap<>(), new HashMap<>()); } - + @Override public Map> getHeadsToBodies() { return Collections.emptyMap(); @@ -190,4 +189,5 @@ private void addNoGoodIfNotAlreadyReturned(Map integerNoGoodMap returnedNogoods.add(idNoGood); } } -} + +} \ No newline at end of file diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithChoice.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithChoice.java index bda74f709..d2d22c212 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithChoice.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithChoice.java @@ -1,19 +1,19 @@ /** * Copyright (c) 2016-2019, the Alpha Team. * All rights reserved. - * + * * Additional changes made by Siemens. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1) Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2) Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -44,6 +44,9 @@ import java.util.TreeSet; import java.util.stream.Stream; +import at.ac.tuwien.kr.alpha.core.programs.atoms.ChoiceAtom; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -54,30 +57,26 @@ import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; import at.ac.tuwien.kr.alpha.commons.AnswerSets; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.IntIterator; import at.ac.tuwien.kr.alpha.core.common.NoGood; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRules; /** * Represents a small ASP program with choices {@code { aa :- not bb. bb :- not aa. }}. */ public class GrounderMockWithChoice implements Grounder { public static final Set EXPECTED = new HashSet<>(asList( - new AnswerSetBuilder() - .predicate("aa") - .build(), - new AnswerSetBuilder() - .predicate("bb") - .build() + new AnswerSetBuilder() + .predicate("aa") + .build(), + new AnswerSetBuilder() + .predicate("bb") + .build() )); private static final int ATOM_AA = 1; @@ -97,29 +96,29 @@ public class GrounderMockWithChoice implements Grounder { private static final int CHOICE_DIS_BR1 = 17; // { -_dis_br1, bb} private static final int CHOICE_DIS_BR2 = 18; // { -dis_br2, aa } private static final Map NOGOODS = Stream.of( - entry(RULE_AA, headFirst(fromOldLiterals(-ATOM_AA, ATOM_BR1))), - entry(BRULE_AA, headFirst(fromOldLiterals(-ATOM_BR1, -ATOM_BB))), - entry(RULE_BB, headFirst(fromOldLiterals(-ATOM_BB, ATOM_BR2))), - entry(BRULE_BB, headFirst(fromOldLiterals(-ATOM_BR2, -ATOM_AA))), - entry(CHOICE_EN_BR1, headFirst(fromOldLiterals(-ATOM_EN_BR1))), - entry(CHOICE_EN_BR2, headFirst(fromOldLiterals(-ATOM_EN_BR2))), - entry(CHOICE_DIS_BR1, headFirst(fromOldLiterals(-ATOM_DIS_BR1, ATOM_BB))), - entry(CHOICE_DIS_BR2, headFirst(fromOldLiterals(-ATOM_DIS_BR2, ATOM_AA))) + entry(RULE_AA, headFirst(fromOldLiterals(-ATOM_AA, ATOM_BR1))), + entry(BRULE_AA, headFirst(fromOldLiterals(-ATOM_BR1, -ATOM_BB))), + entry(RULE_BB, headFirst(fromOldLiterals(-ATOM_BB, ATOM_BR2))), + entry(BRULE_BB, headFirst(fromOldLiterals(-ATOM_BR2, -ATOM_AA))), + entry(CHOICE_EN_BR1, headFirst(fromOldLiterals(-ATOM_EN_BR1))), + entry(CHOICE_EN_BR2, headFirst(fromOldLiterals(-ATOM_EN_BR2))), + entry(CHOICE_DIS_BR1, headFirst(fromOldLiterals(-ATOM_DIS_BR1, ATOM_BB))), + entry(CHOICE_DIS_BR2, headFirst(fromOldLiterals(-ATOM_DIS_BR2, ATOM_AA))) ).collect(entriesToMap()); private static final Map CHOICE_ENABLE = Stream.of( - entry(ATOM_BR1, ATOM_EN_BR1), - entry(ATOM_BR2, ATOM_EN_BR2) + entry(ATOM_BR1, ATOM_EN_BR1), + entry(ATOM_BR2, ATOM_EN_BR2) ).collect(entriesToMap()); private static final Map CHOICE_DISABLE = Stream.of( - entry(ATOM_BR1, ATOM_DIS_BR1), - entry(ATOM_BR2, ATOM_DIS_BR2) + entry(ATOM_BR1, ATOM_DIS_BR1), + entry(ATOM_BR2, ATOM_DIS_BR2) ).collect(entriesToMap()); private static BasicAtom atomAA = Atoms.newBasicAtom(Predicates.getPredicate("aa", 0)); private static BasicAtom atomBB = Atoms.newBasicAtom(Predicates.getPredicate("bb", 0)); - private static BasicRule ruleAA = new BasicRule(Heads.newNormalHead(atomAA), Collections.singletonList(Atoms.newBasicAtom(Predicates.getPredicate("bb", 0)).toLiteral(false))); - private static BasicRule ruleBB = new BasicRule(Heads.newNormalHead(atomBB), Collections.singletonList(Atoms.newBasicAtom(Predicates.getPredicate("aa", 0)).toLiteral(false))); - private static Atom rule1 = new RuleAtom(InternalRule.fromNormalRule(NormalRuleImpl.fromBasicRule(ruleAA)), new BasicSubstitution()); - private static Atom rule2 = new RuleAtom(InternalRule.fromNormalRule(NormalRuleImpl.fromBasicRule(ruleBB)), new BasicSubstitution()); + private static CompiledRule ruleAA = CompiledRules.newCompiledRule(Heads.newNormalHead(atomAA), Atoms.newBasicAtom(Predicates.getPredicate("bb", 0)).toLiteral(false)); + private static CompiledRule ruleBB = CompiledRules.newCompiledRule(Heads.newNormalHead(atomBB), Atoms.newBasicAtom(Predicates.getPredicate("aa", 0)).toLiteral(false)); + private static Atom rule1 = new RuleAtom(ruleAA, new BasicSubstitution()); + private static Atom rule2 = new RuleAtom(ruleBB, new BasicSubstitution()); private static Atom atomEnBR1 = ChoiceAtom.on(1); private static Atom atomEnBR2 = ChoiceAtom.on(2); private static Atom atomDisBR1 = ChoiceAtom.off(3); @@ -174,7 +173,7 @@ public Map getNoGoods(Assignment assignment) { return new HashMap<>(); } } - + private boolean isFirst = true; @Override @@ -186,7 +185,7 @@ public Pair, Map> getChoiceAtoms() { return new ImmutablePair<>(new HashMap<>(), new HashMap<>()); } } - + @Override public Map> getHeadsToBodies() { return Collections.emptyMap(); @@ -211,4 +210,5 @@ public int register(NoGood noGood) { } return solverDerivedNoGoods.get(noGood); } -} + +} \ No newline at end of file diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorageTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorageTest.java index 8e29122e6..95f4491e4 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorageTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/IndexedInstanceStorageTest.java @@ -36,10 +36,10 @@ import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; /** * Copyright (c) 2016, the Alpha Team. diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounderTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounderTest.java new file mode 100644 index 000000000..74ce484f3 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounderTest.java @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2018-2020 Siemens AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package at.ac.tuwien.kr.alpha.core.grounder; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; +import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; +import at.ac.tuwien.kr.alpha.core.common.Assignment; +import at.ac.tuwien.kr.alpha.core.common.AtomStore; +import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; +import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.parser.ProgramPartParser; +import at.ac.tuwien.kr.alpha.core.programs.AnalyzedProgram; +import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; +import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; +import at.ac.tuwien.kr.alpha.core.programs.transformation.StratifiedEvaluation; +import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; +import at.ac.tuwien.kr.alpha.core.solver.TrailAssignment; + +/** + * Tests {@link NaiveGrounder} + * + * Some test cases use atoms of the something/1 predicate to trick the grounder + * into believing that other atoms might become true. This is fragile because future implementations + * of preprocessing techniques might render this trick useless. + * If unit tests in this class begin to fail due to such improvements to preprocessing, this issue must be addressed. + */ +public class NaiveGrounderTest { + private static final ProgramParser PROGRAM_PARSER = new ProgramParserImpl(); + private static final ProgramPartParser PROGRAM_PART_PARSER = new ProgramPartParser(); + private static final NormalizeProgramTransformation NORMALIZE_TRANSFORM = new NormalizeProgramTransformation( + SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + + final Literal litP1X = PROGRAM_PART_PARSER.parseLiteral("p1(X)"); + final Literal litP2X = PROGRAM_PART_PARSER.parseLiteral("p2(X)"); + final Literal litQ2Y = PROGRAM_PART_PARSER.parseLiteral("q2(Y)"); + final Literal litQ1Y = PROGRAM_PART_PARSER.parseLiteral("q1(Y)"); + final Literal litAX = PROGRAM_PART_PARSER.parseLiteral("a(X)"); + final Literal litA1 = PROGRAM_PART_PARSER.parseLiteral("a(1)"); + + @BeforeEach + public void resetRuleIdGenerator() { + InternalRule.resetIdGenerator(); + } + + /** + * Asserts that a ground rule whose positive body is not satisfied by the empty assignment + * is grounded immediately. + */ + @Test + public void groundRuleAlreadyGround() { + InputProgram program = PROGRAM_PARSER.parse("a :- not b. " + + "b :- not a. " + + "c :- b."); + NormalProgram normal = NORMALIZE_TRANSFORM.apply(program); + CompiledProgram prog = new StratifiedEvaluation(null, false).apply(AnalyzedProgram.analyzeNormalProgram(normal)); + + AtomStore atomStore = new AtomStoreImpl(); + Grounder grounder = new GrounderFactory(new GrounderHeuristicsConfiguration(), true).createGrounder(prog, atomStore); + Map noGoods = grounder.getNoGoods(new TrailAssignment(atomStore)); + int litCNeg = Literals.atomToLiteral(atomStore.get(PROGRAM_PART_PARSER.parseBasicAtom("c")), false); + int litB = Literals.atomToLiteral(atomStore.get(PROGRAM_PART_PARSER.parseBasicAtom("b"))); + assertExistsNoGoodContaining(noGoods.values(), litCNeg); + assertExistsNoGoodContaining(noGoods.values(), litB); + } + + /** + * Asserts that a ground rule whose positive non-unary body is not satisfied by the empty assignment + * is grounded immediately. + */ + @Test + public void groundRuleWithLongerBodyAlreadyGround() { + InputProgram program = PROGRAM_PARSER.parse("a :- not b. " + + "b :- not a. " + + "c :- b. " + + "d :- b, c. "); + NormalProgram normal = NORMALIZE_TRANSFORM.apply(program); + InternalProgram prog = new StratifiedEvaluation(null, false).apply(AnalyzedProgram.analyzeNormalProgram(normal)); + + AtomStore atomStore = new AtomStoreImpl(); + Grounder grounder = new GrounderFactory(new GrounderHeuristicsConfiguration(), true).createGrounder(prog, atomStore); + Map noGoods = grounder.getNoGoods(new TrailAssignment(atomStore)); + int litANeg = Literals.atomToLiteral(atomStore.get(PROGRAM_PART_PARSER.parseBasicAtom("a")), false); + int litBNeg = Literals.atomToLiteral(atomStore.get(PROGRAM_PART_PARSER.parseBasicAtom("b")), false); + int litCNeg = Literals.atomToLiteral(atomStore.get(PROGRAM_PART_PARSER.parseBasicAtom("c")), false); + int litDNeg = Literals.atomToLiteral(atomStore.get(PROGRAM_PART_PARSER.parseBasicAtom("d")), false); + assertExistsNoGoodContaining(noGoods.values(), litANeg); + assertExistsNoGoodContaining(noGoods.values(), litBNeg); + assertExistsNoGoodContaining(noGoods.values(), litCNeg); + assertExistsNoGoodContaining(noGoods.values(), litDNeg); + } + + /** + * Asserts that a ground constraint whose positive body is not satisfied by the empty assignment + * is grounded immediately. + */ + @Test + public void groundConstraintAlreadyGround() { + InputProgram program = PROGRAM_PARSER.parse("a :- not b. " + + "b :- not a. " + + ":- b."); + NormalProgram normal = NORMALIZE_TRANSFORM.apply(program); + InternalProgram prog = new StratifiedEvaluation(null, false).apply(AnalyzedProgram.analyzeNormalProgram(normal)); + + AtomStore atomStore = new AtomStoreImpl(); + Grounder grounder = new GrounderFactory(new GrounderHeuristicsConfiguration(), true).createGrounder(prog, atomStore); + Map noGoods = grounder.getNoGoods(new TrailAssignment(atomStore)); + int litB = Literals.atomToLiteral(atomStore.get(PROGRAM_PART_PARSER.parseBasicAtom("b"))); + assertTrue(noGoods.containsValue(NoGood.fromConstraint(Collections.singletonList(litB), Collections.emptyList()))); + } + + @Test + public void avoidDeadEndsWithPermissiveGrounderHeuristicForP1() { + RuleGroundingOrderImpl groundingOrderP1 = new RuleGroundingOrderImpl(litP1X, + Arrays.asList(litP2X, litQ2Y, litQ1Y), -1, false); + testDeadEnd("p1", groundingOrderP1, true); + } + + @Test + public void avoidDeadEndsWithPermissiveGrounderHeuristicForQ1() { + RuleGroundingOrderImpl groundingOrderQ1 = new RuleGroundingOrderImpl(litQ1Y, + Arrays.asList(litQ2Y, litP2X, litP1X), -1, false); + testDeadEnd("q1", groundingOrderQ1, true); + } + + @Test + public void noDeadEndWithPermissiveGrounderHeuristicForP1() { + RuleGroundingOrderImpl groundingOrderP1 = new RuleGroundingOrderImpl(litP1X, + Arrays.asList(litP2X, litQ1Y, litQ2Y), -1, false); + testDeadEnd("p1", groundingOrderP1, true); + } + + @Test + public void noDeadEndWithPermissiveGrounderHeuristicForQ1() { + RuleGroundingOrderImpl groundingOrderQ1 = new RuleGroundingOrderImpl(litQ1Y, + Arrays.asList(litQ2Y, litP1X, litP2X), -1, false); + testDeadEnd("q1", groundingOrderQ1, true); + } + + /** + * Tests the method {@link NaiveGrounder#getGroundInstantiations)} on a + * predefined program: + * + * p1(1). q1(1).
+ * x :- p1(X), p2(X), q1(Y), q2(Y).
+ * p2(X) :- something(X).
+ * q2(X) :- something(X).
+ *
+ * Given one grounding order {@code groundingOrder} for the first rule in this program which starts with + * the literal whose predicate name is {@code predicateNameOfStartingLiteral} and a substitution substituting + * the variable in this literal by 1 it is attempted to ground the rule. + * It is then asserted that ground instantiations are produced if and only if {@code expectNoGoods} is true. + * + * @param predicateNameOfStartingLiteral the predicate name of the starting literal, either "p1" or "q1". + * @param groundingOrder a grounding order for the first rule in the predefined program that starts with the literal + * whose predicate name is {@code predicateNameOfStartingLiteral}. + * @param expectNoGoods {@code true} iff ground instantiations are expected to be produced under the conditions + * described above. + */ + private void testDeadEnd(String predicateNameOfStartingLiteral, RuleGroundingOrderImpl groundingOrder, boolean expectNoGoods) { + String aspStr = "p1(1). q1(1). " + + "x :- p1(X), p2(X), q1(Y), q2(Y). " + + "p2(X) :- something(X). " + + "q2(X) :- something(X). "; + CompiledProgram program = InternalProgram.fromNormalProgram( + NORMALIZE_TRANSFORM.apply( + PROGRAM_PARSER.parse(aspStr))); + + AtomStore atomStore = new AtomStoreImpl(); + NaiveGrounder grounder = (NaiveGrounder) new GrounderFactory(GrounderHeuristicsConfiguration.permissive(), true).createGrounder(program, atomStore, p -> true); + + CompiledRule nonGroundRule = grounder.getNonGroundRule(0); + String strLiteral = "p1".equals(predicateNameOfStartingLiteral) ? "p1(X)" : "p1(Y)"; + final Literal startingLiteral = PROGRAM_PART_PARSER.parseLiteral(strLiteral); + ((RuleGroundingInfoImpl) nonGroundRule.getGroundingInfo()).groundingOrders.put(startingLiteral, groundingOrder); + + grounder.bootstrap(); + TrailAssignment currentAssignment = new TrailAssignment(atomStore); + final Substitution subst1 = BasicSubstitution.specializeSubstitution(startingLiteral, new Instance(Terms.newConstant(1)), + BasicSubstitution.EMPTY_SUBSTITUTION); + final BindingResult bindingResult = grounder.getGroundInstantiations(nonGroundRule, groundingOrder, subst1, currentAssignment); + + assertEquals(expectNoGoods, bindingResult.size() > 0); + } + + @Test + public void testGroundingOfRuleSwitchedOffByFalsePositiveBody() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X). " + + "b(X) :- something(X). "); + testIfGrounderGroundsRule(program, 0, litAX, 1, ThriceTruth.FALSE, false); + } + + @Test + public void testGroundingOfRuleNotSwitchedOffByTruePositiveBody() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X). " + + "b(X) :- something(X). "); + testIfGrounderGroundsRule(program, 0, litAX, 1, ThriceTruth.TRUE, true); + } + + @Test + @Disabled("Currently, rule grounding is not switched off by a true negative body atom") + public void testGroundingOfRuleSwitchedOffByTrueNegativeBody() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), not b(X). " + + "b(X) :- something(X). "); + testIfGrounderGroundsRule(program, 0, litAX, 1, ThriceTruth.TRUE, false); + } + + @Test + public void testGroundingOfRuleNotSwitchedOffByFalseNegativeBody() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), not b(X). " + + "b(X) :- something(X). "); + + testIfGrounderGroundsRule(program, 0, litAX, 1, ThriceTruth.FALSE, true); + } + + /** + * Tests if {@link NaiveGrounder#getGroundInstantiations(CompiledRule, RuleGroundingOrder, Substitution, Assignment)} + * produces ground instantiations for the rule with ID {@code ruleID} in {@code program} when {@code startingLiteral} + * unified with the numeric instance {@code startingInstance} is used as starting literal and {@code b(1)} is assigned + * {@code bTruth}. + * It is asserted that ground instantiations are produced if and only if {@code expectNoGoods} is true. + */ + private void testIfGrounderGroundsRule(InputProgram program, int ruleID, Literal startingLiteral, int startingInstance, ThriceTruth bTruth, + boolean expectNoGoods) { + CompiledProgram internalPrg = InternalProgram.fromNormalProgram(NORMALIZE_TRANSFORM.apply(program)); + AtomStore atomStore = new AtomStoreImpl(); + TrailAssignment currentAssignment = new TrailAssignment(atomStore); + NaiveGrounder grounder = (NaiveGrounder) new GrounderFactory(GrounderHeuristicsConfiguration.permissive(), true).createGrounder(internalPrg, atomStore, p -> true); + + int b = atomStore.putIfAbsent(Atoms.newBasicAtom(Predicates.getPredicate("b", 1), Terms.newConstant(1))); + currentAssignment.growForMaxAtomId(); + currentAssignment.assign(b, bTruth); + + grounder.bootstrap(); + final CompiledRule nonGroundRule = grounder.getNonGroundRule(ruleID); + final Substitution substStartingLiteral = BasicSubstitution.specializeSubstitution(startingLiteral, new Instance(Terms.newConstant(startingInstance)), + BasicSubstitution.EMPTY_SUBSTITUTION); + final BindingResult bindingResult = grounder.getGroundInstantiations(nonGroundRule, nonGroundRule.getGroundingInfo().orderStartingFrom(startingLiteral), + substStartingLiteral, currentAssignment); + assertEquals(expectNoGoods, bindingResult.size() > 0); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_0_reject() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X). " + + "b(X) :- something(X)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litAX, 1, 0, false, Arrays.asList(1)); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_1_accept() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X). " + + "b(X) :- something(X)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litAX, 1, 1, true, Arrays.asList(1)); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_1_reject() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X), b(X+1). " + + "b(X) :- something(X)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litAX, 1, 1, false, Arrays.asList(2)); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_2_accept() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X), b(X+1). " + + "b(X) :- something(X)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litAX, 1, 2, true, Arrays.asList(2)); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_1_accept_two_substitutions() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X,Y). " + + "b(X,Y) :- something(X,Y)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litAX, 1, 1, new ThriceTruth[] {ThriceTruth.TRUE, ThriceTruth.TRUE }, 2, true, + Arrays.asList(0, 0)); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_1_accept_accept_two_substitutions_with_different_remaining_tolerances() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(1), b(X,Y). " + + "b(X,Y) :- something(X,Y)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litA1, 1, 1, new ThriceTruth[] {null, null }, 2, true, Arrays.asList(1, 1)); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_2_reject() { + InputProgram program = PROGRAM_PARSER.parse("a(1). " + + "c(X) :- a(X), b(X), b(X+1), b(X+2). " + + "b(X) :- something(X)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litAX, 1, 2, false, Arrays.asList(3)); + } + + @Test + public void testPermissiveGrounderHeuristicTolerance_2_accept_multiple_facts_of_same_variable() { + InputProgram program = PROGRAM_PARSER.parse("a(1). b(1). " + + "c(X) :- a(X), b(X), b(X+1), b(X+2). " + + "b(X) :- something(X)."); + testPermissiveGrounderHeuristicTolerance(program, 0, litAX, 1, 2, true, Arrays.asList(2)); + } + + private void testPermissiveGrounderHeuristicTolerance(InputProgram program, int ruleID, Literal startingLiteral, int startingInstance, int tolerance, + boolean expectNoGoods, List expectedNumbersOfUnassignedPositiveBodyAtoms) { + testPermissiveGrounderHeuristicTolerance(program, ruleID, startingLiteral, startingInstance, tolerance, new ThriceTruth[] {}, 1, expectNoGoods, + expectedNumbersOfUnassignedPositiveBodyAtoms); + } + + /** + * Tests if {@link NaiveGrounder#getGroundInstantiations(CompiledRule, RuleGroundingOrder, Substitution, Assignment)} + * produces ground instantiations for the rule with ID {@code ruleID} in {@code program} when {@code startingLiteral} + * unified with the numeric instance {@code startingInstance} is used as starting literal and the following + * additional conditions are established: + *

    + *
  • The atoms {@code b([startingInstance], 1), ..., b([startingInstance], n)} are added to the grounder's + * working memory without changing the assignment, where {@code arityOfB-1} occurences of {@code startingInstance} + * are used instead of {@code [startingInstance]} and {@code n} is the length of the {@code truthsOfB} array. + * For example, if the length of {@code truthsOfB} is 2 and {@code arityOfB} is also 2, these atoms are + * {@code b(1,1), b(1,2)}. + *
  • + *
  • The same atoms are assigned the truth values in the {@code truthsOfB} array.
  • + *
+ * It is asserted that ground instantiations are produced if and only if {@code expectNoGoods} is true. + * If ground instantiations are produced, it is also asserted that the numbers of unassigned positive body atoms + * determined by {@code getGroundInstantiations} match those given in {@code expectedNumbersOfUnassignedPositiveBodyAtoms}. + */ + private void testPermissiveGrounderHeuristicTolerance(InputProgram program, int ruleID, Literal startingLiteral, int startingInstance, int tolerance, + ThriceTruth[] truthsOfB, int arityOfB, boolean expectNoGoods, List expectedNumbersOfUnassignedPositiveBodyAtoms) { + CompiledProgram internalPrg = InternalProgram.fromNormalProgram(NORMALIZE_TRANSFORM.apply(program)); + AtomStore atomStore = new AtomStoreImpl(); + TrailAssignment currentAssignment = new TrailAssignment(atomStore); + GrounderHeuristicsConfiguration heuristicConfiguration = GrounderHeuristicsConfiguration.getInstance(tolerance, tolerance); + NaiveGrounder grounder = (NaiveGrounder) new GrounderFactory(heuristicConfiguration, true).createGrounder(internalPrg, atomStore, p -> true); + + int[] bAtomIDs = new int[truthsOfB.length]; + for (int i = 0; i < truthsOfB.length; i++) { + int[] bTerms = new int[arityOfB]; + for (int n = 0; n < arityOfB; n++) { + bTerms[n] = (n == arityOfB - 1) ? i + 1 : startingInstance; + } + bAtomIDs[i] = atomStore.putIfAbsent(atom("b", bTerms)); + } + addAtomsToWorkingMemoryWithoutChangingTheAssignment(atomStore, grounder, bAtomIDs); + assign(currentAssignment, bAtomIDs, truthsOfB); + + grounder.bootstrap(); + final CompiledRule nonGroundRule = grounder.getNonGroundRule(ruleID); + final Substitution substStartingLiteral = BasicSubstitution.specializeSubstitution(startingLiteral, new Instance(Terms.newConstant(startingInstance)), + BasicSubstitution.EMPTY_SUBSTITUTION); + final BindingResult bindingResult = grounder.getGroundInstantiations(nonGroundRule, nonGroundRule.getGroundingInfo().orderStartingFrom(startingLiteral), + substStartingLiteral, currentAssignment); + assertEquals(expectNoGoods, bindingResult.size() > 0); + if (bindingResult.size() > 0) { + assertEquals(expectedNumbersOfUnassignedPositiveBodyAtoms, bindingResult.getNumbersOfUnassignedPositiveBodyAtoms()); + } else { + assertTrue(bindingResult.getNumbersOfUnassignedPositiveBodyAtoms().isEmpty()); + } + } + + /** + * Assigns {@code truthValues} to atoms {@code atomIDs} in {@code currentAssignment}. + */ + private void assign(TrailAssignment currentAssignment, int[] atomIDs, ThriceTruth[] truthValues) { + currentAssignment.growForMaxAtomId(); + for (int i = 0; i < truthValues.length; i++) { + int atomID = atomIDs[i]; + if (truthValues[i] != null) { + currentAssignment.assign(atomID, truthValues[i]); + } + } + } + + /** + * Adds atoms {@code atomIDs} to {@code grounder}'s working memory without changing the assignment. + * This is achieved by creating a temporary assignment on {@code atomStore} in which those atoms are assigned true + * and using this temporary assignment to update the grounder's working memory. + */ + private void addAtomsToWorkingMemoryWithoutChangingTheAssignment(AtomStore atomStore, NaiveGrounder grounder, int[] atomIDs) { + TrailAssignment temporaryAssignment = new TrailAssignment(atomStore); + temporaryAssignment.growForMaxAtomId(); + for (int b : atomIDs) { + temporaryAssignment.assign(b, ThriceTruth.TRUE); + } + grounder.updateAssignment(temporaryAssignment.getNewPositiveAssignmentsIterator()); + } + + private void assertExistsNoGoodContaining(Collection noGoods, int literal) { + for (NoGood noGood : noGoods) { + for (int literalInNoGood : noGood) { + if (literalInNoGood == literal) { + return; + } + } + } + fail("No NoGood exists that contains literal " + literal); + } + + private static Atom atom(String predicateName, int... termInts) { + Term[] terms = new Term[termInts.length]; + for (int i = 0; i < termInts.length; i++) { + terms[i] = Terms.newConstant(termInts[i]); + } + return Atoms.newBasicAtom(Predicates.getPredicate(predicateName, terms.length), terms); + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGeneratorTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGeneratorTest.java new file mode 100644 index 000000000..eb0a06392 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/NoGoodGeneratorTest.java @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2018 Siemens AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package at.ac.tuwien.kr.alpha.core.grounder; + +import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; +import at.ac.tuwien.kr.alpha.core.common.AtomStore; +import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; +import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Tests {@link NoGoodGenerator} + */ +public class NoGoodGeneratorTest { + + private static final ProgramParser PARSER = new ProgramParserImpl(); + private static final NormalizeProgramTransformation NORMALIZE_TRANSFORM = new NormalizeProgramTransformation( + SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + + private static final ConstantTerm A = Terms.newSymbolicConstant("a"); + private static final ConstantTerm B = Terms.newSymbolicConstant("b"); + + private static final VariableTerm X = Terms.newVariable("X"); + private static final VariableTerm Y = Terms.newVariable("Y"); + + /** + * Calls {@link NoGoodGenerator#collectNegLiterals(CompiledRule, Substitution)}, which puts the atom occurring + * negatively in a rule into the atom store. It is then checked whether the atom in the atom store is positive. + */ + @Test + public void collectNeg_ContainsOnlyPositiveLiterals() { + InputProgram input = PARSER.parse("p(a,b). " + + "q(a,b) :- not nq(a,b). " + + "nq(a,b) :- not q(a,b)."); + NormalProgram normal = NORMALIZE_TRANSFORM.apply(input); + CompiledProgram program = InternalProgram.fromNormalProgram(normal); + + CompiledRule rule = program.getRules().get(1); + AtomStore atomStore = new AtomStoreImpl(); + Grounder grounder = new GrounderFactory(new GrounderHeuristicsConfiguration(), true).createGrounder(program, atomStore); + NoGoodGenerator noGoodGenerator = ((NaiveGrounder) grounder).noGoodGenerator; + Substitution substitution = new BasicSubstitution(); + substitution.put(X, A); + substitution.put(Y, B); + List collectedNeg = noGoodGenerator.collectNegLiterals(rule, substitution); + assertEquals(1, collectedNeg.size()); + String negAtomString = atomStore.atomToString(Literals.atomOf(collectedNeg.get(0))); + assertEquals("q(a, b)", negAtomString); + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingOrderTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingOrderTest.java new file mode 100644 index 000000000..a51bdd3a6 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingOrderTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2017-2020, the Alpha Team. + * All rights reserved. + * + * Additional changes made by Siemens. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package at.ac.tuwien.kr.alpha.core.grounder; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.function.Function; + +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.parser.ProgramPartParser; +import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; +import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; + +/** + * Copyright (c) 2017-2019, the Alpha Team. + */ +public class RuleGroundingOrderTest { + + private static final ProgramParser PARSER = new ProgramParserImpl(); + private static final NormalizeProgramTransformation NORMALIZE_TRANSFORM = new NormalizeProgramTransformation( + SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + private static final Function PARSE_AND_PREPROCESS = (str) -> { + return InternalProgram.fromNormalProgram(NORMALIZE_TRANSFORM.apply(PARSER.parse(str))); + }; + + private static final ProgramPartParser PROGRAM_PART_PARSER = new ProgramPartParser(); + + @Test + public void groundingOrder() { + String aspStr = "h(X,C) :- p(X,Y), q(A,B), r(Y,A), s(C)." + + "j(A,B,X,Y) :- r1(A,B), r1(X,Y), r1(A,X), r1(B,Y), A = B." + + "p(a) :- b = a."; + CompiledProgram prog = PARSE_AND_PREPROCESS.apply(aspStr); + CompiledRule rule0 = prog.getRules().get(0); + RuleGroundingInfo rgo0 = new RuleGroundingInfoImpl(rule0); + rgo0.computeGroundingOrders(); + assertEquals(4, rgo0.getStartingLiterals().size()); + + CompiledRule rule1 = prog.getRules().get(1); + RuleGroundingInfo rgo1 = new RuleGroundingInfoImpl(rule1); + rgo1.computeGroundingOrders(); + assertEquals(4, rgo1.getStartingLiterals().size()); + + CompiledRule rule2 = prog.getRules().get(2); + RuleGroundingInfo rgo2 = new RuleGroundingInfoImpl(rule2); + rgo2.computeGroundingOrders(); + assertTrue(rgo2.hasFixedInstantiation()); + } + + @Test + public void groundingOrderUnsafe() { + assertThrows(RuntimeException.class, () -> { + String aspStr = "h(X,C) :- X = Y, Y = C .. 3, C = X."; + CompiledProgram prog = PARSE_AND_PREPROCESS.apply(aspStr); + computeGroundingOrdersForRule(prog, 0); + }); + } + + @Test + public void testPositionFromWhichAllVarsAreBound_ground() { + String aspStr = "a :- b, not c."; + CompiledProgram internalPrg = PARSE_AND_PREPROCESS.apply(aspStr); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(internalPrg, 0); + assertEquals(0, rgo0.getFixedGroundingOrder().getPositionFromWhichAllVarsAreBound()); + } + + @Test + public void testPositionFromWhichAllVarsAreBound_simpleNonGround() { + String aspStr = "a(X) :- b(X), not c(X)."; + CompiledProgram internalPrg = PARSE_AND_PREPROCESS.apply(aspStr); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(internalPrg, 0); + assertEquals(1, rgo0.getStartingLiterals().size()); + for (Literal startingLiteral : rgo0.getStartingLiterals()) { + assertEquals(0, rgo0.orderStartingFrom(startingLiteral).getPositionFromWhichAllVarsAreBound()); + } + } + + @Test + public void testPositionFromWhichAllVarsAreBound_longerSimpleNonGround() { + String aspStr = "a(X) :- b(X), c(X), d(X), not e(X)."; + CompiledProgram internalPrg = PARSE_AND_PREPROCESS.apply(aspStr); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(internalPrg, 0); + assertEquals(3, rgo0.getStartingLiterals().size()); + for (Literal startingLiteral : rgo0.getStartingLiterals()) { + assertEquals(0, rgo0.orderStartingFrom(startingLiteral).getPositionFromWhichAllVarsAreBound()); + } + } + + @Test + public void testToString_longerSimpleNonGround() { + String aspStr = "a(X) :- b(X), c(X), d(X), not e(X)."; + CompiledProgram internalPrg = PARSE_AND_PREPROCESS.apply(aspStr); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(internalPrg, 0); + assertEquals(3, rgo0.getStartingLiterals().size()); + for (Literal startingLiteral : rgo0.getStartingLiterals()) { + switch (startingLiteral.getPredicate().getName()) { + case "b": + assertEquals("b(X) : | c(X), d(X), not e(X)", rgo0.orderStartingFrom(startingLiteral).toString()); + break; + case "c": + assertEquals("c(X) : | b(X), d(X), not e(X)", rgo0.orderStartingFrom(startingLiteral).toString()); + break; + case "d": + assertEquals("d(X) : | b(X), c(X), not e(X)", rgo0.orderStartingFrom(startingLiteral).toString()); + break; + default: + fail("Unexpected starting literal: " + startingLiteral); + } + } + } + + @Test + public void testPositionFromWhichAllVarsAreBound_joinedNonGround() { + String aspStr = "a(X) :- b(X), c(X,Y), d(X,Z), not e(X)."; + CompiledProgram internalPrg = PARSE_AND_PREPROCESS.apply(aspStr); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(internalPrg, 0); + final Literal litBX = PROGRAM_PART_PARSER.parseLiteral("b(X)"); + final Literal litCXY = PROGRAM_PART_PARSER.parseLiteral("c(X,Y)"); + final Literal litDXZ = PROGRAM_PART_PARSER.parseLiteral("d(X,Z)"); + assertTrue(2 <= rgo0.orderStartingFrom(litBX).getPositionFromWhichAllVarsAreBound()); + assertTrue(1 <= rgo0.orderStartingFrom(litCXY).getPositionFromWhichAllVarsAreBound()); + assertTrue(1 <= rgo0.orderStartingFrom(litDXZ).getPositionFromWhichAllVarsAreBound()); + } + + private RuleGroundingInfo computeGroundingOrdersForRule(CompiledProgram program, int ruleIndex) { + CompiledRule rule = program.getRules().get(ruleIndex); + RuleGroundingInfo rgo = new RuleGroundingInfoImpl(rule); + rgo.computeGroundingOrders(); + return rgo; + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/SubstitutionTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/SubstitutionTest.java index 24c2aceea..f42cc365f 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/SubstitutionTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/SubstitutionTest.java @@ -35,26 +35,29 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; import at.ac.tuwien.kr.alpha.core.test.util.SubstitutionTestUtil; -import at.ac.tuwien.kr.alpha.core.util.Substitutions; public class SubstitutionTest { + private static final ProgramParser PARSER = new ProgramParserImpl(); private static final ConstantTerm A = Terms.newSymbolicConstant("a"); private static final ConstantTerm B = Terms.newSymbolicConstant("b"); @@ -108,13 +111,11 @@ public void substituteNegativeBasicAtom() { @Test public void groundAndPrintRule() { - // rule := x :- p(X,Y), not q(X,Y). - CompiledRule rule = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("x", 0))), - Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("q", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(false)); + Rule rule = PARSER.parse("x :- p(X,Y), not q(X,Y).").getRules().get(0); + CompiledRule nonGroundRule = InternalRule.fromNormalRule(Rules.toNormalRule(rule)); Substitution substitution1 = BasicSubstitution.specializeSubstitution(PX, PA, BasicSubstitution.EMPTY_SUBSTITUTION); Substitution substitution2 = BasicSubstitution.specializeSubstitution(PY, PB, substitution1); - String printedString = SubstitutionTestUtil.groundAndPrintRule(rule, substitution2); + String printedString = SubstitutionTestUtil.groundAndPrintRule(nonGroundRule, substitution2); assertEquals("x :- p(a, b), not q(a, b).", printedString); } @@ -162,18 +163,4 @@ private void groundLiteralToString(boolean negated) { String printedString = SubstitutionTestUtil.groundLiteralToString(atom.toLiteral(!negated), substitution, true); assertEquals((negated ? "not " : "") + "p(a, b)", printedString); } - - @Test - public void substitutionFromString() { - // rule := x :- p(X,Y), not q(X,Y). - CompiledRule rule = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("x", 0))), - Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("q", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(false)); - Substitution substitution1 = BasicSubstitution.specializeSubstitution(PX, PA, BasicSubstitution.EMPTY_SUBSTITUTION); - Substitution substitution = BasicSubstitution.specializeSubstitution(PY, PB, substitution1); - RuleAtom ruleAtom = new RuleAtom(rule, substitution); - String substitutionString = (String) ((ConstantTerm) ruleAtom.getTerms().get(1)).getObject(); - Substitution fromString = Substitutions.fromString(substitutionString); - assertEquals(substitution, fromString); - } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/UnificationTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/UnificationTest.java new file mode 100644 index 000000000..04bee51aa --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/UnificationTest.java @@ -0,0 +1,111 @@ +package at.ac.tuwien.kr.alpha.core.grounder; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; +import at.ac.tuwien.kr.alpha.core.parser.ProgramPartParser; + +/** + * Copyright (c) 2021, the Alpha Team. + */ +public class UnificationTest { + + private ProgramPartParser partsParser = new ProgramPartParser(); + + @Test + public void simpleGroundUnification() { + Atom pX = partsParser.parseLiteral("p(X)").getAtom(); + Atom pa = partsParser.parseLiteral("p(abc)").getAtom(); + Unifier unifier = Unification.unifyAtoms(pa, pX); + assertNotNull(unifier); + assertEquals(1, unifier.getMappedVariables().size()); + assertEquals("abc", unifier.eval(Terms.newVariable("X")).toString()); + } + + @Test + public void unificationBothSides() { + Atom left = partsParser.parseLiteral("p(X, 1)").getAtom(); + Atom right = partsParser.parseLiteral("p(d, Y)").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNotNull(unifier); + assertEquals(2, unifier.getMappedVariables().size()); + assertEquals("d", unifier.eval(Terms.newVariable("X")).toString()); + assertEquals("1", unifier.eval(Terms.newVariable("Y")).toString()); + } + + @Test + public void unificationNonGround() { + Atom left = partsParser.parseLiteral("p(X, 13)").getAtom(); + Atom right = partsParser.parseLiteral("p(Z, Y)").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNotNull(unifier); + assertEquals(3, unifier.getMappedVariables().size()); + assertEquals("13", unifier.eval(Terms.newVariable("Y")).toString()); + // Check that the unifier sets X=Z by either mapping X -> Z or Z -> X. + if (unifier.eval(Terms.newVariable("X")) != null) { + // X is mapped, it must map to Z now. + assertEquals("Z", unifier.eval(Terms.newVariable("X")).toString()); + } else { + // X is not mapped, so Z must map to X. + assertEquals("X", unifier.eval(Terms.newVariable("Z")).toString()); + } + } + + @Test + public void unificationWithFunctionTerms() { + Atom left = partsParser.parseLiteral("a(b, f(X, 13), g(Z), d)").getAtom(); + Atom right = partsParser.parseLiteral("a(b, A, g(e), d)").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNotNull(unifier); + assertEquals(3, unifier.getMappedVariables().size()); + assertEquals(left.substitute(unifier).toString(), right.substitute(unifier).toString()); + } + + @Test + public void unificationWithArithmeticTerms() { + Atom left = partsParser.parseLiteral("a(X - (3 * Y))").getAtom(); + Atom right = partsParser.parseLiteral("a(15 - Z)").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNotNull(unifier); + assertEquals(3, unifier.getMappedVariables().size()); + assertEquals(left.substitute(unifier).toString(), right.substitute(unifier).toString()); + } + + @Test + public void nonunificationWithArithmeticTerms() { + Atom left = partsParser.parseLiteral("a(X + 4)").getAtom(); + Atom right = partsParser.parseLiteral("a(Y - 4)").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNull(unifier); + } + + @Test + public void nonunificationWithArithmeticTermsNested() { + Atom left = partsParser.parseLiteral("a(X + 7)").getAtom(); + Atom right = partsParser.parseLiteral("a(Y + (Z - 2))").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNull(unifier); + } + + @Test + public void nonunificationSimple() { + Atom left = partsParser.parseLiteral("a(b,X)").getAtom(); + Atom right = partsParser.parseLiteral("a(c,Y)").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNull(unifier); + } + + @Test + public void nonunificationNested() { + Atom left = partsParser.parseLiteral("a(f(X,a))").getAtom(); + Atom right = partsParser.parseLiteral("a(f(a,b))").getAtom(); + Unifier unifier = Unification.unifyAtoms(left, right); + assertNull(unifier); + } +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/UnifierTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/UnifierTest.java new file mode 100644 index 000000000..a59a958d3 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/UnifierTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018, 2020, the Alpha Team. + * All rights reserved. + * + * Additional changes made by Siemens. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package at.ac.tuwien.kr.alpha.core.grounder; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; + +public class UnifierTest extends SubstitutionTest { + + @Test + public void extendUnifier() { + VariableTerm varX = Terms.newVariable("X"); + VariableTerm varY = Terms.newVariable("Y"); + Unifier sub1 = new Unifier(); + sub1.put(varX, varY); + Unifier sub2 = new Unifier(); + sub2.put(varY, Terms.newConstant("a")); + + sub1.extendWith(sub2); + BasicAtom atom1 = parseAtom("p(X)"); + + Atom atomSubstituted = atom1.substitute(sub1); + assertEquals(Terms.newConstant("a"), atomSubstituted.getTerms().get(0)); + } + + @Test + public void mergeUnifierIntoLeft() { + VariableTerm varX = Terms.newVariable("X"); + VariableTerm varY = Terms.newVariable("Y"); + VariableTerm varZ = Terms.newVariable("Z"); + Term constA = Terms.newConstant("a"); + Unifier left = new Unifier(); + left.put(varX, varY); + left.put(varZ, varY); + Unifier right = new Unifier(); + right.put(varX, constA); + Unifier merged = Unifier.mergeIntoLeft(left, right); + assertEquals(constA, merged.eval(varY)); + assertEquals(constA, merged.eval(varZ)); + } + + private BasicAtom parseAtom(String atom) { + ProgramParser programParser = new ProgramParserImpl(); + InputProgram program = programParser.parse(atom + "."); + return (BasicAtom) program.getFacts().get(0); + } +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationStrategyTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationStrategyTest.java index 6604e3300..397f0faa5 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationStrategyTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiationStrategyTest.java @@ -16,10 +16,10 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiatorTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiatorTest.java index 5e3622252..337bb53f3 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiatorTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/LiteralInstantiatorTest.java @@ -13,16 +13,16 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.ComparisonAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.atoms.EnumerationAtom; -import at.ac.tuwien.kr.alpha.core.atoms.EnumerationLiteral; import at.ac.tuwien.kr.alpha.core.grounder.WorkingMemory; +import at.ac.tuwien.kr.alpha.core.programs.atoms.EnumerationAtom; +import at.ac.tuwien.kr.alpha.core.programs.atoms.EnumerationLiteral; public class LiteralInstantiatorTest { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustifiedTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustifiedTest.java new file mode 100644 index 000000000..cc069e529 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustifiedTest.java @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2018-2019, the Alpha Team. + * All rights reserved. + * + * Additional changes made by Siemens. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2) Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package at.ac.tuwien.kr.alpha.core.grounder.structure; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.function.Function; + +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.core.common.AtomStore; +import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; +import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; +import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; +import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; +import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; +import at.ac.tuwien.kr.alpha.core.solver.TrailAssignment; + +/** + * Copyright (c) 2018-2020, the Alpha Team. + */ +public class AnalyzeUnjustifiedTest { + + private final ProgramParser parser = new ProgramParserImpl(); + private final NormalizeProgramTransformation normalize = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + private final Function parseAndPreprocess = (str) -> { + return InternalProgram.fromNormalProgram(normalize.apply(parser.parse(str))); + }; + + @Test + public void justifySimpleRules() { + String program = "p(X) :- q(X)." + + "q(X) :- p(X)." + + "q(5) :- r." + + "r :- not nr." + + "nr :- not r." + + ":- not p(5)."; + CompiledProgram internalProgram = parseAndPreprocess.apply(program); + AtomStore atomStore = new AtomStoreImpl(); + NaiveGrounder grounder = new NaiveGrounder(internalProgram, atomStore, true); + grounder.getNoGoods(null); + TrailAssignment assignment = new TrailAssignment(atomStore); + int rId = atomStore.get(Atoms.newBasicAtom(Predicates.getPredicate("r", 0))); + int nrId = atomStore.get(Atoms.newBasicAtom(Predicates.getPredicate("nr", 0))); + assignment.growForMaxAtomId(); + assignment.assign(rId, ThriceTruth.FALSE); + assignment.assign(nrId, ThriceTruth.TRUE); + BasicAtom p5 = Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Collections.singletonList(Terms.newConstant(5))); + assignment.assign(atomStore.get(p5), ThriceTruth.MBT); + Set reasons = grounder.justifyAtom(atomStore.get(p5), assignment); + assertFalse(reasons.isEmpty()); + } + + @Test + public void justifyLargerRules() { + String program = "p(X) :- q(X,Y), r(Y), not s(X,Y)." + + "{ q(1,X)} :- dom(X)." + + "dom(1..3)." + + "{r(X)} :- p(X)." + + "{r(2)}." + + "{s(1,2)}." + + ":- not p(1)."; + CompiledProgram internalProgram = parseAndPreprocess.apply(program); + AtomStore atomStore = new AtomStoreImpl(); + NaiveGrounder grounder = new NaiveGrounder(internalProgram, atomStore, true); + grounder.getNoGoods(null); + TrailAssignment assignment = new TrailAssignment(atomStore); + Atom p1 = parser.parse("p(1).").getFacts().get(0); + Atom r2 = parser.parse("r(2).").getFacts().get(0); + Atom s12 = parser.parse("s(1,2).").getFacts().get(0); + Atom q11 = parser.parse("q(1,1).").getFacts().get(0); + Atom q12 = parser.parse("q(1,2).").getFacts().get(0); + Atom q13 = parser.parse("q(1,3).").getFacts().get(0); + int p1Id = atomStore.get(p1); + int r2Id = atomStore.get(r2); + int s12Id = atomStore.get(s12); + int q11Id = atomStore.get(q11); + int q12Id = atomStore.get(q12); + int q13Id = atomStore.get(q13); + assignment.growForMaxAtomId(); + assignment.assign(p1Id, ThriceTruth.MBT); + assignment.assign(r2Id, ThriceTruth.TRUE); + assignment.assign(s12Id, ThriceTruth.TRUE); + assignment.assign(q11Id, ThriceTruth.TRUE); + assignment.assign(q12Id, ThriceTruth.TRUE); + assignment.assign(q13Id, ThriceTruth.FALSE); + + Set reasons = grounder.justifyAtom(p1Id, assignment); + assertFalse(reasons.isEmpty()); + } + + @Test + public void justifyMultipleReasons() { + String program = "n(a). n(b). n(c). n(d). n(e)." + + "s(a,b). s(b,c). s(c,d). s(d,e)." + + "{ q(X) } :- n(X)." + + "p(X) :- q(X)." + + "p(X) :- p(Y), s(Y,X)." + + ":- not p(c)."; + CompiledProgram internalProgram = parseAndPreprocess.apply(program); + AtomStore atomStore = new AtomStoreImpl(); + NaiveGrounder grounder = new NaiveGrounder(internalProgram, atomStore, true); + grounder.getNoGoods(null); + TrailAssignment assignment = new TrailAssignment(atomStore); + Atom qa = parser.parse("q(a).").getFacts().get(0); + Atom qb = parser.parse("q(b).").getFacts().get(0); + Atom qc = parser.parse("q(c).").getFacts().get(0); + Atom qd = parser.parse("q(d).").getFacts().get(0); + Atom qe = parser.parse("q(e).").getFacts().get(0); + int qaId = atomStore.get(qa); + int qbId = atomStore.get(qb); + int qcId = atomStore.get(qc); + int qdId = atomStore.get(qd); + int qeId = atomStore.get(qe); + + assignment.growForMaxAtomId(); + assignment.assign(qaId, ThriceTruth.FALSE); + assignment.assign(qbId, ThriceTruth.FALSE); + assignment.assign(qcId, ThriceTruth.FALSE); + assignment.assign(qdId, ThriceTruth.FALSE); + assignment.assign(qeId, ThriceTruth.FALSE); + + Predicate nq = Predicates.getPredicate("_nq", 2, true); + Atom nqa = Atoms.newBasicAtom(nq, Arrays.asList(Terms.newConstant("1"), Terms.newSymbolicConstant("a"))); + Atom nqb = Atoms.newBasicAtom(nq, Arrays.asList(Terms.newConstant("1"), Terms.newSymbolicConstant("b"))); + Atom nqc = Atoms.newBasicAtom(nq, Arrays.asList(Terms.newConstant("1"), Terms.newSymbolicConstant("c"))); + Atom nqd = Atoms.newBasicAtom(nq, Arrays.asList(Terms.newConstant("1"), Terms.newSymbolicConstant("d"))); + Atom nqe = Atoms.newBasicAtom(nq, Arrays.asList(Terms.newConstant("1"), Terms.newSymbolicConstant("e"))); + int nqaId = atomStore.get(nqa); + int nqbId = atomStore.get(nqb); + int nqcId = atomStore.get(nqc); + int nqdId = atomStore.get(nqd); + int nqeId = atomStore.get(nqe); + + assignment.growForMaxAtomId(); + assignment.assign(nqaId, ThriceTruth.TRUE); + assignment.assign(nqbId, ThriceTruth.TRUE); + assignment.assign(nqcId, ThriceTruth.TRUE); + assignment.assign(nqdId, ThriceTruth.TRUE); + assignment.assign(nqeId, ThriceTruth.TRUE); + + Atom pc = parser.parse("p(c).").getFacts().get(0); + Set reasons = grounder.justifyAtom(atomStore.get(pc), assignment); + assertFalse(reasons.isEmpty()); + } + + @Test + public void justifyNegatedFactsRemovedFromReasons() { + String program = "forbidden(2,9). forbidden(1,9)." + + "p(X) :- q(X)." + + "q(X) :- p(X)." + + "q(5) :- r." + + "r :- not nr, not forbidden(2,9), not forbidden(1,9)." + + "nr :- not r." + + ":- not p(5)."; + CompiledProgram internalProgram = parseAndPreprocess.apply(program); + AtomStore atomStore = new AtomStoreImpl(); + NaiveGrounder grounder = new NaiveGrounder(internalProgram, atomStore, true); + grounder.getNoGoods(null); + TrailAssignment assignment = new TrailAssignment(atomStore); + int rId = atomStore.get(Atoms.newBasicAtom(Predicates.getPredicate("r", 0))); + int nrId = atomStore.get(Atoms.newBasicAtom(Predicates.getPredicate("nr", 0))); + assignment.growForMaxAtomId(); + assignment.assign(rId, ThriceTruth.FALSE); + assignment.assign(nrId, ThriceTruth.TRUE); + BasicAtom p5 = Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Collections.singletonList(Terms.newConstant(5))); + assignment.assign(atomStore.get(p5), ThriceTruth.MBT); + Set reasons = grounder.justifyAtom(atomStore.get(p5), assignment); + assertFalse(reasons.isEmpty()); + for (Literal literal : reasons) { + // Check that facts are not present in justification. + assertNotEquals(literal.getPredicate(), Predicates.getPredicate("forbidden", 2)); + } + } +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/parser/ParserTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/parser/ParserTest.java index bf260d5e7..3557a6fa0 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/parser/ParserTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/parser/ParserTest.java @@ -40,6 +40,8 @@ import java.util.Optional; import java.util.stream.Stream; +import at.ac.tuwien.kr.alpha.api.programs.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.junit.jupiter.api.Test; @@ -50,21 +52,41 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; -import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.ChoiceHead; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.IntervalTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; /** * Copyright (c) 2016, the Alpha Team. */ public class ParserTest { + + private static final String UNIT_TEST_EXPECT_UNSAT = + "p(1). p(2). " + + ":- p(X), p(Y), X + Y = 3." + + "#test expected_unsat(expect: unsat) {" + + "given {}" + + "}"; + + private static final String UNIT_TEST_BASIC_TEST = + "a :- b. #test ensure_a(expect: 1) { given { b. } assertForAll { :- not a. } }"; + private static final String UNIT_TEST_MORE_ASSERTIONS = + "a :- b. #test ensure_a(expect: 1) { given { b. } assertForAll { :- not a. } assertForSome { :- not a.} }"; + + private static final String UNIT_TEST_MORE_TCS = + "a :- b. #test ensure_a(expect: 1) { given { b. } assertForAll { :- not a. }} " + + "#test ensure_not_c (expect: 1) { given { b.} assertForAll { :- c. }}"; + + private static final String UNIT_TEST_KEYWORDS_AS_IDS = + "assert(a) :- given(b). # test test(expect: 1) { given { given(b). } assertForAll { :- not assert(a). :- assertForSome(b).}}"; + private final ProgramParserImpl parser = new ProgramParserImpl(); @Test @@ -193,7 +215,7 @@ public void testMissingDotNotIgnored() { @Test public void parseEnumerationDirective() { - ASPCore2Program parsedProgram = parser.parse("p(a,1)." + + InputProgram parsedProgram = parser.parse("p(a,1)." + "# enumeration_predicate_is mune." + "r(X) :- p(X), mune(X)." + "p(b,2)."); @@ -229,4 +251,58 @@ public void stringWithEscapedQuotes() throws IOException { assertEquals("\"a string with \"quotes\"\"", stringWithQuotes); } + @Test + public void unitTestExpectUnsat() { + InputProgram prog = parser.parse(UNIT_TEST_EXPECT_UNSAT); + assertEquals(1, prog.getTestCases().size()); + TestCase tc = prog.getTestCases().get(0); + assertEquals("expected_unsat", tc.getName()); + assertTrue(tc.getInput().isEmpty()); + assertTrue(tc.getAssertions().isEmpty()); + } + + @Test + public void unitTestBasicTest() { + InputProgram prog = parser.parse(UNIT_TEST_BASIC_TEST); + assertEquals(1, prog.getTestCases().size()); + TestCase tc = prog.getTestCases().get(0); + assertEquals("ensure_a", tc.getName()); + assertEquals(1, tc.getInput().size()); + assertEquals(1, tc.getAssertions().size()); + assertEquals(Assertion.Mode.FOR_ALL, tc.getAssertions().get(0).getMode()); + } + + @Test + public void unitTestMultipleAsserts() { + InputProgram prog = parser.parse(UNIT_TEST_MORE_ASSERTIONS); + assertEquals(1, prog.getTestCases().size()); + TestCase tc = prog.getTestCases().get(0); + assertEquals("ensure_a", tc.getName()); + assertEquals(1, tc.getInput().size()); + assertEquals(2, tc.getAssertions().size()); + assertEquals(Assertion.Mode.FOR_ALL, tc.getAssertions().get(0).getMode()); + assertEquals(Assertion.Mode.FOR_SOME, tc.getAssertions().get(1).getMode()); + } + + @Test + public void unitTestMoreTCs() { + InputProgram prog = parser.parse(UNIT_TEST_MORE_TCS); + assertEquals(2, prog.getTestCases().size()); + TestCase tc1 = prog.getTestCases().get(0); + assertEquals("ensure_a", tc1.getName()); + TestCase tc2 = prog.getTestCases().get(1); + assertEquals("ensure_not_c", tc2.getName()); + } + + @Test + public void unitTestKeywordsAsIds() { + InputProgram prog = parser.parse(UNIT_TEST_KEYWORDS_AS_IDS); + assertEquals(1, prog.getTestCases().size()); + TestCase tc = prog.getTestCases().get(0); + assertEquals("test", tc.getName()); + assertEquals(1, tc.getInput().size()); + assertEquals(1, tc.getAssertions().size()); + assertEquals(Assertion.Mode.FOR_ALL, tc.getAssertions().get(0).getMode()); + } + } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/AtomsTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/AtomsTest.java new file mode 100644 index 000000000..ac961bebe --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/AtomsTest.java @@ -0,0 +1,146 @@ +package at.ac.tuwien.kr.alpha.core.programs.atoms; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; +import at.ac.tuwien.kr.alpha.api.externals.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.externals.Externals; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Test for basic functionality of various implementations of {@link Atom}. + * + * Copyright (c) 2019-2020, the Alpha Team. + */ +public class AtomsTest { + + private final ProgramParser parser; + private Map externals; + + public AtomsTest() throws NoSuchMethodException, SecurityException { + externals = new HashMap<>(); + externals.put("isFoo", Externals.processPredicateMethod(AtomsTest.class.getMethod("isFoo", int.class))); + externals.put("extWithOutput", Externals.processPredicateMethod(AtomsTest.class.getMethod("extWithOutput", int.class))); + parser = new ProgramParserImpl(); + } + + @Predicate + public static final boolean isFoo(int bar) { + return 0xF00 == bar; + } + + @Predicate + public static final Set>> extWithOutput(int in) { + Set>> retVal = new HashSet<>(); + List> lst = new ArrayList<>(); + lst.add(Terms.newConstant(in)); + retVal.add(lst); + return retVal; + } + + @Test + public void testIsBasicAtomGround() { + InputProgram p = parser.parse("bla(blubb, foo(bar))."); + Atom a = p.getFacts().get(0); + assertBasicAtomGround(a, true); + InputProgram p1 = parser.parse("foo(1, 2, 3, \"bar\")."); + Atom a1 = p1.getFacts().get(0); + assertBasicAtomGround(a1, true); + InputProgram p2 = parser.parse("foo(BAR)."); + Atom a2 = p2.getFacts().get(0); + assertBasicAtomGround(a2, false); + InputProgram p3 = parser.parse("foo(b, a, r(\"bla\", BLUBB))."); + Atom a3 = p3.getFacts().get(0); + assertBasicAtomGround(a3, false); + } + + @Test + public void testAreBasicAtomsEqual() { + InputProgram p1 = parser.parse("bla(blubb, foo(bar)). bla(blubb, foo(bar))."); + Atom a1 = p1.getFacts().get(0); + Atom a2 = p1.getFacts().get(1); + assertEquals(a1, a2); + InputProgram p2 = parser.parse("foo(1, 2, 3, \"bar\"). foo(1, 2, 3, \"bar\")."); + Atom a3 = p2.getFacts().get(0); + Atom a4 = p2.getFacts().get(1); + assertEquals(a3, a4); + InputProgram p3 = parser.parse("foo(BAR). foo(BAR)."); + Atom a5 = p3.getFacts().get(0); + Atom a6 = p3.getFacts().get(1); + assertEquals(a5, a6); + InputProgram p4 = parser.parse("foo(b, a, r(\"bla\", BLUBB)). foo(b, a, r(\"bla\", BLUBB))."); + Atom a7 = p4.getFacts().get(0); + Atom a8 = p4.getFacts().get(1); + assertEquals(a7, a8); + + assertNotEquals(a1, a3); + assertNotEquals(a3, a1); + assertNotEquals(a1, a5); + assertNotEquals(a5, a1); + assertNotEquals(a1, a7); + assertNotEquals(a7, a1); + } + + @Test + public void testIsExternalAtomGround() { + InputProgram p1 = parser.parse("a :- &isFoo[1].", externals); + Atom ext1 = p1.getRules().get(0).getBody().stream().findFirst().get().getAtom(); + assertExternalAtomGround(ext1, true); + InputProgram p2 = parser.parse("a :- &isFoo[bar(1)].", externals); + Atom ext2 = p2.getRules().get(0).getBody().stream().findFirst().get().getAtom(); + assertExternalAtomGround(ext2, true); + InputProgram p3 = parser.parse("a :- &isFoo[BLA].", externals); + Atom ext3 = p3.getRules().get(0).getBody().stream().findFirst().get().getAtom(); + assertExternalAtomGround(ext3, false); + } + + @Test + @SuppressWarnings("unlikely-arg-type") + public void testAreExternalAtomsEqual() { + InputProgram p1 = parser.parse("a :- &isFoo[1].", externals); + Atom ext1 = p1.getRules().get(0).getBody().stream().findFirst().get().getAtom(); + InputProgram p2 = parser.parse("a :- &isFoo[1].", externals); + Atom ext2 = p2.getRules().get(0).getBody().stream().findFirst().get().getAtom(); + assertEquals(ext1, ext2); + assertEquals(ext2, ext1); + + assertNotEquals(null, ext1); + assertNotEquals("bla", ext1); + assertEquals(ext1.hashCode(), ext2.hashCode()); + } + + @Test + public void testExternalHasOutput() { + InputProgram p = parser.parse("a:- &extWithOutput[1](OUT).", externals); + Atom ext = p.getRules().get(0).getBody().stream().findFirst().get().getAtom(); + assertExternalAtomGround(ext, false); + assertTrue(((ExternalAtom) ext).hasOutput()); + } + + private void assertBasicAtomGround(Atom a, boolean expectedGround) { + assertTrue(a instanceof BasicAtom); + assertEquals(expectedGround, a.isGround()); + } + + private void assertExternalAtomGround(Atom a, boolean expectedGround) { + assertTrue(a instanceof ExternalAtom); + assertEquals(expectedGround, a.isGround()); + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtomTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtomTest.java new file mode 100644 index 000000000..e89317207 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtomTest.java @@ -0,0 +1,69 @@ +package at.ac.tuwien.kr.alpha.core.programs.atoms; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; +import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; + +/** + * Copyright (c) 2022, the Alpha Team. + */ +public class RuleAtomTest { + + private static final ProgramParser PARSER = new ProgramParserImpl(); + private static final VariableTerm X = Terms.newVariable("X"); + private static final VariableTerm Y = Terms.newVariable("Y"); + private static final Predicate PREDICATE = Predicates.getPredicate("p", 1); + private static final BasicAtom PX = Atoms.newBasicAtom(PREDICATE, X); + private static final BasicAtom PY = Atoms.newBasicAtom(PREDICATE, Y); + + @Test + public void substitutionObtainableFromRuleAtom() { + Rule rule = PARSER.parse("q(X) :- p(X,Y).").getRules().get(0); + CompiledRule nonGroundRule = InternalRule.fromNormalRule(Rules.toNormalRule(rule)); + // Build substitution X -> a, Y -> b. + Substitution substitution = BasicSubstitution.specializeSubstitution( + PY, new Instance(Terms.newSymbolicConstant("b")), BasicSubstitution.specializeSubstitution( + PX, new Instance(Terms.newSymbolicConstant("a")), BasicSubstitution.EMPTY_SUBSTITUTION)); + + RuleAtom ruleAtom = new RuleAtom(nonGroundRule, substitution); + RuleAtom.RuleAtomData substitutionFromRuleAtom = (RuleAtom.RuleAtomData) ((ConstantTerm) ruleAtom.getTerms().get(0)).getObject(); + assertEquals(substitution, substitutionFromRuleAtom.getSubstitution()); + } + + @Test + public void substitutionWithFunctionTermsObtainableFromRuleAtom() { + Rule rule = PARSER.parse("q(X) :- p(X,Y).").getRules().get(0); + CompiledRule nonGroundRule = InternalRule.fromNormalRule(Rules.toNormalRule(rule)); + // Build substitution X -> b(a,a), Y -> b(b(a,a),b(a,a)). + BasicAtom atomForSpecialize = Atoms.newBasicAtom(Predicates.getPredicate("p", 2), X, Y); + ConstantTerm aTerm = Terms.newSymbolicConstant("a"); + Instance instanceForSpecialize = new Instance(Terms.newFunctionTerm("b", aTerm, aTerm), + Terms.newFunctionTerm("b", + Terms.newFunctionTerm("b", aTerm, aTerm), + Terms.newFunctionTerm("b", aTerm, aTerm))); + Substitution substitution = BasicSubstitution.specializeSubstitution( + atomForSpecialize, instanceForSpecialize, BasicSubstitution.EMPTY_SUBSTITUTION); + + RuleAtom ruleAtom = new RuleAtom(nonGroundRule, substitution); + RuleAtom.RuleAtomData substitutionFromRuleAtom = (RuleAtom.RuleAtomData) ((ConstantTerm) ruleAtom.getTerms().get(0)).getObject(); + assertEquals(substitution, substitutionFromRuleAtom.getSubstitution()); + } +} \ No newline at end of file diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformationTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformationTest.java index d008dd21b..345cc41bb 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformationTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ProgramTransformationTest.java @@ -15,11 +15,10 @@ import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Program; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; import at.ac.tuwien.kr.alpha.commons.externals.Externals; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; -// TODO This is a functional test and should not be run with standard unit tests public class ProgramTransformationTest { private static final Logger LOGGER = LoggerFactory.getLogger(ProgramTransformationTest.class); @@ -68,17 +67,17 @@ public void choiceHeadToNormalSimpleTest() { @Test public void intervalTermToIntervalAtomSimpleTest() { - genericTransformationTest(intervalRewriting, NormalProgramImpl::fromInputProgram, "interval.1"); + genericTransformationTest(intervalRewriting, Programs::toNormalProgram, "interval.1"); } @Test public void intervalTermToIntervalAtomExternalAtomTest() { - genericTransformationTest(intervalRewriting, NormalProgramImpl::fromInputProgram, "interval-external_atom"); + genericTransformationTest(intervalRewriting, Programs::toNormalProgram, "interval-external_atom"); } @Test public void intervalTermToIntervalAtomComparisonAtomTest() { - genericTransformationTest(intervalRewriting, NormalProgramImpl::fromInputProgram, "interval-comparison_atom"); + genericTransformationTest(intervalRewriting, Programs::toNormalProgram, "interval-comparison_atom"); } @SuppressWarnings("unused") @@ -88,4 +87,4 @@ public static boolean sayTrue(int val) { return true; } -} +} \ No newline at end of file diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingRuleAnalysisTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingRuleAnalysisTest.java new file mode 100644 index 000000000..f4ec2ce48 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingRuleAnalysisTest.java @@ -0,0 +1,207 @@ +package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import at.ac.tuwien.kr.alpha.test.RuleParser; +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateElement; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; +import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticOperator; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; + +public class AggregateRewritingRuleAnalysisTest { + + //@formatter:off + private static final String BINDING_AGGREGATE_NO_GLOBALS = + "p(X) :- X = #max{N : q(N)}, X < 10, p(X, Y)."; + private static final String NONBINDING_AGGREGATE_NO_GLOBALS_1 = + "p(X) :- X < #max{N : q(N)}, X < 10, p(X, Y)."; + private static final String NONBINDING_AGGREGATE_NO_GLOBALS_2 = + "p(X) :- X < #max{N : q(N)}, X < 10, X = 3 + Y, Y = Z + 4, r(S, Z)."; + private static final String BINDING_AGGREGATES_NO_GLOBALS_INCLUDED = + "p :- not p(X), 3 < #max { Y : q(Y) }, X = #count { Y : q(Y) }."; + private static final String BINDING_AGGREGATE_WITH_GLOBALS_1 = + "graph_vertex_degree(G, V, D) :-" + + " graph(G)," + + " graph_vertex(G, V)," + + " D = #count{ VN : graph_edge(G, e(V, VN)); VN : graph_edge(G, e(VN, V)) }."; + private static final String BINDING_AGGREGATE_WITH_GLOBALS_2 = + "graph_max_degree_vertices(G, DMAX, N) :-" + + " graph(G)," + + " DMAX = #max{ DV : graph_vertex_degree(G, V, DV)}," + + " N = #count{ V : graph_vertex_degree(G, V, DMAX)}."; + //@formatter:on + + private static final AggregateRewritingRuleAnalysis analyze(String rule) { + return AggregateRewritingRuleAnalysis.analyzeRuleDependencies(RuleParser.parse(rule)); + } + + @Test + public void bindingAggregateNoGlobals() { + AggregateRewritingRuleAnalysis analysis = analyze(BINDING_AGGREGATE_NO_GLOBALS); + assertEquals(1, analysis.globalVariablesPerAggregate.size()); + assertEquals(1, analysis.dependenciesPerAggregate.size()); + + AggregateLiteral aggregate = new ArrayList<>(analysis.globalVariablesPerAggregate.keySet()).get(0); + assertTrue(analysis.globalVariablesPerAggregate.get(aggregate).isEmpty()); + assertEquals(0, analysis.dependenciesPerAggregate.get(aggregate).size()); + } + + @Test + public void nonBindingAggregateNoGlobals1() { + AggregateRewritingRuleAnalysis analysis = analyze(NONBINDING_AGGREGATE_NO_GLOBALS_1); + assertEquals(1, analysis.globalVariablesPerAggregate.size()); + assertEquals(1, analysis.dependenciesPerAggregate.size()); + + AggregateLiteral aggregate = new ArrayList<>(analysis.globalVariablesPerAggregate.keySet()).get(0); + assertTrue(analysis.globalVariablesPerAggregate.get(aggregate).isEmpty()); + assertFalse(analysis.dependenciesPerAggregate.get(aggregate).isEmpty()); + + Set dependencies = analysis.dependenciesPerAggregate.get(aggregate); + assertEquals(1, dependencies.size()); + + Literal pXY = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")), true); + assertTrue(dependencies.contains(pXY)); + } + + @Test + public void nonBindingAggregateNoGlobals2() { + AggregateRewritingRuleAnalysis analysis = analyze(NONBINDING_AGGREGATE_NO_GLOBALS_2); + assertEquals(1, analysis.globalVariablesPerAggregate.size()); + assertEquals(1, analysis.dependenciesPerAggregate.size()); + + AggregateLiteral aggregate = new ArrayList<>(analysis.globalVariablesPerAggregate.keySet()).get(0); + assertTrue(analysis.globalVariablesPerAggregate.get(aggregate).isEmpty()); + assertFalse(analysis.dependenciesPerAggregate.get(aggregate).isEmpty()); + + Set dependencies = analysis.dependenciesPerAggregate.get(aggregate); + assertEquals(3, dependencies.size()); + + Literal threePlusY = Literals.fromAtom( + Atoms.newComparisonAtom(Terms.newVariable("X"), + Terms.newArithmeticTerm(Terms.newConstant(3), ArithmeticOperator.PLUS, Terms.newVariable("Y")), + ComparisonOperators.EQ), + true); + assertTrue(dependencies.contains(threePlusY)); + + Literal zPlusFour = Literals.fromAtom( + Atoms.newComparisonAtom(Terms.newVariable("Y"), + Terms.newArithmeticTerm(Terms.newVariable("Z"), ArithmeticOperator.PLUS, Terms.newConstant(4)), + ComparisonOperators.EQ), + true); + assertTrue(dependencies.contains(zPlusFour)); + + Literal rSZ = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("r", 2), Terms.newVariable("S"), Terms.newVariable("Z")), true); + assertTrue(dependencies.contains(rSZ)); + } + + @Test + public void bindingAggregateWithGlobals1() { + AggregateRewritingRuleAnalysis analysis = analyze(BINDING_AGGREGATE_WITH_GLOBALS_1); + assertEquals(1, analysis.globalVariablesPerAggregate.size()); + assertEquals(1, analysis.dependenciesPerAggregate.size()); + + AggregateLiteral aggregate = new ArrayList<>(analysis.globalVariablesPerAggregate.keySet()).get(0); + assertFalse(analysis.globalVariablesPerAggregate.get(aggregate).isEmpty()); + assertFalse(analysis.dependenciesPerAggregate.get(aggregate).isEmpty()); + + Set globalVars = analysis.globalVariablesPerAggregate.get(aggregate); + assertTrue(globalVars.contains(Terms.newVariable("G"))); + assertTrue(globalVars.contains(Terms.newVariable("V"))); + + Set dependencies = analysis.dependenciesPerAggregate.get(aggregate); + assertEquals(2, dependencies.size()); + + Literal graph = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("graph", 1), Terms.newVariable("G")), true); + assertTrue(dependencies.contains(graph)); + + Literal graphVertex = Literals.fromAtom( + Atoms.newBasicAtom(Predicates.getPredicate("graph_vertex", 2), Terms.newVariable("G"), Terms.newVariable("V")), true); + assertTrue(dependencies.contains(graphVertex)); + } + + @Test + public void bindingAggregateWithGlobals2() { + AggregateRewritingRuleAnalysis analysis = analyze(BINDING_AGGREGATE_WITH_GLOBALS_2); + assertEquals(2, analysis.globalVariablesPerAggregate.size()); + assertEquals(2, analysis.dependenciesPerAggregate.size()); + + // Verify correct analysis of max aggregate + List vertexDegreeTerms = Collections.singletonList(Terms.newVariable("DV")); + Literal vertexDegreeLiteral = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("graph_vertex_degree", 3), Terms.newVariable("G"), + Terms.newVariable("V"), Terms.newVariable("DV")), true); + List vertexDegreeLiterals = Collections.singletonList(vertexDegreeLiteral); + AggregateElement vertexDegree = Atoms.newAggregateElement(vertexDegreeTerms, vertexDegreeLiterals); + AggregateLiteral maxAggregate = Literals.fromAtom( + Atoms.newAggregateAtom(ComparisonOperators.EQ, Terms.newVariable("DMAX"), AggregateFunctionSymbol.MAX, + Collections.singletonList(vertexDegree)), + true); + assertTrue(analysis.globalVariablesPerAggregate.containsKey(maxAggregate)); + + Set maxAggrGlobalVars = analysis.globalVariablesPerAggregate.get(maxAggregate); + assertEquals(1, maxAggrGlobalVars.size()); + assertTrue(maxAggrGlobalVars.contains(Terms.newVariable("G"))); + + assertTrue(analysis.dependenciesPerAggregate.containsKey(maxAggregate)); + Set maxAggrDependencies = analysis.dependenciesPerAggregate.get(maxAggregate); + assertEquals(1, maxAggrDependencies.size()); + Literal graph = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("graph", 1), Terms.newVariable("G")), true); + assertTrue(maxAggrDependencies.contains(graph)); + + // Verify correct analysis of count aggregate + List maxVertexDegreeTerms = Collections.singletonList(Terms.newVariable("V")); + Literal maxVertexDegreeLiteral = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("graph_vertex_degree", 3), Terms.newVariable("G"), + Terms.newVariable("V"), Terms.newVariable("DMAX")), true); + List maxVertexDegreeLiterals = Collections.singletonList(maxVertexDegreeLiteral); + AggregateElement maxVertexDegree = Atoms.newAggregateElement(maxVertexDegreeTerms, maxVertexDegreeLiterals); + AggregateLiteral countAggregate = Literals.fromAtom( + Atoms.newAggregateAtom(ComparisonOperators.EQ, Terms.newVariable("N"), AggregateFunctionSymbol.COUNT, + Collections.singletonList(maxVertexDegree)), + true); + assertTrue(analysis.globalVariablesPerAggregate.containsKey(countAggregate)); + Set cntAggrGlobalVars = analysis.globalVariablesPerAggregate.get(countAggregate); + assertEquals(2, cntAggrGlobalVars.size()); + assertTrue(cntAggrGlobalVars.contains(Terms.newVariable("G"))); + assertTrue(cntAggrGlobalVars.contains(Terms.newVariable("DMAX"))); + + assertTrue(analysis.dependenciesPerAggregate.containsKey(countAggregate)); + Set cntAggrDependencies = analysis.dependenciesPerAggregate.get(countAggregate); + assertEquals(2, cntAggrDependencies.size()); + assertTrue(cntAggrDependencies.contains(graph)); + assertTrue(cntAggrDependencies.contains(maxAggregate)); + } + + @Test + public void bindingAggregateGlobalsNotIncluded() { + AggregateRewritingRuleAnalysis analysis = analyze(BINDING_AGGREGATES_NO_GLOBALS_INCLUDED); + assertEquals(2, analysis.globalVariablesPerAggregate.size()); + assertEquals(2, analysis.dependenciesPerAggregate.size()); + + // Check that the #max aggregate does not include "not p(X)" as its dependency. + for (Map.Entry> aggregateDependencies : analysis.dependenciesPerAggregate.entrySet()) { + if (aggregateDependencies.getKey().getAtom().getAggregateFunction() == AggregateFunctionSymbol.MAX) { + for (Literal dependency : aggregateDependencies.getValue()) { + assertFalse(dependency.isNegated()); + } + } + } + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingInfoTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/rules/RuleGroundingInfoTest.java similarity index 86% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingInfoTest.java rename to alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/rules/RuleGroundingInfoTest.java index 4f95d0f2c..6edbd02ed 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleGroundingInfoTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/rules/RuleGroundingInfoTest.java @@ -25,24 +25,25 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package at.ac.tuwien.kr.alpha.core.grounder; +package at.ac.tuwien.kr.alpha.core.rules; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticOperator; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; import org.junit.jupiter.api.Test; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfo; +import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfoImpl; /** * Copyright (c) 2017-2021, the Alpha Team. @@ -52,7 +53,7 @@ public class RuleGroundingInfoTest { @Test public void groundingOrder() { // r1 := h(X,C) :- p(X,Y), q(A,B), r(Y,A), s(C). - CompiledRule r1 = new InternalRule( + CompiledRule r1 = CompiledRules.newCompiledRule( Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("h", 2), Terms.newVariable("X"), Terms.newVariable("C"))), Atoms.newBasicAtom(Predicates.getPredicate("p", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("q", 2), Terms.newVariable("A"), Terms.newVariable("B")).toLiteral(), @@ -63,7 +64,7 @@ public void groundingOrder() { assertEquals(4, rgo1.getStartingLiterals().size()); // r2 := j(A,A,X,Y) :- r1(A,A), r1(X,Y), r1(A,X), r1(A,Y). - CompiledRule r2 = new InternalRule( + CompiledRule r2 = CompiledRules.newCompiledRule( Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("j", 4), Terms.newVariable("A"), Terms.newVariable("A"), Terms.newVariable("X"), Terms.newVariable("Y"))), Atoms.newBasicAtom(Predicates.getPredicate("r1", 2), Terms.newVariable("A"), Terms.newVariable("A")).toLiteral(), @@ -75,7 +76,7 @@ public void groundingOrder() { assertEquals(4, rgo2.getStartingLiterals().size()); // r3 := p(a) :- b = a. - CompiledRule r3 = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newSymbolicConstant("a"))), + CompiledRule r3 = CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newSymbolicConstant("a"))), Atoms.newComparisonAtom(Terms.newSymbolicConstant("b"), Terms.newSymbolicConstant("a"), ComparisonOperators.EQ).toLiteral()); RuleGroundingInfo rgo3 = new RuleGroundingInfoImpl(r3); rgo3.computeGroundingOrders(); @@ -90,7 +91,7 @@ public void groundingOrder() { public void groundingOrderUnsafe() { assertThrows(RuntimeException.class, () -> { // rule := h(X, Z) :- Y = X + 1, X = Z + 1, Z = Y - 2. - CompiledRule rule = new InternalRule( + CompiledRule rule = CompiledRules.newCompiledRule( Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("h", 2), Terms.newVariable("X"), Terms.newVariable("Z"))), Atoms.newComparisonAtom( Terms.newVariable("Y"), @@ -111,7 +112,7 @@ public void groundingOrderUnsafe() { @Test public void testPositionFromWhichAllVarsAreBound_ground() { // rule := a :- b, not c. - CompiledRule rule = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 0))), + CompiledRule rule = CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 0))), Atoms.newBasicAtom(Predicates.getPredicate("b", 0)).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("c", 0)).toLiteral(false)); RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(rule); @@ -121,7 +122,7 @@ public void testPositionFromWhichAllVarsAreBound_ground() { @Test public void testPositionFromWhichAllVarsAreBound_simpleNonGround() { // rule := a(X) :- b(X), not c(X). - CompiledRule rule = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), + CompiledRule rule = CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), Atoms.newBasicAtom(Predicates.getPredicate("b", 1), Terms.newVariable("X")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("c", 1), Terms.newVariable("X")).toLiteral(false)); RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(rule); @@ -134,7 +135,7 @@ public void testPositionFromWhichAllVarsAreBound_simpleNonGround() { @Test public void testPositionFromWhichAllVarsAreBound_longerSimpleNonGround() { // rule := a(X) :- b(X), c(X), d(X), not e(X). - CompiledRule rule = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), + CompiledRule rule = CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), Atoms.newBasicAtom(Predicates.getPredicate("b", 1), Terms.newVariable("X")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("c", 1), Terms.newVariable("X")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("d", 1), Terms.newVariable("X")).toLiteral(), @@ -149,7 +150,7 @@ public void testPositionFromWhichAllVarsAreBound_longerSimpleNonGround() { @Test public void testToString_longerSimpleNonGround() { // rule := a(X) :- b(X), c(X), d(X), not e(X). - CompiledRule rule = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), + CompiledRule rule = CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), Atoms.newBasicAtom(Predicates.getPredicate("b", 1), Terms.newVariable("X")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("c", 1), Terms.newVariable("X")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("d", 1), Terms.newVariable("X")).toLiteral(), @@ -176,7 +177,7 @@ public void testToString_longerSimpleNonGround() { @Test public void testPositionFromWhichAllVarsAreBound_joinedNonGround() { // rule := a(X) :- b(X), c(X, Y), d(X, Z), not e(X). - CompiledRule rule = new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), + CompiledRule rule = CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newVariable("X"))), Atoms.newBasicAtom(Predicates.getPredicate("b", 1), Terms.newVariable("X")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("c", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("d", 2), Terms.newVariable("X"), Terms.newVariable("Z")).toLiteral(), diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AtomCounterTests.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AtomCounterTests.java index f43a858e8..b5d69b652 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AtomCounterTests.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AtomCounterTests.java @@ -37,22 +37,21 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.programs.atoms.ChoiceAtom; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; -// TODO should this be part of an AtomStoreTest?? public class AtomCounterTests { private AtomStore atomStore; @@ -125,7 +124,7 @@ private void createChoiceAtom() { private void createRuleAtom() { BasicAtom atomAA = Atoms.newBasicAtom(Predicates.getPredicate("aa", 0)); CompiledRule ruleAA = new InternalRule(Heads.newNormalHead(atomAA), - Collections.singletonList(Atoms.newBasicAtom(Predicates.getPredicate("bb", 0)).toLiteral(false))); + Collections.singleton(Atoms.newBasicAtom(Predicates.getPredicate("bb", 0)).toLiteral(false))); atomStore.putIfAbsent(new RuleAtom(ruleAA, new BasicSubstitution())); } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManagerTests.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManagerTests.java index 692e6840a..23eff4511 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManagerTests.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ChoiceManagerTests.java @@ -25,27 +25,26 @@ */ package at.ac.tuwien.kr.alpha.core.solver; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collection; -import java.util.Collections; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; import at.ac.tuwien.kr.alpha.core.common.NoGood; import at.ac.tuwien.kr.alpha.core.grounder.Grounder; import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; public class ChoiceManagerTests { private Grounder grounder; @@ -54,19 +53,11 @@ public class ChoiceManagerTests { @BeforeEach public void setUp() { - /* - * program := - * h :- b1, b2, not b3, not b4. - */ - CompiledProgram program = new InternalProgram(Collections.singletonList( - new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("h", 0))), - Atoms.newBasicAtom(Predicates.getPredicate("b1", 0)).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("b2", 0)).toLiteral(), - Atoms.newBasicAtom(Predicates.getPredicate("b3", 0)).toLiteral(false), - Atoms.newBasicAtom(Predicates.getPredicate("b4", 0)).toLiteral(false)) - ), Collections.emptyList()); + String testProgram = "h :- b1, b2, not b3, not b4."; + InputProgram parsedProgram = new ProgramParserImpl().parse(testProgram); + CompiledProgram internalProgram = InternalProgram.fromNormalProgram(new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG).apply(parsedProgram)); atomStore = new AtomStoreImpl(); - grounder = new NaiveGrounder(program, atomStore, true); + grounder = new NaiveGrounder(internalProgram, atomStore, true); WritableAssignment assignment = new TrailAssignment(atomStore); NoGoodStore store = new NoGoodStoreAlphaRoaming(assignment); choiceManager = new ChoiceManager(assignment, store); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaHeuristicTestAssumptions.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaHeuristicTestAssumptions.java index 6102ee79f..faa380f8e 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaHeuristicTestAssumptions.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaHeuristicTestAssumptions.java @@ -25,7 +25,7 @@ */ package at.ac.tuwien.kr.alpha.core.solver.heuristics; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -35,13 +35,14 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; import at.ac.tuwien.kr.alpha.core.common.NoGood; @@ -49,8 +50,7 @@ import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRules; import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.NaiveNoGoodStore; import at.ac.tuwien.kr.alpha.core.solver.TrailAssignment; @@ -83,11 +83,11 @@ public void setUp() { */ List facts = Arrays.asList(Atoms.newBasicAtom(Predicates.getPredicate("b1", 0)), Atoms.newBasicAtom(Predicates.getPredicate("b2", 0))); List rules = Arrays.asList( - new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("b3", 0))), Atoms.newBasicAtom(Predicates.getPredicate("nb3", 0)).toLiteral(false)), - new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("nb3", 0))), Atoms.newBasicAtom(Predicates.getPredicate("b3", 0)).toLiteral(false)), - new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("b4", 0))), Atoms.newBasicAtom(Predicates.getPredicate("nb4", 0)).toLiteral(false)), - new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("nb4", 0))), Atoms.newBasicAtom(Predicates.getPredicate("b4", 0)).toLiteral(false)), - new InternalRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("h", 0))), + CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("b3", 0))), Atoms.newBasicAtom(Predicates.getPredicate("nb3", 0)).toLiteral(false)), + CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("nb3", 0))), Atoms.newBasicAtom(Predicates.getPredicate("b3", 0)).toLiteral(false)), + CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("b4", 0))), Atoms.newBasicAtom(Predicates.getPredicate("nb4", 0)).toLiteral(false)), + CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("nb4", 0))), Atoms.newBasicAtom(Predicates.getPredicate("b4", 0)).toLiteral(false)), + CompiledRules.newCompiledRule(Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("h", 0))), Atoms.newBasicAtom(Predicates.getPredicate("b1", 0)).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("b2", 0)).toLiteral(), Atoms.newBasicAtom(Predicates.getPredicate("b3", 0)).toLiteral(false), diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtomsTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtomsTest.java index d0c5babe6..39a33527d 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtomsTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeapOfActiveAtomsTest.java @@ -31,10 +31,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.core.atoms.Literals; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; import at.ac.tuwien.kr.alpha.core.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.NoGoodStoreAlphaRoaming; import at.ac.tuwien.kr.alpha.core.solver.TrailAssignment; diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeuristicTestUtils.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeuristicTestUtils.java index 0a6606e15..ce4b7d8ad 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeuristicTestUtils.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/HeuristicTestUtils.java @@ -29,9 +29,9 @@ import java.util.Collection; import java.util.HashSet; -import at.ac.tuwien.kr.alpha.core.atoms.Literals; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; import at.ac.tuwien.kr.alpha.core.solver.NoGoodStoreAlphaRoaming; import at.ac.tuwien.kr.alpha.core.solver.WritableAssignment; import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristicTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristicTest.java index 4af6a0e77..1b2d98150 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristicTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/ReplayHeuristicTest.java @@ -25,7 +25,7 @@ */ package at.ac.tuwien.kr.alpha.core.solver.heuristics; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomToLiteral; +import static at.ac.tuwien.kr.alpha.core.programs.atoms.Literals.atomToLiteral; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDSTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDSTest.java index aa18db17f..7e2bd1eaf 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDSTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/VSIDSTest.java @@ -34,10 +34,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.core.atoms.Literals; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.programs.atoms.Literals; import at.ac.tuwien.kr.alpha.core.solver.NoGoodStoreAlphaRoaming; import at.ac.tuwien.kr.alpha.core.solver.TrailAssignment; import at.ac.tuwien.kr.alpha.core.solver.WritableAssignment; diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/SubstitutionTestUtil.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/SubstitutionTestUtil.java index 9da1d7f24..61055d5c2 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/SubstitutionTestUtil.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/SubstitutionTestUtil.java @@ -31,7 +31,7 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; public class SubstitutionTestUtil { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/TestUtils.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/TestUtils.java index e185a25d5..c69f5858c 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/TestUtils.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/TestUtils.java @@ -19,10 +19,10 @@ import at.ac.tuwien.kr.alpha.api.programs.Program; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.NoGood; import at.ac.tuwien.kr.alpha.core.solver.Antecedent; diff --git a/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AlphaAssertions.java b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AlphaAssertions.java index 7de3ef84d..cce21dafa 100644 --- a/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AlphaAssertions.java +++ b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AlphaAssertions.java @@ -1,18 +1,18 @@ package at.ac.tuwien.kr.alpha.test; -import static java.util.Collections.emptySet; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.programs.Program; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; import java.util.StringJoiner; -import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.programs.Program; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import static java.util.Collections.emptySet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class AlphaAssertions { diff --git a/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AnswerSetsParser.java b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AnswerSetsParser.java index c98e29f3a..34f60e7c5 100644 --- a/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AnswerSetsParser.java +++ b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AnswerSetsParser.java @@ -2,6 +2,8 @@ import java.util.Collections; import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.CharStream; @@ -12,12 +14,15 @@ import org.antlr.v4.runtime.misc.ParseCancellationException; import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Lexer; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; import at.ac.tuwien.kr.alpha.core.parser.ParseTreeVisitor; +// TODO this class should be called something different since it's turning into a general "atom set snippet parser" +// TODO this is duplicated from core module, need to pull out test utils into separate testsupport module public class AnswerSetsParser { - + private static final ParseTreeVisitor VISITOR = new ParseTreeVisitor(Collections.emptyMap(), false); public static Set parse(String s) { @@ -41,4 +46,31 @@ public static Set parse(CharStream stream) { return VISITOR.translate(parser.answer_sets()); } + + public static Set parseAtoms(String s) { + Set tmp = parse("{" + s + "}"); + if (tmp.size() > 1) { + throw new IllegalArgumentException( + "Cannot parse multiset of atoms! Use answer set parsing methods instead!"); + } + if (tmp.isEmpty()) { + return Collections.emptySet(); + } + AnswerSet as = tmp.stream().findFirst().get(); + Set atoms = as.getPredicates() + .stream() + .map( + (pred) -> as.getPredicateInstances(pred).stream() + .map((atom) -> { + if (!(atom instanceof BasicAtom)) { + throw new IllegalArgumentException("Expected a BasicAtom, but got: " + atom); + } + return (BasicAtom) atom; + }).collect(Collectors.toSet())) + .reduce(new TreeSet(), (result, element) -> { + result.addAll(element); + return result; + }); + return atoms; + } } diff --git a/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/MockActionImplementationProvider.java b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/MockActionImplementationProvider.java new file mode 100644 index 000000000..affe5f555 --- /dev/null +++ b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/MockActionImplementationProvider.java @@ -0,0 +1,79 @@ +package at.ac.tuwien.kr.alpha.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.ac.tuwien.kr.alpha.core.actions.AbstractActionImplementationProvider; + +public class MockActionImplementationProvider extends AbstractActionImplementationProvider { + + @SuppressWarnings("unused") + private static final Logger LOGGER = LoggerFactory.getLogger(MockActionImplementationProvider.class); + + private final ByteArrayOutputStream stdoutMock = new ByteArrayOutputStream(); + private final InputStream stdinMock; + private Map mockedFileOutputs; + private Map mockedFileInputs; + + public MockActionImplementationProvider(String inputBuffer) { + stdinMock = IOUtils.toInputStream(inputBuffer, "UTF-8"); + } + + @Override + protected OutputStream getStdoutStream() { + return stdoutMock; + } + + public String getStdoutContent() { + return stdoutMock.toString(); + } + + public void resetStdoutContent() { + stdoutMock.reset(); + } + + public void setMockedFileOutputs(Map mockedFileOutputs) { + this.mockedFileOutputs = mockedFileOutputs; + } + + public void setMockedFileInputs(Map mockedFileInputs) { + this.mockedFileInputs = mockedFileInputs; + } + + public Map getMockedFileOutputs() { + return mockedFileOutputs; + } + + public Map getMockedFileInputs() { + return mockedFileInputs; + } + + @Override + protected InputStream getStdinStream() { + return stdinMock; + } + + @Override + public OutputStream getFileOutputStream(String path) throws IOException { + if (mockedFileOutputs.containsKey(path)) { + return mockedFileOutputs.get(path); + } + throw new IOException("Path does not exist!"); + } + + @Override + public InputStream getInputStream(String path) throws IOException { + if (mockedFileInputs.containsKey(path)) { + return mockedFileInputs.get(path); + } + throw new IOException("Path does not exist!"); + } + +} diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleParser.java b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/RuleParser.java similarity index 80% rename from alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleParser.java rename to alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/RuleParser.java index 4893a20d8..d66576a44 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleParser.java +++ b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/RuleParser.java @@ -1,9 +1,9 @@ -package at.ac.tuwien.kr.alpha; +package at.ac.tuwien.kr.alpha.test; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; public class RuleParser { diff --git a/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaFactory.java b/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaFactory.java index 9a3093255..9905d39f5 100644 --- a/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaFactory.java +++ b/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaFactory.java @@ -1,56 +1,52 @@ package at.ac.tuwien.kr.alpha.api.impl; +import java.util.Collections; import java.util.function.Supplier; import at.ac.tuwien.kr.alpha.api.Alpha; +import at.ac.tuwien.kr.alpha.api.config.AggregateRewritingConfig; import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.commons.programs.reification.Reifier; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.util.IdGenerator; +import at.ac.tuwien.kr.alpha.commons.util.IntIdGenerator; +import at.ac.tuwien.kr.alpha.core.actions.ActionExecutionServiceImpl; +import at.ac.tuwien.kr.alpha.core.actions.ActionImplementationProvider; +import at.ac.tuwien.kr.alpha.core.actions.DefaultActionImplementationProvider; import at.ac.tuwien.kr.alpha.core.grounder.GrounderFactory; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; import at.ac.tuwien.kr.alpha.core.programs.transformation.ProgramTransformation; -import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewriting; -import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders.AggregateEncoderFactory; +import at.ac.tuwien.kr.alpha.core.programs.transformation.StratifiedEvaluation; import at.ac.tuwien.kr.alpha.core.solver.SolverConfig; import at.ac.tuwien.kr.alpha.core.solver.SolverFactory; import at.ac.tuwien.kr.alpha.core.solver.heuristics.HeuristicsConfiguration; -public final class AlphaFactory { +public class AlphaFactory { - private AlphaFactory() { - throw new AssertionError("Cannot instantiate utility class!"); + protected ProgramTransformation newProgramNormalizer(AggregateRewritingConfig aggregateCfg) { + return new NormalizeProgramTransformation(aggregateCfg); } - public static Alpha newAlpha(SystemConfig cfg) { - Supplier parserFactory = () -> new ProgramParserImpl(); - - // AggregateEncoderFactory depends on parser factory since stringtemplate-based aggregate encoders need to use the same parser that's used - // for input programs. - AggregateEncoderFactory aggregateEncoderFactory = new AggregateEncoderFactory(parserFactory, - cfg.getAggregateRewritingConfig().isUseSortingGridEncoding(), cfg.getAggregateRewritingConfig().isSupportNegativeValuesInSums()); - - // Factory for aggregate rewriting (depends on encoders provided by above factory). - Supplier aggregateRewritingFactory = () -> new AggregateRewriting(aggregateEncoderFactory.newCountEqualsEncoder(), - aggregateEncoderFactory.newCountLessOrEqualEncoder(), aggregateEncoderFactory.newSumEqualsEncoder(), - aggregateEncoderFactory.newSumLessOrEqualEncoder(), aggregateEncoderFactory.newMinEncoder(), aggregateEncoderFactory.newMaxEncoder()); - - // Factory for NormalizeProgramTransformation - needs a supplier for AggregateRewriting due to AggregateRewritings' dependency to encoder - // factory. - Supplier> programNormalizationFactory = () -> new NormalizeProgramTransformation( - aggregateRewritingFactory); + protected Supplier newStratifiedEvaluationFactory(ActionImplementationProvider actionImplementationProvider, + boolean generateActionWitnesses) { + return () -> new StratifiedEvaluation(new ActionExecutionServiceImpl(actionImplementationProvider), generateActionWitnesses); + } - // GrounderFactory - Since every grounder instance is only good for one program instance, we need a factory. + protected GrounderFactory newGrounderFactory(SystemConfig cfg) { GrounderHeuristicsConfiguration grounderHeuristicsCfg = GrounderHeuristicsConfiguration.getInstance(cfg.getGrounderToleranceConstraints(), cfg.getGrounderToleranceRules()); grounderHeuristicsCfg.setAccumulatorEnabled(cfg.isGrounderAccumulatorEnabled()); - GrounderFactory grounderFactory = new GrounderFactory( + return new GrounderFactory( grounderHeuristicsCfg, cfg.isDebugInternalChecks()); + } - // SolverFactory - Same as for GrounderFactory, we need a new Solver for each program. + protected SolverFactory newSolverFactory(SystemConfig cfg) { SolverConfig solverCfg = new SolverConfig(); solverCfg.setDisableJustifications(cfg.isDisableJustificationSearch()); solverCfg.setDisableNogoodDeletion(cfg.isDisableNoGoodDeletion()); @@ -62,16 +58,42 @@ public static Alpha newAlpha(SystemConfig cfg) { .setMomsStrategy(cfg.getMomsStrategy()) .setReplayChoices(cfg.getReplayChoices()) .build()); - SolverFactory solverFactory = new SolverFactory(cfg.getSolverName(), cfg.getNogoodStoreName(), solverCfg); + return new SolverFactory(cfg.getSolverName(), cfg.getNogoodStoreName(), solverCfg); + } + + protected ActionImplementationProvider newActionImplementationProvider() { + return new DefaultActionImplementationProvider(); + } + + public Alpha buildInstance(SystemConfig cfg) { + ActionImplementationProvider actionImplementationProvider = newActionImplementationProvider(); + ProgramParser parser = new ProgramParserImpl(actionImplementationProvider, Collections.emptyMap()); + ProgramTransformation programNormalizer = new NormalizeProgramTransformation(cfg.getAggregateRewritingConfig()); + + // Stratified evaluation factory - since every instance of stratified evaluation is only good for one program, we need a factory. + Supplier stratifiedEvaluationFactory = newStratifiedEvaluationFactory(actionImplementationProvider, cfg.isDebugInternalChecks()); + + // GrounderFactory - Since every grounder instance is only good for one program instance, we need a factory. + GrounderFactory grounderFactory = newGrounderFactory(cfg); + + // SolverFactory - Same as for GrounderFactory, we need a new Solver for each program. + SolverFactory solverFactory = newSolverFactory(cfg); // Now that all dependencies are taken care of, build new Alpha instance. - return new AlphaImpl(parserFactory, programNormalizationFactory, grounderFactory, solverFactory, cfg.isEvaluateStratifiedPart(), - cfg.isSortAnswerSets()); + return new AlphaImpl(parser, programNormalizer, stratifiedEvaluationFactory, grounderFactory, solverFactory, new Reifier(() -> { + IdGenerator idGen = new IntIdGenerator(0); + return () -> Terms.newConstant(idGen.getNextId()); + }), cfg.isSortAnswerSets()); } // Create Alpha instance with default config. public static Alpha newAlpha() { - return newAlpha(new SystemConfig()); + return AlphaFactory.newAlpha(new SystemConfig()); + } + + public static Alpha newAlpha(SystemConfig cfg) { + AlphaFactory factory = new AlphaFactory(); + return factory.buildInstance(cfg); } } diff --git a/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java b/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java index 934ce13bd..f24c9df63 100644 --- a/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java +++ b/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java @@ -1,19 +1,19 @@ /** * Copyright (c) 2017-2019, the Alpha Team. * All rights reserved. - * + *

* Additional changes made by Siemens. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + *

* 1) Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * + * list of conditions and the following disclaimer. + *

* 2) Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,25 +27,6 @@ */ package at.ac.tuwien.kr.alpha.api.impl; -import java.io.IOException; -import java.io.InputStream; -import java.nio.channels.Channels; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import com.google.common.annotations.VisibleForTesting; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.DebugSolvingContext; @@ -58,6 +39,11 @@ import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.analysis.ComponentGraph; import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestResult; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.reification.Reifier; import at.ac.tuwien.kr.alpha.commons.util.Util; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; @@ -65,40 +51,61 @@ import at.ac.tuwien.kr.alpha.core.grounder.GrounderFactory; import at.ac.tuwien.kr.alpha.core.programs.AnalyzedProgram; import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; import at.ac.tuwien.kr.alpha.core.programs.transformation.ProgramTransformation; import at.ac.tuwien.kr.alpha.core.programs.transformation.StratifiedEvaluation; import at.ac.tuwien.kr.alpha.core.solver.SolverFactory; +import com.google.common.annotations.VisibleForTesting; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.channels.Channels; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class AlphaImpl implements Alpha { private static final Logger LOGGER = LoggerFactory.getLogger(AlphaImpl.class); - private final Supplier parserFactory; - private final Supplier> programNormalizationFactory; - + private final ProgramParser parser; + private final ProgramTransformation programNormalization; + private final Supplier stratifiedEvaluationFactory; private final GrounderFactory grounderFactory; private final SolverFactory solverFactory; - - private final boolean enableStratifiedEvaluation; + private final TestRunner testRunner; + private final Reifier reifier; private final boolean sortAnswerSets; - AlphaImpl(Supplier parserFactory, Supplier> programNormalizationFactory, + AlphaImpl(ProgramParser parser, ProgramTransformation programNormalization, + Supplier stratifiedEvaluationFactory, GrounderFactory grounderFactory, SolverFactory solverFactory, - boolean enableStratifiedEvaluation, boolean sortAnswerSets) { - this.parserFactory = parserFactory; - this.programNormalizationFactory = programNormalizationFactory; + Reifier reifier, + boolean sortAnswerSets) { + this.parser = parser; + this.programNormalization = programNormalization; + this.stratifiedEvaluationFactory = stratifiedEvaluationFactory; this.grounderFactory = grounderFactory; this.solverFactory = solverFactory; - this.enableStratifiedEvaluation = enableStratifiedEvaluation; + this.reifier = reifier; + this.testRunner = new TestRunner(this); this.sortAnswerSets = sortAnswerSets; } @Override public InputProgram readProgram(InputConfig cfg) throws IOException { - InputProgramImpl.Builder prgBuilder = InputProgramImpl.builder(); + InputProgramBuilder prgBuilder = Programs.builder(); InputProgram tmpProg; if (!cfg.getFiles().isEmpty()) { tmpProg = readProgramFiles(cfg.isLiterate(), cfg.getPredicateMethods(), cfg.getFiles()); @@ -113,14 +120,12 @@ public InputProgram readProgram(InputConfig cfg) throws IOException { @Override public InputProgram readProgramFiles(boolean literate, Map externals, List paths) throws IOException { - return readProgramFiles(literate, externals, paths.stream().map(Paths::get).collect(Collectors.toList()).toArray(new Path[] {})); + return readProgramFiles(literate, externals, paths.stream().map(Paths::get).collect(Collectors.toList()).toArray(new Path[]{})); } @Override - @SuppressWarnings("resource") public InputProgram readProgramFiles(boolean literate, Map externals, Path... paths) throws IOException { - ProgramParser parser = parserFactory.get(); - InputProgramImpl.Builder prgBuilder = InputProgramImpl.builder(); + InputProgramBuilder prgBuilder = Programs.builder(); InputProgram tmpProg; for (Path path : paths) { InputStream stream; @@ -137,7 +142,7 @@ public InputProgram readProgramFiles(boolean literate, Map externals) { - return parserFactory.get().parse(aspString, externals); + return parser.parse(aspString, externals); } @Override @@ -145,19 +150,28 @@ public InputProgram readProgramString(String aspString) { return readProgramString(aspString, Collections.emptyMap()); } + @Override + public InputProgram readProgramStream(InputStream is) throws IOException { + return parser.parse(is); + } + + @Override + public InputProgram readProgramStream(InputStream is, Map externals) throws IOException { + return parser.parse(is, externals); + } + @Override public NormalProgram normalizeProgram(InputProgram program) { - return programNormalizationFactory.get().apply(program); + return programNormalization.apply(program); } @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { + LOGGER.debug("Preprocessing InternalProgram!"); LOGGER.debug("Preprocessing InternalProgram!"); InternalProgram retVal = InternalProgram.fromNormalProgram(program); - if (enableStratifiedEvaluation) { - AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); - retVal = new StratifiedEvaluation().apply(analyzed); - } + AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); + retVal = stratifiedEvaluationFactory.get().apply(analyzed); return retVal; } @@ -197,9 +211,9 @@ public Stream solve(NormalProgram program, java.util.function.Predica /** * Solves the given program and filters answer sets based on the passed predicate. - * + * * @param program an {@link InternalProgram} to solve - * @param filter {@link Predicate} filtering {@at.ac.tuwien.kr.alpha.common.Predicate}s in the returned answer sets + * @param filter {@link Predicate} filtering {@link at.ac.tuwien.kr.alpha.api.programs.Predicate}s in the returned answer sets * @return a Stream of answer sets representing stable models of the given program */ private Stream solve(CompiledProgram program, java.util.function.Predicate filter) { @@ -210,7 +224,7 @@ private Stream solve(CompiledProgram program, java.util.function.Pred /** * Prepares a solver (and accompanying grounder) instance pre-loaded with the given program. Use this if the * solver is needed after reading answer sets (e.g. for obtaining statistics). - * + * * @param program the program to solve. * @param filter a (java util) predicate that filters (asp-)predicates which should be contained in the answer * set stream from the solver. @@ -243,11 +257,7 @@ public DebugSolvingContext prepareDebugSolve(final NormalProgram program, java.u final ComponentGraph compGraph; final AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(program); final NormalProgram preprocessed; - if (enableStratifiedEvaluation) { - preprocessed = new StratifiedEvaluation().apply(analyzed).toNormalProgram(); - } else { - preprocessed = program; - } + preprocessed = stratifiedEvaluationFactory.get().apply(analyzed).toNormalProgram(); depGraph = analyzed.getDependencyGraph(); compGraph = analyzed.getComponentGraph(); final Solver solver = prepareSolverFor(analyzed, filter); @@ -277,6 +287,7 @@ public DependencyGraph getDependencyGraph() { public ComponentGraph getComponentGraph() { return compGraph; } + }; } @@ -290,4 +301,14 @@ public Solver prepareSolverFor(NormalProgram program, java.util.function.Predica return prepareSolverFor(performProgramPreprocessing(program), filter); } + @Override + public Set reify(InputProgram program) { + return reifier.reifyProgram(program); + } + + @Override + public TestResult test(InputProgram program) { + return testRunner.test(program); + } + } diff --git a/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/TestRunner.java b/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/TestRunner.java new file mode 100644 index 000000000..1b408270e --- /dev/null +++ b/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/TestRunner.java @@ -0,0 +1,110 @@ +package at.ac.tuwien.kr.alpha.api.impl; + +import at.ac.tuwien.kr.alpha.api.Alpha; +import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestResult; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.tests.Tests; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.function.IntPredicate; +import java.util.stream.Collectors; + +class TestRunner { + + private static final Logger LOGGER = LoggerFactory.getLogger(TestRunner.class); + + private final Alpha alpha; + + TestRunner(final Alpha alpha) { + this.alpha = alpha; + } + + TestResult test(InputProgram program) { + LOGGER.info("Running unit tests.."); + NormalProgram programUnderTest = alpha.normalizeProgram(program); + List testCaseResults = program.getTestCases().stream() + .map((tc) -> runTestCase(programUnderTest, tc)) + .collect(Collectors.toList()); + return () -> testCaseResults; + } + + private TestResult.TestCaseResult runTestCase(NormalProgram programUnderTest, TestCase testCase) { + LOGGER.info("Running test case " + testCase.getName()); + List facts = new ArrayList<>(programUnderTest.getFacts()); + facts.addAll(testCase.getInput()); + NormalProgram prog = Programs.newNormalProgram(programUnderTest.getRules(), facts, programUnderTest.getInlineDirectives()); + Set answerSets; + try { + answerSets = alpha.solve(prog).collect(Collectors.toSet()); + } catch (Throwable t) { + LOGGER.error("Test execution failed due to internal error", t); + return Tests.newTestCaseResult( + testCase.getName(), Optional.of("Test execution failed due to internal error: " + t.getMessage()), 0, 0, Collections.emptyMap()); + } + IntPredicate answerSetsVerifier = testCase.getAnswerSetCountVerifier(); + Optional answerSetCountErrMsg; + if (!answerSetsVerifier.test(answerSets.size())) { + answerSetCountErrMsg = Optional.of("Answer Set count incorrect, verifier: " + answerSetsVerifier + " failed, count is " + answerSets.size()); + } else { + answerSetCountErrMsg = Optional.empty(); + } + int passedCnt = 0; + int failedCnt = 0; + Map> assertionErrors = new LinkedHashMap<>(); + for (Assertion assertion : testCase.getAssertions()) { + List errors; + try { + errors = evaluateAssertion(answerSets, assertion); + } catch (Throwable t) { + errors = List.of("Test execution failed due to internal error: " + t.getMessage()); + LOGGER.error("Test execution failed due to internal error", t); + } + if (!errors.isEmpty()) { + failedCnt++; + assertionErrors.put(assertion, errors); + } else { + passedCnt++; + } + } + return Tests.newTestCaseResult(testCase.getName(), answerSetCountErrMsg, passedCnt, failedCnt, assertionErrors); + } + + private List evaluateAssertion(Set answerSets, Assertion assertion) { + java.util.function.Predicate matcher = (as) -> this.answerSetSatisfiesAssertion(as, assertion); + List errorList = new ArrayList<>(); + switch (assertion.getMode()) { + case FOR_ALL: + if (!answerSets.stream().allMatch(matcher)) { + errorList.addAll( + answerSets.stream() + .filter(matcher.negate()) + .map((as) -> "Universal assertion failed on answer set: " + as) + .collect(Collectors.toSet()) + ); + } + break; + case FOR_SOME: + if (answerSets.stream().noneMatch(matcher)) { + errorList.add("No answer set matches existential assertion!"); + } + break; + default: + throw new UnsupportedOperationException("Unsupported assertion mode: " + assertion.getMode()); + } + return errorList; + } + + private boolean answerSetSatisfiesAssertion(AnswerSet as, Assertion assertion) { + InputProgram verifierWithInput = Programs.builder(assertion.getVerifier()).addFacts(new ArrayList<>(as.asFacts())).build(); + return alpha.solve(verifierWithInput).findAny().isPresent(); + } + +} diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ActionsTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ActionsTest.java new file mode 100644 index 000000000..c954bfb46 --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ActionsTest.java @@ -0,0 +1,106 @@ +package at.ac.tuwien.kr.alpha; + +import at.ac.tuwien.kr.alpha.api.Alpha; +import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.core.actions.ActionImplementationProvider; +import at.ac.tuwien.kr.alpha.core.actions.OutputStreamHandle; +import at.ac.tuwien.kr.alpha.test.util.MockedActionsAlphaFactory; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * End-to-end tests covering Evolog action support. + */ +public class ActionsTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(ActionsTest.class); + + private static final String HELLO_WORLD = "hello_result(RES) : @streamWrite[STDOUT, \"Hello World!\"] = RES :- &stdout(STDOUT)."; + + private static final String WRITE_TO_FILE = "outfile(\"dummy.file\")." + + "outfile_open_result(F, R) : @fileOutputStream[F] = R :- outfile(F)." + + "outfile_write_result(F, R) : @streamWrite[HD, \"Foo bar!\"] = R :- outfile_open_result(F, success(stream(HD)))." + + "outfile_close_result(F, R) : @outputStreamClose[HD] = R :- outfile_open_result(F, success(stream(HD))), outfile_write_result(F, success(ok))."; + + /** + * Simple smoke test which verifies correct behavior of an Evolog "Hello World" program. + */ + @Test + public void helloWorld() { + MockedActionsAlphaFactory alphaFactory = new MockedActionsAlphaFactory(); + Alpha alpha = alphaFactory.buildInstance(new SystemConfig()); + InputProgram program = alpha.readProgramString(HELLO_WORLD); + alpha.solve(program); + assertEquals("Hello World!", alphaFactory.getActionImplementationMock().getStdoutContent()); + } + + @Test + //@Disabled + @SuppressWarnings("unchecked") + public void writeToFile() { + Map mockedFileOutputs = new HashMap<>(); + ByteArrayOutputStream dummyFileContent = new ByteArrayOutputStream(); + mockedFileOutputs.put("dummy.file", dummyFileContent); + MockedActionsAlphaFactory alphaFactory = new MockedActionsAlphaFactory(); + alphaFactory.getActionImplementationMock().setMockedFileOutputs(mockedFileOutputs); + ActionImplementationProvider actionProvider = alphaFactory.getActionImplementationMock(); + Alpha alpha = alphaFactory.buildInstance(new SystemConfig()); + InputProgram program = alpha.readProgramString(WRITE_TO_FILE); + Set answerSets = alpha.solve(program).collect(Collectors.toSet()); + LOGGER.debug("Got answer sets: {}", answerSets); + assertEquals(1, answerSets.size()); + AnswerSet answerSet = answerSets.stream().findFirst().get(); + /* + * Note: We have to check answer set content here because we have no way of constructing an equal instance for + * the outputStreamHandle that is constructed when executing the "fileOutputStream" action. * + */ + assertEquals(1, answerSet.query(Atoms.query(Predicates.getPredicate("outfile_open_result", 2)) + .withFilter(0, term -> term instanceof ConstantTerm && ((ConstantTerm) term).getObject().endsWith("dummy.file")) + .withFunctionTerm(1, "success", 1) + .withFilter(1, (term) -> { + FunctionTerm funcTerm = (FunctionTerm) term; + assertEquals(1, funcTerm.getTerms().size()); + assertTrue(funcTerm.getTerms().get(0) instanceof FunctionTerm && ((FunctionTerm) funcTerm.getTerms().get(0)).getSymbol().equals("stream")); + ConstantTerm streamTerm = (ConstantTerm) ((FunctionTerm) funcTerm.getTerms().get(0)).getTerms().get(0); + return streamTerm.getObject() instanceof OutputStreamHandle; + }) + ).size()); + assertEquals(1, answerSet.query(Atoms.query(Predicates.getPredicate("outfile_write_result", 2)) + .withFilter(0, term -> term instanceof ConstantTerm && ((ConstantTerm) term).getObject().endsWith("dummy.file")) + .withFunctionTerm(1, "success", 1) + .withFilter(1, (term) -> { + FunctionTerm funcTerm = (FunctionTerm) term; + assertEquals(1, funcTerm.getTerms().size()); + return funcTerm.getTerms().get(0) instanceof ConstantTerm && ((ConstantTerm) funcTerm.getTerms().get(0)).getObject().equals("ok"); + }) + ).size()); + assertEquals(1, answerSet.query(Atoms.query(Predicates.getPredicate("outfile_close_result", 2)) + .withFilter(0, term -> term instanceof ConstantTerm && ((ConstantTerm) term).getObject().endsWith("dummy.file")) + .withFunctionTerm(1, "success", 1) + .withFilter(1, (term) -> { + FunctionTerm funcTerm = (FunctionTerm) term; + assertEquals(1, funcTerm.getTerms().size()); + return funcTerm.getTerms().get(0) instanceof ConstantTerm && ((ConstantTerm) funcTerm.getTerms().get(0)).getObject().equals("ok"); + }) + ).size()); + assertEquals("Foo bar!", dummyFileContent.toString()); + } + +} diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateLiteralSplittingTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateLiteralSplittingTest.java index 137074843..9481ebc5f 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateLiteralSplittingTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateLiteralSplittingTest.java @@ -1,17 +1,16 @@ package at.ac.tuwien.kr.alpha; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateLiteralSplitting; +import at.ac.tuwien.kr.alpha.test.RuleParser; +import org.junit.jupiter.api.Test; import java.util.List; -import org.junit.jupiter.api.Test; - -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateLiteralSplitting; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -// TODO This is a functional test and should not be run with standard unit tests public class AggregateLiteralSplittingTest { //@formatter:off diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateOperatorNormalizationTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateOperatorNormalizationTest.java index 707fcd6a6..72ecd207b 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateOperatorNormalizationTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateOperatorNormalizationTest.java @@ -1,25 +1,22 @@ package at.ac.tuwien.kr.alpha; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; -import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticOperator; +import at.ac.tuwien.kr.alpha.api.programs.terms.ArithmeticTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateOperatorNormalization; +import at.ac.tuwien.kr.alpha.test.RuleParser; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; -// TODO This is a functional test and should not be run with standard unit tests public class AggregateOperatorNormalizationTest { //@formatter:off @@ -39,7 +36,6 @@ public class AggregateOperatorNormalizationTest { "bla :- dom(X), not X > #count{N : thing(N)}."; public static final String OPERATOR_NORMALIZATION_GE_NEG_ASP = "bla :- dom(X), not X >= #count{N : thing(N)}."; - /** * Operator normalization must also make sure that literals with only a right-hand term * are normalized to left-hand term only (and then operator-normalized if necessary) @@ -177,7 +173,9 @@ private static void assertAggregateBoundIncremented(Rule sourceRule, Rule< ArithmeticTerm incrementTerm = (ArithmeticTerm) comparisonRightHandTerm; assertEquals(ArithmeticOperator.PLUS, incrementTerm.getOperator()); assertEquals(Terms.newConstant(1), incrementTerm.getRightOperand()); - assertEquals(sourceAggregate.getAtom().getLowerBoundTerm(), incrementTerm.getLeftOperand()); + Term sourceBound = sourceAggregate.getAtom().getLowerBoundTerm() != null ? sourceAggregate.getAtom().getLowerBoundTerm() + : sourceAggregate.getAtom().getUpperBoundTerm(); + assertEquals(sourceBound, incrementTerm.getLeftOperand()); } } diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingContextTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingContextTest.java index bd7011667..e872f081e 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingContextTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingContextTest.java @@ -1,28 +1,26 @@ package at.ac.tuwien.kr.alpha; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.junit.jupiter.api.Test; - import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewritingContext; import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewritingContext.AggregateInfo; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.junit.jupiter.api.Test; + +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -// TODO This is a functional test and should not be run with standard unit tests public class AggregateRewritingContextTest { //@formatter:off diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingTest.java index df015f477..245304cc5 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingTest.java @@ -1,25 +1,23 @@ package at.ac.tuwien.kr.alpha; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -// TODO This is a functional test and should not be run with standard unit tests public class AggregateRewritingTest { //@formatter:off diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ArithmeticTermsRewritingTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ArithmeticTermsRewritingTest.java index c812bfe95..3c6e195de 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ArithmeticTermsRewritingTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ArithmeticTermsRewritingTest.java @@ -1,16 +1,5 @@ package at.ac.tuwien.kr.alpha; -import static java.util.stream.Collectors.toList; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.junit.jupiter.api.Test; - import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.externals.Predicate; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; @@ -18,19 +7,28 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ExternalLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.externals.Externals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; import at.ac.tuwien.kr.alpha.core.programs.transformation.ArithmeticTermsRewriting; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.util.stream.Collectors.toList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Copyright (c) 2021, the Alpha Team. */ -// TODO This is a functional test and should not be run with standard unit tests public class ArithmeticTermsRewritingTest { private final Map externalsOfThisClass = Externals.scan(ArithmeticTermsRewritingTest.class); @@ -45,7 +43,7 @@ public static Set>> externalForArithmeticTermsRewriti @Test public void rewriteRule() { - NormalProgram inputProgram = NormalProgramImpl.fromInputProgram(parser.parse("p(X+1) :- q(Y/2), r(f(X*2),Y), X-2 = Y*3, X = 0..9.")); + NormalProgram inputProgram = Programs.toNormalProgram(parser.parse("p(X+1) :- q(Y/2), r(f(X*2),Y), X-2 = Y*3, X = 0..9.")); assertEquals(1, inputProgram.getRules().size()); ArithmeticTermsRewriting arithmeticTermsRewriting = new ArithmeticTermsRewriting(); NormalProgram rewrittenProgram = arithmeticTermsRewriting.apply(inputProgram); @@ -58,7 +56,7 @@ public void rewriteRule() { @Test public void rewriteExternalAtom() { - NormalProgram inputProgram = NormalProgramImpl.fromInputProgram(parser.parse("p :- Y = 13, &extArithTest[Y*5](Y-4).")); + NormalProgram inputProgram = Programs.toNormalProgram(parser.parse("p :- Y = 13, &extArithTest[Y*5](Y-4).")); assertEquals(1, inputProgram.getRules().size()); ArithmeticTermsRewriting arithmeticTermsRewriting = new ArithmeticTermsRewriting(); NormalProgram rewrittenProgram = arithmeticTermsRewriting.apply(inputProgram); diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/FixedInterpretationLiteralsTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/FixedInterpretationLiteralsTest.java index 0aafb40c7..530040d78 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/FixedInterpretationLiteralsTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/FixedInterpretationLiteralsTest.java @@ -1,33 +1,23 @@ package at.ac.tuwien.kr.alpha; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import org.junit.jupiter.api.Test; - import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.externals.AspStandardLibrary; import at.ac.tuwien.kr.alpha.commons.externals.Externals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; -// // TODO This is a functional test and should not be run with standard unit tests public class FixedInterpretationLiteralsTest { @at.ac.tuwien.kr.alpha.api.externals.Predicate diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleToStringTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleToStringTest.java index 46f359403..f099fb724 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleToStringTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleToStringTest.java @@ -25,25 +25,20 @@ */ package at.ac.tuwien.kr.alpha; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.util.List; - -import org.junit.jupiter.api.Test; - import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; -import at.ac.tuwien.kr.alpha.core.rules.InternalRule; -import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; +import at.ac.tuwien.kr.alpha.core.programs.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; -/** - * Tests {@link BasicRule#toString()} and {@link InternalRule#toString()}. - */ public class RuleToStringTest { private final ProgramParser parser = new ProgramParserImpl(); @@ -93,7 +88,7 @@ private void parseSingleRuleAndCheckToString(String rule) { } private void constructNonGroundRuleAndCheckToString(String textualRule) { - CompiledRule nonGroundRule = InternalRule.fromNormalRule(NormalRuleImpl.fromBasicRule(parseSingleRule(textualRule))); + CompiledRule nonGroundRule = InternalRule.fromNormalRule(Rules.toNormalRule(parseSingleRule(textualRule))); assertEquals(textualRule, nonGroundRule.toString()); } diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/StratifiedEvaluationTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/StratifiedEvaluationTest.java index 1a53a980f..7c6c5fdae 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/StratifiedEvaluationTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/StratifiedEvaluationTest.java @@ -27,25 +27,10 @@ */ package at.ac.tuwien.kr.alpha; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertAnswerSetsEqual; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; - import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.DebugSolvingContext; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; @@ -53,12 +38,22 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.externals.Externals; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertAnswerSetsEqual; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; -// TODO This is an integration test and should be run in an extra suite public class StratifiedEvaluationTest { // Alpha instance with default configuration (evolog support and stratified evaluation enabled) @@ -105,6 +100,7 @@ public void testNonGroundableRule() { assertAnswerSetsEqual("p(a), q(a,b)", answerSets); } + @Test public void testCountAggregate() { String asp = "a. b :- 1 <= #count { 1 : a }."; @@ -145,6 +141,7 @@ public static boolean sayTrue(Object o) { return true; } + @Test public void testNegatedExternalLiteral() throws Exception { String asp = "claimedTruth(bla). truth(X) :- claimedTruth(X), &sayTrue[X]. lie(X) :- claimedTruth(X), not &sayTrue[X]."; @@ -160,7 +157,7 @@ public void testNegatedExternalLiteral() throws Exception { */ @Test public void testPartnerUnitsProblemTopologicalOrder() throws IOException { - InputProgram prg = Programs.fromInputStream( + InputProgram prg = alpha.readProgramStream( StratifiedEvaluationTest.class.getResourceAsStream("/partial-eval/pup_topological_order.asp"), new HashMap<>()); DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(prg); @@ -175,6 +172,12 @@ public void testPartnerUnitsProblemTopologicalOrder() throws IOException { * * @throws IOException */ + /** + * Verifies correct handling of negated basic literals in StratifiedEvaluation. + * For details, see comments in test program + * + * @throws IOException + */ @Test public void testNegatedLiteralInRecursiveRule() throws IOException { //@formatter:off @@ -184,54 +187,44 @@ public void testNegatedLiteralInRecursiveRule() throws IOException { + "inc_value(4), inc_value(5), inc_value(6), inc_value(7), " + "inc_value(8)"; //@formatter:on - InputProgram prog = Programs.fromInputStream( + InputProgram prog = alpha.readProgramStream( StratifiedEvaluationTest.class.getResourceAsStream("/partial-eval/recursive_w_negated_condition.asp"), new HashMap<>()); // Run stratified evaluation and solve - SystemConfig cfgWithStratEval = new SystemConfig(); - cfgWithStratEval.setEvaluateStratifiedPart(true); - Alpha alphaStratEval = AlphaFactory.newAlpha(cfgWithStratEval); - DebugSolvingContext dbgWithStratEval = alphaStratEval.prepareDebugSolve(prog); - Set asStrat = dbgWithStratEval.getSolver().collectSet(); - assertAnswerSetsEqual(expectedAnswerSet, asStrat); - - // Solve without stratified evaluation - SystemConfig cfgNoStratEval = new SystemConfig(); - cfgNoStratEval.setEvaluateStratifiedPart(false); - Alpha alphaNoStratEval = AlphaFactory.newAlpha(cfgNoStratEval); - DebugSolvingContext dbgNoStratEval = alphaNoStratEval.prepareDebugSolve(prog); - Set as = dbgNoStratEval.getSolver().collectSet(); + DebugSolvingContext dbg = alpha.prepareDebugSolve(prog); + Set as = dbg.getSolver().collectSet(); assertAnswerSetsEqual(expectedAnswerSet, as); } + @Test public void testRecursiveRanking() { //@formatter:off - String asp = "thing(a).\n" + - "thing(b).\n" + - "thing(c).\n" + - "thing_before(a, b).\n" + - "thing_before(b, c).\n" + - "has_prev_thing(X) :- thing(X), thing_succ(_, X).\n" + - "first_thing(X) :- thing(X), not has_prev_thing(X).\n" + - "thing_not_succ(X, Y) :-\n" + - " thing(X),\n" + - " thing(Y),\n" + - " thing(INTM),\n" + - " thing_before(X, Y),\n" + - " thing_before(X, INTM),\n" + - " thing_before(INTM, X).\n" + - "thing_succ(X, Y) :-\n" + - " thing(X),\n" + - " thing(Y),\n" + - " thing_before(X, Y),\n" + - " not thing_not_succ(X, Y).\n" + - "thing_rank(X, 1) :- first_thing(X).\n" + - "thing_rank(X, R) :-\n" + - " thing(X),\n" + - " thing_succ(Y, X),\n" + - " thing_rank(Y, K),\n" + + String asp = "thing(a).\n" + + "thing(b).\n" + + "thing(c).\n" + + "thing_before(a, b).\n" + + "thing_before(b, c).\n" + + "has_prev_thing(X) :- thing(X), thing_succ(_, X).\n" + + "first_thing(X) :- thing(X), not has_prev_thing(X).\n" + + "thing_not_succ(X, Y) :-\n" + + " thing(X),\n" + + " thing(Y),\n" + + " thing(INTM),\n" + + " thing_before(X, Y),\n" + + " thing_before(X, INTM),\n" + + " thing_before(INTM, X).\n" + + "thing_succ(X, Y) :-\n" + + " thing(X),\n" + + " thing(Y),\n" + + " thing_before(X, Y),\n" + + " not thing_not_succ(X, Y).\n" + + "thing_rank(X, 1) :- first_thing(X).\n" + + "thing_rank(X, R) :-\n" + + " thing(X),\n" + + " thing_succ(Y, X),\n" + + " thing_rank(Y, K),\n" + " R = K + 1."; //@formatter:on DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(alpha.readProgramString(asp)); diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImplTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImplTest.java index 96907fad6..9b25373ec 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImplTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImplTest.java @@ -27,65 +27,54 @@ */ package at.ac.tuwien.kr.alpha.api.impl; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptySet; -import static java.util.Collections.singleton; -import static java.util.Collections.singletonList; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.config.Heuristic; import at.ac.tuwien.kr.alpha.api.config.InputConfig; import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; -import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.rules.Rule; +import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestResult; import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.externals.AspStandardLibrary; import at.ac.tuwien.kr.alpha.commons.externals.Externals; import at.ac.tuwien.kr.alpha.commons.externals.MethodPredicateInterpretation; -import at.ac.tuwien.kr.alpha.commons.literals.Literals; -import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.programs.rules.Rules; +import at.ac.tuwien.kr.alpha.commons.programs.rules.heads.Heads; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.core.rules.BasicRule; import at.ac.tuwien.kr.alpha.test.AnswerSetsParser; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.*; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.*; +import static org.junit.jupiter.api.Assertions.*; -// TODO This is a functional test and should not be run with standard unit tests public class AlphaImplTest { - + private static final Logger LOGGER = LoggerFactory.getLogger(AspStandardLibrary.class); - + //@formatter:off private static final String STRINGSTUFF_ASP = "string(\"bla\")." @@ -114,8 +103,30 @@ public class AlphaImplTest { + ":- not has_resultstring."; //@formatter:on + private static final String UNIT_TEST_EXPECT_UNSAT = + "p(1). p(2). " + + ":- p(X), p(Y), X + Y = 3." + + "#test expected_unsat(expect: unsat) {" + + "given {}" + + "}"; + + private static final String UNIT_TEST_BASIC_TEST = + "a :- b. #test ensure_a(expect: 1) { given { b. } assertForAll { :- not a. } }"; + private static final String UNIT_TEST_MORE_ASSERTIONS = + "a :- b. #test ensure_a(expect: 1) { given { b. } assertForAll { :- not a. } assertForSome { :- not a.} }"; + + private static final String UNIT_TEST_MORE_TCS = + "a :- b. #test ensure_a(expect: 1) { given { b. } assertForAll { :- not a. }} " + + "#test ensure_not_c (expect: 1) { given { b.} assertForAll { :- c. }}"; + + private static final String UNIT_TEST_FAILING_ASSERTION = + "a :- b. #test ensure_c(expect: 1) { given { b. } assertForAll { :- not c. } }"; + + private static final String UNIT_TEST_FAILING_COUNT = + "a :- b. #test ensure_a(expect: 2) { given { b. } assertForAll { :- not a. } }"; + private static int invocations; - + @at.ac.tuwien.kr.alpha.api.externals.Predicate public static boolean isOne(int term) { invocations++; @@ -150,22 +161,22 @@ public void addsFacts() { Thingy a = new Thingy(); Thingy b = new Thingy(); List things = asList(a, b); - InputProgram program = InputProgramImpl.builder().addFacts(Externals.asFacts(Thingy.class, things)).build(); + InputProgram program = Programs.builder().addFacts(Externals.asFacts(Thingy.class, things)).build(); Set actual = system.solve(program).collect(Collectors.toSet()); - Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("thingy").instance(a).instance(b).build())); + Set expected = Set.of(new AnswerSetBuilder().predicate("thingy").instance(a).instance(b).build()); assertEquals(expected, actual); } @Test public void withExternalTypeConflict() { assertThrows(IllegalArgumentException.class, () -> { - Alpha system = AlphaFactory.newAlpha(); - InputConfig inputCfg = InputConfig.forString("a :- &isFoo[\"adsfnfdsf\"]."); - inputCfg.addPredicateMethod("isFoo", Externals.processPredicateMethod(this.getClass().getMethod("isFoo", Integer.class))); - Set actual = system.solve(system.readProgram(inputCfg)).collect(Collectors.toSet()); - Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("a").build())); - assertEquals(expected, actual); -}); + Alpha system = AlphaFactory.newAlpha(); + InputConfig inputCfg = InputConfig.forString("a :- &isFoo[\"adsfnfdsf\"]."); + inputCfg.addPredicateMethod("isFoo", Externals.processPredicateMethod(this.getClass().getMethod("isFoo", Integer.class))); + Set actual = system.solve(system.readProgram(inputCfg)).collect(Collectors.toSet()); + Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("a").build())); + assertEquals(expected, actual); + }); } @Test @@ -225,12 +236,12 @@ public void noInput() throws Exception { @Test public void smallGraphWithWrongType() { assertThrows(IllegalArgumentException.class, () -> { - Alpha system = AlphaFactory.newAlpha(); - InputConfig cfg = InputConfig.forString("a :- &connected[\"hello\",2]."); - cfg.addPredicateMethod("connected", Externals.processPredicate((Integer a, Integer b) -> (a == 1 && b == 2) || (b == 2 || b == 3))); - InputProgram prog = system.readProgram(cfg); + Alpha system = AlphaFactory.newAlpha(); + InputConfig cfg = InputConfig.forString("a :- &connected[\"hello\",2]."); + cfg.addPredicateMethod("connected", Externals.processPredicate((Integer a, Integer b) -> (a == 1 && b == 2) || (b == 2 || b == 3))); + InputProgram prog = system.readProgram(cfg); - system.solve(prog).collect(Collectors.toSet()); + system.solve(prog).collect(Collectors.toSet()); }); } @@ -308,22 +319,6 @@ public String toString() { public int compareTo(Thingy o) { return 0; } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (!(o instanceof Thingy)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return 1; - } } private static class SubThingy extends Thingy { @@ -333,15 +328,15 @@ private static class SubThingy extends Thingy { public void withExternalSubtype() throws Exception { SubThingy thingy = new SubThingy(); - BasicRule rule = new BasicRule( + Rule rule = Rules.newRule( Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newConstant("x"))), - singletonList(Literals.fromAtom(Atoms.newExternalAtom(Predicates.getPredicate("thinger", 1), + singleton(Literals.fromAtom(Atoms.newExternalAtom(Predicates.getPredicate("thinger", 1), new MethodPredicateInterpretation(this.getClass().getMethod("thinger", Thingy.class)), singletonList(Terms.newConstant(thingy)), emptyList()), true))); Alpha system = AlphaFactory.newAlpha(); - InputProgram prog = new InputProgramImpl(singletonList(rule), emptyList(), new InlineDirectivesImpl()); + InputProgram prog = Programs.newInputProgram(singletonList(rule), emptyList(), Programs.newInlineDirectives()); Set actual = system.solve(prog).collect(Collectors.toSet()); Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("p").instance("x").build())); @@ -368,10 +363,10 @@ public void withExternalViaAnnotation() throws Exception { @Test public void errorDuplicateExternal() { assertThrows(IllegalArgumentException.class, () -> { - InputConfig cfg = InputConfig.forString("someString."); - cfg.addPredicateMethods(Externals.scan(this.getClass())); - cfg.addPredicateMethods(Externals.scan(this.getClass())); -}); + InputConfig cfg = InputConfig.forString("someString."); + cfg.addPredicateMethods(Externals.scan(this.getClass())); + cfg.addPredicateMethods(Externals.scan(this.getClass())); + }); } @Test @@ -439,7 +434,7 @@ public void withExternalInvocationCounted3() throws Exception { Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("a").build())); assertEquals(expected, actual); } - + @Test @SuppressWarnings("unchecked") public void programWithExternalStringStuff() throws IOException { @@ -474,6 +469,27 @@ public void withNegatedExternal() throws IOException { } } + @Test + public void reifyInput() { + String aspInput = "p(X) :- q(X), not r(X)."; + Alpha system = AlphaFactory.newAlpha(); + InputProgram input = system.readProgramString(aspInput); + Set reified = system.reify(input); + + Set reifiedPredicates = reified.stream() + .filter((a) -> a.getPredicate().equals(Predicates.getPredicate("predicate", 3))) + .collect(Collectors.toSet()); + Set reifiedRuleHeads = reified.stream() + .filter((a) -> a.getPredicate().equals(Predicates.getPredicate("rule_head", 2))) + .collect(Collectors.toSet()); + Set reifiedBodyLiterals = reified.stream() + .filter((a) -> a.getPredicate().equals(Predicates.getPredicate("rule_bodyLiteral", 2))) + .collect(Collectors.toSet()); + assertEquals(3, reifiedPredicates.size()); + assertEquals(1, reifiedRuleHeads.size()); + assertEquals(2, reifiedBodyLiterals.size()); + } + @Test public void basicUsage() throws Exception { Alpha system = AlphaFactory.newAlpha(); @@ -504,37 +520,80 @@ public void filterTest() { assertEquals(expected, actual); } - /** - * Verifies that no stratified evaluation is performed up-front when disabled in config. - */ @Test - public void disableStratifiedEvalTest() { - // Note: This might be cleaner if the test used the debugSolve method from the interface - String progstr = "p(a). q(X) :- p(X)."; - SystemConfig cfg = new SystemConfig(); - cfg.setEvaluateStratifiedPart(false); - AlphaImpl system = (AlphaImpl) AlphaFactory.newAlpha(cfg); - InputProgram input = system.readProgramString(progstr); - NormalProgram normal = system.normalizeProgram(input); - CompiledProgram preprocessed = system.performProgramPreprocessing(normal); - assertFalse(preprocessed.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("q", 1), Terms.newSymbolicConstant("a"))), - "Preprocessed program contains fact derived from stratifiable rule, but should not!"); + public void passingUnitTestExpectUnsat() { + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgramString(UNIT_TEST_EXPECT_UNSAT); + TestResult testResult = alpha.test(prog); + assertTrue(testResult.isSuccess()); } - /** - * Verifies that stratified evaluation is performed up-front if not otherwise configured. - */ @Test - public void enableStratifiedEvalTest() { - // Note: This might be cleaner if the test used the debugSolve method from the interface - String progstr = "p(a). q(X) :- p(X)."; - SystemConfig cfg = new SystemConfig(); - AlphaImpl system = (AlphaImpl) AlphaFactory.newAlpha(cfg); - InputProgram input = system.readProgramString(progstr); - NormalProgram normal = system.normalizeProgram(input); - CompiledProgram preprocessed = system.performProgramPreprocessing(normal); - assertTrue(preprocessed.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("q", 1), Terms.newSymbolicConstant("a"))), - "Preprocessed program does not contain fact derived from stratifiable rule, but should!"); + public void passingUnitTestBasicTest() { + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgramString(UNIT_TEST_BASIC_TEST); + TestResult testResult = alpha.test(prog); + assertTrue(testResult.isSuccess()); + assertEquals(1, testResult.getTestCaseResults().size()); + TestResult.TestCaseResult tcResult = testResult.getTestCaseResults().get(0); + assertTrue(tcResult.isSuccess()); + assertEquals(1, tcResult.getAssertionsPassed()); + assertEquals(0, tcResult.getAssertionsFailed()); + assertFalse(tcResult.answerSetCountVerificationResult().isPresent()); + assertTrue(tcResult.getAssertionErrors().isEmpty()); + } + + @Test + public void passingUnitTestMultipleAssertions() { + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgramString(UNIT_TEST_MORE_ASSERTIONS); + TestResult testResult = alpha.test(prog); + assertTrue(testResult.isSuccess()); + assertEquals(1, testResult.getTestCaseResults().size()); + TestResult.TestCaseResult tcResult = testResult.getTestCaseResults().get(0); + assertTrue(tcResult.isSuccess()); + assertEquals(2, tcResult.getAssertionsPassed()); + assertEquals(0, tcResult.getAssertionsFailed()); + assertFalse(tcResult.answerSetCountVerificationResult().isPresent()); + assertTrue(tcResult.getAssertionErrors().isEmpty()); + } + + @Test + public void passingUnitTestMultipleTestCases() { + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgramString(UNIT_TEST_MORE_TCS); + TestResult testResult = alpha.test(prog); + assertTrue(testResult.isSuccess()); + assertEquals(2, testResult.getTestCaseResults().size()); + } + + @Test + public void failingAssertionUnitTest() { + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgramString(UNIT_TEST_FAILING_ASSERTION); + TestResult testResult = alpha.test(prog); + assertFalse(testResult.isSuccess()); + assertEquals(1, testResult.getTestCaseResults().size()); + TestResult.TestCaseResult tcResult = testResult.getTestCaseResults().get(0); + assertFalse(tcResult.isSuccess()); + assertEquals(0, tcResult.getAssertionsPassed()); + assertEquals(1, tcResult.getAssertionsFailed()); + assertFalse(tcResult.answerSetCountVerificationResult().isPresent()); + assertEquals(1, tcResult.getAssertionErrors().size()); + } + + @Test + public void failingAnswerSetCountUnitTest() { + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgramString(UNIT_TEST_FAILING_COUNT); + TestResult testResult = alpha.test(prog); + assertFalse(testResult.isSuccess()); + assertEquals(1, testResult.getTestCaseResults().size()); + TestResult.TestCaseResult tcResult = testResult.getTestCaseResults().get(0); + assertFalse(tcResult.isSuccess()); + assertEquals(1, tcResult.getAssertionsPassed()); + assertEquals(0, tcResult.getAssertionsFailed()); + assertTrue(tcResult.answerSetCountVerificationResult().isPresent()); } /** @@ -616,16 +675,18 @@ private void problematicRun(String program, long seed, int limit) throws IOExcep InputProgram prog = system.readProgram(inputCfg); assertFalse(system.solve(prog).limit(limit).collect(Collectors.toList()).isEmpty()); } - + // Detailed reproduction test-case for github issue #239. @Test + @Disabled("This test relies on stratified evaluation being disabled, which is not supported anymore.") public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOException { final ProgramParser parser = new ProgramParserImpl(); - InputProgramImpl.Builder bld = InputProgramImpl.builder(); + InputProgramBuilder bld = Programs.builder(); bld.accumulate(parser.parse(Files.newInputStream(Paths.get("src", "test", "resources", "HanoiTower_Alpha.asp"), StandardOpenOption.READ))); - bld.accumulate(parser.parse(Files.newInputStream(Paths.get("src", "test", "resources", "HanoiTower_instances", "simple.asp"), StandardOpenOption.READ))); + bld.accumulate( + parser.parse(Files.newInputStream(Paths.get("src", "test", "resources", "HanoiTower_instances", "simple.asp"), StandardOpenOption.READ))); InputProgram parsedProgram = bld.build(); - + SystemConfig config = new SystemConfig(); config.setSolverName("default"); config.setNogoodStoreName("alpharoaming"); @@ -633,14 +694,12 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE config.setBranchingHeuristic(Heuristic.valueOf("VSIDS")); config.setDebugInternalChecks(true); config.setDisableJustificationSearch(false); - config.setEvaluateStratifiedPart(false); config.setReplayChoices(Arrays.asList(21, 26, 36, 56, 91, 96, 285, 166, 101, 290, 106, 451, 445, 439, 448, - 433, 427, 442, 421, 415, 436, 409, 430, 397, 391, 424, 385, 379, - 418, 373, 412, 406, 394, 388, 382, 245, 232, 208 - )); + 433, 427, 442, 421, 415, 436, 409, 430, 397, 391, 424, 385, 379, + 418, 373, 412, 406, 394, 388, 382, 245, 232, 208)); Alpha alpha = AlphaFactory.newAlpha(config); Optional answerSet = alpha.solve(parsedProgram).findFirst(); assertTrue(answerSet.isPresent()); } - + } diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/ReificationTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/ReificationTest.java new file mode 100644 index 000000000..4131b6f52 --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/ReificationTest.java @@ -0,0 +1,305 @@ +package at.ac.tuwien.kr.alpha.api.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import at.ac.tuwien.kr.alpha.api.Alpha; +import at.ac.tuwien.kr.alpha.api.ComparisonOperator; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.atoms.AtomQuery; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; + +/** + * Integration tests for program reification, i.e. generating sets of facts + * describing arbitrary ASP programs. + */ +public class ReificationTest { + + private final Alpha alpha = AlphaFactory.newAlpha(); + + private static final Map> CMP_OP_IDS; + + static { + Map> operators = new HashMap<>(); + operators.put(ComparisonOperators.EQ, Terms.newSymbolicConstant("eq")); + operators.put(ComparisonOperators.NE, Terms.newSymbolicConstant("ne")); + operators.put(ComparisonOperators.LE, Terms.newSymbolicConstant("le")); + operators.put(ComparisonOperators.LT, Terms.newSymbolicConstant("lt")); + operators.put(ComparisonOperators.GE, Terms.newSymbolicConstant("ge")); + operators.put(ComparisonOperators.GT, Terms.newSymbolicConstant("gt")); + CMP_OP_IDS = Collections.unmodifiableMap(operators); + } + + @Test + public void propositionalFact() { + Set reified = alpha.reify(alpha.readProgramString("aRatherUselessFact.")); + List factAtomResult = reified.stream().filter(Atoms.query("fact", 1)).collect(Collectors.toList()); + assertEquals(1, factAtomResult.size()); + BasicAtom factAtom = factAtomResult.get(0); + Term idTerm = factAtom.getTerms().get(0); + assertTrue(reified.stream().anyMatch( + Atoms.query("atom_type", 2) + .withTermEquals(0, idTerm) + .withTermEquals(1, Terms.newSymbolicConstant("basic")))); + assertTrue(reified.stream().anyMatch( + Atoms.query("basicAtom_numTerms", 2) + .withTermEquals(0, idTerm) + .withTermEquals(1, Terms.newConstant(0)))); + Optional predicateAtomResult = reified.stream().filter(Atoms.query("basicAtom_predicate", 2) + .withTermEquals(0, idTerm)).findFirst(); + assertTrue(predicateAtomResult.isPresent()); + Term predicateIdTerm = predicateAtomResult.get().getTerms().get(1); + Optional predicateDescriptorResult = reified.stream().filter(Atoms.query("predicate", 3) + .withTermEquals(0, predicateIdTerm)).findFirst(); + assertTrue(predicateDescriptorResult.isPresent()); + BasicAtom predicateDescriptor = predicateDescriptorResult.get(); + assertEquals(Terms.newConstant("aRatherUselessFact"), predicateDescriptor.getTerms().get(1)); + assertEquals(Terms.newConstant(0), predicateDescriptor.getTerms().get(2)); + } + + @Test + public void positiveRule() { + Set reified = alpha.reify(alpha.readProgramString("p(X) :- q(X), r(X).")); + List ruleDescriptorResult = reified.stream().filter(Atoms.query("rule", 1)) + .collect(Collectors.toList()); + assertEquals(1, ruleDescriptorResult.size()); + BasicAtom ruleDescriptor = ruleDescriptorResult.get(0); + Term ruleId = ruleDescriptor.getTerms().get(0); + List headDescriptorResult = reified.stream().filter( + Atoms.query("rule_head", 2) + .withTermEquals(0, ruleId)) + .collect(Collectors.toList()); + assertEquals(1, headDescriptorResult.size()); + BasicAtom headDescriptor = headDescriptorResult.get(0); + Term headId = headDescriptor.getTerms().get(1); + assertEquals(1, reified.stream().filter( + Atoms.query("head_type", 2) + .withTermEquals(0, headId) + .withTermEquals(1, Terms.newSymbolicConstant("normal"))) + .count()); + List headAtomDescriptorResult = reified.stream().filter( + Atoms.query("normalHead_atom", 2) + .withTermEquals(0, headId)) + .collect(Collectors.toList()); + assertEquals(1, headAtomDescriptorResult.size()); + BasicAtom headAtomDescriptor = headAtomDescriptorResult.get(0); + Term headAtomId = headAtomDescriptor.getTerms().get(1); + Set atomTypeDescriptors = reified.stream().filter( + Atoms.query("atom_type", 2) + .withTermEquals(1, Terms.newSymbolicConstant("basic"))) + .collect(Collectors.toSet()); + assertEquals(3, atomTypeDescriptors.size()); + assertEquals(1, atomTypeDescriptors.stream().filter(Atoms.query("atom_type", 2).withTermEquals(0, headAtomId)) + .collect(Collectors.toList()).size()); + assertEquals(1, reified.stream().filter( + Atoms.query("rule_numBodyLiterals", 2) + .withTermEquals(0, ruleId) + .withTermEquals(1, Terms.newConstant(2))) + .count()); + Set bodyLiteralDescriptors = reified.stream().filter( + Atoms.query("rule_bodyLiteral", 2) + .withTermEquals(0, ruleId)) + .collect(Collectors.toSet()); + assertEquals(2, bodyLiteralDescriptors.size()); + for (BasicAtom bodyLiteralDescriptor : bodyLiteralDescriptors) { + assertEquals(1, reified.stream().filter( + Atoms.query("literal_polarity", 2) + .withTermEquals(0, bodyLiteralDescriptor.getTerms().get(1)) + .withTermEquals(1, Terms.newSymbolicConstant("pos"))) + .count()); + assertEquals(1, reified.stream().filter( + Atoms.query("literal_atom", 2) + .withTermEquals(0, bodyLiteralDescriptor.getTerms().get(1))) + .count()); + } + assertEquals(3, reified.stream().filter( + Atoms.query("term_type", 2) + .withTermEquals(1, Terms.newSymbolicConstant("variable"))) + .count()); + assertEquals(3, reified.stream().filter( + Atoms.query("variableTerm_symbol", 2) + .withTermEquals(1, Terms.newConstant("X"))) + .count()); + } + + @Test + public void ruleWithNegativeLiteral() { + Set reified = alpha.reify(alpha.readProgramString("p(X) :- q(X), not r(X).")); + List> qIds = findLiteralIdsForPredicate(Predicates.getPredicate("q", 1), Terms.newConstant(0), + reified); + assertEquals(1, qIds.size()); + assertEquals(1, + reified.stream().filter( + Atoms.query("literal_polarity", 2) + .withTermEquals(0, qIds.get(0)) + .withTermEquals(1, Terms.newSymbolicConstant("pos"))) + .count()); + List> rIds = findLiteralIdsForPredicate(Predicates.getPredicate("r", 1), Terms.newConstant(0), + reified); + assertEquals(1, rIds.size()); + assertEquals(1, + reified.stream().filter( + Atoms.query("literal_polarity", 2) + .withTermEquals(0, rIds.get(0)) + .withTermEquals(1, Terms.newSymbolicConstant("neg"))) + .count()); + } + + @Test + public void comparisonAtom() { + Set reified = alpha.reify(alpha.readProgramString("p(X) :- X = 42.")); + List> eqLitIds = findLiteralIdsForComparisonOperator(ComparisonOperators.EQ, Terms.newConstant(0), reified); + assertEquals(1, eqLitIds.size()); + } + + @Test + public void aggregateAtom() { + Set reified = alpha.reify(alpha.readProgramString("aggregateTrue :- X < #count{X : p(X)} < Y, X = 1, Y = 3.")); + List> countLitIds = findLiteralIdsForAggregate(Terms.newSymbolicConstant("count"), Terms.newConstant(0), reified); + assertEquals(1, countLitIds.size()); + } + + @Test + public void externalAtom() { + Set reified = alpha.reify(alpha.readProgramString("foo :- &stdlib_string_concat[\"foo\", \"bar\"](FOOBAR).")); + List> strcatLitIds = findLiteralIdsForExternal(Terms.newConstant("stdlib_string_concat"), Terms.newConstant(0), reified); + assertEquals(1, strcatLitIds.size()); + } + + @Test + public void constraint() { + Set reified = alpha.reify(alpha.readProgramString(":- p(X), q(X).")); + assertEquals(1, reified.stream().filter(Atoms.query("constraint", 1)).count()); + assertTrue(reified.stream().noneMatch(Atoms.query("rule", 1))); + } + + private static List> findLiteralIdsForPredicate(Predicate predicate, ConstantTerm reifiedRuleId, + Set reifiedProgram) { + ConstantTerm predicateId = findPredicateId(predicate, reifiedProgram); + return ruleBodyLiteralIdStream(reifiedRuleId, reifiedProgram) + .filter((literalId) -> { + List> atomIdResult = reifiedProgram.stream() + .filter(Atoms.query("literal_atom", 2).withTermEquals(0, literalId)) + .map((literalToAtomDescriptor) -> (ConstantTerm) literalToAtomDescriptor.getTerms() + .get(1)) + .collect(Collectors.toList()); + if (atomIdResult.isEmpty()) { + return false; + } + ConstantTerm atomId = atomIdResult.get(0); + List> predicateIdOfBasicAtomResult = reifiedProgram.stream() + .filter(Atoms.query("basicAtom_predicate", 2).withTermEquals(0, atomId)) + .map((atomToPredicateDescriptor) -> (ConstantTerm) atomToPredicateDescriptor.getTerms() + .get(1)) + .collect(Collectors.toList()); + return predicateIdOfBasicAtomResult.isEmpty() ? false + : predicateIdOfBasicAtomResult.get(0).equals(predicateId); + }) + .collect(Collectors.toList()); + } + + private static List> findLiteralIdsForAggregate(ConstantTerm aggregateFunction, ConstantTerm reifiedRuleId, Set reifiedProgram) { + return ruleBodyLiteralIdStream(reifiedRuleId, reifiedProgram) + .filter((literalId) -> { + List> atomIdResult = reifiedProgram.stream() + .filter(Atoms.query("literal_atom", 2).withTermEquals(0, literalId)) + .map((literalToAtomDescriptor) -> (ConstantTerm) literalToAtomDescriptor.getTerms() + .get(1)) + .collect(Collectors.toList()); + if (atomIdResult.isEmpty()) { + return false; + } + ConstantTerm atomId = atomIdResult.get(0); + return reifiedProgram.stream() + .anyMatch( + Atoms.query("aggregateAtom_aggregateFunction", 2) + .withTermEquals(0, atomId) + .withTermEquals(1, aggregateFunction)); + }).collect(Collectors.toList()); + } + + private static List> findLiteralIdsForExternal(ConstantTerm methodName, ConstantTerm reifiedRuleId, Set reifiedProgram) { + return ruleBodyLiteralIdStream(reifiedRuleId, reifiedProgram) + .filter((literalId) -> { + List> atomIdResult = reifiedProgram.stream() + .filter(Atoms.query("literal_atom", 2).withTermEquals(0, literalId)) + .map((literalToAtomDescriptor) -> (ConstantTerm) literalToAtomDescriptor.getTerms() + .get(1)) + .collect(Collectors.toList()); + if (atomIdResult.isEmpty()) { + return false; + } + ConstantTerm atomId = atomIdResult.get(0); + return reifiedProgram.stream() + .anyMatch( + Atoms.query("externalAtom_name", 2) + .withTermEquals(0, atomId) + .withTermEquals(1, methodName)); + }).collect(Collectors.toList()); + } + + private static List> findLiteralIdsForComparisonOperator(ComparisonOperator operator, + ConstantTerm reifiedRuleId, Set reifiedProgram) { + return ruleBodyLiteralIdStream(reifiedRuleId, reifiedProgram) + .filter((literalId) -> { + List> atomIdResult = reifiedProgram.stream() + .filter(Atoms.query("literal_atom", 2).withTermEquals(0, literalId)) + .map((literalToAtomDescriptor) -> (ConstantTerm) literalToAtomDescriptor.getTerms() + .get(1)) + .collect(Collectors.toList()); + if (atomIdResult.isEmpty()) { + return false; + } + ConstantTerm atomId = atomIdResult.get(0); + return reifiedProgram.stream() + .anyMatch( + Atoms.query("comparisonAtom_operator", 2) + .withTermEquals(0, atomId) + .withTermEquals(1, CMP_OP_IDS.get(operator))); + }).collect(Collectors.toList()); + } + + private static ConstantTerm findPredicateId(Predicate predicate, Set reifiedProgram) { + List reifiedPredicateResult = reifiedProgram.stream() + .filter(queryForReifiedPredicate(predicate)) + .collect(Collectors.toList()); + if (reifiedPredicateResult.size() > 1) { + Assertions.fail("Expected only one atom when querying for reified predicate!"); + } + return (ConstantTerm) reifiedPredicateResult.get(0).getTerms().get(0); + } + + private static AtomQuery queryForReifiedPredicate(Predicate predicate) { + return Atoms.query("predicate", 3) + .withTermEquals(1, Terms.newConstant(predicate.getName())) + .withTermEquals(2, Terms.newConstant(predicate.getArity())); + } + + private static Stream> ruleBodyLiteralIdStream(ConstantTerm ruleId, + Set reifiedProgram) { + return reifiedProgram.stream() + .filter(Atoms.query("rule_bodyLiteral", 2).withTermEquals(0, ruleId)) + // After filtering we have atoms describing body literals - extract the second + // term which is the id of the literal + .map((bodyLiteralDescriptor) -> (ConstantTerm) bodyLiteralDescriptor.getTerms().get(1)); + } + +} diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HanoiTowerTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HanoiTowerTest.java index bb6231461..13021d7c5 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HanoiTowerTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HanoiTowerTest.java @@ -25,10 +25,7 @@ */ package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.ignoreTestForNaiveSolver; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.ignoreTestForNonDefaultDomainIndependentHeuristics; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.*; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; @@ -36,28 +33,27 @@ import java.util.Optional; import java.util.SortedSet; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; import org.junit.jupiter.api.Disabled; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; /** - * Tests {@link AbstractSolver} using some hanoi tower test cases (see https://en.wikipedia.org/wiki/Tower_of_Hanoi). + * Tests {@link Solver} using some hanoi tower test cases (see Towers of Hanoi). * */ -// TODO This is a functional test and should not be run with standard unit tests public class HanoiTowerTest { @SuppressWarnings("unused") @@ -106,8 +102,6 @@ private void testHanoiTower(int instance, SystemConfig cfg) throws IOException { } private void testHanoiTower(String instance, SystemConfig cfg) throws IOException { - // TODO should be read by the Alpha instance constructed in buildSolverForRegressionTest, - // do not instantiate parsers "free-style"! InputProgram prog = new ProgramParserImpl().parse( Paths.get("src", "test", "resources", "HanoiTower_Alpha.asp"), Paths.get("src", "test", "resources", "HanoiTower_instances", instance + ".asp")); @@ -142,7 +136,7 @@ private int getSteps(InputProgram parsedProgram) { Predicate steps = Predicates.getPredicate("steps", 1); for (Atom atom : parsedProgram.getFacts()) { if (atom.getPredicate().getName().equals(steps.getName()) && atom.getPredicate().getArity() == steps.getArity()) { - return Integer.valueOf(atom.getTerms().get(0).toString()); + return Integer.parseInt(atom.getTerms().get(0).toString()); } } throw new IllegalArgumentException("No steps atom found in input program."); diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HeadBodyTransformationTests.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HeadBodyTransformationTests.java index 63b6ff59b..07f80ac83 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HeadBodyTransformationTests.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HeadBodyTransformationTests.java @@ -36,13 +36,13 @@ import java.util.Optional; import java.util.stream.Collectors; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import org.junit.jupiter.api.Disabled; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; /** * Tests rule transformations described in the following research paper, and their effects on performance: diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/OmigaBenchmarksTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/OmigaBenchmarksTest.java index 31c67bae2..9ae96e5cd 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/OmigaBenchmarksTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/OmigaBenchmarksTest.java @@ -35,17 +35,18 @@ import java.nio.file.Paths; import java.util.Optional; +import at.ac.tuwien.kr.alpha.api.Solver; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import org.junit.jupiter.api.Disabled; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.config.SystemConfig; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; /** - * Tests {@link AbstractSolver} using Omiga benchmark problems. + * Tests {@link Solver} using Omiga benchmark problems. * */ // TODO This is actually a performance benchmark and should not be run with standard unit tests diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/RacksTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/RacksTest.java index 6bca18e5e..7fd811e8a 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/RacksTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/RacksTest.java @@ -32,6 +32,7 @@ import java.nio.file.Paths; import java.util.Optional; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.junit.jupiter.api.Disabled; @@ -39,11 +40,10 @@ import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; import at.ac.tuwien.kr.alpha.api.config.SystemConfig; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; /** - * Tests {@link AbstractSolver} using a racks configuration problem. + * Tests {@link Solver} using a racks configuration problem. * */ // TODO This is a functional test and should not be run with standard unit tests diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverTests.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverTests.java index b6a27ad22..65556fc3e 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverTests.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverTests.java @@ -27,37 +27,27 @@ */ package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.assertRegressionTestAnswerSets; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.assertRegressionTestAnswerSetsWithBase; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.collectRegressionTestAnswerSets; -import static java.util.Collections.singleton; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.SortedSet; - import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.programs.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; -import at.ac.tuwien.kr.alpha.core.parser.InlineDirectivesImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; import at.ac.tuwien.kr.alpha.test.AnswerSetsParser; -// TODO This is a functional test and should not be run with standard unit tests +import java.util.*; + +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.*; +import static java.util.Collections.singleton; +import static org.junit.jupiter.api.Assertions.*; + public class SolverTests { private static class Thingy implements Comparable { @@ -78,10 +68,10 @@ public void testObjectProgram(SystemConfig cfg) { final Atom fact = Atoms.newBasicAtom(Predicates.getPredicate("foo", 1), Terms.newConstant(thingy)); - final InputProgram program = new InputProgramImpl( + final InputProgram program = Programs.newInputProgram( Collections.emptyList(), Collections.singletonList(fact), - new InlineDirectivesImpl() + Programs.newInlineDirectives() ); assertEquals(singleton(new AnswerSetBuilder() @@ -764,15 +754,15 @@ public void instanceEnumerationMultipleIdentifiers(SystemConfig cfg) { } private void assertPropositionalPredicateFalse(AnswerSet answerSet, Predicate predicate) { - assertEquals(null, answerSet.getPredicateInstances(predicate)); + assertNull(answerSet.getPredicateInstances(predicate)); } private void assertEnumerationPositions(SortedSet positions, int numPositions) { assertEquals(numPositions, positions.size()); - boolean usedPositions[] = new boolean[numPositions]; + boolean[] usedPositions = new boolean[numPositions]; for (Atom position : positions) { @SuppressWarnings("unchecked") - Integer atomPos = ((ConstantTerm) position.getTerms().get(1)).getObject() - 1; + int atomPos = ((ConstantTerm) position.getTerms().get(1)).getObject() - 1; assertTrue(atomPos < numPositions); usedPositions[atomPos] = true; } @@ -803,17 +793,17 @@ public void smallCardinalityAggregate(SystemConfig cfg) { ); } - // TODO @AntoniusW what are these? Can we get rid of them? If not, where do I move them? - // @RegressionTest - // public void dummyGrounder(SystemConfig cfg) { - // AtomStore atomStore = new AtomStoreImpl(); - // assertEquals(GrounderMockWithBasicProgram.EXPECTED, buildSolverForRegressionTest(atomStore, new GrounderMockWithBasicProgram(atomStore), cfg).collectSet()); - // } - - // @RegressionTest - // public void choiceGrounder(SystemConfig cfg) { - // AtomStore atomStore = new AtomStoreImpl(); - // assertEquals(GrounderMockWithChoice.EXPECTED, buildSolverForRegressionTest(atomStore, new GrounderMockWithChoice(atomStore), cfg).collectSet()); - // } + // TODO these look obsolete - confirm if they can be removed +// @RegressionTest +// public void dummyGrounder(SystemConfig cfg) { +// AtomStore atomStore = new AtomStoreImpl(); +// assertEquals(DummyGrounder.EXPECTED, buildSolverForRegressionTest(atomStore, new DummyGrounder(atomStore), cfg).collectSet()); +// } +// +// @RegressionTest +// public void choiceGrounder(SystemConfig cfg) { +// AtomStore atomStore = new AtomStoreImpl(); +// assertEquals(ChoiceGrounder.EXPECTED, buildSolverForRegressionTest(atomStore, new ChoiceGrounder(atomStore), cfg).collectSet()); +// } } diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/StratifiedEvaluationRegressionTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/StratifiedEvaluationRegressionTest.java index 62ba483dd..ada29162d 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/StratifiedEvaluationRegressionTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/StratifiedEvaluationRegressionTest.java @@ -10,6 +10,8 @@ import java.util.Set; import java.util.function.Consumer; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import org.apache.commons.lang3.tuple.ImmutablePair; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -26,8 +28,6 @@ import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; // TODO This is a functional test and should not be run with standard unit tests public class StratifiedEvaluationRegressionTest { @@ -129,7 +129,7 @@ private static void verifyProgramBasic(NormalProgram evaluated) { assertFactsContainedInProgram(evaluated, Atoms.newBasicAtom(Predicates.getPredicate("a", 0)), Atoms.newBasicAtom(Predicates.getPredicate("b", 0))); assertEquals(2, evaluated.getFacts().size()); - assertTrue(evaluated.getRules().size() == 0); + assertTrue(evaluated.getRules().isEmpty()); } private static void verifyAnswerSetsBasic(Set answerSets) { @@ -140,7 +140,7 @@ private static void verifyProgramBasicMultiInstance(NormalProgram evaluated) { assertFactsContainedInProgram(evaluated, Atoms.newBasicAtom(Predicates.getPredicate("q", 1), Terms.newSymbolicConstant("a")), Atoms.newBasicAtom(Predicates.getPredicate("q", 1), Terms.newSymbolicConstant("b"))); - assertTrue(evaluated.getRules().size() == 0); + assertTrue(evaluated.getRules().isEmpty()); } private static void verifyAnswerSetsBasicMultiInstance(Set answerSets) { diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringRandomGraphTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringRandomGraphTest.java index 19bf3f7e5..1740d5133 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringRandomGraphTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringRandomGraphTest.java @@ -25,29 +25,29 @@ */ package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; - import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Random; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; import org.junit.jupiter.api.Disabled; import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; -// TODO This is a functional test and should not be run with standard unit tests +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; + public class ThreeColouringRandomGraphTest { private static final long DEBUG_TIMEOUT_FACTOR = 5; @@ -108,7 +108,7 @@ private void testThreeColouring(int nVertices, int nEdges, SystemConfig cfg) { ":- e(N1,N2), blue(N1), blue(N2)." + ":- e(N1,N2), red(N1), red(N2)." + ":- e(N1,N2), green(N1), green(N2)."); - InputProgramImpl.Builder prgBuilder = InputProgramImpl.builder(tmpPrg); + InputProgramBuilder prgBuilder = Programs.builder(tmpPrg); prgBuilder.addFacts(createVertices(nVertices)); prgBuilder.addFacts(createEdges(nVertices, nEdges)); InputProgram program = prgBuilder.build(); diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringTestWithRandom.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringTestWithRandom.java index 9f29deae8..7af25b780 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringTestWithRandom.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringTestWithRandom.java @@ -25,39 +25,39 @@ */ package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; - import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Random; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; import org.junit.jupiter.api.Disabled; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; + +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; /** - * Tests {@link AbstractSolver} using some three-coloring test cases, as described in: + * Tests {@link Solver} using some three-coloring test cases, as described in: * Lefèvre, Claire; Béatrix, Christopher; Stéphan, Igor; Garcia, Laurent (2017): * ASPeRiX, a first-order forward chaining approach for answer set computing. * In Theory and Practice of Logic Programming, pp. 1-45. DOI: * 10.1017/S1471068416000569 */ -// TODO This is a functional test and should not be run with standard unit tests public class ThreeColouringTestWithRandom { private static final long DEBUG_TIMEOUT_FACTOR = 5; @@ -189,7 +189,7 @@ public void testN101(SystemConfig cfg) { private void testThreeColouring(int n, boolean shuffle, int seed, SystemConfig cfg) { InputProgram tmpPrg = new ProgramParserImpl() .parse("col(V,C) :- v(V), c(C), not ncol(V,C)." + "ncol(V,C) :- col(V,D), c(C), C != D." + ":- e(V,U), col(V,C), col(U,C)."); - InputProgramImpl.Builder prgBuilder = InputProgramImpl.builder().accumulate(tmpPrg); + InputProgramBuilder prgBuilder = Programs.builder().accumulate(tmpPrg); prgBuilder.addFacts(createColors("1", "2", "3")); prgBuilder.addFacts(createVertices(n)); prgBuilder.addFacts(createEdges(n, shuffle, seed)); diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringWheelTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringWheelTest.java index 554b6f8b5..a3ad1c447 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringWheelTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringWheelTest.java @@ -25,37 +25,37 @@ */ package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; - import java.util.ArrayList; import java.util.List; import java.util.Optional; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; import org.junit.jupiter.api.Disabled; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.programs.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.InputProgramImpl; -import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; + +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; /** - * Tests {@link AbstractSolver} using some three-coloring test cases, as described in: + * Tests {@link Solver} using some three-coloring test cases, as described in: * Lefèvre, Claire; Béatrix, Christopher; Stéphan, Igor; Garcia, Laurent (2017): * ASPeRiX, a first-order forward chaining approach for answer set computing. * In Theory and Practice of Logic Programming, pp. 1-45. * DOI: 10.1017/S1471068416000569 */ -// TODO This is a functional test and should not be run with standard unit tests public class ThreeColouringWheelTest { private static final long DEBUG_TIMEOUT_FACTOR = 5; @@ -105,7 +105,7 @@ private void testThreeColouring(int n, SystemConfig cfg) { "col(V,C) :- v(V), c(C), not ncol(V,C)." + "ncol(V,C) :- col(V,D), c(C), C != D." + ":- e(V,U), col(V,C), col(U,C)."); - InputProgramImpl.Builder prgBuilder = InputProgramImpl.builder(tmpPrg); + InputProgramBuilder prgBuilder = Programs.builder(tmpPrg); prgBuilder.addFacts(createColors("red", "blue", "green")); prgBuilder.addFacts(createVertices(n)); prgBuilder.addFacts(createEdges(n)); diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestConfigProvider.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestConfigProvider.java index 7a5e06633..93a5e3ad7 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestConfigProvider.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestConfigProvider.java @@ -21,7 +21,7 @@ public class RegressionTestConfigProvider { private static final boolean DEFAULT_ENABLE_DEBUG_CHECKS = false; /** - * Creates a list of {@link RegressionTestConfig}s with all config combinations that are to be tested im methods tagged using + * Creates a list of {@link SystemConfig}s with all config combinations that are to be tested im methods tagged using * "RegressionTest" annotation. * Exact number of combinations depends on the "CI" environment variable that can be used to signal that a test is being run in a CI * environment. @@ -39,7 +39,6 @@ private static List buildConfigs() { String[] gtcValues = new String[]{DEFAULT_GROUNDER_TOLERANCE, "permissive" }; String grounderToleranceRules = DEFAULT_GROUNDER_TOLERANCE; boolean[] grounderAccumulatorValues = ci ? new boolean[]{DEFAULT_DISABLE_INSTANCE_REMOVAL, true } : new boolean[]{DEFAULT_DISABLE_INSTANCE_REMOVAL }; - boolean[] evaluateStratifiedValues = new boolean[]{false, true }; boolean[] enableDebugChecksValues = new boolean[]{DEFAULT_ENABLE_DEBUG_CHECKS, true }; //@formatter:on @@ -58,21 +57,18 @@ private static List buildConfigs() { for (String branchingHeuristicName : heuristics) { for (String grounderToleranceConstraints : gtcValues) { for (boolean grounderAccumulatorEnabled : grounderAccumulatorValues) { - for (boolean evaluateStratified : evaluateStratifiedValues) { - for (boolean enableDebugChecks : enableDebugChecksValues) { - SystemConfig cfg = new SystemConfig(); - cfg.setSolverName(solverName); - cfg.setNogoodStoreName(nogoodStoreName); - cfg.setBranchingHeuristicName(branchingHeuristicName); - cfg.setGrounderToleranceRules(grounderToleranceRules); - cfg.setGrounderToleranceConstraints(grounderToleranceConstraints); - cfg.setGrounderAccumulatorEnabled(grounderAccumulatorEnabled); - cfg.setEvaluateStratifiedPart(evaluateStratified); - cfg.setDebugInternalChecks(enableDebugChecks); - cfg.setSeed(seed); - - configsToTest.add(cfg); - } + for (boolean enableDebugChecks : enableDebugChecksValues) { + SystemConfig cfg = new SystemConfig(); + cfg.setSolverName(solverName); + cfg.setNogoodStoreName(nogoodStoreName); + cfg.setBranchingHeuristicName(branchingHeuristicName); + cfg.setGrounderToleranceRules(grounderToleranceRules); + cfg.setGrounderToleranceConstraints(grounderToleranceConstraints); + cfg.setGrounderAccumulatorEnabled(grounderAccumulatorEnabled); + cfg.setDebugInternalChecks(enableDebugChecks); + cfg.setSeed(seed); + + configsToTest.add(cfg); } } } @@ -84,7 +80,7 @@ private static List buildConfigs() { } /** - * Provides {@link RegressionTestConfig}s specifically for tests concerned with AggregateRewriting. + * Provides {@link SystemConfig}s specifically for tests concerned with AggregateRewriting. * All parameters fixed to default values except stratified evaluation, sorting grid encoding for count rewriting * and negative sum element support. * @@ -92,40 +88,34 @@ private static List buildConfigs() { */ private static List buildConfigsForAggregateTests() { List configsToTest = new ArrayList<>(); - - boolean[] evaluateStratifiedValues = new boolean[] {true, false }; boolean[] useSortingGridValues = new boolean[] {true, false }; boolean[] supportNegativeSumElementsValues = new boolean[] {true, false }; - for (boolean evalStratified : evaluateStratifiedValues) { - for (boolean useSortingGrid : useSortingGridValues) { - for (boolean supportNegativeElements : supportNegativeSumElementsValues) { - // new RegressionTestConfig( - // DEFAULT_SOLVER_NAME, DEFAULT_GROUNDER_NAME, DEFAULT_NOGOOD_STORE, Heuristic.valueOf(DEFAULT_BRANCHING_HEURISTIC), - // 0, DEFAULT_ENABLE_DEBUG_CHECKS, DEFAULT_GROUNDER_TOLERANCE, DEFAULT_GROUNDER_TOLERANCE, DEFAULT_DISABLE_INSTANCE_REMOVAL, - // evalStratified, - // useSortingGrid, supportNegativeElements)); - AggregateRewritingConfig aggCfg = new AggregateRewritingConfig(); - aggCfg.setUseSortingGridEncoding(useSortingGrid); - aggCfg.setSupportNegativeValuesInSums(supportNegativeElements); - - SystemConfig cfg = new SystemConfig(); - cfg.setSolverName(DEFAULT_SOLVER_NAME); - cfg.setNogoodStoreName(DEFAULT_NOGOOD_STORE); - cfg.setBranchingHeuristicName(DEFAULT_BRANCHING_HEURISTIC); - cfg.setSeed(0); - cfg.setDebugInternalChecks(DEFAULT_ENABLE_DEBUG_CHECKS); - cfg.setGrounderToleranceRules(DEFAULT_GROUNDER_TOLERANCE); - cfg.setGrounderToleranceConstraints(DEFAULT_GROUNDER_TOLERANCE); - cfg.setGrounderAccumulatorEnabled(DEFAULT_DISABLE_INSTANCE_REMOVAL); - cfg.setEvaluateStratifiedPart(evalStratified); - cfg.setAggregateRewritingConfig(aggCfg); - - configsToTest.add(cfg); - } + for (boolean useSortingGrid : useSortingGridValues) { + for (boolean supportNegativeElements : supportNegativeSumElementsValues) { + // new RegressionTestConfig( + // DEFAULT_SOLVER_NAME, DEFAULT_GROUNDER_NAME, DEFAULT_NOGOOD_STORE, Heuristic.valueOf(DEFAULT_BRANCHING_HEURISTIC), + // 0, DEFAULT_ENABLE_DEBUG_CHECKS, DEFAULT_GROUNDER_TOLERANCE, DEFAULT_GROUNDER_TOLERANCE, DEFAULT_DISABLE_INSTANCE_REMOVAL, + // evalStratified, + // useSortingGrid, supportNegativeElements)); + AggregateRewritingConfig aggCfg = new AggregateRewritingConfig(); + aggCfg.setUseSortingGridEncoding(useSortingGrid); + aggCfg.setSupportNegativeValuesInSums(supportNegativeElements); + + SystemConfig cfg = new SystemConfig(); + cfg.setSolverName(DEFAULT_SOLVER_NAME); + cfg.setNogoodStoreName(DEFAULT_NOGOOD_STORE); + cfg.setBranchingHeuristicName(DEFAULT_BRANCHING_HEURISTIC); + cfg.setSeed(0); + cfg.setDebugInternalChecks(DEFAULT_ENABLE_DEBUG_CHECKS); + cfg.setGrounderToleranceRules(DEFAULT_GROUNDER_TOLERANCE); + cfg.setGrounderToleranceConstraints(DEFAULT_GROUNDER_TOLERANCE); + cfg.setGrounderAccumulatorEnabled(DEFAULT_DISABLE_INSTANCE_REMOVAL); + cfg.setAggregateRewritingConfig(aggCfg); + + configsToTest.add(cfg); } } - return configsToTest; } @@ -145,7 +135,7 @@ public static List provideAggregateTestConfigs() { return retVal; } - private static final String[] nonDeprecatedHeuristics() { + private static String[] nonDeprecatedHeuristics() { final List nonDeprecatedHeuristicsNames = new ArrayList<>(); for (Field field : Heuristic.class.getFields()) { if (field.getAnnotation(Deprecated.class) == null) { diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestUtils.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestUtils.java index 82f2b88df..c4301385b 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestUtils.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestUtils.java @@ -1,16 +1,5 @@ package at.ac.tuwien.kr.alpha.regressiontests.util; -import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertAnswerSetsEqual; -import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertAnswerSetsEqualWithBase; -import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; - -import java.time.Duration; -import java.util.Set; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Assumptions; -import org.junit.jupiter.api.function.Executable; - import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; @@ -19,6 +8,16 @@ import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.function.Executable; + +import java.time.Duration; +import java.util.Set; +import java.util.stream.Collectors; + +import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertAnswerSetsEqual; +import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertAnswerSetsEqualWithBase; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; public final class RegressionTestUtils { diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/test/util/MockedActionsAlphaFactory.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/test/util/MockedActionsAlphaFactory.java new file mode 100644 index 000000000..fffd0cd20 --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/test/util/MockedActionsAlphaFactory.java @@ -0,0 +1,25 @@ +package at.ac.tuwien.kr.alpha.test.util; + +import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; +import at.ac.tuwien.kr.alpha.core.actions.ActionImplementationProvider; +import at.ac.tuwien.kr.alpha.test.MockActionImplementationProvider; + +public class MockedActionsAlphaFactory extends AlphaFactory { + + private MockActionImplementationProvider actionImplementationMock = new MockActionImplementationProvider(""); + + + public MockActionImplementationProvider getActionImplementationMock() { + return actionImplementationMock; + } + + public void setActionImplementationMock(MockActionImplementationProvider actionImplementationMock) { + this.actionImplementationMock = actionImplementationMock; + } + + @Override + protected ActionImplementationProvider newActionImplementationProvider() { + return actionImplementationMock; + } + +} diff --git a/build.gradle.kts b/build.gradle.kts index bd335656d..4cff4f84b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,39 @@ +import net.researchgate.release.ReleaseExtension + plugins { jacoco - id("com.github.kt3k.coveralls") version "2.12.0" + id("jacoco-report-aggregation") + id("net.researchgate.release") version "3.0.2" } tasks.wrapper { - gradleVersion = "7.3.2" + gradleVersion = "7.6" distributionType = Wrapper.DistributionType.ALL } + +dependencies { + jacocoAggregation(project(":alpha-cli-app")) +} + +reporting { + reports { + val jacocoAggregatedTestReport by creating(JacocoCoverageReport::class) { + testType.set(TestSuiteType.UNIT_TEST) + } + } +} + +repositories { + maven ("https://plugins.gradle.org/m2/") + mavenCentral { metadataSources { mavenPom() } } +} + +configure { + failOnUnversionedFiles.set(true) + // Tag template currently doesn't work with non-interactive release, see https://github.com/researchgate/gradle-release/issues/371 + // tagTemplate.set("v${version}") + with(git) { + requireBranch.set("master") + } +} \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c1b2ed676..f12104bb8 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -2,6 +2,11 @@ plugins { `kotlin-dsl` } +tasks.withType().configureEach { + kotlinOptions { + jvmTarget = "11" + } +} repositories { mavenCentral { metadataSources { mavenPom() } } } diff --git a/buildSrc/src/main/kotlin/alpha.java-common-conventions.gradle.kts b/buildSrc/src/main/kotlin/alpha.java-common-conventions.gradle.kts index deace0036..eb65b0a59 100644 --- a/buildSrc/src/main/kotlin/alpha.java-common-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/alpha.java-common-conventions.gradle.kts @@ -13,15 +13,17 @@ repositories { mavenCentral { metadataSources { mavenPom() } } } -java.sourceCompatibility = JavaVersion.VERSION_1_8 -java.targetCompatibility = JavaVersion.VERSION_1_8 +java.sourceCompatibility = JavaVersion.VERSION_11 +java.targetCompatibility = JavaVersion.VERSION_11 dependencies { implementation("org.apache.commons:commons-collections4:4.4") + implementation("org.apache.commons:commons-compress:1.23.0") // Explicitly depend on newer version than pulled-in by commons-lang3:3.12.0 to avoid several CVEs (cf. issue #362) implementation("org.apache.commons:commons-lang3:3.12.0") - implementation("org.apache.commons:commons-text:1.9") + implementation("org.apache.commons:commons-text:1.10.0") - implementation("org.reflections:reflections:0.9.11") + implementation("org.reflections:reflections:0.10.2") + implementation("com.google.guava:guava:32.1.1-jre") implementation("org.slf4j:slf4j-api:1.7.32") // JUnit 5 @@ -37,6 +39,8 @@ dependencies { testImplementation("org.slf4j:slf4j-simple:1.7.32") testFixturesApi(jupiter("api")) + testFixturesApi("org.slf4j:slf4j-api:1.7.32") + testFixturesImplementation("commons-io:commons-io:2.11.0") } // JUnit 5 diff --git a/examples/3col_with_tests.asp b/examples/3col_with_tests.asp new file mode 100644 index 000000000..8f57337e0 --- /dev/null +++ b/examples/3col_with_tests.asp @@ -0,0 +1,66 @@ +%%% Basic Encoding of the Graph 3-Coloring Problem %%% +% Graphs are interpreted as having undirected edges. + +% Edges are undirected +edge(Y, X) :- edge(X, Y). + +% Guess color for each vertex +red(V) :- vertex(V), not green(V), not blue(V). +green(V) :- vertex(V), not red(V), not blue(V). +blue(V) :- vertex(V), not red(V), not green(V). + +% Check for invalid colorings +:- vertex(V1), vertex(V2), edge(V1, V2), red(V1), red(V2). +:- vertex(V1), vertex(V2), edge(V1, V2), green(V1), green(V2). +:- vertex(V1), vertex(V2), edge(V1, V2), blue(V1), blue(V2). + +%% Verify that directed edges are converted to undirected ones. +#test no_asymmetric_edge(expect: >0) { + given { + vertex(a). + vertex(b). + vertex(c). + edge(a, b). + edge(b, c). + edge(c, a). + } + assertForAll { + :- edge(A, B), not edge(B, A). + } +} + +#test triangle_colorings(expect: 6) { + given { + vertex(a). + vertex(b). + vertex(c). + edge(a, b). + edge(b, c). + edge(c, a). + } + % Make sure all vertices are colored in all answer sets + assertForAll { + colored(V) :- vertex(V), red(V). + colored(V) :- vertex(V), green(V). + colored(V) :- vertex(V), blue(V). + :- vertex(V), not colored(V). + } + % Make sure we do not have neighboring vertices of same color in any answer set + assertForAll { + :- edge(V1, V2), red(V1), red(V2). + :- edge(V1, V2), green(V1), green(V2). + :- edge(V1, V2), blue(V1), blue(V2). + } + % In at least one answer set, vertex a should be red + assertForSome { + :- not red(a). + } + % In at least one answer set, vertex a should be green + assertForSome { + :- not green(a). + } + % In at least one answer set, vertex a should be blue + assertForSome { + :- not blue(a). + } +} diff --git a/examples/greet-me.evl b/examples/greet-me.evl new file mode 100644 index 000000000..8bf5bdcda --- /dev/null +++ b/examples/greet-me.evl @@ -0,0 +1,7 @@ +prompt_text("Hello user, what's your name? "). +write_prompt_res(R) : @streamWrite[STDOUT, PROMPT] = R :- prompt_text(PROMPT), &stdout(STDOUT). +usr_input_res(INP) : @streamReadLine[STDIN] = INP :- write_prompt_res(success(_)), &stdin(STDIN). +write_greeting_res(R) : @streamWrite[STDOUT, GREETING] = R :- + usr_input_res(success(line(NAME))), + &stdlib_string_concat["Hello, it is the utmost pleasure to finally greet you from an Evolog program, ", NAME](GREETING), + &stdout(STDOUT). diff --git a/examples/write_something.evl b/examples/write_something.evl new file mode 100644 index 000000000..cb113762b --- /dev/null +++ b/examples/write_something.evl @@ -0,0 +1,9 @@ +outfile("/home/michael/asp_snippets/evolog-actions/hello.out"). + +open_result(PATH, RES) : @fileOutputStream[PATH] = RES :- outfile(PATH). + +write_result(PATH, RES) : @streamWrite[STREAM, "HelloEvologWorld!"] = RES :- open_result(PATH, success(stream(STREAM))), outfile(PATH). + +can_close(PATH, FD) :- write_result(PATH, success(ok)), open_result(PATH, success(stream(FD))), outfile(PATH). + +close_result(PATH, RES) : @outputStreamClose[STREAM] = RES :- write_result(PATH, success(ok)), open_result(PATH, success(stream(STREAM))), outfile(PATH). diff --git a/gradle.properties b/gradle.properties index 79a8403fc..94628898d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -version=0.7.0-SNAPSHOT +version=0.8.0-SNAPSHOT group=at.ac.tuwien.kr.alpha org.gradle.warning.mode=all diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac0b842f1..f42e62f37 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c78733..c53aefaa5 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». # # Important for patching: #