diff --git a/.gitattributes b/.gitattributes index 6d809091d..4adffdef2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,4 +16,4 @@ *.gpg filter=lfs diff=lfs merge=lfs binary *.bin filter=lfs diff=lfs merge=lfs binary -alpha-core/benchmarks/** linguist-vendored +alpha-solver/benchmarks/** linguist-vendored diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e9b76d03..8df9c80a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: submodules: recursive fetch-depth: 0 # See https://github.com/marketplace/actions/gradle-wrapper-validation - - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/actions/wrapper-validation@v5 # See https://github.com/marketplace/actions/setup-java-jdk - uses: actions/setup-java@v3 with: diff --git a/.gitignore b/.gitignore index 42635d337..748e63db9 100644 --- a/.gitignore +++ b/.gitignore @@ -107,4 +107,4 @@ gradle-app.setting /.dbeaver /Scripts /.vscode/ -workspace.code-workspace +*.code-workspace 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 5fa09a7bc..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,6 +1,7 @@ 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; @@ -9,7 +10,7 @@ import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.config.InputConfig; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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; @@ -27,48 +28,58 @@ 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 */ - ASPCore2Program readProgram(InputConfig cfg) throws IOException; + 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 */ - ASPCore2Program readProgramFiles(boolean literate, Map externals, List paths) throws IOException; + InputProgram readProgramFiles(boolean literate, Map externals, List paths) throws IOException; /** * see {@link Alpha#readProgramFiles(boolean, Map, List)} */ - ASPCore2Program readProgramFiles(boolean literate, Map externals, Path... paths) throws IOException; + 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 */ - ASPCore2Program readProgramString(String aspString, Map externals); + InputProgram readProgramString(String aspString, Map externals); /** * Convenience method to parse ASP strings not containing any user-defined external atoms, see {@link Alpha#readProgramString(String, Map)}. */ - ASPCore2Program readProgramString(String aspString); + 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 */ - DebugSolvingContext prepareDebugSolve(final ASPCore2Program program); + DebugSolvingContext prepareDebugSolve(final InputProgram program); /** * Prepares a {@link DebugSolvingContext} for the given {@link NormalProgram} to debug program preprocessing. @@ -78,12 +89,12 @@ 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 */ - DebugSolvingContext prepareDebugSolve(final ASPCore2Program program, java.util.function.Predicate filter); + DebugSolvingContext prepareDebugSolve(final InputProgram program, java.util.function.Predicate filter); /** * Prepares a {@link DebugSolvingContext} for the given {@link NormalProgram} to debug program preprocessing. @@ -94,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(ASPCore2Program 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(ASPCore2Program program, java.util.function.Predicate filter); + 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 */ @@ -117,34 +131,39 @@ 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(ASPCore2Program 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(ASPCore2Program program, java.util.function.Predicate filter); + 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); @@ -155,11 +174,11 @@ public interface Alpha { * @param program an ASP program to reify * @return a set of {@link BasicAtom}s encoding the given program */ - Set reify(ASPCore2Program program); + Set reify(InputProgram program); /** * Runs all test cases of the given program. */ - TestResult test(ASPCore2Program 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 1015fb833..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 @@ -32,7 +32,7 @@ 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(AtomQuery query); 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 ca649725d..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 @@ -1,11 +1,11 @@ package at.ac.tuwien.kr.alpha.api; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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.terms.Term; /** - * A comparison operator that can be used in {@link ASPCore2Program}s. + * A comparison operator that can be used in {@link InputProgram}s. * * Copyright (c) 2021, the Alpha Team. */ diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/DebugSolvingContext.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/DebugSolvingContext.java index 60966193a..2f9ab8fcf 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/DebugSolvingContext.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/DebugSolvingContext.java @@ -1,6 +1,6 @@ package at.ac.tuwien.kr.alpha.api; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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.analysis.ComponentGraph; import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; @@ -13,13 +13,13 @@ public interface DebugSolvingContext { /** - * The normalized version of the {@link ASPCore2Program} that is being solved. - * See {@link Alpha#normalizeProgram(ASPCore2Program)}. + * The normalized version of the {@link InputProgram} that is being solved. + * See {@link Alpha#normalizeProgram(InputProgram)}. */ NormalProgram getNormalizedProgram(); /** - * The fully preprocessed version of the {@link ASPCore2Program} that is being solved. + * The fully preprocessed version of the {@link InputProgram} that is being solved. * This differs from the value of {@link DebugSolvingContext#getNormalizedProgram()} in the stratified part of the normalized program may * already be evaluated depending on the respective configuration of {@link Alpha}. */ 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 bbe8680bf..5343b4bf4 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 @@ -37,10 +37,11 @@ @FunctionalInterface public interface PredicateInterpretation { - Set>> TRUE = singleton(emptyList()); - Set>> FALSE = emptySet(); + + Set> TRUE = singleton(emptyList()); + Set> FALSE = emptySet(); String EVALUATE_RETURN_TYPE_NAME_PREFIX = Set.class.getName() + "<" + List.class.getName() + "<" + ConstantTerm.class.getName(); - Set>> evaluate(List terms); + Set> evaluate(List terms); } 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/SystemConfig.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/config/SystemConfig.java index 27019ce10..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,20 +44,18 @@ 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 String DEFAULT_GROUNDER_NAME = "naive"; + 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; public static final BinaryNoGoodPropagationEstimationStrategy DEFAULT_MOMS_STRATEGY = BinaryNoGoodPropagationEstimationStrategy.CountBinaryWatches; public static final long DEFAULT_SEED = System.nanoTime(); - public static final boolean DEFAULT_DETERMINISTIC = false; public static final boolean DEFAULT_PRINT_STATS = false; public static final boolean DEFAULT_QUIET = false; public static final boolean DEFAULT_DISABLE_JUSTIFICATION_SEARCH = false; 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; @@ -65,10 +63,9 @@ public class SystemConfig { public static final String DEFAULT_ATOM_SEPARATOR = ", "; public static final AggregateRewritingConfig DEFAULT_AGGREGATE_REWRITING_CONFIG = new AggregateRewritingConfig(); - private String grounderName = DEFAULT_GROUNDER_NAME; + private boolean acceptEvologPrograms = DEFAULT_ACCEPT_EVOLOG; private String solverName = DEFAULT_SOLVER_NAME; private String nogoodStoreName = DEFAULT_NOGOOD_STORE_NAME; - private boolean deterministic = DEFAULT_DETERMINISTIC; private long seed = DEFAULT_SEED; private boolean debugInternalChecks = DEFAULT_DEBUG_INTERNAL_CHECKS; private Heuristic branchingHeuristic = DEFAULT_BRANCHING_HEURISTIC; @@ -78,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; @@ -86,17 +82,6 @@ public class SystemConfig { private String atomSeparator = DEFAULT_ATOM_SEPARATOR; private AggregateRewritingConfig aggregateRewritingConfig = DEFAULT_AGGREGATE_REWRITING_CONFIG; - public String getGrounderName() { - return this.grounderName; - } - - /** - * Sets the name of the grounder implementation to use. - */ - public void setGrounderName(String grounderName) { - this.grounderName = grounderName; - } - public String getSolverName() { return this.solverName; } @@ -119,18 +104,6 @@ public void setNogoodStoreName(String nogoodStoreName) { this.nogoodStoreName = nogoodStoreName; } - public boolean isDeterministic() { - return this.deterministic; - } - - /** - * If set, 0 will be used as random seed for solver-internal branching heuristics, resulting in answer sets of the same program being found - * in a fixed sequence. - */ - public void setDeterministic(boolean deterministic) { - this.deterministic = deterministic; - } - public long getSeed() { return this.seed; } @@ -224,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; } @@ -280,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/programs/ASPCore2Program.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/InputProgram.java similarity index 62% rename from alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/ASPCore2Program.java rename to alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/InputProgram.java index fa444b184..54f697292 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/ASPCore2Program.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/InputProgram.java @@ -1,21 +1,19 @@ package at.ac.tuwien.kr.alpha.api.programs; +import at.ac.tuwien.kr.alpha.api.programs.modules.Module; 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; -/** - * A {@link Program} that conforms to Alphas implementation of the ASP-Core2-Standard. - * - * Copyright (c) 2021, the Alpha Team. - */ -public interface ASPCore2Program extends Program> { +public interface InputProgram extends Program> { /** * The test cases associated with this program. */ List getTestCases(); + List getModules(); + } 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 c6eff6bea..f5a932c52 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,7 +1,10 @@ package at.ac.tuwien.kr.alpha.api.programs; +import at.ac.tuwien.kr.alpha.api.programs.modules.Module; import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; +import java.util.List; + /** * A {@link Program} consisting only of facts and {@link NormalRule}s, i.e. no disjunctive- or choice-rules, and no aggregates in rule bodies. * @@ -9,4 +12,6 @@ */ public interface NormalProgram extends Program { + List getModules(); + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/ProgramParser.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/ProgramParser.java index 39f23cae8..d8195a9f6 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/ProgramParser.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/ProgramParser.java @@ -9,40 +9,40 @@ import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; /** - * A parser for {@link ASPCore2Program}s. + * A parser for {@link InputProgram}s. * * Copyright (c) 2021, the Alpha Team. */ public interface ProgramParser { - default ASPCore2Program parse(String programString) { + default InputProgram parse(String programString) { return parse(programString, Collections.emptyMap()); } - default ASPCore2Program parse(InputStream programSource) throws IOException { + default InputProgram parse(InputStream programSource) throws IOException { return parse(programSource, Collections.emptyMap()); } - default ASPCore2Program parse(Path programPath) throws IOException { + default InputProgram parse(Path programPath) throws IOException { return parse(programPath, Collections.emptyMap()); } - default ASPCore2Program parse(Path... programSources) throws IOException { + default InputProgram parse(Path... programSources) throws IOException { return parse(Collections.emptyMap(), programSources); } - default ASPCore2Program parse(Iterable programSources) throws IOException { + default InputProgram parse(Iterable programSources) throws IOException { return parse(programSources, Collections.emptyMap()); } - ASPCore2Program parse(String programString, Map externalPredicateDefinitions); + InputProgram parse(String programString, Map externalPredicateDefinitions); - ASPCore2Program parse(InputStream programSource, Map externalPredicateDefinitions) throws IOException; + InputProgram parse(InputStream programSource, Map externalPredicateDefinitions) throws IOException; - ASPCore2Program parse(Path programPath, Map externalPredicateDefinitions) throws IOException; + InputProgram parse(Path programPath, Map externalPredicateDefinitions) throws IOException; - ASPCore2Program parse(Map externalPredicateDefinitions, Path... programSources) throws IOException; + InputProgram parse(Map externalPredicateDefinitions, Path... programSources) throws IOException; - ASPCore2Program parse(Iterable programSources, Map externalPredicateDefinitions) throws IOException; + InputProgram parse(Iterable programSources, Map externalPredicateDefinitions) throws IOException; } 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 bd5127cf2..f5de58e46 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 @@ -24,7 +24,8 @@ enum AggregateFunctionSymbol { COUNT, MAX, MIN, - SUM + SUM, + LIST } ComparisonOperator getLowerBoundOperator(); @@ -44,6 +45,11 @@ enum AggregateFunctionSymbol { @Override AggregateLiteral toLiteral(boolean positive); + @Override + default AggregateLiteral toLiteral() { + return toLiteral(true); + } + interface AggregateElement { List getElementTerms(); 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 8d014fd04..d8c8095df 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 @@ -42,7 +42,7 @@ default Literal toLiteral() { Set getOccurringVariables(); - Atom substitute(Substitution substitution); // Introduce parameterized interface Substituable to get atom types right? + Atom substitute(Substitution substitution); // Introduce parameterized interface Substitutable to get atom types right? Atom renameVariables(String newVariablePrefix); 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 d4b2f946c..ef97f8f28 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,6 +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.programs.literals.ExternalLiteral; import at.ac.tuwien.kr.alpha.api.programs.terms.Term; /** @@ -21,4 +22,12 @@ public interface ExternalAtom extends Atom, VariableNormalizableAtom { PredicateInterpretation getInterpretation(); + @Override + default ExternalLiteral toLiteral() { + return toLiteral(true); + } + + @Override + ExternalLiteral toLiteral(boolean positive); + } diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ModuleAtom.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ModuleAtom.java new file mode 100644 index 000000000..42fedae92 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/atoms/ModuleAtom.java @@ -0,0 +1,60 @@ +package at.ac.tuwien.kr.alpha.api.programs.atoms; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; + +import java.util.List; +import java.util.Optional; + +/** + * An atom that is implemented using an additional ASP program (i.e. a module). + * Note that a module atom itself can not be instantiated, but needs to be compiled + * into some kind of instantiable atom by linking it to an ASP program that implements + * the referenced module. + */ +public interface ModuleAtom extends Atom { + + String getModuleName(); + + List getInput(); + + List getOutput(); + + ModuleInstantiationMode getInstantiationMode(); + + @Override + ModuleAtom substitute(Substitution substitution); + + @Override + ModuleAtom withTerms(List terms); + + interface ModuleInstantiationMode { + Optional requestedAnswerSets(); + + ModuleInstantiationMode ALL = Optional::empty; + + static ModuleInstantiationMode forNumAnswerSets(int answerSets) { + return new ModuleInstantiationMode() { + @Override + public Optional requestedAnswerSets() { + return Optional.of(answerSets); + } + + @Override + public int hashCode() { + return answerSets; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ModuleInstantiationMode)) { + return false; + } + return ((ModuleInstantiationMode) obj).requestedAnswerSets().equals(this.requestedAnswerSets()); + } + }; + } + + } + +} 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 4824480e9..074c36205 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 @@ -1,18 +1,18 @@ package at.ac.tuwien.kr.alpha.api.programs.literals; -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.terms.Term; import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; +import java.util.List; +import java.util.Set; + /** - * A literal according to the ASP Core 2 Standard. + *

A literal according to the ASP Core 2 Standard. * Wraps an {@link Atom} that may or may not be negated. - * + *

* Copyright (c) 2017-2021, the Alpha Team. */ // TODO go through implementations and pull out stuff that can be default-implemented here diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/ModuleLiteral.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/ModuleLiteral.java new file mode 100644 index 000000000..98bc092f0 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/literals/ModuleLiteral.java @@ -0,0 +1,17 @@ +package at.ac.tuwien.kr.alpha.api.programs.literals; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.ModuleAtom; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; + +public interface ModuleLiteral extends Literal{ + + @Override + ModuleAtom getAtom(); + + @Override + ModuleLiteral negate(); + + @Override + ModuleLiteral substitute(Substitution substitution); + +} diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/modules/Module.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/modules/Module.java new file mode 100644 index 000000000..d43bdce6c --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/modules/Module.java @@ -0,0 +1,18 @@ +package at.ac.tuwien.kr.alpha.api.programs.modules; + +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; + +import java.util.Set; + +public interface Module { + + String getName(); + + Predicate getInputSpec(); + + Set getOutputSpec(); + + InputProgram getImplementation(); + +} 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 index 8f2d8ebc8..92bdc6776 100644 --- 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 @@ -14,4 +14,6 @@ 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/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..42919da69 --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/ActionHead.java @@ -0,0 +1,24 @@ +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; + +/** + * Rule head implementation representing the head of an Evolog "Action Rule". + * In addition to a regular head atom, an action head encodes an action name (the name of an action function to be called + * when the rule fires) as well as a list input terms to said action function and one variable representing the result + * (i.e. output term) of the action function. + *

+ * Copyright (c) 2024, the Alpha Team. + */ +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/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/programs/rules/heads/NormalHead.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/NormalHead.java index c9a1ee01c..b8b9269f4 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/NormalHead.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/rules/heads/NormalHead.java @@ -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/programs/tests/Assertion.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/programs/tests/Assertion.java index 70da34ddc..4acf1e5f8 100644 --- 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 @@ -1,6 +1,6 @@ package at.ac.tuwien.kr.alpha.api.programs.tests; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; public interface Assertion { @@ -23,7 +23,7 @@ public String toString() { Mode getMode(); - ASPCore2Program getVerifier(); + InputProgram getVerifier(); } diff --git a/alpha-cli-app/build.gradle.kts b/alpha-cli-app/build.gradle.kts index a62227309..c96c15b31 100644 --- a/alpha-cli-app/build.gradle.kts +++ b/alpha-cli-app/build.gradle.kts @@ -69,5 +69,6 @@ tasks.create("bundledJar") { } tasks.test { + dependsOn(":alpha-solver:test") useJUnitPlatform() } 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 853a6d310..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 @@ -55,8 +55,8 @@ import at.ac.tuwien.kr.alpha.api.config.AlphaConfig; 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.impl.AlphaImpl; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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; import at.ac.tuwien.kr.alpha.api.programs.analysis.ComponentGraph; import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; @@ -86,9 +86,9 @@ public static void main(String[] args) { Main.exitWithMessage(commandLineParser.getUsageMessage(), 1); } - Alpha alpha = new AlphaImpl(cfg.getSystemConfig()); + Alpha alpha = AlphaFactory.newAlpha(cfg.getSystemConfig()); - ASPCore2Program program = null; + InputProgram program = null; try { program = alpha.readProgram(cfg.getInputConfig()); } catch (FileNotFoundException e) { 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 857705f97..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 @@ -92,16 +92,12 @@ public class CommandLineParser { 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_GROUNDER = Option.builder("g").longOpt("grounder").hasArg(true).argName("grounder") - .desc("the grounder implementation to use (default: " + SystemConfig.DEFAULT_GROUNDER_NAME + ")").build(); private static final Option OPT_SOLVER = Option.builder("s").longOpt("solver").hasArg(true).argName("solver") .desc("the solver implementation to use (default: " + SystemConfig.DEFAULT_SOLVER_NAME + ")").build(); private static final Option OPT_NOGOOD_STORE = Option.builder("r").longOpt("store").hasArg(true).argName("store") .desc("the nogood store to use (default: " + SystemConfig.DEFAULT_NOGOOD_STORE_NAME + ")").build(); private static final Option OPT_SORT = Option.builder("sort").longOpt("sort").hasArg(false) .desc("sort answer sets (default: " + SystemConfig.DEFAULT_SORT_ANSWER_SETS + ")").build(); - private static final Option OPT_DETERMINISTIC = Option.builder("d").longOpt("deterministic").hasArg(false) - .desc("disables randomness (default: " + SystemConfig.DEFAULT_DETERMINISTIC + ")").build(); private static final Option OPT_SEED = Option.builder("e").longOpt("seed").hasArg(true).argName("seed").type(Integer.class) .desc("set seed (default: System.nanoTime())").build(); private static final Option OPT_DEBUG_INTERNAL_CHECKS = Option.builder("dbgs").longOpt("DebugEnableInternalChecks") @@ -128,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 + ")") @@ -171,11 +164,9 @@ public class CommandLineParser { CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_REIFY); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_RUN_TESTS); - CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_SOLVER); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NOGOOD_STORE); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_SORT); - CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_DETERMINISTIC); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_SEED); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_DEBUG_INTERNAL_CHECKS); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_BRANCHING_HEURISTIC); @@ -187,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); @@ -229,11 +219,9 @@ private void initializeGlobalOptionHandlers() { */ // help is handled separately, therefore dummy handler this.globalOptionHandlers.put(CommandLineParser.OPT_HELP.getOpt(), (o, c) -> { }); - this.globalOptionHandlers.put(CommandLineParser.OPT_GROUNDER.getOpt(), this::handleGrounder); this.globalOptionHandlers.put(CommandLineParser.OPT_SOLVER.getOpt(), this::handleSolver); this.globalOptionHandlers.put(CommandLineParser.OPT_NOGOOD_STORE.getOpt(), this::handleNogoodStore); this.globalOptionHandlers.put(CommandLineParser.OPT_SORT.getOpt(), this::handleSort); - this.globalOptionHandlers.put(CommandLineParser.OPT_DETERMINISTIC.getOpt(), this::handleDeterministic); this.globalOptionHandlers.put(CommandLineParser.OPT_SEED.getOpt(), this::handleSeed); this.globalOptionHandlers.put(CommandLineParser.OPT_DEBUG_INTERNAL_CHECKS.getOpt(), this::handleInternalChecks); this.globalOptionHandlers.put(CommandLineParser.OPT_BRANCHING_HEURISTIC.getOpt(), this::handleBranchingHeuristic); @@ -244,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); @@ -341,10 +328,6 @@ private void handleInput(Option opt, InputConfig cfg) { cfg.getFiles().add(optVal); } - private void handleGrounder(Option opt, SystemConfig cfg) { - cfg.setGrounderName(opt.getValue(SystemConfig.DEFAULT_GROUNDER_NAME)); - } - private void handleSolver(Option opt, SystemConfig cfg) { cfg.setSolverName(opt.getValue(SystemConfig.DEFAULT_SOLVER_NAME)); } @@ -367,13 +350,7 @@ private void handleSort(Option opt, SystemConfig cfg) { cfg.setSortAnswerSets(true); } - private void handleDeterministic(Option opt, SystemConfig cfg) { - cfg.setDeterministic(true); - cfg.setSeed(0); - } - private void handleSeed(Option opt, SystemConfig cfg) { - cfg.setDeterministic(false); String optVal = opt.getValue(); long seed; if (optVal != null) { @@ -455,10 +432,6 @@ 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); } diff --git a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/AnswerSetToXlsxWriterTest.java b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/AnswerSetToXlsxWriterTest.java index f1bf9e441..c3887321f 100644 --- a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/AnswerSetToXlsxWriterTest.java +++ b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/AnswerSetToXlsxWriterTest.java @@ -19,6 +19,7 @@ import at.ac.tuwien.kr.alpha.app.mappers.AnswerSetToWorkbookMapperTest; import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; +// TODO this is an integration test public class AnswerSetToXlsxWriterTest { @Test diff --git a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/MainTest.java b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/MainTest.java index a6b26f307..35ef774fc 100644 --- a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/MainTest.java +++ b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/MainTest.java @@ -39,6 +39,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +// TODO this is an end-to-end test public class MainTest { private static final String INPUT = "p(a). " + System.lineSeparator() + " b :- p(X)." + System.lineSeparator(); @@ -48,10 +49,10 @@ public class MainTest { private static Stream provideCommandLineArguments() { return Stream.of( - Arguments.of((Object) new String[]{"-DebugEnableInternalChecks", "-g", "naive", "-s", "default", "-e", "1119654162577372", "-n", "20", "-str", INPUT}), - Arguments.of((Object) new String[]{"-DebugEnableInternalChecks", "-g", "naive", "-s", "default", "-n", "0", "-str", INPUT}), - Arguments.of((Object) new String[]{"-DebugEnableInternalChecks", "-g", "naive", "-s", "default", "-n", "1", "-str", INPUT}), - Arguments.of((Object) new String[]{"-g", "naive", "-s", "default", "-r", "naive", "-e", "1119654162577372", "--numAS", "1", "-str", INPUT})); + Arguments.of((Object) new String[]{"-DebugEnableInternalChecks", "-s", "default", "-e", "1119654162577372", "-n", "20", "-str", INPUT}), + Arguments.of((Object) new String[]{"-DebugEnableInternalChecks", "-s", "default", "-n", "0", "-str", INPUT}), + Arguments.of((Object) new String[]{"-DebugEnableInternalChecks", "-s", "default", "-n", "1", "-str", INPUT}), + Arguments.of((Object) new String[]{"-s", "default", "-r", "naive", "-e", "1119654162577372", "--numAS", "1", "-str", INPUT})); } /** diff --git a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/ComponentGraphWriterTest.java b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/ComponentGraphWriterTest.java index fff165831..23655f106 100644 --- a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/ComponentGraphWriterTest.java +++ b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/ComponentGraphWriterTest.java @@ -8,9 +8,10 @@ import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.DebugSolvingContext; -import at.ac.tuwien.kr.alpha.api.impl.AlphaImpl; +import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; import at.ac.tuwien.kr.alpha.api.programs.analysis.ComponentGraph; +// TODO This is a functional test and should not be run with standard unit tests public class ComponentGraphWriterTest { private static final String LS = System.lineSeparator(); @@ -53,7 +54,7 @@ public void smokeTest() { "n1 -> n5 [xlabel=\"-\" labeldistance=0.1]" + LS + "n2 -> n5 [xlabel=\"+\" labeldistance=0.1]" + LS + "}" + LS; - Alpha alpha = new AlphaImpl(); + Alpha alpha = AlphaFactory.newAlpha(); DebugSolvingContext dbgResult = alpha.prepareDebugSolve(alpha.readProgramString(asp)); ComponentGraph compgraph = dbgResult.getComponentGraph(); ComponentGraphWriter writer = new ComponentGraphWriter(); diff --git a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/DependencyGraphWriterTest.java b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/DependencyGraphWriterTest.java index b487e8479..8d5929e80 100644 --- a/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/DependencyGraphWriterTest.java +++ b/alpha-cli-app/src/test/java/at/ac/tuwien/kr/alpha/app/DependencyGraphWriterTest.java @@ -8,9 +8,10 @@ import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.DebugSolvingContext; -import at.ac.tuwien.kr.alpha.api.impl.AlphaImpl; +import at.ac.tuwien.kr.alpha.api.impl.AlphaFactory; import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; +// TODO This is a functional test and should not be run with standard unit tests public class DependencyGraphWriterTest { private static final String LS = System.lineSeparator(); @@ -50,7 +51,7 @@ public void smokeTest() { "n6 -> n4 [xlabel=\"+\" labeldistance=0.1]" + LS + "n6 -> n5 [xlabel=\"+\" labeldistance=0.1]" + LS + "}" + LS; - Alpha alpha = new AlphaImpl(); + Alpha alpha = AlphaFactory.newAlpha(); DebugSolvingContext dbgResult = alpha.prepareDebugSolve(alpha.readProgramString(asp)); DependencyGraph depgraph = dbgResult.getDependencyGraph(); DependencyGraphWriter writer = new DependencyGraphWriter(); 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 2e9e9fba0..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 @@ -16,12 +16,13 @@ import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.impl.AlphaImpl; +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.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 public class AnswerSetToWorkbookMapperTest { private AnswerSetToWorkbookMapper mapper = new AnswerSetToWorkbookMapper(); @@ -46,7 +47,7 @@ public void solveAndWriteWorkbookTest() { + "p(N) :- p(I), N = I + 1, N <= MX, maxP(MX)." + "q(A, B) :- p(A), p(B)."; //@formatter:on - Alpha alpha = new AlphaImpl(); + Alpha alpha = AlphaFactory.newAlpha(); List answerSets = alpha.solve(alpha.readProgramString(progstr)).collect(Collectors.toList()); assertEquals(1, answerSets.size()); AnswerSet as = answerSets.get(0); 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>> stringLength(String str) { * Concatenates the two given strings */ @Predicate(name = "stdlib_string_concat") - public static Set>> stringConcat(String s1, String s2) { + public static Set>> stringConcat(String s1, Object 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(); + } + } + + // TODO we could add something to convert string to list + @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); + } + + @Predicate(name = "regex_matches") + public static Set>> regexMatchesInString(String regex, String str) { + Matcher matcher = Pattern.compile(regex).matcher(str); // Note: This could be done more efficiently by caching patterns. + Set>> result = new LinkedHashSet<>(); + while (matcher.find()) { + result.add(List.of(Terms.newConstant(matcher.group(1)), Terms.newConstant(matcher.start(1)), Terms.newConstant(matcher.end(1)))); + } + return result; + } + } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/BinaryPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BinaryPredicateInterpretation.java similarity index 96% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/BinaryPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BinaryPredicateInterpretation.java index e71e56aa1..5f506a2f8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/BinaryPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BinaryPredicateInterpretation.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.common.fixedinterpretations; +package at.ac.tuwien.kr.alpha.commons.externals; import java.util.List; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/BindingMethodPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BindingMethodPredicateInterpretation.java similarity index 94% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/BindingMethodPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BindingMethodPredicateInterpretation.java index 04eda3c1a..9bf1d25b8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/BindingMethodPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/BindingMethodPredicateInterpretation.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.common.fixedinterpretations; +package at.ac.tuwien.kr.alpha.commons.externals; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.StringUtils; @@ -52,7 +52,7 @@ public BindingMethodPredicateInterpretation(Method method) { @Override @SuppressWarnings("unchecked") - public Set>> evaluate(List terms) { + public Set> evaluate(List terms) { if (terms.size() != method.getParameterCount()) { throw new IllegalArgumentException( "Parameter count mismatch when calling " + method.getName() + ". " + @@ -90,7 +90,7 @@ public Set>> evaluate(List terms) { } try { - return (Set>>) method.invoke(null, arguments); + return (Set>) method.invoke(null, arguments); } catch (IllegalAccessException | InvocationTargetException ex) { throw new RuntimeException("Error invoking method " + method + "with args [" + StringUtils.join(arguments) + "], expection is: " + ex.getMessage()); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/externals/Externals.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/Externals.java similarity index 86% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/externals/Externals.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/Externals.java index aa9153e95..cbe65ff16 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/externals/Externals.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/Externals.java @@ -23,34 +23,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.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; +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.externals.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; 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.programs.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; -import at.ac.tuwien.kr.alpha.core.common.fixedinterpretations.BinaryPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.common.fixedinterpretations.BindingMethodPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.common.fixedinterpretations.IntPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.common.fixedinterpretations.LongPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.common.fixedinterpretations.MethodPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.common.fixedinterpretations.SuppliedPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.common.fixedinterpretations.UnaryPredicateInterpretation; +import org.reflections.Reflections; +import org.reflections.scanners.MethodAnnotationsScanner; + +import java.lang.reflect.Method; +import java.util.*; public final class Externals { @@ -128,7 +115,7 @@ public static PredicateInterpretation processPredicate(java.util.function return new BinaryPredicateInterpretation<>(predicate); } - public static PredicateInterpretation processPredicate(java.util.function.Supplier>>> supplier) { + public static PredicateInterpretation processPredicate(java.util.function.Supplier>> supplier) { return new SuppliedPredicateInterpretation(supplier); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/IntPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/IntPredicateInterpretation.java similarity index 96% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/IntPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/IntPredicateInterpretation.java index f77e18429..c0ceaa262 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/IntPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/IntPredicateInterpretation.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.common.fixedinterpretations; +package at.ac.tuwien.kr.alpha.commons.externals; import java.util.List; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/LongPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/LongPredicateInterpretation.java similarity index 96% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/LongPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/LongPredicateInterpretation.java index 9c5a08f2b..fd3182200 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/LongPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/LongPredicateInterpretation.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.common.fixedinterpretations; +package at.ac.tuwien.kr.alpha.commons.externals; import java.util.List; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/MethodPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/MethodPredicateInterpretation.java similarity index 97% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/MethodPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/MethodPredicateInterpretation.java index e4afa4c39..d1abdc97a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/MethodPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/MethodPredicateInterpretation.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.common.fixedinterpretations; +package at.ac.tuwien.kr.alpha.commons.externals; import org.apache.commons.lang3.ClassUtils; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/NonBindingPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/NonBindingPredicateInterpretation.java similarity index 95% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/NonBindingPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/NonBindingPredicateInterpretation.java index 26c84ed23..6f63d7f3f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/NonBindingPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/NonBindingPredicateInterpretation.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.common.fixedinterpretations; +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.programs.terms.ConstantTerm; @@ -51,7 +51,7 @@ public NonBindingPredicateInterpretation() { } @Override - public Set>> evaluate(List terms) { + public Set> evaluate(List terms) { if (terms.size() != arity) { throw new IllegalArgumentException("Exactly " + arity + " term(s) required."); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/SuppliedPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/SuppliedPredicateInterpretation.java similarity index 85% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/SuppliedPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/SuppliedPredicateInterpretation.java index 4e5f72637..4d46a6186 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/SuppliedPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/SuppliedPredicateInterpretation.java @@ -25,10 +25,9 @@ * 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.common.fixedinterpretations; +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.programs.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import java.util.List; @@ -36,14 +35,14 @@ import java.util.function.Supplier; public class SuppliedPredicateInterpretation implements BindingPredicateInterpretation { - private final Supplier>>> supplier; + private final Supplier>> supplier; - public SuppliedPredicateInterpretation(Supplier>>> supplier) { + public SuppliedPredicateInterpretation(Supplier>> supplier) { this.supplier = supplier; } @Override - public Set>> evaluate(List terms) { + public Set> evaluate(List terms) { if (!terms.isEmpty()) { throw new IllegalArgumentException("Can only be used without any arguments."); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/UnaryPredicateInterpretation.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/UnaryPredicateInterpretation.java similarity index 96% rename from alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/UnaryPredicateInterpretation.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/UnaryPredicateInterpretation.java index fbc170287..7c7f0a5da 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/fixedinterpretations/UnaryPredicateInterpretation.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/externals/UnaryPredicateInterpretation.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.common.fixedinterpretations; +package at.ac.tuwien.kr.alpha.commons.externals; import java.util.List; diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/ASPCore2ProgramImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InputProgramImpl.java similarity index 77% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/ASPCore2ProgramImpl.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InputProgramImpl.java index 32c5ccacf..fdf4d0021 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/ASPCore2ProgramImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/InputProgramImpl.java @@ -27,12 +27,13 @@ */ package at.ac.tuwien.kr.alpha.commons.programs; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; 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.api.programs.modules.Module; import at.ac.tuwien.kr.alpha.commons.util.Util; import java.util.Collections; @@ -43,15 +44,18 @@ *

* Copyright (c) 2017-2019, the Alpha Team. */ -class ASPCore2ProgramImpl extends AbstractProgram> implements ASPCore2Program{ +// TODO rename this to InputProgramImpl or some such +class InputProgramImpl extends AbstractProgram> implements InputProgram { - static final ASPCore2ProgramImpl EMPTY = new ASPCore2ProgramImpl(Collections.emptyList(), Collections.emptyList(), new InlineDirectivesImpl(), Collections.emptyList()); + static final InputProgramImpl EMPTY = new InputProgramImpl(Collections.emptyList(), Collections.emptyList(), new InlineDirectivesImpl(), Collections.emptyList(), Collections.emptyList()); private final List testCases; + private final List modules; - ASPCore2ProgramImpl(List> rules, List facts, InlineDirectives inlineDirectives, List testCases) { + InputProgramImpl(List> rules, List facts, InlineDirectives inlineDirectives, List testCases, List modules) { super(rules, facts, inlineDirectives); this.testCases = testCases; + this.modules = modules; } @Override @@ -59,6 +63,10 @@ public List getTestCases() { return testCases; } + public List getModules() { + return modules; + } + @Override public String toString() { String ls = System.lineSeparator(); 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 index 8bbfc4365..13b5233d2 100644 --- 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 @@ -5,6 +5,7 @@ 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.modules.Module; import at.ac.tuwien.kr.alpha.api.programs.rules.NormalRule; /** @@ -14,8 +15,16 @@ */ class NormalProgramImpl extends AbstractProgram implements NormalProgram { - NormalProgramImpl(List rules, List facts, InlineDirectives inlineDirectives) { + private final List modules; + + NormalProgramImpl(List rules, List facts, InlineDirectives inlineDirectives, List modules) { super(rules, facts, inlineDirectives); + this.modules = modules; + } + + @Override + public List getModules() { + return modules; } } 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 index e42a486fe..0d6895e9a 100644 --- 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 @@ -4,10 +4,11 @@ import java.util.Collections; import java.util.List; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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.modules.Module; 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; @@ -20,36 +21,46 @@ private Programs() { throw new AssertionError("Cannot instantiate utility class!"); } - public static ASPCore2Program emptyProgram() { - return ASPCore2ProgramImpl.EMPTY; + public static InputProgram emptyProgram() { + return InputProgramImpl.EMPTY; } - public static ASPCore2Program newASPCore2Program(List> rules, List facts, InlineDirectives inlineDirectives, List testCases) { - return new ASPCore2ProgramImpl(rules, facts, inlineDirectives, testCases); + public static InputProgram newInputProgram(List> rules, List facts, InlineDirectives inlineDirectives, List testCases, List modules) { + return new InputProgramImpl(rules, facts, inlineDirectives, testCases, modules); } - public static ASPCore2Program newASPCore2Program(List> rules, List facts, InlineDirectives inlineDirectives) { - return new ASPCore2ProgramImpl(rules, facts, inlineDirectives, Collections.emptyList()); + // TODO rename method + public static InputProgram newInputProgram(List> rules, List facts, InlineDirectives inlineDirectives, List testCases) { + return new InputProgramImpl(rules, facts, inlineDirectives, testCases, Collections.emptyList()); } - public static ASPCore2ProgramBuilder builder() { - return new ASPCore2ProgramBuilder(); + // TODO rename method + public static InputProgram newInputProgram(List> rules, List facts, InlineDirectives inlineDirectives) { + return new InputProgramImpl(rules, facts, inlineDirectives, Collections.emptyList(), Collections.emptyList()); } - public static ASPCore2ProgramBuilder builder(ASPCore2Program program) { - return new ASPCore2ProgramBuilder(program); + public static InputProgramBuilder builder() { + return new InputProgramBuilder(); } - public static NormalProgram newNormalProgram(List rules, List facts, InlineDirectives inlineDirectives) { - return new NormalProgramImpl(rules, facts, inlineDirectives); + public static InputProgramBuilder builder(InputProgram program) { + return new InputProgramBuilder(program); } - public static NormalProgram toNormalProgram(ASPCore2Program inputProgram) { +// public static NormalProgram newNormalProgram(List rules, List facts, InlineDirectives inlineDirectives) { +// return new NormalProgramImpl(rules, facts, inlineDirectives, Collections.emptyList()); +// } + + public static NormalProgram newNormalProgram(List rules, List facts, InlineDirectives inlineDirectives, List modules) { + return new NormalProgramImpl(rules, facts, inlineDirectives, modules); + } + + 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()); + return new NormalProgramImpl(normalRules, inputProgram.getFacts(), inputProgram.getInlineDirectives(), inputProgram.getModules()); } public static InlineDirectives newInlineDirectives() { @@ -57,68 +68,81 @@ public static InlineDirectives newInlineDirectives() { } /** - * Builder for more complex program construction scenarios, ensuring that an {@link AspCore2ProgramImpl} is immutable + * Builder for more complex program construction scenarios, ensuring that an {@link InputProgramImpl} is immutable */ - public static class ASPCore2ProgramBuilder { + // 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<>(); + private List modules = new ArrayList<>(); - public ASPCore2ProgramBuilder(ASPCore2Program prog) { + public InputProgramBuilder(InputProgram prog) { this.addRules(prog.getRules()); this.addFacts(prog.getFacts()); this.addInlineDirectives(prog.getInlineDirectives()); this.addTestCases(prog.getTestCases()); + this.addModules(prog.getModules()); } - public ASPCore2ProgramBuilder() { + public InputProgramBuilder() { } - public ASPCore2ProgramBuilder addRules(List> rules) { + public InputProgramBuilder addRules(List> rules) { this.rules.addAll(rules); return this; } - public ASPCore2ProgramBuilder addRule(Rule r) { + public InputProgramBuilder addRule(Rule r) { this.rules.add(r); return this; } - public ASPCore2ProgramBuilder addFacts(List facts) { + public InputProgramBuilder addFacts(List facts) { this.facts.addAll(facts); return this; } - public ASPCore2ProgramBuilder addFact(Atom fact) { + public InputProgramBuilder addFact(Atom fact) { this.facts.add(fact); return this; } - public ASPCore2ProgramBuilder addInlineDirectives(InlineDirectives inlineDirectives) { + public InputProgramBuilder addInlineDirectives(InlineDirectives inlineDirectives) { this.inlineDirectives.accumulate(inlineDirectives); return this; } - public ASPCore2ProgramBuilder addTestCase(TestCase testCase) { + public InputProgramBuilder addTestCase(TestCase testCase) { this.testCases.add(testCase); return this; } - public ASPCore2ProgramBuilder addTestCases(List testCases) { + public InputProgramBuilder addTestCases(List testCases) { this.testCases.addAll(testCases); return this; } - public ASPCore2ProgramBuilder accumulate(ASPCore2Program prog) { - return this.addRules(prog.getRules()).addFacts(prog.getFacts()).addInlineDirectives(prog.getInlineDirectives()).addTestCases(prog.getTestCases()); + public InputProgramBuilder addModule(Module module) { + this.modules.add(module); + return this; + } + + public InputProgramBuilder addModules(List modules) { + this.modules.addAll(modules); + return this; + } + + public InputProgramBuilder accumulate(InputProgram prog) { + return this.addRules(prog.getRules()).addFacts(prog.getFacts()).addInlineDirectives(prog.getInlineDirectives()).addTestCases(prog.getTestCases()).addModules(prog.getModules()); } - public ASPCore2Program build() { - return Programs.newASPCore2Program(this.rules, this.facts, this.inlineDirectives, this.testCases); + public InputProgram build() { + return Programs.newInputProgram(this.rules, this.facts, this.inlineDirectives, this.testCases, this.modules); } } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AbstractAtom.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AbstractAtom.java index 4a54b90f4..0d59ce8df 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AbstractAtom.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/AbstractAtom.java @@ -79,7 +79,7 @@ public Set getOccurringVariables() { /** * Returns whether this atom is ground, i.e., variable-free. * - * @return true iff the terms of this atom contain no {@link VariableTermImpl}. + * @return true iff the terms of this atom contain no {@link VariableTerm}. */ @Override public abstract boolean isGround(); @@ -98,4 +98,7 @@ public Atom renameVariables(String newVariablePrefix) { @Override public abstract int hashCode(); + @Override + public abstract String toString(); + } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/Atoms.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/Atoms.java index 8658c58d1..92bbbbb66 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/Atoms.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/Atoms.java @@ -7,16 +7,14 @@ 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.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.*; 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.programs.terms.FunctionTerm; import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import at.ac.tuwien.kr.alpha.commons.programs.atoms.AggregateAtomImpl.AggregateElementImpl; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; public final class Atoms { @@ -63,6 +61,10 @@ public static ExternalAtom newExternalAtom(Predicate predicate, PredicateInterpr return new ExternalAtomImpl(predicate, interpretation, input, output); } + public static ModuleAtom newModuleAtom(String moduleName, ModuleAtom.ModuleInstantiationMode instantiationMode, List input, List output) { + return new ModuleAtomImpl(moduleName, input, output, instantiationMode); + } + public static AtomQuery query(Predicate predicate) { return AtomQueryImpl.forPredicate(predicate); } @@ -71,4 +73,8 @@ public static AtomQuery query(String predicateName, int predicateArity) { return AtomQueryImpl.forPredicate(predicateName, predicateArity); } + public static FunctionTerm toFunctionTerm(Atom atom) { + return Terms.newFunctionTerm(atom.getPredicate().getName(), atom.getTerms()); + } + } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ModuleAtomImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ModuleAtomImpl.java new file mode 100644 index 000000000..72178d72b --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ModuleAtomImpl.java @@ -0,0 +1,131 @@ +package at.ac.tuwien.kr.alpha.commons.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.ModuleAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.ModuleLiteral; +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.literals.Literals; +import at.ac.tuwien.kr.alpha.commons.util.Util; +import org.apache.commons.collections4.ListUtils; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +class ModuleAtomImpl extends AbstractAtom implements ModuleAtom { + + private final String moduleName; + private final List input; + private final List output; + private final ModuleInstantiationMode instantiationMode; + + ModuleAtomImpl(String moduleName, List input, List output, ModuleInstantiationMode instantiationMode) { + this.moduleName = Objects.requireNonNull(moduleName); + this.input = Objects.requireNonNull(input); + this.output = Objects.requireNonNull(output); + this.instantiationMode = Objects.requireNonNull(instantiationMode); + } + + @Override + public String getModuleName() { + return moduleName; + } + + @Override + public List getInput() { + return input; + } + + @Override + public List getOutput() { + return output; + } + + @Override + public ModuleInstantiationMode getInstantiationMode() { + return instantiationMode; + } + + @Override + public ModuleAtom withTerms(List terms) { + if (terms.size() != this.input.size() + this.output.size()) { + throw new IllegalArgumentException( + "Cannot apply term list " + terms + " to module atom " + this + ", terms has invalid size!"); + } + List newInput = terms.subList(0, this.input.size()); + List newOutput = terms.subList(this.input.size(), terms.size()); + return new ModuleAtomImpl(this.moduleName, newInput, newOutput, this.instantiationMode); + } + + @Override + public ModuleAtom substitute(Substitution substitution) { + List substitutedInput = this.input.stream().map(t -> t.substitute(substitution)).collect(Collectors.toList()); + List substitutedOutput = this.output.stream().map(t -> t.substitute(substitution)).collect(Collectors.toList()); + return new ModuleAtomImpl(this.moduleName, substitutedInput, substitutedOutput, this.instantiationMode); + } + + @Override + public List getTerms() { + return ListUtils.union(input, output); + } + + @Override + public Predicate getPredicate() { + return Predicates.getPredicate(moduleName, output.size()); + } + + @Override + public boolean isGround() { + for (Term t : input) { + if (!t.isGround()) { + return false; + } + } + for (Term t : output) { + if (!t.isGround()) { + return false; + } + } + return true; + } + + @Override + public ModuleLiteral toLiteral(boolean positive) { + return Literals.fromAtom(this, positive); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ModuleAtomImpl that = (ModuleAtomImpl) o; + return Objects.equals(moduleName, that.moduleName) + && Objects.equals(input, that.input) + && Objects.equals(output, that.output) + && Objects.equals(instantiationMode, that.instantiationMode); + } + + @Override + public int hashCode() { + return Objects.hash(moduleName, input, output, instantiationMode); + } + + @Override + public String toString() { + String result = "#" + moduleName; + if (!input.isEmpty()) { + result += Util.join("[", input, "]"); + } + if (!output.isEmpty()) { + result += Util.join("(", output, ")"); + } + return result; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java index c2d87b3e6..9246fa39e 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ExternalLiteralImpl.java @@ -27,12 +27,6 @@ */ package at.ac.tuwien.kr.alpha.commons.programs.literals; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -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.atoms.ExternalAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.ExternalLiteral; @@ -40,11 +34,13 @@ 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; +import java.util.*; +import java.util.function.Predicate; + /** - * Contains a potentially negated {@link ExternalAtomImpl}. + * Contains a potentially negated {@link ExternalAtom}. */ class ExternalLiteralImpl extends AbstractLiteral implements ExternalLiteral { @@ -67,7 +63,7 @@ public ExternalLiteralImpl negate() { } /** - * @see AbstractAtom#substitute(BasicSubstitution) + * @see Literal#substitute(Substitution) */ @Override public ExternalLiteralImpl substitute(Substitution substitution) { @@ -132,10 +128,13 @@ public List getSatisfyingSubstitutions(Substitution partialSubstit for (Term t : input) { substitutes.add(t.substitute(partialSubstitution)); } - Set>> results = getAtom().getInterpretation().evaluate(substitutes); + Set> results = getAtom().getInterpretation().evaluate(substitutes); if (results == null) { throw new NullPointerException("Predicate " + getPredicate().getName() + " returned null. It must return a Set."); } + if (results.stream().anyMatch(trms -> trms.stream().anyMatch(Predicate.not(Term::isGround)))) { + throw new IllegalStateException("Predicate " + getPredicate().getName() + " returned non-ground term."); + } if (this.isNegated()) { return this.isNegatedLiteralSatisfied(results) ? Collections.singletonList(partialSubstitution) : Collections.emptyList(); @@ -165,10 +164,10 @@ public List getSatisfyingSubstitutions(Substitution partialSubstit * @return true iff no list in externalMethodResult equals the external atom's output term * list as substituted by the grounder, false otherwise */ - private boolean isNegatedLiteralSatisfied(Set>> externalMethodResult) { + private boolean isNegatedLiteralSatisfied(Set> externalMethodResult) { List externalAtomOutTerms = this.getAtom().getOutput(); boolean outputMatches; - for (List> resultTerms : externalMethodResult) { + for (List resultTerms : externalMethodResult) { outputMatches = true; for (int i = 0; i < externalAtomOutTerms.size(); i++) { if (!resultTerms.get(i).equals(externalAtomOutTerms.get(i))) { @@ -187,10 +186,10 @@ private boolean isNegatedLiteralSatisfied(Set>> externalMet return true; } - private List buildSubstitutionsForOutputs(Substitution partialSubstitution, Set>> outputs) { + private List buildSubstitutionsForOutputs(Substitution partialSubstitution, Set> outputs) { List retVal = new ArrayList<>(); List externalAtomOutputTerms = this.getAtom().getOutput(); - for (List> bindings : outputs) { + for (List bindings : outputs) { if (bindings.size() < externalAtomOutputTerms.size()) { throw new RuntimeException( "Predicate " + getPredicate().getName() + " returned " + bindings.size() + " terms when at least " + externalAtomOutputTerms.size() diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/Literals.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/Literals.java index 82b91f24b..afdbe1934 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/Literals.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/Literals.java @@ -1,13 +1,7 @@ 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; -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.AggregateLiteral; -import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; -import at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral; -import at.ac.tuwien.kr.alpha.api.programs.literals.ExternalLiteral; +import at.ac.tuwien.kr.alpha.api.programs.atoms.*; +import at.ac.tuwien.kr.alpha.api.programs.literals.*; public final class Literals { @@ -30,7 +24,11 @@ public static ComparisonLiteral fromAtom(ComparisonAtom atom, boolean positive) public static ExternalLiteral fromAtom(ExternalAtom atom, boolean positive) { return new ExternalLiteralImpl(atom, positive); } - + + public static ModuleLiteral fromAtom(ModuleAtom atom, boolean positive) { + return new ModuleLiteralImpl(atom, positive); + } + public static ComparisonLiteral newComparisonLiteral(ComparisonAtom atom, boolean positive) { return new ComparisonLiteralImpl(atom, positive); } diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ModuleLiteralImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ModuleLiteralImpl.java new file mode 100644 index 000000000..2b30d8640 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/literals/ModuleLiteralImpl.java @@ -0,0 +1,84 @@ +package at.ac.tuwien.kr.alpha.commons.programs.literals; + +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.atoms.ModuleAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.ModuleLiteral; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; +import at.ac.tuwien.kr.alpha.api.programs.terms.VariableTerm; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +class ModuleLiteralImpl extends AbstractLiteral implements ModuleLiteral { + + ModuleLiteralImpl(ModuleAtom atom, boolean positive) { + super(atom, positive); + } + + @Override + public ModuleAtom getAtom() { + return (ModuleAtom) atom; + } + + @Override + public ModuleLiteral negate() { + return new ModuleLiteralImpl(getAtom(), isNegated()); + } + + @Override + public ModuleLiteral substitute(Substitution substitution) { + return new ModuleLiteralImpl(getAtom().substitute(substitution), positive); + } + + // TODO introduce common abstract supertype for external an module literals to avoid code duplication (same goes for atoms!) + @Override + public Set getBindingVariables() { + // If the external atom is negative, then all variables of input and output are non-binding + // and there are no binding variables (like for ordinary atoms). + // If the external atom is positive, then variables of output are binding. + + if (this.isNegated()) { + return Collections.emptySet(); + } + + List output = getAtom().getOutput(); + + Set binding = new HashSet<>(output.size()); + + for (Term out : output) { + if (out instanceof VariableTerm) { + binding.add((VariableTerm) out); + } + } + + return binding; + } + + @Override + public Set getNonBindingVariables() { + List input = getAtom().getInput(); + List output = getAtom().getOutput(); + + // External atoms have their input always non-binding, since they cannot + // be queried without some concrete input. + Set nonbindingVariables = new HashSet<>(); + for (Term term : input) { + nonbindingVariables.addAll(term.getOccurringVariables()); + } + + // If the external atom is negative, then all variables of input and output are + // non-binding. + if (this.isNegated()) { + for (Term out : output) { + if (out instanceof VariableTerm) { + nonbindingVariables.add((VariableTerm) out); + } + } + } + + return nonbindingVariables; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/modules/ModuleImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/modules/ModuleImpl.java new file mode 100644 index 000000000..be4fd2d31 --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/modules/ModuleImpl.java @@ -0,0 +1,43 @@ +package at.ac.tuwien.kr.alpha.commons.programs.modules; + +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.modules.Module; + +import java.util.Set; + +class ModuleImpl implements Module { + + private final String name; + private final Predicate inputSpec; + private final Set outputSpec; + private final InputProgram implementation; + + ModuleImpl(String name, Predicate inputSpec, Set outputSpec, InputProgram implementation) { + this.name = name; + this.inputSpec = inputSpec; + this.outputSpec = outputSpec; + this.implementation = implementation; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public Predicate getInputSpec() { + return this.inputSpec; + } + + @Override + public Set getOutputSpec() { + return this.outputSpec; + } + + @Override + public InputProgram getImplementation() { + return this.implementation; + } + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/modules/Modules.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/modules/Modules.java new file mode 100644 index 000000000..0d8d04e0b --- /dev/null +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/modules/Modules.java @@ -0,0 +1,19 @@ +package at.ac.tuwien.kr.alpha.commons.programs.modules; + +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.modules.Module; + +import java.util.Set; + +public final class Modules { + + private Modules() { + throw new AssertionError("Cannot instantiate utility class!"); + } + + public static Module newModule(final String name, final Predicate inputSpec, final Set outputSpec, final InputProgram implementation) { + return new ModuleImpl(name, inputSpec, outputSpec, implementation); + } + +} 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 index dba92f359..c21c7e0cb 100644 --- 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 @@ -6,8 +6,8 @@ import java.util.function.Supplier; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; 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; @@ -35,6 +35,7 @@ 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. @@ -193,7 +194,7 @@ public Reifier(Supplier>> idGeneratorProvider) { this.idGeneratorProvider = idGeneratorProvider; } - public Set reifyProgram(ASPCore2Program program) { + public Set reifyProgram(InputProgram program) { ReificationContext ctx = new ReificationContext(idGeneratorProvider.get()); reifyDirectives(ctx, program.getInlineDirectives()); for (Atom fact : program.getFacts()) { diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/AbstractRule.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/AbstractRule.java index 9326cad6b..c243d840b 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/AbstractRule.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/AbstractRule.java @@ -1,17 +1,15 @@ package at.ac.tuwien.kr.alpha.commons.programs.rules; -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.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.Collections; +import java.util.LinkedHashSet; +import java.util.Objects; +import java.util.Set; /** * An abstract representation of a rule with a specific type of @{link Head} (type parameter H) @@ -26,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<>(); diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/BasicRule.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/BasicRule.java index e2bd1e178..77aac0ea3 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/BasicRule.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/BasicRule.java @@ -27,18 +27,18 @@ */ package at.ac.tuwien.kr.alpha.commons.programs.rules; -import java.util.List; - import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; 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. */ class BasicRule extends AbstractRule { - BasicRule(Head head, List body) { + BasicRule(Head head, Set body) { super(head, 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 index 828560f6f..acd5ee0d5 100644 --- 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 @@ -1,11 +1,11 @@ package at.ac.tuwien.kr.alpha.commons.programs.rules; -import java.util.List; - 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. @@ -14,8 +14,21 @@ */ class NormalRuleImpl extends AbstractRule implements NormalRule { - NormalRuleImpl(NormalHead head, List body) { + 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 index dc0396863..ddae7bf49 100644 --- 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 @@ -1,44 +1,38 @@ package at.ac.tuwien.kr.alpha.commons.programs.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.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.programs.rules.heads.Heads; 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, List body) { + public static Rule newRule(Head head, Set body) { return new BasicRule(head, body); } public static Rule newRule(Head head, Literal... body) { - List bodyLst = new ArrayList<>(); - for (Literal lit : body) { - bodyLst.add(lit); - } + Set bodyLst = new LinkedHashSet<>(Arrays.asList(body)); return new BasicRule(head, bodyLst); } - public static NormalRule newNormalRule(NormalHead head, List body) { + public static NormalRule newNormalRule(NormalHead head, Set body) { return new NormalRuleImpl(head, body); } public static NormalRule newNormalRule(NormalHead head, Literal... body) { - List bodyLst = new ArrayList<>(); - for (Literal lit : body) { - bodyLst.add(lit); - } + Set bodyLst = new LinkedHashSet<>(Arrays.asList(body)); return new NormalRuleImpl(head, bodyLst); } @@ -48,9 +42,8 @@ public static NormalRule toNormalRule(Rule rule) { 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())); + 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/programs/rules/heads/Heads.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/Heads.java index 6e7aeebf1..d2d271258 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/Heads.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/Heads.java @@ -1,16 +1,18 @@ package at.ac.tuwien.kr.alpha.commons.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.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.NormalHead; 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 { private 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/programs/rules/heads/NormalHeadImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/NormalHeadImpl.java index 7bae74aba..1422d8e75 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/NormalHeadImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/rules/heads/NormalHeadImpl.java @@ -1,6 +1,8 @@ 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.NormalHead; /** @@ -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/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/programs/terms/FunctionTermImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/FunctionTermImpl.java index dd7a2e396..d993a0915 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/FunctionTermImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/FunctionTermImpl.java @@ -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/programs/terms/Terms.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/Terms.java index d38088b6b..5e689ca4e 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/Terms.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/programs/terms/Terms.java @@ -1,17 +1,9 @@ package at.ac.tuwien.kr.alpha.commons.programs.terms; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -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.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.api.programs.terms.*; import at.ac.tuwien.kr.alpha.commons.programs.terms.ArithmeticTermImpl.MinusTerm; import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; @@ -24,6 +16,9 @@ */ public final class Terms { + public static final String LIST_TERM_SYMBOL = "lst"; + public static final ConstantTerm EMPTY_LIST = Terms.newSymbolicConstant("lst_empty"); + /** * Since this is purely a utility class, it may not be instantiated. * @@ -70,6 +65,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<>(); @@ -79,6 +83,20 @@ public static > List> asTermList(T... va return retVal; } + /** + * Constructs a single list term from a list of terms. + */ + public static Term asListTerm(Collection terms) { + List reversedTerms = new ArrayList<>(terms); + Collections.reverse(reversedTerms); + // iterate over the list in reverse order to build the list term from the back. + Term tail = EMPTY_LIST; + for (Term t : reversedTerms) { + tail = Terms.newFunctionTerm(LIST_TERM_SYMBOL, t, tail); + } + return tail; + } + public static List renameTerms(List terms, String prefix, int counterStartingValue) { List renamedTerms = new ArrayList<>(terms.size()); AbstractTerm.RenameCounterImpl renameCounter = new AbstractTerm.RenameCounterImpl(counterStartingValue); 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 index b7f95a5e6..a62753c8e 100644 --- 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 @@ -1,14 +1,14 @@ package at.ac.tuwien.kr.alpha.commons.programs.tests; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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 ASPCore2Program verifier; + private final InputProgram verifier; - AssertionImpl(final Mode mode, final ASPCore2Program verifier) { + AssertionImpl(final Mode mode, final InputProgram verifier) { this.mode = mode; this.verifier = verifier; } @@ -19,7 +19,7 @@ public Mode getMode() { } @Override - public ASPCore2Program getVerifier() { + public InputProgram getVerifier() { return verifier; } 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 index 3962e5684..a750dc7c4 100644 --- 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 @@ -7,7 +7,7 @@ import java.util.function.IntPredicate; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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; @@ -24,7 +24,7 @@ public static TestCase newTestCase(final String name, final IntPredicate answerS return new TestCaseImpl(name, answerSetCountVerifier, input, assertions); } - public static Assertion newAssertion(final Assertion.Mode mode, final ASPCore2Program verifier) { + public static Assertion newAssertion(final Assertion.Mode mode, final InputProgram verifier) { return new AssertionImpl(mode, verifier); } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/externals/AspStandardLibraryTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibraryTest.java similarity index 72% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/externals/AspStandardLibraryTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibraryTest.java index 474ad496c..2569c8f3e 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/externals/AspStandardLibraryTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/externals/AspStandardLibraryTest.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.core.externals; +package at.ac.tuwien.kr.alpha.commons.externals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -6,6 +6,7 @@ import java.util.List; import java.util.Set; +import java.util.function.Function; import org.junit.jupiter.api.Test; @@ -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/programs/atoms/BasicAtomImplTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImplTest.java new file mode 100644 index 000000000..a500b850a --- /dev/null +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/BasicAtomImplTest.java @@ -0,0 +1,64 @@ +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.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}. + * + * Copyright (c) 2019-2021, the Alpha Team. + */ +public class BasicAtomImplTest { + + @Test + public void testIsBasicAtomGround() { + BasicAtomImpl a = new BasicAtomImpl(Predicates.getPredicate("bla", 2), Terms.newSymbolicConstant("blubb"), + Terms.newFunctionTerm("foo", Terms.newSymbolicConstant("bar"))); + assertTrue(a.isGround()); + BasicAtomImpl a1 = new BasicAtomImpl(Predicates.getPredicate("foo", 4), Terms.newConstant(1), Terms.newConstant(2), Terms.newConstant(3), + Terms.newConstant("bar")); + assertTrue(a1.isGround()); + BasicAtomImpl a2 = new BasicAtomImpl(Predicates.getPredicate("foo", 1), Terms.newVariable("BAR")); + assertFalse(a2.isGround()); + BasicAtomImpl a3 = new BasicAtomImpl(Predicates.getPredicate("foo", 3), Terms.newSymbolicConstant("b"), Terms.newSymbolicConstant("a"), + Terms.newFunctionTerm("r", Terms.newConstant("bla"), Terms.newVariable("BLUBB"))); + assertFalse(a3.isGround()); + } + + @Test + public void testAreBasicAtomsEqual() { + BasicAtomImpl a1 = new BasicAtomImpl(Predicates.getPredicate("bla", 2), Terms.newSymbolicConstant("blubb"), + Terms.newFunctionTerm("foo", Terms.newSymbolicConstant("bar"))); + BasicAtomImpl a2 = new BasicAtomImpl(Predicates.getPredicate("bla", 2), Terms.newSymbolicConstant("blubb"), + Terms.newFunctionTerm("foo", Terms.newSymbolicConstant("bar"))); + assertEquals(a1, a2); + + BasicAtomImpl a3 = new BasicAtomImpl(Predicates.getPredicate("foo", 4), Terms.newConstant(1), Terms.newConstant(2), Terms.newConstant(3), + Terms.newConstant("bar")); + BasicAtomImpl a4 = new BasicAtomImpl(Predicates.getPredicate("foo", 4), Terms.newConstant(1), Terms.newConstant(2), Terms.newConstant(3), + Terms.newConstant("bar")); + assertEquals(a3, a4); + + BasicAtomImpl a5 = new BasicAtomImpl(Predicates.getPredicate("foo", 1), Terms.newVariable("BAR")); + BasicAtomImpl a6 = new BasicAtomImpl(Predicates.getPredicate("foo", 1), Terms.newVariable("BAR")); + assertEquals(a5, a6); + + BasicAtomImpl a7 = new BasicAtomImpl(Predicates.getPredicate("foo", 3), Terms.newSymbolicConstant("b"), Terms.newSymbolicConstant("a"), + Terms.newFunctionTerm("r", Terms.newConstant("bla"), Terms.newVariable("BLUBB"))); + BasicAtomImpl a8 = new BasicAtomImpl(Predicates.getPredicate("foo", 3), Terms.newSymbolicConstant("b"), Terms.newSymbolicConstant("a"), + Terms.newFunctionTerm("r", Terms.newConstant("bla"), Terms.newVariable("BLUBB"))); + assertEquals(a7, a8); + + 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/programs/atoms/ExternalAtomImplTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImplTest.java new file mode 100644 index 000000000..9365625f6 --- /dev/null +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ExternalAtomImplTest.java @@ -0,0 +1,95 @@ +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.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.programs.terms.Terms; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; + +public class ExternalAtomImplTest { + + private Map externals; + + public ExternalAtomImplTest() throws NoSuchMethodException, SecurityException { + externals = new HashMap<>(); + externals.put("isFoo", Externals.processPredicateMethod(ExternalAtomImplTest.class.getMethod("isFoo", int.class))); + externals.put("extWithOutput", Externals.processPredicateMethod(ExternalAtomImplTest.class.getMethod("extWithOutput", int.class))); + } + + @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 testIsExternalAtomGround() { + List ext1Input = new ArrayList<>(); + ext1Input.add(Terms.newConstant(1)); + // ext1 := &isFoo[1] + ExternalAtom ext1 = Atoms.newExternalAtom(Predicates.getPredicate("isFoo", 1), externals.get("isFoo"), ext1Input, Collections.emptyList()); + assertTrue(ext1.isGround()); + + // ext2 := &isFoo[bar(1)] + List ext2Input = new ArrayList<>(); + ext2Input.add(Terms.newFunctionTerm("bar", Terms.newConstant(1))); + ExternalAtom ext2 = Atoms.newExternalAtom(Predicates.getPredicate("isFoo", 1), externals.get("isFoo"), ext2Input, Collections.emptyList()); + assertTrue(ext2.isGround()); + + // ext3 := &isFoo[BLA] + List ext3Input = new ArrayList<>(); + ext3Input.add(Terms.newVariable("BLA")); + ExternalAtom ext3 = Atoms.newExternalAtom(Predicates.getPredicate("isFoo", 1), externals.get("isFoo"), ext3Input, Collections.emptyList()); + assertFalse(ext3.isGround()); + } + + @Test + @SuppressWarnings("unlikely-arg-type") + public void testAreExternalAtomsEqual() { + // ext1 := &isFoo[1] + List ext1Input = new ArrayList<>(); + ext1Input.add(Terms.newConstant(1)); + ExternalAtom ext1 = Atoms.newExternalAtom(Predicates.getPredicate("isFoo", 1), externals.get("isFoo"), ext1Input, Collections.emptyList()); + // ext2 := &isFoo[1] + List ext2Input = new ArrayList<>(); + ext2Input.add(Terms.newConstant(1)); + ExternalAtom ext2 = Atoms.newExternalAtom(Predicates.getPredicate("isFoo", 1), externals.get("isFoo"), ext2Input, Collections.emptyList()); + + assertEquals(ext1, ext2); + assertEquals(ext2, ext1); + + assertNotEquals(null, ext1); + assertNotEquals("bla", ext1); + assertEquals(ext1.hashCode(), ext2.hashCode()); + } + + @Test + public void testExternalHasOutput() { + // ext := &extWithOutput[1](OUT) + List input = new ArrayList<>(); + List output = new ArrayList<>(); + input.add(Terms.newConstant(1)); + output.add(Terms.newVariable("OUT")); + ExternalAtom ext = Atoms.newExternalAtom(Predicates.getPredicate("extWithOutput", 2), externals.get("extWithOutput"), input, output); + + assertFalse(ext.isGround()); + assertTrue(ext.hasOutput()); + } + +} diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ModuleAtomImplTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ModuleAtomImplTest.java new file mode 100644 index 000000000..efa2d1353 --- /dev/null +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/atoms/ModuleAtomImplTest.java @@ -0,0 +1,74 @@ +package at.ac.tuwien.kr.alpha.commons.programs.atoms; + +import java.util.List; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.ModuleAtom; +import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class ModuleAtomImplTest { + + @Test + public void withTerms() { + ModuleAtom moduleAtom = new ModuleAtomImpl("someModule", + List.of(Terms.newVariable("X"), Terms.newVariable("Y")), + List.of(Terms.newVariable("Z")), ModuleAtom.ModuleInstantiationMode.ALL); + ModuleAtom newModuleAtom = moduleAtom.withTerms(List.of(Terms.newConstant(1), Terms.newConstant(2), Terms.newConstant(3))); + // Check correct construction of original atom (also check that withTerms didn't modify the original atom) + assertEquals(moduleAtom.getInput().size(), 2); + assertEquals(moduleAtom.getOutput().size(), 1); + assertEquals(moduleAtom.getModuleName(), "someModule"); + assertEquals(moduleAtom.getInstantiationMode(), ModuleAtom.ModuleInstantiationMode.ALL); + // Check terms of new atom + assertEquals(newModuleAtom.getInput().size(), 2); + assertEquals(newModuleAtom.getOutput().size(), 1); + assertEquals(newModuleAtom.getModuleName(), "someModule"); + assertEquals(newModuleAtom.getInstantiationMode(), ModuleAtom.ModuleInstantiationMode.ALL); + assertEquals(List.of(Terms.newConstant(1), Terms.newConstant(2)), newModuleAtom.getInput()); + assertEquals(List.of(Terms.newConstant(3)), newModuleAtom.getOutput()); + } + + @Test + public void withTermsNewTermsTooLong() { + ModuleAtom moduleAtom = new ModuleAtomImpl("someModule", + List.of(Terms.newVariable("X"), Terms.newVariable("Y")), + List.of(Terms.newVariable("Z")), ModuleAtom.ModuleInstantiationMode.ALL); + assertThrows(IllegalArgumentException.class, + () -> moduleAtom.withTerms( + List.of(Terms.newConstant(1), Terms.newConstant(2), + Terms.newConstant(3), Terms.newConstant(4)))); + } + + @Test + public void withTermsNewTermsTooShort() { + ModuleAtom moduleAtom = new ModuleAtomImpl("someModule", + List.of(Terms.newVariable("X"), Terms.newVariable("Y")), + List.of(Terms.newVariable("Z")), ModuleAtom.ModuleInstantiationMode.ALL); + assertThrows(IllegalArgumentException.class, + () -> moduleAtom.withTerms(List.of(Terms.newConstant(1)))); + } + + @Test + public void moduleAtomsEqual() { + ModuleAtom m1 = new ModuleAtomImpl("someModule", + List.of(Terms.newVariable("X"), Terms.newVariable("Y")), + List.of(Terms.newVariable("Z")), ModuleAtom.ModuleInstantiationMode.ALL); + ModuleAtom m2 = new ModuleAtomImpl("someModule", + List.of(Terms.newVariable("X"), Terms.newVariable("Y")), + List.of(Terms.newVariable("Z")), ModuleAtom.ModuleInstantiationMode.ALL); + assertEquals(m1, m2); + assertEquals(m1.hashCode(), m2.hashCode()); + + ModuleAtom m3 = new ModuleAtomImpl("someModule", + List.of(Terms.newVariable("X"), Terms.newVariable("Y")), + List.of(Terms.newVariable("Z")), ModuleAtom.ModuleInstantiationMode.forNumAnswerSets(3)); + ModuleAtom m4 = new ModuleAtomImpl("someModule", + List.of(Terms.newVariable("X"), Terms.newVariable("Y")), + List.of(Terms.newVariable("Z")), ModuleAtom.ModuleInstantiationMode.forNumAnswerSets(3)); + assertNotEquals(m1, m3); + assertEquals(m3, m4); + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/LiteralBindingNonBindingVariablesTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/literals/LiteralBindingNonBindingVariablesTest.java similarity index 52% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/LiteralBindingNonBindingVariablesTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/literals/LiteralBindingNonBindingVariablesTest.java index ae7589fc1..8bd512135 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/LiteralBindingNonBindingVariablesTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/literals/LiteralBindingNonBindingVariablesTest.java @@ -23,30 +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.core.programs.atoms; +package at.ac.tuwien.kr.alpha.commons.programs.literals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -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.common.fixedinterpretations.PredicateInterpretation; -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.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.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.core.common.fixedinterpretations.IntPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.commons.externals.IntPredicateInterpretation; +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()} @@ -55,117 +50,110 @@ */ public class LiteralBindingNonBindingVariablesTest { - private final Map externals = new HashMap<>(); - private final ProgramParser parser = new ProgramParserImpl(); - @Test public void testPositiveBasicLiteral() { - Literal literal = parser.parse("p(X,Y) :- q(X,Y).").getRules().get(0).getBody().stream().findFirst().get(); - assertEquals(false, literal.isNegated()); + // literal := q(X, Y) + Literal literal = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("q", 2), Terms.newVariable("X"), Terms.newVariable("Y")), true); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "X", "Y"); expectVariables(literal.getNonBindingVariables()); } @Test public void testNegativeBasicLiteral() { - Literal literal = parser.parse("p(X,Y) :- q(X,Y), not r(X,Y).").getRules().get(0).getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := not r(X, Y) + Literal literal = Literals.fromAtom(Atoms.newBasicAtom(Predicates.getPredicate("r", 2), Terms.newVariable("X"), Terms.newVariable("Y")), false); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "X", "Y"); } @Test public void testPositiveComparisonLiteral_EQ_LeftAssigning() { - Rule rule = parser.parse("p(X) :- q(X,Y), Y = 5.").getRules().get(0); - Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate() == ComparisonOperators.EQ.toPredicate()).findFirst().get(); - assertEquals(false, literal.isNegated()); + // literal := Y = 5 + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.EQ), true); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @Test public void testNegativeComparisonLiteral_EQ_LeftAssigning() { - Rule rule = parser.parse("p(X) :- q(X,Y), not Y = 5.").getRules().get(0); - Literal literal = rule.getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := not Y = 5 + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.EQ), false); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } @Test public void testPositiveComparisonLiteral_EQ_RightAssigning() { - Rule rule = parser.parse("p(X) :- q(X,Y), 5 = Y.").getRules().get(0); - Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate() == ComparisonOperators.EQ.toPredicate()).findFirst().get(); - assertEquals(false, literal.isNegated()); + // literal := 5 = Y + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.EQ), true); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @Test public void testNegativeComparisonLiteral_EQ_RightAssigning() { - Literal literal = parser.parse("p(X) :- q(X,Y), not 5 = Y.").getRules().get(0).getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := 5 = Y + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.EQ), false); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } - @Test - @Disabled("Literals of this kind are compiled away by VariableEqualityRemoval") - public void testPositiveComparisonLiteral_EQ_Bidirectional() { - Rule rule = parser.parse("p(X) :- q(X,Y), X = Y.").getRules().get(0); - Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate() == ComparisonOperators.EQ.toPredicate()).findFirst().get(); - assertEquals(false, literal.isNegated()); - expectVariables(literal.getBindingVariables()); - expectVariables(literal.getNonBindingVariables(), "X", "Y"); - } - @Test public void testNegativeComparisonLiteral_EQ_Bidirectional() { - Literal literal = parser.parse("p(X) :- q(X,Y), not X = Y.").getRules().get(0).getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := not X = Y + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("X"), Terms.newVariable("Y"), ComparisonOperators.EQ), false); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "X", "Y"); } @Test public void testPositiveComparisonLiteral_NEQ_LeftAssigning() { - Rule rule = parser.parse("p(X) :- q(X,Y), Y != 5.").getRules().get(0); - Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate() == ComparisonOperators.NE.toPredicate()).findFirst().get(); - assertEquals(false, literal.isNegated()); + // literal := Y != 5 + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.NE), true); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } @Test public void testNegativeComparisonLiteral_NEQ_LeftAssigning() { - Literal literal = parser.parse("p(X) :- q(X,Y), not Y != 5.").getRules().get(0).getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := not Y != 5 + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("Y"), Terms.newConstant(5), ComparisonOperators.NE), false); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @Test public void testPositiveComparisonLiteral_NEQ_RightAssigning() { - Rule rule = parser.parse("p(X) :- q(X,Y), 5 != Y.").getRules().get(0); - Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate() == ComparisonOperators.NE.toPredicate()).findFirst().get(); - assertEquals(false, literal.isNegated()); + // literal := 5 != Y + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.NE), true); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "Y"); } @Test public void testNegativeComparisonLiteral_NEQ_RightAssigning() { - Literal literal = parser.parse("p(X) :- q(X,Y), not 5 != Y.").getRules().get(0).getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := not 5 != Y + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newConstant(5), Terms.newVariable("Y"), ComparisonOperators.NE), false); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables(), "Y"); expectVariables(literal.getNonBindingVariables()); } @Test public void testPositiveComparisonLiteral_NEQ_Bidirectional() { - Rule rule = parser.parse("p(X) :- q(X,Y), X != Y.").getRules().get(0); - Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate() == ComparisonOperators.NE.toPredicate()).findFirst().get(); - assertEquals(false, literal.isNegated()); + // literal := X != Y + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("X"), Terms.newVariable("Y"), ComparisonOperators.NE), true); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables()); expectVariables(literal.getNonBindingVariables(), "X", "Y"); } @@ -173,27 +161,35 @@ public void testPositiveComparisonLiteral_NEQ_Bidirectional() { @Test @Disabled("Literals of this kind are compiled away by VariableEqualityRemoval") public void testNegativeComparisonLiteral_NEQ_Bidirectional() { - Literal literal = parser.parse("p(X) :- q(X,Y), not X != Y.").getRules().get(0).getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := not X != Y + Literal literal = Literals.fromAtom(Atoms.newComparisonAtom(Terms.newVariable("X"), Terms.newVariable("Y"), ComparisonOperators.NE), false); + assertTrue(literal.isNegated()); expectVariables(literal.getBindingVariables(), "X", "Y"); expectVariables(literal.getNonBindingVariables()); } @Test public void testPositiveExternalLiteral() { - externals.put("ext", new IntPredicateInterpretation(i -> i > 0)); - Rule rule = parser.parse("p(X) :- q(Y), &ext[Y](X).", externals).getRules().get(0); - Literal literal = rule.getBody().stream().filter((lit) -> lit.getPredicate().getName().equals("ext")).findFirst().get(); - assertEquals(false, literal.isNegated()); + // literal := &ext[Y](X) + List extInput = new ArrayList<>(); + List extOutput = new ArrayList<>(); + 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); + assertFalse(literal.isNegated()); expectVariables(literal.getBindingVariables(), "X"); expectVariables(literal.getNonBindingVariables(), "Y"); } @Test public void testNegativeExternalLiteral() { - externals.put("ext", new IntPredicateInterpretation(i -> i > 0)); - Literal literal = parser.parse("p(X) :- q(Y), not &ext[Y](X).", externals).getRules().get(0).getNegativeBody().stream().findFirst().get(); - assertEquals(true, literal.isNegated()); + // literal := not &ext[Y](X) + List extInput = new ArrayList<>(); + List extOutput = new ArrayList<>(); + 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); + 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/programs/terms/TermsTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermsTest.java index b8612344a..3c3d8aba7 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermsTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/programs/terms/TermsTest.java @@ -4,9 +4,11 @@ import java.util.List; +import at.ac.tuwien.kr.alpha.api.programs.terms.Term; import org.junit.jupiter.api.Test; 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 +32,37 @@ 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()); + } + + @Test + public void asListTermSingleElement() { + List terms = List.of(Terms.newConstant(1)); + Term lstTerm = Terms.asListTerm(terms); + assertEquals(Terms.newFunctionTerm(Terms.LIST_TERM_SYMBOL, Terms.newConstant(1), Terms.EMPTY_LIST), lstTerm); + } + + @Test + public void asListTermEmptyList() { + assertEquals(Terms.asListTerm(List.of()), Terms.EMPTY_LIST); + } + + @Test + public void asListTermMultipleElements() { + List terms = List.of(Terms.newConstant(1), Terms.newConstant(2), Terms.newConstant(3)); + Term lstTerm = Terms.asListTerm(terms); + assertEquals(Terms.newFunctionTerm(Terms.LIST_TERM_SYMBOL, Terms.newConstant(1), + Terms.newFunctionTerm(Terms.LIST_TERM_SYMBOL, Terms.newConstant(2), + Terms.newFunctionTerm(Terms.LIST_TERM_SYMBOL, Terms.newConstant(3), + Terms.EMPTY_LIST))), lstTerm); + } + } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/SimpleAnswerSetFormatterTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/SimpleAnswerSetFormatterTest.java similarity index 85% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/SimpleAnswerSetFormatterTest.java rename to alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/SimpleAnswerSetFormatterTest.java index 0b14388ad..b187bc242 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/common/SimpleAnswerSetFormatterTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/util/SimpleAnswerSetFormatterTest.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.core.common; +package at.ac.tuwien.kr.alpha.commons.util; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -7,7 +7,6 @@ import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.util.AnswerSetFormatter; import at.ac.tuwien.kr.alpha.commons.AnswerSetBuilder; -import at.ac.tuwien.kr.alpha.commons.util.SimpleAnswerSetFormatter; public class SimpleAnswerSetFormatterTest { 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 44039084e..9eca2e92b 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)?; @@ -32,7 +34,13 @@ choice_elements : choice_element (SEMICOLON choice_elements)?; choice_element : classical_literal (COLON naf_literals?)?; -aggregate : NAF? (lt=term lop=binop)? aggregate_function CURLY_OPEN aggregate_elements CURLY_CLOSE (uop=binop ut=term)?; +aggregate : (classic_aggregate | list_aggregate); + +list_aggregate: term EQUAL AGGREGATE_LIST CURLY_OPEN list_comprehension CURLY_CLOSE; + +list_comprehension: term COLON naf_literals; // Note: Term is expected to be a function term or basic_term + +classic_aggregate: NAF? (lt=term lop=binop)? aggregate_function CURLY_OPEN aggregate_elements CURLY_CLOSE (uop=binop ut=term)?; aggregate_elements : aggregate_element (SEMICOLON aggregate_elements)?; @@ -44,7 +52,7 @@ weight_at_level : term (AT term)? (COMMA terms)?; naf_literals : naf_literal (COMMA naf_literals)?; -naf_literal : NAF? (external_atom | classical_literal | builtin_atom); +naf_literal : NAF? (external_atom | module_atom | classical_literal | builtin_atom); id : ID | TEST_EXPECT | TEST_UNSAT | TEST_GIVEN | TEST_ASSERT_ALL | TEST_ASSERT_SOME | DIRECTIVE_ENUM | DIRECTIVE_TEST; @@ -54,6 +62,10 @@ classical_literal : MINUS? basic_atom; builtin_atom : term binop term; +predicate_spec: id '/' NUMBER; + +predicate_specs: predicate_spec (COMMA predicate_specs)?; + binop : EQUAL | UNEQUAL | LESS | GREATER | LESS_OR_EQ | GREATER_OR_EQ; terms : term (COMMA terms)?; @@ -81,13 +93,18 @@ interval_bound : numeral | VARIABLE; external_atom : MINUS? AMPERSAND id (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; // NOT Core2 syntax. -directive : directive_enumeration | directive_test; // NOT Core2 syntax, allows solver specific directives. Further directives shall be added here. +module_atom : SHARP id (CURLY_OPEN NUMBER CURLY_CLOSE)? (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; // NOT Core2 syntax. + +directive : directive_enumeration | directive_test | directive_module; // NOT Core2 syntax, allows solver specific directives. Further directives shall be added here. 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; +// Alpha-specific language extension: Program Modularization (-> https://github.com/madmike200590/evolog-thesis) +directive_module: SHARP DIRECTIVE_MODULE id PAREN_OPEN module_signature PAREN_CLOSE CURLY_OPEN statements CURLY_CLOSE; + basic_terms : basic_term (COMMA basic_terms)? ; basic_term : ground_term | variable_term; @@ -110,3 +127,5 @@ test_assert_all : TEST_ASSERT_ALL CURLY_OPEN statements? CURLY_CLOSE; test_assert_some : TEST_ASSERT_SOME CURLY_OPEN statements? CURLY_CLOSE; +module_signature : predicate_spec ARROW CURLY_OPEN ('*' | predicate_specs) 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 1e5582d82..1825d3607 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 @@ -28,6 +28,7 @@ SQUARE_OPEN : '['; SQUARE_CLOSE : ']'; CURLY_OPEN : '{'; CURLY_CLOSE : '}'; +ARROW : '=>'; EQUAL : '='; UNEQUAL : '<>' | '!='; LESS : '<'; @@ -39,6 +40,7 @@ AGGREGATE_COUNT : '#count'; AGGREGATE_MAX : '#max'; AGGREGATE_MIN : '#min'; AGGREGATE_SUM : '#sum'; +AGGREGATE_LIST : '#list'; DIRECTIVE_ENUM : 'enumeration_predicate_is'; @@ -49,6 +51,8 @@ TEST_GIVEN : 'given'; TEST_ASSERT_ALL : 'assertForAll'; TEST_ASSERT_SOME : 'assertForSome'; +DIRECTIVE_MODULE : 'module'; + ID : ('a'..'z') ( 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' )*; VARIABLE : ('A'..'Z') ( 'A'..'Z' | 'a'..'z' | '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..aac6d0504 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/AbstractActionImplementationProvider.java @@ -0,0 +1,213 @@ +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(); + byte[] data = (str + "\n").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..b1d6f3ada --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionExecutionService.java @@ -0,0 +1,25 @@ +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 { + + /** + * Executes the action with the given name using the provided input terms. + * If the action has been executed before with the same parameters, a cached result is returned. + * The general contract is that an action function is only called once per unique firing ground instance of an action rule + * in order to ensure that, regardless of how often a solver evaluates an action rule, the associated side effect is + * only executed once. + * + * @param actionName the name of the action function to call + * @param sourceRuleId the id of the rule which is fired to cause the action execution + * @param sourceRuleInstance the ground substitution used in firing the source rule + * @param inputTerms the input terms for the action (a subset of substition "sourceRuleInstance") + * @return an ActionWitness wrapping the input to and output of the executed action function. + */ + 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..ec37895ae --- /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 at.ac.tuwien.kr.alpha.api.grounder.Substitution; +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.Term; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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); + ActionResultTerm 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..a20e2eab4 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/actions/ActionWitness.java @@ -0,0 +1,45 @@ +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.ActionResultTerm; +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 ActionResultTerm actionResult; + + public ActionWitness(int ruleId, Substitution groundSubstitution, String actionName, List actionInput, ActionResultTerm 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 ActionResultTerm 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..39a479951 --- /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.CREATE, 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/common/AtomStore.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/AtomStore.java index c02edbd48..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 @@ -116,4 +116,8 @@ default String noGoodToString(T noGood) { } AtomCounter getAtomCounter(); + + static boolean isAtom(int atom) { + return atom >= 0; + } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderFactory.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderFactory.java index 1228c74b5..ad6f80701 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderFactory.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderFactory.java @@ -35,22 +35,22 @@ import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; public final class GrounderFactory { - public static Grounder getInstance(String name, CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { - switch (name.toLowerCase()) { - case "naive": - return new NaiveGrounder(program, atomStore, filter, heuristicsConfiguration, debugInternalChecks, bridges); - } - throw new IllegalArgumentException("Unknown grounder requested."); + + private final GrounderHeuristicsConfiguration heuristicsConfig; + private final boolean enableDebugChecks; + + public GrounderFactory(GrounderHeuristicsConfiguration heuristicsConfig, boolean enabledDebugChecks) { + this.heuristicsConfig = heuristicsConfig; + this.enableDebugChecks = enabledDebugChecks; } - - public static Grounder getInstance(String name, CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks) { - return getInstance(name, program, atomStore, filter, heuristicsConfiguration, debugInternalChecks, new Bridge[] {}); + + public Grounder createGrounder(CompiledProgram program, AtomStore atomStore) { + return createGrounder(program, atomStore, InputConfig.DEFAULT_FILTER); } - public static Grounder getInstance(String name, CompiledProgram program, AtomStore atomStore, boolean debugInternalChecks) { - return getInstance(name, program, atomStore, InputConfig.DEFAULT_FILTER, - new GrounderHeuristicsConfiguration(), debugInternalChecks); + // TODO eliminate this method, filter should never go this deep into core, can be applied on answer sets from top-level + public Grounder createGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter) { + return new NaiveGrounder(program, atomStore, filter, heuristicsConfig, enableDebugChecks, new Bridge[] {}); } + } 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 1c051b8d1..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 @@ -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 2675337ce..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 @@ -108,6 +108,10 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final LiteralInstantiator ruleInstantiator; private final DefaultLazyGroundingInstantiationStrategy instantiationStrategy; + public NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks) { + this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, new Bridge[] {}); + } + public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } 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 68d3839fc..ef9b4d5a4 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 @@ -112,7 +112,7 @@ private LiteralInstantiationResult instantiateFixedInterpretationLiteral(FixedIn } /** - * Calculates a substitution that adds an enumeration index (see {@link EnumerationLiteral#addEnumerationIndexToSubstitution(BasicSubstitution)}) + * Calculates a substitution that adds an enumeration index (see {@link EnumerationLiteral#addEnumerationIndexToSubstitution(Substitution)}) * to the given partial substitution. Due to the special nature of enumeration literals, this method will always return * {@link LiteralInstantiationResult.Type#CONTINUE} as its result type. This method assumes that the partial substitution has * not been applied to the passed literal. 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 b9e2cc758..0fc248b81 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 @@ -30,8 +30,8 @@ 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.ASPCore2Program; 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.*; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; @@ -47,9 +47,10 @@ 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.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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.modules.Modules; 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; @@ -58,6 +59,7 @@ import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.tree.TerminalNode; +import org.apache.commons.lang3.tuple.ImmutablePair; import java.util.*; import java.util.function.IntPredicate; @@ -69,15 +71,15 @@ public class ParseTreeVisitor extends ASPCore2BaseVisitor { private final Map externals; private final boolean acceptVariables; - private InlineDirectives inlineDirectives; + //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 ASPCore2ProgramBuilder currentLevelProgramBuilder; - private Stack programBuilders = new Stack<>(); + private InputProgramBuilder currentLevelProgramBuilder; + private Stack programBuilders = new Stack<>(); public ParseTreeVisitor(Map externals) { this(externals, true); @@ -95,7 +97,7 @@ private UnsupportedOperationException notSupported(RuleContext ctx) { /** * Translates a program context (referring to a node in an ATN specific to ANTLR) to the internal representation of Alpha. */ - public ASPCore2Program translate(ASPCore2Parser.ProgramContext input) { + public InputProgram translate(ASPCore2Parser.ProgramContext input) { return visitProgram(input); } @@ -145,7 +147,7 @@ public String visitTerminal(TerminalNode node) { } @Override - public ASPCore2Program visitProgram(ASPCore2Parser.ProgramContext ctx) { + public InputProgram visitProgram(ASPCore2Parser.ProgramContext ctx) { // program : statements? query?; if (ctx.query() != null) { throw notSupported(ctx.query()); @@ -154,10 +156,11 @@ public ASPCore2Program visitProgram(ASPCore2Parser.ProgramContext ctx) { if (ctx.statements() == null) { return Programs.emptyProgram(); } - inlineDirectives = Programs.newInlineDirectives(); + + //inlineDirectives = Programs.newInlineDirectives(); currentLevelProgramBuilder = Programs.builder(); visitStatements(ctx.statements()); - currentLevelProgramBuilder.addInlineDirectives(inlineDirectives); + //currentLevelProgramBuilder.addInlineDirectives(inlineDirectives); return currentLevelProgramBuilder.build(); } @@ -178,7 +181,7 @@ public Object visitStatement_fact(ASPCore2Parser.Statement_factContext ctx) { currentLevelProgramBuilder.addFact(((NormalHead) head).getAtom()); } else { // Treat facts with choice or disjunction in the head like a rule. - currentLevelProgramBuilder.addRule(Rules.newRule(head, Collections.emptyList())); + currentLevelProgramBuilder.addRule(Rules.newRule(head, Collections.emptySet())); } return null; } @@ -222,11 +225,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 @@ -247,6 +254,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)?; @@ -287,12 +303,17 @@ public List visitNaf_literals(ASPCore2Parser.Naf_literalsContext ctx) { @Override public Object visitDirective_enumeration(ASPCore2Parser.Directive_enumerationContext ctx) { // directive_enumeration : DIRECTIVE_ENUM id DOT; - inlineDirectives.addDirective(InlineDirectives.DIRECTIVE.enum_predicate_is, visitId(ctx.id())); + InlineDirectives directives = Programs.newInlineDirectives(); + directives.addDirective(InlineDirectives.DIRECTIVE.enum_predicate_is, visitId(ctx.id())); + currentLevelProgramBuilder.addInlineDirectives(directives); return null; } @Override public Object visitDirective_test(ASPCore2Parser.Directive_testContext ctx) { + if (!programBuilders.empty()) { + throw new IllegalStateException("Test directives are not allowed in nested programs!"); + } // 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()); @@ -311,14 +332,52 @@ public Object visitDirective_test(ASPCore2Parser.Directive_testContext ctx) { return null; } + public Object visitDirective_module(ASPCore2Parser.Directive_moduleContext ctx) { + if (!programBuilders.empty()) { + throw new IllegalStateException("Module directives are not allowed in nested programs!"); + } + // directive_module: SHARP DIRECTIVE_MODULE id PAREN_OPEN module_signature PAREN_CLOSE CURLY_OPEN statements CURLY_CLOSE; + String name = visitId(ctx.id()); + ImmutablePair> moduleSignature = visitModule_signature(ctx.module_signature()); + startNestedProgram(); + visitStatements(ctx.statements()); + InputProgram moduleImplementation = endNestedProgram(); + currentLevelProgramBuilder.addModule(Modules.newModule(name, moduleSignature.getLeft(), moduleSignature.getRight(), moduleImplementation)); + return null; + } + + public ImmutablePair> visitModule_signature(ASPCore2Parser.Module_signatureContext ctx) { + Predicate inputPredicate = visitPredicate_spec(ctx.predicate_spec()); + Set outputPredicates = ctx.predicate_specs() != null ? visitPredicate_specs(ctx.predicate_specs()) : Collections.emptySet(); + return ImmutablePair.of(inputPredicate, outputPredicates); + } + + @Override + public Set visitPredicate_specs(ASPCore2Parser.Predicate_specsContext ctx) { + // predicate_specs : predicate_spec (COMMA predicate_specs)?; + Set result = new LinkedHashSet<>(); + result.add(visitPredicate_spec(ctx.predicate_spec())); + if (ctx.predicate_specs() != null) { + result.addAll(visitPredicate_specs(ctx.predicate_specs())); + } + return result; + } + @Override - public List visitBody(ASPCore2Parser.BodyContext ctx) { + public Predicate visitPredicate_spec(ASPCore2Parser.Predicate_specContext ctx) { + String symbol = visitId(ctx.id()); + int arity = Integer.parseInt(ctx.NUMBER().getText()); + return Predicates.getPredicate(symbol, arity); + } + + @Override + public Set visitBody(ASPCore2Parser.BodyContext ctx) { // body : ( naf_literal | aggregate ) (COMMA body)?; if (ctx == null) { - return Collections.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())); @@ -332,7 +391,19 @@ public List visitBody(ASPCore2Parser.BodyContext ctx) { @Override public AggregateLiteral visitAggregate(ASPCore2Parser.AggregateContext ctx) { - // aggregate : NAF? (lt=term lop=binop)? aggregate_function CURLY_OPEN aggregate_elements CURLY_CLOSE (uop=binop ut=term)?; + // aggregate : (classic_aggregate | list_aggregate); + if (ctx.classic_aggregate() != null) { + return visitClassic_aggregate(ctx.classic_aggregate()); + } else if (ctx.list_aggregate() != null) { + return visitList_aggregate(ctx.list_aggregate()); + } else { + throw notSupported(ctx); + } + } + + @Override + public AggregateLiteral visitClassic_aggregate(ASPCore2Parser.Classic_aggregateContext ctx) { + // classic_aggregate: NAF? (lt=term lop=binop)? aggregate_function CURLY_OPEN aggregate_elements CURLY_CLOSE (uop=binop ut=term)?; boolean isPositive = ctx.NAF() == null; Term lt = null; ComparisonOperator lop = null; @@ -351,6 +422,23 @@ public AggregateLiteral visitAggregate(ASPCore2Parser.AggregateContext ctx) { return Atoms.newAggregateAtom(lop, lt, uop, ut, aggregateFunction, aggregateElements).toLiteral(isPositive); } + @Override + public AggregateLiteral visitList_aggregate(ASPCore2Parser.List_aggregateContext ctx) { + // list_aggregate: term EQUAL AGGREGATE_LIST CURLY_OPEN list_comprehension CURLY_CLOSE; + Term listResultTerm = (Term) visit(ctx.term()); + ImmutablePair> listComprehension = visitList_comprehension(ctx.list_comprehension()); + return Atoms.newAggregateAtom(ComparisonOperators.EQ, listResultTerm, AggregateAtom.AggregateFunctionSymbol.LIST, + List.of(Atoms.newAggregateElement(List.of(listComprehension.left), listComprehension.right))).toLiteral(); + } + + @Override + public ImmutablePair> visitList_comprehension(ASPCore2Parser.List_comprehensionContext ctx) { + // list_comprehension: term COLON naf_literals; + Term elementTerm = (Term) visit(ctx.term()); + List elementSelectors = visitNaf_literals(ctx.naf_literals()); + return ImmutablePair.of(elementTerm, elementSelectors); + } + @Override public List visitAggregate_elements(ASPCore2Parser.Aggregate_elementsContext ctx) { // aggregate_elements : aggregate_element (SEMICOLON aggregate_elements)?; @@ -409,7 +497,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()); @@ -473,6 +561,8 @@ public Literal visitNaf_literal(ASPCore2Parser.Naf_literalContext ctx) { return Literals.fromAtom(visitClassical_literal(ctx.classical_literal()), !isCurrentLiteralNegated); } else if (ctx.external_atom() != null) { return Literals.fromAtom(visitExternal_atom(ctx.external_atom()), !isCurrentLiteralNegated); + } else if (ctx.module_atom() != null) { + return Literals.fromAtom(visitModule_atom(ctx.module_atom()), !isCurrentLiteralNegated); } throw notSupported(ctx); } @@ -523,7 +613,7 @@ public ConstantTerm visitTerm_number(ASPCore2Parser.Term_numberContext public Integer visitNumeral(ASPCore2Parser.NumeralContext ctx) { // numeral : MINUS? NUMBER; - int absValue = Integer.valueOf(ctx.NUMBER().getText()); + int absValue = Integer.parseInt(ctx.NUMBER().getText()); return ctx.MINUS() != null ? -1 * absValue : absValue; } @@ -588,6 +678,21 @@ public ExternalAtom visitExternal_atom(ASPCore2Parser.External_atomContext ctx) outputTerms); } + @Override + public ModuleAtom visitModule_atom(ASPCore2Parser.Module_atomContext ctx) { + // module_atom : SHARP id (CURLY_OPEN NUMBER CURLY_CLOSE)? (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; + String moduleName = visitId(ctx.id()); + ModuleAtom.ModuleInstantiationMode instantiationMode; + if (ctx.NUMBER() != null) { + instantiationMode = ModuleAtom.ModuleInstantiationMode.forNumAnswerSets(Integer.parseInt(ctx.NUMBER().getText())); + } else { + instantiationMode = ModuleAtom.ModuleInstantiationMode.ALL; + } + List inputTerms = visitTerms(ctx.input); + List outputTerms = visitTerms(ctx.output); + return Atoms.newModuleAtom(moduleName, instantiationMode, inputTerms, outputTerms); + } + @Override public IntervalTerm visitTerm_interval(ASPCore2Parser.Term_intervalContext ctx) { // interval : lower = interval_bound DOT DOT upper = interval_bound; @@ -648,7 +753,7 @@ public IntPredicate visitTest_satisfiability_condition(ASPCore2Parser.Test_satis return Tests.newIsUnsatCondition(); } else { // binop? NUMBER - int num = Integer.valueOf(ctx.NUMBER().getText()); + int num = Integer.parseInt(ctx.NUMBER().getText()); if (ctx.binop() == null) { return Tests.newAnswerSetCountCondition(ComparisonOperators.EQ, num); } else { @@ -697,14 +802,23 @@ public Assertion visitTestVerifier(Assertion.Mode assertionMode, ASPCore2Parser. return Tests.newAssertion(assertionMode, Programs.emptyProgram()); } List stmts = ctx.statement(); - programBuilders.push(currentLevelProgramBuilder); - currentLevelProgramBuilder = new ASPCore2ProgramBuilder(); + startNestedProgram(); for (ASPCore2Parser.StatementContext stmtCtx : stmts) { visit(stmtCtx); } - ASPCore2Program verifier = currentLevelProgramBuilder.build(); - currentLevelProgramBuilder = programBuilders.pop(); + InputProgram verifier = endNestedProgram(); return Tests.newAssertion(assertionMode, verifier); } + private void startNestedProgram() { + programBuilders.push(currentLevelProgramBuilder); + currentLevelProgramBuilder = new InputProgramBuilder(); + } + + private InputProgram endNestedProgram() { + InputProgram result = currentLevelProgramBuilder.build(); + currentLevelProgramBuilder = programBuilders.pop(); + return result; + } + } 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 cc63f903d..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,13 +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.ASPCore2Program; 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.ASPCore2ProgramBuilder; -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.externals.Externals; +import at.ac.tuwien.kr.alpha.commons.programs.Programs.InputProgramBuilder; +import at.ac.tuwien.kr.alpha.commons.externals.Externals; public class ProgramParserImpl implements ProgramParser { @@ -37,14 +38,20 @@ 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 ASPCore2Program parse(String s) { + public InputProgram parse(String s) { return parse(s, Collections.emptyMap()); } @Override - public ASPCore2Program parse(String s, Map externals) { + public InputProgram parse(String s, Map externals) { try { return parse(CharStreams.fromString(s), externals); } catch (RecognitionException | ParseCancellationException e) { @@ -55,11 +62,11 @@ public ASPCore2Program parse(String s, Map exte } } - public ASPCore2Program parse(CharStream stream) { + public InputProgram parse(CharStream stream) { return parse(stream, Collections.emptyMap()); } - public ASPCore2Program parse(CharStream stream, Map externals) { + public InputProgram parse(CharStream stream, Map externals) { //@formatter:off /* * // In order to require less memory: use unbuffered streams and avoid constructing a full parse tree. @@ -132,18 +139,18 @@ public ASPCore2Program parse(CharStream stream, Map externalPredicateDefinitions) throws IOException { + public InputProgram parse(InputStream programSource, Map externalPredicateDefinitions) throws IOException { return parse(CharStreams.fromStream(programSource), externalPredicateDefinitions); } @Override - public ASPCore2Program parse(Path programPath, Map externalPredicateDefinitions) throws IOException { + public InputProgram parse(Path programPath, Map externalPredicateDefinitions) throws IOException { return parse(CharStreams.fromPath(programPath), externalPredicateDefinitions); } @Override - public ASPCore2Program parse(Map externalPredicateDefinitions, Path... programSources) throws IOException { - ASPCore2ProgramBuilder bld = Programs.builder(); + public InputProgram parse(Map externalPredicateDefinitions, Path... programSources) throws IOException { + InputProgramBuilder bld = Programs.builder(); for (Path src : programSources) { bld.accumulate(parse(src, externalPredicateDefinitions)); } @@ -151,8 +158,8 @@ public ASPCore2Program parse(Map externalPredic } @Override - public ASPCore2Program parse(Iterable programSources, Map externalPredicateDefinitions) throws IOException { - ASPCore2ProgramBuilder bld = Programs.builder(); + public InputProgram parse(Iterable programSources, Map externalPredicateDefinitions) throws IOException { + 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 f34a8eee8..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 @@ -43,9 +43,10 @@ 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/InternalProgram.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/InternalProgram.java index 43e69b984..ea79c1ec6 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 @@ -104,9 +104,9 @@ public Map getRulesById() { public NormalProgram toNormalProgram() { List normalRules = new ArrayList<>(); for (CompiledRule rule : getRules()) { - normalRules.add(Rules.newNormalRule(rule.getHead(), new ArrayList<>(rule.getBody()))); + normalRules.add(Rules.newNormalRule(rule.getHead(), new LinkedHashSet<>(rule.getBody()))); } - return Programs.newNormalProgram(normalRules, getFacts(), getInlineDirectives()); + return Programs.newNormalProgram(normalRules, getFacts(), getInlineDirectives(), Collections.emptyList()); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationAtom.java index 97b9865fc..0eb7a0cab 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationAtom.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/atoms/EnumerationAtom.java @@ -167,5 +167,10 @@ public boolean equals(Object o) { public int hashCode() { return 31 * ENUMERATION_PREDICATE.hashCode() + getTerms().hashCode(); } - + + @Override + public String toString() { + return String.format("%s(%s,%s,%s)", ENUMERATION_PREDICATE.getName(), enumIdTerm, valueTerm, indexTerm); + } + } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/CompiledRule.java index c31ad509c..633a4c5c8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/CompiledRule.java @@ -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/programs/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/InternalRule.java index 2a485d31f..c6bbf7239 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/rules/InternalRule.java @@ -43,7 +43,9 @@ 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. @@ -67,7 +69,7 @@ public class InternalRule extends AbstractRule implements CompiledRu * @param head the head of the rule. * @param body the list of body literals of the rule. */ - public InternalRule(NormalHead head, List body) { + public InternalRule(NormalHead head, Set body) { super(head, body); if (body.isEmpty()) { throw new IllegalArgumentException( @@ -101,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()); @@ -125,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); } @@ -151,7 +156,6 @@ public int getRuleId() { return this.ruleId; } - @Override public boolean isGround() { if (!isConstraint() && !getHead().isGround()) { return false; @@ -180,4 +184,6 @@ public boolean equals(Object o) { 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 b556c642a..82e4e1b68 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,7 +1,9 @@ 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; @@ -22,6 +24,7 @@ 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; /** @@ -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,24 +59,25 @@ public NormalProgram apply(NormalProgram inputProgram) { return inputProgram; } // Create new program with rewritten rules. - return Programs.newNormalProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return Programs.newNormalProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives(), inputProgram.getModules()); } /** * 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. + * {@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(); @@ -89,11 +97,11 @@ private NormalRule rewriteRule(NormalRule inputProgramRule) { /** * Checks whether a normal rule contains an {@link ArithmeticTerm} outside of a - * {@link at.ac.tuwien.kr.alpha.common.atoms.ComparisonLiteral}. + * {@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}. + * {@link at.ac.tuwien.kr.alpha.api.programs.literals.ComparisonLiteral}. */ private boolean containsArithmeticTermsToRewrite(NormalRule inputProgramRule) { if (!inputProgramRule.isConstraint()) { @@ -111,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) { @@ -135,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 5783dd2d9..31e41846b 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,11 +27,9 @@ */ 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.ASPCore2Program; +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; @@ -43,7 +41,7 @@ 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.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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; @@ -53,12 +51,12 @@ * Copyright (c) 2017-2021, the Alpha Team. */ // TODO this could already give NormalProgram as result type -public class ChoiceHeadToNormal extends ProgramTransformation { +public class ChoiceHeadToNormal extends ProgramTransformation { private final static String PREDICATE_NEGATION_PREFIX = "_n"; @Override - public ASPCore2Program apply(ASPCore2Program inputProgram) { - ASPCore2ProgramBuilder programBuilder = Programs.builder(); + public InputProgram apply(InputProgram inputProgram) { + InputProgramBuilder programBuilder = Programs.builder(); List> additionalRules = new ArrayList<>(); List> srcRules = new ArrayList<>(inputProgram.getRules()); @@ -104,11 +102,11 @@ public ASPCore2Program apply(ASPCore2Program 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(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(Rules.newRule(Heads.newNormalHead(head), guessingRuleBodyWithHead)); @@ -116,7 +114,7 @@ public ASPCore2Program apply(ASPCore2Program inputProgram) { } } return programBuilder.addRules(srcRules).addRules(additionalRules).addFacts(inputProgram.getFacts()) - .addInlineDirectives(inputProgram.getInlineDirectives()).build(); + .addInlineDirectives(inputProgram.getInlineDirectives()).addModules(inputProgram.getModules()).build(); } private static boolean containsIntervalTerms(Atom atom) { 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 9d20fb69f..a1cee5073 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,12 +1,9 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -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.ASPCore2Program; 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; @@ -18,7 +15,7 @@ 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.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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; @@ -30,10 +27,10 @@ * Copyright (c) 2017-2020, the Alpha Team. */ // TODO this should happen during/after internalization -public class EnumerationRewriting extends ProgramTransformation { +public class EnumerationRewriting extends ProgramTransformation { @Override - public ASPCore2Program apply(ASPCore2Program inputProgram) { + public InputProgram apply(InputProgram inputProgram) { // Read enumeration predicate from directive. String enumDirective = inputProgram.getInlineDirectives().getDirectiveValue(InlineDirectives.DIRECTIVE.enum_predicate_is); if (enumDirective == null) { @@ -42,13 +39,13 @@ public ASPCore2Program apply(ASPCore2Program inputProgram) { } Predicate enumPredicate = Predicates.getPredicate(enumDirective, 3); - ASPCore2ProgramBuilder programBuilder = Programs.builder().addInlineDirectives(inputProgram.getInlineDirectives()); + InputProgramBuilder programBuilder = Programs.builder().addInlineDirectives(inputProgram.getInlineDirectives()); checkFactsAreEnumerationFree(inputProgram.getFacts(), enumPredicate); programBuilder.addFacts(inputProgram.getFacts()); List> srcRules = new ArrayList<>(inputProgram.getRules()); - programBuilder.addRules(rewriteRules(srcRules, enumPredicate)); + programBuilder.addRules(rewriteRules(srcRules, enumPredicate)).addModules(inputProgram.getModules()); return programBuilder.build(); } @@ -69,7 +66,7 @@ private List> rewriteRules(List> srcRules, Predicate enumP if (rule.getHead() != null && ((NormalHead) rule.getHead()).getAtom().getPredicate().equals(enumPredicate)) { 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()) { 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 90d532aff..08d5c94e1 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; @@ -61,14 +58,12 @@ public class IntervalTermToIntervalAtom extends ProgramTransformation intervalReplacements = new LinkedHashMap<>(); - List rewrittenBody = new ArrayList<>(); + Set rewrittenBody = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { Literal rewrittenLiteral = rewriteLiteral(literal, intervalReplacements); @@ -78,6 +73,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()); @@ -182,6 +178,6 @@ public NormalProgram apply(NormalProgram inputProgram) { if (!didChange) { return inputProgram; } - return Programs.newNormalProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return Programs.newNormalProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives(), inputProgram.getModules()); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ModuleLinker.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ModuleLinker.java new file mode 100644 index 000000000..ae13024df --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ModuleLinker.java @@ -0,0 +1,132 @@ +package at.ac.tuwien.kr.alpha.core.programs.transformation; + +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.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.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.ModuleAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.programs.literals.ModuleLiteral; +import at.ac.tuwien.kr.alpha.api.programs.modules.Module; +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.api.programs.terms.Term; +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.terms.Terms; +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.SetUtils; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Program transformation that translates {@link at.ac.tuwien.kr.alpha.api.programs.literals.ModuleLiteral}s into + * {@link at.ac.tuwien.kr.alpha.api.programs.literals.ExternalLiteral}s by constructing {@link at.ac.tuwien.kr.alpha.api.programs.atoms.ExternalAtom}s + * which solve the ASP implementation of the module with the given inputs. + */ +public class ModuleLinker extends ProgramTransformation { + + // Note: References to a standard library of modules that are always available for linking should be member variables of a linker. + private final Alpha moduleRunner; + + public ModuleLinker(Alpha moduleRunner) { + this.moduleRunner = moduleRunner; + } + + + @Override + public NormalProgram apply(NormalProgram inputProgram) { + Map moduleTable = inputProgram.getModules().stream().collect(Collectors.toMap(Module::getName, Function.identity())); + List transformedRules = inputProgram.getRules().stream() + .map(rule -> containsModuleAtom(rule) ? linkModuleAtoms(rule, moduleTable) : rule) + .collect(Collectors.toList()); + return Programs.newNormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives(), Collections.emptyList()); + } + + private NormalRule linkModuleAtoms(NormalRule rule, Map moduleTable) { + Set newBody = rule.getBody().stream() + .map(literal -> { + if (literal instanceof ModuleLiteral) { + ModuleLiteral moduleLiteral = (ModuleLiteral) literal; + return translateModuleAtom(moduleLiteral.getAtom(), moduleTable).toLiteral(!moduleLiteral.isNegated()); + } else { + return literal; + } + }) + .collect(Collectors.toSet()); + return Rules.newNormalRule(rule.getHead(), newBody); + } + + private ExternalAtom translateModuleAtom(ModuleAtom atom, Map moduleTable) { + if (!moduleTable.containsKey(atom.getModuleName())) { + throw new IllegalArgumentException("Module " + atom.getModuleName() + " not found in module table."); + } + Module definition = moduleTable.get(atom.getModuleName()); + // verify inputs + Predicate inputSpec = definition.getInputSpec(); + if (atom.getInput().size() != inputSpec.getArity()) { + throw new IllegalArgumentException("Module " + atom.getModuleName() + " expects " + inputSpec.getArity() + " inputs, but " + atom.getInput().size() + " were given."); + } + NormalProgram normalizedImplementation = moduleRunner.normalizeProgram(definition.getImplementation()); + // verify outputs + Set outputSpec = definition.getOutputSpec(); + Set expectedOutputPredicates; + if (outputSpec.isEmpty()) { + expectedOutputPredicates = calculateOutputPredicates(normalizedImplementation); + } else { + expectedOutputPredicates = outputSpec; + } + if (atom.getOutput().size() != expectedOutputPredicates.size()) { + throw new IllegalArgumentException("Module " + atom.getModuleName() + " expects " + outputSpec.size() + " outputs, but " + atom.getOutput().size() + " were given."); + } + // create the actual interpretation + PredicateInterpretation interpretation = terms -> { + BasicAtom inputAtom = Atoms.newBasicAtom(inputSpec, terms); + NormalProgram program = Programs.newNormalProgram(normalizedImplementation.getRules(), + ListUtils.union(List.of(inputAtom), normalizedImplementation.getFacts()), normalizedImplementation.getInlineDirectives(), Collections.emptyList()); + java.util.function.Predicate filter = outputSpec.isEmpty() ? p -> true : outputSpec::contains; + Stream answerSets = moduleRunner.solve(program, filter); + if (atom.getInstantiationMode().requestedAnswerSets().isPresent()) { + answerSets = answerSets.limit(atom.getInstantiationMode().requestedAnswerSets().get()); + } + return answerSets.map(as -> answerSetToTerms(as, expectedOutputPredicates)).collect(Collectors.toSet()); + }; + return Atoms.newExternalAtom(atom.getPredicate(), interpretation, atom.getInput(), atom.getOutput()); + } + + private static boolean containsModuleAtom(NormalRule rule) { + return rule.getBody().stream().anyMatch(literal -> literal instanceof ModuleLiteral); + } + + private static Set calculateOutputPredicates(NormalProgram program) { + return SetUtils.union(program.getFacts().stream().map(Atom::getPredicate).collect(Collectors.toSet()), + program.getRules().stream() + .filter(java.util.function.Predicate.not(Rule::isConstraint)) + .map(Rule::getHead).map(NormalHead::getAtom).map(Atom::getPredicate) + .collect(Collectors.toSet())); + } + + private static List answerSetToTerms(AnswerSet answerSet, Set moduleOutputSpec) { + List terms = new ArrayList<>(); + for (Predicate predicate : moduleOutputSpec) { + if (!answerSet.getPredicates().contains(predicate)) { + terms.add(Terms.EMPTY_LIST); + } else { + terms.add(Terms.asListTerm(answerSet.getPredicateInstances(predicate).stream() + .map(Atoms::toFunctionTerm).collect(Collectors.toList()))); + } + } + return terms; + } + + +} 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 f8d3303f0..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,7 +1,7 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; import at.ac.tuwien.kr.alpha.api.config.AggregateRewritingConfig; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.commons.programs.Programs; import at.ac.tuwien.kr.alpha.core.programs.atoms.EnumerationAtom; @@ -12,7 +12,7 @@ * * Copyright (c) 2019-2021, the Alpha Team. */ -public class NormalizeProgramTransformation extends ProgramTransformation { +public class NormalizeProgramTransformation extends ProgramTransformation { private final AggregateRewritingConfig aggregateRewritingCfg; @@ -21,8 +21,8 @@ public NormalizeProgramTransformation(AggregateRewritingConfig aggregateCfg) { } @Override - public NormalProgram apply(ASPCore2Program inputProgram) { - ASPCore2Program tmpPrg; + public NormalProgram apply(InputProgram inputProgram) { + InputProgram tmpPrg; // Remove variable equalities. tmpPrg = new VariableEqualityRemoval().apply(inputProgram); // Transform choice rules. 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 23b47bc83..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,9 +1,6 @@ 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.ASPCore2Program; +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; @@ -14,11 +11,14 @@ 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.programs.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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; + /** * * Rewrites all predicates of a given Program such that they are internal and hence hidden from answer sets. @@ -27,8 +27,8 @@ */ public class PredicateInternalizer { - public static ASPCore2Program makePrefixedPredicatesInternal(ASPCore2Program program, String prefix) { - ASPCore2ProgramBuilder prgBuilder = Programs.builder(); + public static InputProgram makePrefixedPredicatesInternal(InputProgram program, String prefix) { + InputProgramBuilder prgBuilder = Programs.builder(); for (Atom atom : program.getFacts()) { if (atom.getPredicate().getName().startsWith(prefix)) { prgBuilder.addFact(PredicateInternalizer.makePredicateInternal((BasicAtom) atom)); @@ -56,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) { 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 34fed23dc..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.programs.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.programs.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); @@ -52,10 +63,17 @@ public class StratifiedEvaluation extends ProgramTransformation> modifiedInLastEvaluationRun = new HashMap<>(); - private List additionalFacts = new ArrayList<>(); // The additional facts derived by stratified evaluation. Note that it may contain duplicates. + private Set outputFacts = new HashSet<>(); // The additional facts derived by stratified evaluation. Note that it may contain duplicates. private Set 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 @@ -82,6 +100,9 @@ public InternalProgram apply(AnalyzedProgram inputProgram) { workingMemory.reset(); + // 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)); @@ -91,13 +112,12 @@ public InternalProgram apply(AnalyzedProgram inputProgram) { } // Build the program resulting from evaluating the stratified part. - additionalFacts.addAll(inputProgram.getFacts()); // Add original input facts to newly derived ones. List outputRules = new ArrayList<>(); inputProgram.getRulesById().entrySet().stream().filter((entry) -> !solvedRuleIds.contains(entry.getKey())) .forEach((entry) -> outputRules.add(entry.getValue())); // NOTE: if InternalProgram requires solved rules, they should be added here. - return new InternalProgram(outputRules, additionalFacts); + return new InternalProgram(outputRules, new ArrayList<>(outputFacts)); } private void evaluateComponent(ComponentGraph.SCComponent comp) { @@ -114,9 +134,7 @@ private void evaluateComponent(ComponentGraph.SCComponent comp) { evaluateRules(evaluationInfo.nonRecursiveRules, true); for (IndexedInstanceStorage instanceStorage : workingMemory.modified()) { // Directly record all newly derived instances as additional facts. - for (Instance recentlyAddedInstance : instanceStorage.getRecentlyAddedInstances()) { - additionalFacts.add(Atoms.newBasicAtom(instanceStorage.getPredicate(), recentlyAddedInstance.terms)); - } + recordRecentlyAddedInstances(instanceStorage); instanceStorage.markRecentlyAddedInstancesDone(); } } @@ -134,9 +152,7 @@ private void evaluateComponent(ComponentGraph.SCComponent comp) { // Since we are stratified we never have to backtrack, therefore just collect the added instances. for (IndexedInstanceStorage instanceStorage : workingMemory.modified()) { // Directly record all newly derived instances as additional facts. - for (Instance recentlyAddedInstance : instanceStorage.getRecentlyAddedInstances()) { - additionalFacts.add(Atoms.newBasicAtom(instanceStorage.getPredicate(), recentlyAddedInstance.terms)); - } + recordRecentlyAddedInstances(instanceStorage); modifiedInLastEvaluationRun.putIfAbsent(instanceStorage.getPredicate(), new LinkedHashSet<>()); modifiedInLastEvaluationRun.get(instanceStorage.getPredicate()).addAll(instanceStorage.getRecentlyAddedInstances()); instanceStorage.markRecentlyAddedInstancesDone(); @@ -149,6 +165,12 @@ private void evaluateComponent(ComponentGraph.SCComponent comp) { .forEach((rule) -> solvedRuleIds.add(rule.getRuleId())); } + private void recordRecentlyAddedInstances(IndexedInstanceStorage instanceStorage) { + for (Instance recentlyAddedInstance : instanceStorage.getRecentlyAddedInstances()) { + outputFacts.add(Atoms.newBasicAtom(instanceStorage.getPredicate(), recentlyAddedInstance.terms)); + } + } + private void evaluateRules(Set rules, boolean isInitialRun) { workingMemory.reset(); LOGGER.debug("Starting component evaluation run..."); @@ -225,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). @@ -255,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<>(); @@ -280,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. @@ -297,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()); } @@ -305,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<>(); @@ -348,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 3c84b54a0..9cf70d16b 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,21 +27,14 @@ */ 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.ASPCore2Program; +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.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; @@ -57,15 +50,15 @@ * * Copyright (c) 2017-2021, the Alpha Team. */ -public class VariableEqualityRemoval extends ProgramTransformation { +public class VariableEqualityRemoval extends ProgramTransformation { @Override - public ASPCore2Program apply(ASPCore2Program inputProgram) { + public InputProgram apply(InputProgram inputProgram) { List> rewrittenRules = new ArrayList<>(); for (Rule rule : inputProgram.getRules()) { rewrittenRules.add(findAndReplaceVariableEquality(rule)); } - return Programs.newASPCore2Program(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return Programs.newInputProgram(rewrittenRules, inputProgram.getFacts(), inputProgram.getInlineDirectives(), Collections.emptyList(), inputProgram.getModules()); } 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(); 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 b959269d2..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; @@ -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,7 +83,7 @@ private static List> splitAggregatesInRule(Rule sourceRule) { } // Third, turn computed bodies into rules again. List> rewrittenRules = new ArrayList<>(); - for (List rewrittenBody : rewrittenBodies) { + 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 12e3273b6..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,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 at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; @@ -22,7 +20,7 @@ import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; /** - * Transforms an {@link AspCore2ProgramImpl} 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: @@ -41,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. */ @@ -52,7 +50,7 @@ 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)); } 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 aff59e893..265ca735a 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,14 +1,7 @@ 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.ASPCore2Program; +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; @@ -16,22 +9,23 @@ 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.programs.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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.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. * * Copyright (c) 2020, the Alpha Team. */ -public class AggregateRewriting extends ProgramTransformation { +public class AggregateRewriting extends ProgramTransformation { private final AbstractAggregateEncoder countEqualsEncoder; private final AbstractAggregateEncoder countLessOrEqualEncoder; @@ -39,6 +33,7 @@ public class AggregateRewriting extends ProgramTransformation> outputRules = new ArrayList<>(); for (Rule inputRule : inputProgram.getRules()) { @@ -89,7 +86,7 @@ public ASPCore2Program apply(ASPCore2Program inputProgram) { } // Substitute AggregateLiterals with generated result literals. outputRules.addAll(rewriteRulesWithAggregates(ctx)); - ASPCore2ProgramBuilder resultBuilder = Programs.builder().addRules(outputRules).addFacts(inputProgram.getFacts()) + InputProgramBuilder resultBuilder = Programs.builder().addRules(outputRules).addFacts(inputProgram.getFacts()).addModules(inputProgram.getModules()) .addInlineDirectives(inputProgram.getInlineDirectives()); // Add sub-programs deriving respective aggregate literals. for (Map.Entry, Set> aggToRewrite : ctx.getAggregateFunctionsToRewrite() @@ -123,6 +120,8 @@ private AbstractAggregateEncoder getEncoderForAggregateFunction(AggregateFunctio } else { throw new UnsupportedOperationException("No fitting encoder for aggregate function " + function + "and operator " + operator + "!"); } + case LIST: + return listEncoder; default: throw new UnsupportedOperationException("Unsupported aggregate function/comparison operator: " + function + ", " + operator); } @@ -138,7 +137,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); 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 c7e3f2fc2..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; @@ -28,6 +14,12 @@ 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 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 1433f1665..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,15 +1,5 @@ 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; @@ -18,6 +8,9 @@ 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 4b6c431b1..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,13 +1,7 @@ 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.ASPCore2Program; +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.AggregateElement; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; @@ -19,13 +13,20 @@ 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.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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 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, @@ -49,10 +50,10 @@ protected AbstractAggregateEncoder(AggregateFunctionSymbol aggregateFunctionToEn * Encodes all aggregate literals in the given set of aggregate referenced by the given {@link AggregateInfo}. * * @param aggregatesToEncode the aggregates to encode. - * @return all rules encoding the given aggregates as an {@link AspCore2ProgramImpl}. + * @return all rules encoding the given aggregates as an {@link InputProgram}. */ - public ASPCore2Program encodeAggregateLiterals(Set aggregatesToEncode) { - ASPCore2ProgramBuilder programBuilder = Programs.builder(); + public InputProgram encodeAggregateLiterals(Set aggregatesToEncode) { + InputProgramBuilder programBuilder = Programs.builder(); for (AggregateInfo aggregateInfo : aggregatesToEncode) { programBuilder.accumulate(encodeAggregateLiteral(aggregateInfo)); } @@ -65,7 +66,7 @@ public ASPCore2Program encodeAggregateLiterals(Set aggregatesToEn * @param aggregateToEncode * @return */ - public ASPCore2Program encodeAggregateLiteral(AggregateInfo aggregateToEncode) { + public InputProgram encodeAggregateLiteral(AggregateInfo aggregateToEncode) { AggregateLiteral literalToEncode = aggregateToEncode.getLiteral(); if (literalToEncode.getAtom().getAggregateFunction() != this.aggregateFunctionToEncode) { throw new IllegalArgumentException( @@ -76,13 +77,13 @@ public ASPCore2Program encodeAggregateLiteral(AggregateInfo aggregateToEncode) { + literalToEncode.getAtom().getAggregateFunction() + " with operator " + literalToEncode.getAtom().getLowerBoundOperator()); } String aggregateId = aggregateToEncode.getId(); - ASPCore2Program literalEncoding = PredicateInternalizer.makePrefixedPredicatesInternal(encodeAggregateResult(aggregateToEncode), aggregateId); + InputProgram literalEncoding = PredicateInternalizer.makePrefixedPredicatesInternal(encodeAggregateResult(aggregateToEncode), aggregateId); List> elementEncodingRules = new ArrayList<>(); for (AggregateElement elementToEncode : literalToEncode.getAtom().getAggregateElements()) { Rule elementRule = encodeAggregateElement(aggregateToEncode, elementToEncode); elementEncodingRules.add(PredicateInternalizer.makePrefixedPredicatesInternal(elementRule, aggregateId)); } - return Programs.newASPCore2Program(ListUtils.union(literalEncoding.getRules(), elementEncodingRules), literalEncoding.getFacts(), Programs.newInlineDirectives()); + return Programs.newInputProgram(ListUtils.union(literalEncoding.getRules(), elementEncodingRules), literalEncoding.getFacts(), Programs.newInlineDirectives()); } /** @@ -93,7 +94,7 @@ public ASPCore2Program encodeAggregateLiteral(AggregateInfo aggregateToEncode) { * @param aggregateToEncode * @return */ - protected abstract ASPCore2Program encodeAggregateResult(AggregateInfo aggregateToEncode); + protected abstract InputProgram encodeAggregateResult(AggregateInfo aggregateToEncode); /** * Encodes individual aggregate elements. For each aggregate element, a rule is created that fires for each tuple matching the element. @@ -105,7 +106,7 @@ public ASPCore2Program encodeAggregateLiteral(AggregateInfo aggregateToEncode) { protected Rule encodeAggregateElement(AggregateInfo aggregateInfo, AggregateElement element) { BasicAtom headAtom = buildElementRuleHead(aggregateInfo.getId(), element, aggregateInfo.getAggregateArguments()); return Rules.newRule(Heads.newNormalHead(headAtom), - ListUtils.union(element.getElementLiterals(), new ArrayList<>(aggregateInfo.getDependencies()))); + 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/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..61ca3c0b1 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/AggregateEncoders.java @@ -0,0 +1,40 @@ +package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; + +import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom.AggregateFunctionSymbol; +import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; + +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); + } + + public static AbstractAggregateEncoder newListEncoder() { + return new ListEncoder(new ProgramParserImpl()); + } + +} 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 0789c0330..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,12 +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.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 { @@ -16,16 +15,16 @@ public final class CountEncoder extends StringtemplateBasedAggregateEncoder { private static final ST CNT_LE_SORTING_GRID_TEMPLATE = AGGREGATE_ENCODINGS.getInstanceOf("cnt_le_sorting_grid"); 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(ComparisonOperator acceptedOperator, ST encodingTemplate) { super(AggregateFunctionSymbol.COUNT, acceptedOperator, encodingTemplate); } - public static CountEncoder buildCountLessOrEqualEncoder(boolean useSortingGrid) { + static CountEncoder buildCountLessOrEqualEncoder(boolean useSortingGrid) { return new CountEncoder(ComparisonOperators.LE, useSortingGrid ? CNT_LE_SORTING_GRID_TEMPLATE : CNT_LE_COUNTING_GRID_TEMPLATE); } - public static CountEncoder buildCountEqualsEncoder() { + 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/ListEncoder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/ListEncoder.java new file mode 100644 index 000000000..10c3b8fcd --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/encoders/ListEncoder.java @@ -0,0 +1,61 @@ +package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.encoders; + +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.ProgramParser; +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.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.util.Util; +import at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates.AggregateRewritingContext; +import org.stringtemplate.v4.ST; + +import java.util.Set; + +public class ListEncoder extends AbstractAggregateEncoder { + + private static final ST LIST_AGGREGATION = Util.aspStringTemplate( + // First, establish ordering of elements (which we need to establish the order within the list) + "$id$_element_greater(ARGS, N, K) :- $id$_element(ARGS, N), $id$_element(ARGS, K), N > K. " + + "$id$_element_not_successor(ARGS, N, K) :- $id$_element_greater(ARGS, N, I), $id$_element_greater(ARGS, I, K). " + + "$id$_element_successor(ARGS, N, K) :- $id$_element_greater(ARGS, N, K), not $id$_element_not_successor(ARGS, N, K). " + + "$id$_element_has_successor(ARGS, N) :- $id$_element_successor(ARGS, _, N). " + + // Now build the list as a recursively nested function term + "$id$_lst_element(ARGS, IDX, lst(N, lst_empty)) :- $id$_element(ARGS, N), not $id$_element_has_successor(ARGS, N), IDX = 0. " + + "$id$_lst_element(ARGS, IDX, lst(N, lst(K, TAIL))) :- $id$_element(ARGS, N), $id$_element_successor(ARGS, K, N), $id$_lst_element(ARGS, PREV_IDX, lst(K, TAIL)), IDX = PREV_IDX + 1. " + + "$id$_has_next_element(ARGS, IDX) :- $id$_lst_element(ARGS, IDX, _), NEXT_IDX = IDX + 1, $id$_lst_element(ARGS, NEXT_IDX, _). " + + "$aggregate_result$(ARGS, LIST) :- $id$_lst_element(ARGS, IDX, LIST), not $id$_has_next_element(ARGS, IDX)."); + + private final ProgramParser parser; + + protected ListEncoder(ProgramParser parser) { + super(AggregateAtom.AggregateFunctionSymbol.LIST, Set.of(ComparisonOperators.EQ)); + this.parser = parser; + } + + @Override + protected InputProgram encodeAggregateResult(AggregateRewritingContext.AggregateInfo aggregateToEncode) { + ST encodingTemplate = new ST(LIST_AGGREGATION); + encodingTemplate.add("id", aggregateToEncode.getId()); + encodingTemplate.add("aggregate_result", aggregateToEncode.getOutputAtom().getPredicate().getName()); + return parser.parse(encodingTemplate.render()); + } + + @Override + protected BasicAtom buildElementRuleHead(String aggregateId, AggregateAtom.AggregateElement element, Term aggregateArguments) { + Predicate headPredicate = Predicates.getPredicate(this.getElementTuplePredicateSymbol(aggregateId), 2); + if (element.getElementTerms().size() != 1) { + throw new IllegalArgumentException("List elements may only consist of one term."); + } + Term value = element.getElementTerms().get(0); + return Atoms.newBasicAtom(headPredicate, aggregateArguments, value); + } + + @Override + protected String getElementTuplePredicateSymbol(String aggregateId) { + return aggregateId + "_element"; + } +} 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 179014554..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,13 +1,7 @@ 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.ASPCore2Program; +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.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.AggregateAtom; @@ -24,7 +18,7 @@ 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.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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; @@ -33,6 +27,11 @@ 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.transformation.aggregates.AggregateRewritingContext.AggregateInfo; +import org.apache.commons.collections4.SetUtils; +import org.stringtemplate.v4.ST; + +import java.util.LinkedHashSet; +import java.util.Set; public class MinMaxEncoder extends AbstractAggregateEncoder { @@ -72,7 +71,7 @@ public MinMaxEncoder(AggregateFunctionSymbol func) { } @Override - protected ASPCore2Program encodeAggregateResult(AggregateInfo aggregateToEncode) { + protected InputProgram encodeAggregateResult(AggregateInfo aggregateToEncode) { ST encodingTemplate = null; if (this.getAggregateFunctionToEncode() == AggregateFunctionSymbol.MAX) { encodingTemplate = new ST(MAX_LITERAL_ENCODING); @@ -112,7 +111,7 @@ protected ASPCore2Program 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( @@ -121,7 +120,7 @@ protected ASPCore2Program encodeAggregateResult(AggregateInfo aggregateToEncode) resultRuleBody.add(aggregateResult); resultRuleBody.add(aggregateValueComparison); resultRuleBody.addAll(aggregateToEncode.getDependencies()); - ASPCore2ProgramBuilder bld = Programs.builder(parser.parse(encodingTemplate.render())); + 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 8869c66fe..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,13 +1,7 @@ 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.ASPCore2Program; +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; @@ -23,6 +17,11 @@ 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 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. @@ -53,7 +52,7 @@ protected StringtemplateBasedAggregateEncoder(AggregateFunctionSymbol aggregateF } @Override - protected ASPCore2Program encodeAggregateResult(AggregateInfo aggregateToEncode) { + protected InputProgram encodeAggregateResult(AggregateInfo aggregateToEncode) { String aggregateId = aggregateToEncode.getId(); /* @@ -81,10 +80,10 @@ protected ASPCore2Program encodeAggregateResult(AggregateInfo aggregateToEncode) String coreEncodingAsp = coreEncodingTemplate.render(); // Create the basic program - ASPCore2Program coreEncoding = new EnumerationRewriting().apply(parser.parse(coreEncodingAsp)); + InputProgram coreEncoding = new EnumerationRewriting().apply(parser.parse(coreEncodingAsp)); // Add the programatically created bound rule and return - return Programs.newASPCore2Program(ListUtils.union(coreEncoding.getRules(), Collections.singletonList(boundRule)), coreEncoding.getFacts(), + return Programs.newInputProgram(ListUtils.union(coreEncoding.getRules(), Collections.singletonList(boundRule)), coreEncoding.getFacts(), Programs.newInlineDirectives()); } @@ -95,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 Rules.newRule(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 Rules.newRule(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 3995d6c27..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,20 +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.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.programs.terms.FunctionTerm; import at.ac.tuwien.kr.alpha.api.programs.terms.Term; -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.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.Util; +import org.stringtemplate.v4.ST; +import org.stringtemplate.v4.STGroup; /** * Aggregate encoder handling sum aggregates. @@ -36,11 +35,11 @@ private SumEncoder(ComparisonOperator acceptedOperator, ST encodingTemplate) { super(AggregateFunctionSymbol.SUM, acceptedOperator, encodingTemplate); } - public static SumEncoder buildSumLessOrEqualEncoder(boolean supportNegativeIntegers) { + static SumEncoder buildSumLessOrEqualEncoder(boolean supportNegativeIntegers) { return new SumEncoder(ComparisonOperators.LE, supportNegativeIntegers ? SUM_LE_TEMPLATE : NON_NEG_ELEMENTS_SUM_LE_TEMPLATE); } - public static SumEncoder buildSumEqualsEncoder(boolean supportNegativeIntegers) { + static SumEncoder buildSumEqualsEncoder(boolean supportNegativeIntegers) { return new SumEncoder(ComparisonOperators.EQ, supportNegativeIntegers ? SUM_EQ_TEMPLATE : NON_NEG_ELEMENTS_SUM_EQ_TEMPLATE); } @@ -56,4 +55,4 @@ protected BasicAtom buildElementRuleHead(String aggregateId, AggregateElement el return Atoms.newBasicAtom(headPredicate, aggregateArguments, elementTuple, element.getElementTerms().get(0)); } -} \ No newline at end of file +} 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/solver/Atoms.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/Atoms.java deleted file mode 100644 index 9ba91dbfa..000000000 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/Atoms.java +++ /dev/null @@ -1,9 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.solver; - -public final class Atoms { - - public static boolean isAtom(int atom) { - return atom >= 0; - } - -} 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 343fe2eab..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 @@ -205,7 +205,7 @@ public Choice backtrack() { return choice; } - void addChoiceInformation(Pair, Map> choiceAtoms, Map> headsToBodies) { + public void addChoiceInformation(Pair, Map> choiceAtoms, Map> headsToBodies) { choicePointInfluenceManager.addInformation(choiceAtoms); addHeadsToBodies(headsToBodies); } 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 ab5642ad8..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 @@ -51,7 +51,6 @@ import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.StatisticsReportingSolver; -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.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; @@ -102,17 +101,17 @@ private static class SearchState { private final PerformanceLog performanceLog; - public DefaultSolver(AtomStore atomStore, Grounder grounder, NoGoodStore store, WritableAssignment assignment, Random random, SystemConfig config, HeuristicsConfiguration heuristicsConfiguration) { + public DefaultSolver(SolverConfig cfg, AtomStore atomStore, Grounder grounder, NoGoodStore store, WritableAssignment assignment) { super(atomStore, grounder); this.assignment = assignment; this.store = store; this.choiceManager = new ChoiceManager(assignment, store); - this.choiceManager.setChecksEnabled(config.isDebugInternalChecks()); + this.choiceManager.setChecksEnabled(cfg.isEnableDebugChecks()); this.learner = new GroundConflictNoGoodLearner(assignment, atomStore); - this.branchingHeuristic = chainFallbackHeuristic(grounder, assignment, random, heuristicsConfiguration); - this.disableJustifications = config.isDisableJustificationSearch(); - this.disableNoGoodDeletion = config.isDisableNoGoodDeletion(); + this.branchingHeuristic = chainFallbackHeuristic(grounder, assignment, new Random(cfg.getRandomSeed()), cfg.getHeuristicsConfiguration()); + this.disableJustifications = cfg.isDisableJustifications(); + this.disableNoGoodDeletion = cfg.isDisableNogoodDeletion(); this.performanceLog = new PerformanceLog(choiceManager, (TrailAssignment) assignment, 1000); } 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 ea86c4e44..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 @@ -38,6 +38,8 @@ 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/SolverConfig.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/SolverConfig.java new file mode 100644 index 000000000..7af9920ea --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/SolverConfig.java @@ -0,0 +1,53 @@ +package at.ac.tuwien.kr.alpha.core.solver; + +import at.ac.tuwien.kr.alpha.core.solver.heuristics.HeuristicsConfiguration; + +public class SolverConfig { + + private boolean enableDebugChecks; + private boolean disableJustifications; + private boolean disableNogoodDeletion; + private HeuristicsConfiguration heuristicsConfiguration; + private long randomSeed; + + public boolean isEnableDebugChecks() { + return this.enableDebugChecks; + } + + public void setEnableDebugChecks(boolean enableDebugChecks) { + this.enableDebugChecks = enableDebugChecks; + } + + public boolean isDisableJustifications() { + return this.disableJustifications; + } + + public void setDisableJustifications(boolean disableJustifications) { + this.disableJustifications = disableJustifications; + } + + public boolean isDisableNogoodDeletion() { + return this.disableNogoodDeletion; + } + + public void setDisableNogoodDeletion(boolean disableNogoodDeletion) { + this.disableNogoodDeletion = disableNogoodDeletion; + } + + public HeuristicsConfiguration getHeuristicsConfiguration() { + return this.heuristicsConfiguration; + } + + public void setHeuristicsConfiguration(HeuristicsConfiguration heuristicsConfiguration) { + this.heuristicsConfiguration = heuristicsConfiguration; + } + + public long getRandomSeed() { + return this.randomSeed; + } + + public void setRandomSeed(long randomSeed) { + this.randomSeed = randomSeed; + } + +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/SolverFactory.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/SolverFactory.java index e6af12d0a..4d3df1154 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/SolverFactory.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/SolverFactory.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016-2017, the Alpha Team. + * Copyright (c) 2016-2021, the Alpha Team. * All rights reserved. * * Additional changes made by Siemens. @@ -28,23 +28,27 @@ package at.ac.tuwien.kr.alpha.core.solver; import at.ac.tuwien.kr.alpha.api.Solver; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.grounder.Grounder; -import at.ac.tuwien.kr.alpha.core.solver.heuristics.HeuristicsConfiguration; -import at.ac.tuwien.kr.alpha.core.solver.heuristics.HeuristicsConfigurationBuilder; - -import java.util.Random; public final class SolverFactory { - - public static Solver getInstance(SystemConfig config, AtomStore atomStore, Grounder grounder) { - final String solverName = config.getSolverName(); - final String nogoodStoreName = config.getNogoodStoreName(); - final Random random = new Random(config.getSeed()); - final boolean debugInternalChecks = config.isDebugInternalChecks(); - final HeuristicsConfiguration heuristicsConfiguration = buildHeuristicsConfiguration(config); - final WritableAssignment assignment = new TrailAssignment(atomStore, debugInternalChecks); + + private final String solverName; + private final String nogoodStoreName; + private final SolverConfig solverConfig; + + public SolverFactory(String solverName, String noGoodStoreName, SolverConfig solverConfig) { + this.solverName = solverName; + this.nogoodStoreName = noGoodStoreName; + this.solverConfig = solverConfig; + } + + public Solver createSolver(Grounder grounder, AtomStore atomStore) { + return SolverFactory.createSolver(solverName, nogoodStoreName, solverConfig, atomStore, grounder); + } + + private static Solver createSolver(String solverName, String nogoodStoreName, SolverConfig solverConfig, AtomStore atomStore, Grounder grounder) { + final WritableAssignment assignment = new TrailAssignment(atomStore, solverConfig.isEnableDebugChecks()); NoGoodStore store; @@ -53,26 +57,19 @@ public static Solver getInstance(SystemConfig config, AtomStore atomStore, Groun store = new NaiveNoGoodStore(assignment); break; case "alpharoaming": - store = new NoGoodStoreAlphaRoaming(assignment, debugInternalChecks); + store = new NoGoodStoreAlphaRoaming(assignment, solverConfig.isEnableDebugChecks()); break; default: throw new IllegalArgumentException("Unknown store requested."); } switch (solverName.toLowerCase()) { - case "naive" : + case "naive": return new NaiveSolver(atomStore, grounder); case "default": - return new DefaultSolver(atomStore, grounder, store, assignment, random, config, heuristicsConfiguration); + return new DefaultSolver(solverConfig, atomStore, grounder, store, assignment); } throw new IllegalArgumentException("Unknown solver requested."); } - private static HeuristicsConfiguration buildHeuristicsConfiguration(SystemConfig config) { - HeuristicsConfigurationBuilder heuristicsConfigurationBuilder = HeuristicsConfiguration.builder(); - heuristicsConfigurationBuilder.setHeuristic(config.getBranchingHeuristic()); - heuristicsConfigurationBuilder.setMomsStrategy(config.getMomsStrategy()); - heuristicsConfigurationBuilder.setReplayChoices(config.getReplayChoices()); - return heuristicsConfigurationBuilder.build(); - } } 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 ed7e4b1fb..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 @@ -45,7 +45,6 @@ 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.Atoms.isAtom; 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; @@ -338,7 +337,7 @@ private boolean assignmentsConsistent(ThriceTruth oldTruth, ThriceTruth value) { } private ConflictCause assignWithTrail(int atom, ThriceTruth value, Antecedent impliedBy) { - if (!isAtom(atom)) { + if (!AtomStore.isAtom(atom)) { throw new IllegalArgumentException("not an atom"); } if (value == null) { diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaRandomSignHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaRandomSignHeuristic.java index 4e2cbc238..e2b539dc4 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaRandomSignHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/AlphaRandomSignHeuristic.java @@ -25,15 +25,14 @@ */ package at.ac.tuwien.kr.alpha.core.solver.heuristics; +import java.util.Random; + 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.solver.ChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; import at.ac.tuwien.kr.alpha.core.solver.heuristics.activity.BodyActivityProviderFactory.BodyActivityType; -import static at.ac.tuwien.kr.alpha.core.solver.Atoms.isAtom; - -import java.util.Random; - public class AlphaRandomSignHeuristic extends DependencyDrivenHeuristic { public AlphaRandomSignHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random) { @@ -51,7 +50,7 @@ protected void incrementSignCounter(Integer literal) { @Override public boolean chooseSign(int atom) { - if (!isAtom(atom)) { + if (!AtomStore.isAtom(atom)) { throw new IllegalArgumentException("Atom must be a positive integer."); } 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 9ced45803..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,25 +25,24 @@ */ package at.ac.tuwien.kr.alpha.core.common; -import static org.junit.jupiter.api.Assertions.assertEquals; - +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.ASPCore2Program; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ProgramTest { - + @Test public void testToString() { - ASPCore2Program parsedProgram = new ProgramParserImpl().parse( + InputProgram parsedProgram = new ProgramParserImpl().parse( "p(a)." + System.lineSeparator() + - "q(X) :- p(X)." + System.lineSeparator() + - "p(b)."); + "q(X) :- p(X)." + System.lineSeparator() + + "p(b)."); assertEquals( "p(a)." + System.lineSeparator() + - "p(b)." + System.lineSeparator() + - "q(X) :- p(X)." + System.lineSeparator(), + "p(b)." + System.lineSeparator() + + "q(X) :- p(X)." + System.lineSeparator(), parsedProgram.toString()); } -} \ No newline at end of file +} 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 349249c17..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 @@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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; @@ -35,11 +35,11 @@ public void renameVariables() { @Test public void testRulesEqual() { - ASPCore2Program p1 = parser.parse("p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X)."); + InputProgram p1 = parser.parse("p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X)."); Rule r1 = p1.getRules().get(0); - ASPCore2Program p2 = parser.parse("p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X)."); + InputProgram p2 = parser.parse("p(X, Y) :- bla(X), blub(Y), foo(X, Y), not bar(X)."); Rule r2 = p2.getRules().get(0); - ASPCore2Program p3 = parser.parse("p(X, Y) :- bla(X), blub(X), foo(X, X), not bar(X)."); + 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)); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/depgraph/DependencyGraphImplTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/depgraph/DependencyGraphImplTest.java deleted file mode 100644 index 65e4f32ae..000000000 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/depgraph/DependencyGraphImplTest.java +++ /dev/null @@ -1,276 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.depgraph; - -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.List; -import java.util.Map; - -import org.junit.jupiter.api.Test; - -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; -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.ProgramParser; -import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; -import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph.Node; -import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.AnalyzedProgram; -import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; -import at.ac.tuwien.kr.alpha.core.test.util.DependencyGraphUtils; - -public class DependencyGraphImplTest { - - private ProgramParser parser = new ProgramParserImpl(); - private NormalizeProgramTransformation normalizeTransform = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); - - // Currently not used anywhere, but keep as it might come in handy - @SuppressWarnings("unused") - private static String generateRandomProgram(int numRules, int numPredicates, int maxRuleBodyLiterals) { - String[] predicates = new String[numPredicates]; - for (int i = 0; i < predicates.length; i++) { - predicates[i] = "p" + Integer.toString(i + 1); - } - - StringBuilder prgBuilder = new StringBuilder(); - String tmpAtom; - int tmpBodyLiterals; - for (int i = 0; i < numRules; i++) { - tmpBodyLiterals = 1 + ((int) (Math.random() * maxRuleBodyLiterals)); - tmpAtom = predicates[(int) (Math.random() * predicates.length)]; - prgBuilder.append(tmpAtom).append(" :- "); - for (int j = 0; j < tmpBodyLiterals; j++) { - tmpAtom = predicates[(int) (Math.random() * predicates.length)]; - prgBuilder.append(tmpAtom); - if (j < (tmpBodyLiterals - 1)) { - prgBuilder.append(", "); - } - } - prgBuilder.append("."); - prgBuilder.append("\n"); - } - return prgBuilder.toString(); - } - - @Test - public void edgesEqualTest() { - Predicate testPredicate = Predicates.getPredicate("test", 2, false, false); - EdgeImpl e1 = new EdgeImpl(new NodeImpl(testPredicate), true); - EdgeImpl e2 = new EdgeImpl(new NodeImpl(testPredicate), true); - assertEquals(e1, e2); - } - - @Test - public void reachabilityCheckSimpleTest() { - ASPCore2Program prog = parser.parse("b :- a."); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - - Node a = dg.getNodeForPredicate(Predicates.getPredicate("a", 0)); - Node b = dg.getNodeForPredicate(Predicates.getPredicate("b", 0)); - - NodeImpl nonExistent = new NodeImpl(Predicates.getPredicate("notHere", 0)); - - assertTrue(DependencyGraphUtils.isReachableFrom(a, a, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(b, a, dg)); - assertFalse(DependencyGraphUtils.isReachableFrom(a, b, dg)); - assertFalse(DependencyGraphUtils.isReachableFrom(nonExistent, a, dg)); - assertFalse(DependencyGraphUtils.isReachableFrom(nonExistent, b, dg)); - } - - @Test - public void reachabilityCheckWithHopsTest() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a.").append("\n"); - bld.append("c :- b.").append("\n"); - bld.append("d :- c.").append("\n"); - - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - Node a = dg.getNodeForPredicate(Predicates.getPredicate("a", 0)); - Node b = dg.getNodeForPredicate(Predicates.getPredicate("b", 0)); - Node c = dg.getNodeForPredicate(Predicates.getPredicate("c", 0)); - Node d = dg.getNodeForPredicate(Predicates.getPredicate("d", 0)); - - assertTrue(DependencyGraphUtils.isReachableFrom(d, a, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(c, a, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(b, a, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(a, a, dg)); - - assertTrue(DependencyGraphUtils.isReachableFrom(d, b, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(c, b, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(b, b, dg)); - - assertTrue(DependencyGraphUtils.isReachableFrom(d, c, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(c, c, dg)); - - assertFalse(DependencyGraphUtils.isReachableFrom(a, d, dg)); - assertFalse(DependencyGraphUtils.isReachableFrom(a, c, dg)); - assertFalse(DependencyGraphUtils.isReachableFrom(a, b, dg)); - } - - @Test - public void reachabilityWithCyclesTest() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a, f1.").append("\n"); - bld.append("c :- b.").append("\n"); - bld.append("d :- c.").append("\n"); - bld.append("a :- d.").append("\n"); - bld.append("x :- d, f1."); - - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - Node a = dg.getNodeForPredicate(Predicates.getPredicate("a", 0)); - Node b = dg.getNodeForPredicate(Predicates.getPredicate("b", 0)); - Node c = dg.getNodeForPredicate(Predicates.getPredicate("c", 0)); - Node d = dg.getNodeForPredicate(Predicates.getPredicate("d", 0)); - Node f1 = dg.getNodeForPredicate(Predicates.getPredicate("f1", 0)); - Node x = dg.getNodeForPredicate(Predicates.getPredicate("x", 0)); - Node notInGraph = new NodeImpl(Predicates.getPredicate("notInGraph", 0)); - - assertTrue(DependencyGraphUtils.isReachableFrom(d, a, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(c, a, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(b, a, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(a, a, dg)); - - assertTrue(DependencyGraphUtils.isReachableFrom(d, b, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(c, b, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(b, b, dg)); - - assertTrue(DependencyGraphUtils.isReachableFrom(d, c, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(c, c, dg)); - - assertTrue(DependencyGraphUtils.isReachableFrom(a, d, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(a, c, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(a, b, dg)); - - assertTrue(DependencyGraphUtils.isReachableFrom(x, f1, dg)); - assertTrue(DependencyGraphUtils.isReachableFrom(c, f1, dg)); - - assertFalse(DependencyGraphUtils.isReachableFrom(notInGraph, a, dg)); - } - - @Test - public void stronglyConnectedComponentsSimpleTest() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a.").append("\n"); - bld.append("a :- b.").append("\n"); - - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - Node a = dg.getNodeForPredicate(Predicates.getPredicate("a", 0)); - Node b = dg.getNodeForPredicate(Predicates.getPredicate("b", 0)); - - List componentA = new ArrayList<>(); - componentA.add(a); - assertTrue(DependencyGraphUtils.areStronglyConnected(componentA, dg)); - assertFalse(DependencyGraphUtils.isStronglyConnectedComponent(componentA, dg)); - - - List componentB = new ArrayList<>(); - componentB.add(b); - assertTrue(DependencyGraphUtils.areStronglyConnected(componentB, dg)); - assertFalse(DependencyGraphUtils.isStronglyConnectedComponent(componentB, dg)); - - List componentAll = new ArrayList<>(); - componentAll.add(a); - componentAll.add(b); - assertTrue(DependencyGraphUtils.areStronglyConnected(componentAll, dg)); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(componentAll, dg)); - } - - @Test - public void stronglyConnectedComponentsMultipleComponentsTest() { - String inputProgram = "f0.\n" + - "f1.\n" + - "f2.\n" + - "f3.\n" + - "a :- f0, f1, not b.\n" + - "b :- f0, f1, not a.\n" + - "c :- f2, f3, not d.\n" + - "d :- f2, f3, not c.\n" + - "x :- a, c, y.\n" + - "y :- b, d, x.\n" + - "z :- x, y, z."; - - ASPCore2Program prog = parser.parse(inputProgram); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - - Node f0 = dg.getNodeForPredicate(Predicates.getPredicate("f0", 0)); - Node f1 = dg.getNodeForPredicate(Predicates.getPredicate("f1", 0)); - Node f2 = dg.getNodeForPredicate(Predicates.getPredicate("f2", 0)); - Node f3 = dg.getNodeForPredicate(Predicates.getPredicate("f3", 0)); - Node a = dg.getNodeForPredicate(Predicates.getPredicate("a", 0)); - Node b = dg.getNodeForPredicate(Predicates.getPredicate("b", 0)); - Node c = dg.getNodeForPredicate(Predicates.getPredicate("c", 0)); - Node d = dg.getNodeForPredicate(Predicates.getPredicate("d", 0)); - Node x = dg.getNodeForPredicate(Predicates.getPredicate("x", 0)); - Node y = dg.getNodeForPredicate(Predicates.getPredicate("y", 0)); - Node z = dg.getNodeForPredicate(Predicates.getPredicate("z", 0)); - - StronglyConnectedComponentsAlgorithm.SccResult sccResult = StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg); - Map nodesByComponent = sccResult.nodesByComponentId; - List> stronglyConnectedComponents = sccResult.stronglyConnectedComponents; - assertEquals(8, stronglyConnectedComponents.size()); - - for (int i = 0; i < stronglyConnectedComponents.size(); i++) { - List stronglyConnectedComponent = stronglyConnectedComponents.get(i); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(stronglyConnectedComponent, dg)); - for (Node node : stronglyConnectedComponent) { - assertEquals(Integer.valueOf(i), nodesByComponent.get(node)); - } - } - - List c1 = new ArrayList<>(); - c1.add(a); - c1.add(b); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c1, dg)); - assertEquals(nodesByComponent.get(a), nodesByComponent.get(b)); - - List c2 = new ArrayList<>(); - c2.add(c); - c2.add(d); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c2, dg)); - assertEquals(nodesByComponent.get(c), nodesByComponent.get(d)); - - List c3 = new ArrayList<>(); - c3.add(x); - c3.add(y); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c3, dg)); - assertEquals(nodesByComponent.get(x), nodesByComponent.get(y)); - - List c4 = new ArrayList<>(); - c4.add(z); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c4, dg)); - - List c5 = new ArrayList<>(); - c5.add(f0); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c5, dg)); - - List c6 = new ArrayList<>(); - c6.add(f1); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c6, dg)); - - List c7 = new ArrayList<>(); - c7.add(f2); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c7, dg)); - - List c8 = new ArrayList<>(); - c8.add(f3); - assertTrue(DependencyGraphUtils.isStronglyConnectedComponent(c8, dg)); - } - -} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/depgraph/StratificationAlgorithmTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/depgraph/StratificationAlgorithmTest.java deleted file mode 100644 index c50acaf9b..000000000 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/depgraph/StratificationAlgorithmTest.java +++ /dev/null @@ -1,241 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.depgraph; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; - -import org.junit.jupiter.api.Test; - -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; -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.ProgramParser; -import at.ac.tuwien.kr.alpha.api.programs.analysis.ComponentGraph; -import at.ac.tuwien.kr.alpha.api.programs.analysis.ComponentGraph.SCComponent; -import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph; -import at.ac.tuwien.kr.alpha.api.programs.analysis.DependencyGraph.Node; -import at.ac.tuwien.kr.alpha.commons.Predicates; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.AnalyzedProgram; -import at.ac.tuwien.kr.alpha.core.programs.transformation.NormalizeProgramTransformation; - -public class StratificationAlgorithmTest { - - private ProgramParser parser = new ProgramParserImpl(); - private NormalizeProgramTransformation normalizeTransform = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); - - private boolean predicateIsBeforePredicateInOrder(Predicate predBefore, Predicate predAfter, List order) { - boolean foundPredBefore = false; - for (SCComponent component : order) { - for (Node node : component.getNodes()) { - if (node.getPredicate() == predBefore) { - foundPredBefore = true; - } - if (node.getPredicate() == predAfter) { - // Found second predicate, return true if we already found the first predicate. - return foundPredBefore; - } - } - } - return false; - } - - @Test - public void stratifyOneRuleTest() { - ASPCore2Program prog = parser.parse("a :- b."); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - ComponentGraph cg = ComponentGraphImpl.buildComponentGraph(dg, StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg)); - List strata = StratificationAlgorithm.calculateStratification(cg); - - Predicate a = Predicates.getPredicate("a", 0); - Predicate b = Predicates.getPredicate("b", 0); - - assertEquals(2, strata.size()); - assertTrue(predicateIsBeforePredicateInOrder(b, a, strata)); - } - - @Test - public void stratifyTwoRulesTest() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a.").append("\n"); - bld.append("c :- b.").append("\n"); - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - ComponentGraph cg = ComponentGraphImpl.buildComponentGraph(dg, StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg)); - List strata = StratificationAlgorithm.calculateStratification(cg); - - Predicate a = Predicates.getPredicate("a", 0); - Predicate b = Predicates.getPredicate("b", 0); - Predicate c = Predicates.getPredicate("c", 0); - - assertEquals(3, strata.size()); - assertTrue(predicateIsBeforePredicateInOrder(a, b, strata)); - assertTrue(predicateIsBeforePredicateInOrder(b, c, strata)); - assertTrue(predicateIsBeforePredicateInOrder(a, c, strata)); - } - - @Test - public void stratifyWithNegativeDependencyTest() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a.").append("\n"); - bld.append("c :- b.").append("\n"); - bld.append("d :- not c.").append("\n"); - bld.append("e :- d.").append("\n"); - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - ComponentGraph cg = ComponentGraphImpl.buildComponentGraph(dg, StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg)); - List strata = StratificationAlgorithm.calculateStratification(cg); - - Predicate a = Predicates.getPredicate("a", 0); - Predicate b = Predicates.getPredicate("b", 0); - Predicate c = Predicates.getPredicate("c", 0); - Predicate d = Predicates.getPredicate("d", 0); - Predicate e = Predicates.getPredicate("e", 0); - - assertEquals(5, strata.size()); - assertTrue(predicateIsBeforePredicateInOrder(a, b, strata)); - assertTrue(predicateIsBeforePredicateInOrder(b, c, strata)); - assertTrue(predicateIsBeforePredicateInOrder(c, d, strata)); - assertTrue(predicateIsBeforePredicateInOrder(d, e, strata)); - } - - @Test - public void stratifyWithPositiveCycleTest() { - StringBuilder bld = new StringBuilder(); - bld.append("ancestor_of(X, Y) :- parent_of(X, Y)."); - bld.append("ancestor_of(X, Z) :- parent_of(X, Y), ancestor_of(Y, Z)."); - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - ComponentGraph cg = ComponentGraphImpl.buildComponentGraph(dg, StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg)); - List strata = StratificationAlgorithm.calculateStratification(cg); - - Predicate ancestorOf = Predicates.getPredicate("ancestor_of", 2); - Predicate parentOf = Predicates.getPredicate("parent_of", 2); - - assertEquals(2, strata.size()); - assertTrue(predicateIsBeforePredicateInOrder(parentOf, ancestorOf, strata)); - } - - @Test - public void stratifyLargeGraphTest() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a."); - bld.append("c :- b."); - bld.append("d :- c."); - bld.append("e :- d."); - bld.append("f :- not e."); - bld.append("g :- d, j, not f."); - bld.append("h :- not c."); - bld.append("i :- h, not j."); - bld.append("j :- h, not i."); - bld.append("k :- g, not l."); - bld.append("l :- g, not k."); - bld.append("m :- not k, not l."); - bld.append("n :- m, not i, not j."); - bld.append("p :- not m, not n."); - - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - ComponentGraph cg = ComponentGraphImpl.buildComponentGraph(dg, StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg)); - List strata = StratificationAlgorithm.calculateStratification(cg); - - Predicate a = Predicates.getPredicate("a", 0); - Predicate b = Predicates.getPredicate("b", 0); - Predicate c = Predicates.getPredicate("c", 0); - Predicate d = Predicates.getPredicate("d", 0); - Predicate e = Predicates.getPredicate("e", 0); - Predicate f = Predicates.getPredicate("f", 0); - Predicate h = Predicates.getPredicate("h", 0); - - assertTrue(predicateIsBeforePredicateInOrder(a, h, strata)); - assertTrue(predicateIsBeforePredicateInOrder(b, h, strata)); - assertTrue(predicateIsBeforePredicateInOrder(c, h, strata)); - - assertTrue(predicateIsBeforePredicateInOrder(a, f, strata)); - assertTrue(predicateIsBeforePredicateInOrder(b, f, strata)); - assertTrue(predicateIsBeforePredicateInOrder(c, f, strata)); - assertTrue(predicateIsBeforePredicateInOrder(d, f, strata)); - assertTrue(predicateIsBeforePredicateInOrder(e, f, strata)); - } - - @Test - public void stratifyAvoidDuplicatesTest() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a."); - bld.append("c :- b."); - bld.append("d :- c."); - bld.append("e :- d."); - bld.append("f :- not e."); - bld.append("g :- d, j, not f."); - bld.append("h :- not c."); - bld.append("i :- h, not j."); - bld.append("j :- h, not i."); - bld.append("k :- g, not l."); - bld.append("l :- g, not k."); - bld.append("m :- not k, not l."); - bld.append("n :- m, not i, not j."); - bld.append("p :- not m, not n."); - - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - ComponentGraph cg = ComponentGraphImpl.buildComponentGraph(dg, StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg)); - List strata = StratificationAlgorithm.calculateStratification(cg); - - Predicate a = Predicates.getPredicate("a", 0); - Predicate b = Predicates.getPredicate("b", 0); - Predicate c = Predicates.getPredicate("c", 0); - Predicate d = Predicates.getPredicate("d", 0); - Predicate e = Predicates.getPredicate("e", 0); - Predicate f = Predicates.getPredicate("f", 0); - Predicate h = Predicates.getPredicate("h", 0); - - assertEquals(7, strata.size()); - assertTrue(predicateIsBeforePredicateInOrder(a, b, strata)); - assertTrue(predicateIsBeforePredicateInOrder(b, c, strata)); - assertTrue(predicateIsBeforePredicateInOrder(c, h, strata)); - assertTrue(predicateIsBeforePredicateInOrder(c, d, strata)); - assertTrue(predicateIsBeforePredicateInOrder(d, e, strata)); - assertTrue(predicateIsBeforePredicateInOrder(e, f, strata)); - assertTrue(predicateIsBeforePredicateInOrder(d, f, strata)); - } - - @Test - public void avoidDuplicatesTest1() { - StringBuilder bld = new StringBuilder(); - bld.append("b :- a."); - bld.append("c :- b."); - bld.append("c :- a."); - - ASPCore2Program prog = parser.parse(bld.toString()); - NormalProgram normalProg = normalizeTransform.apply(prog); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalProg); - DependencyGraph dg = analyzed.getDependencyGraph(); - ComponentGraph cg = ComponentGraphImpl.buildComponentGraph(dg, StronglyConnectedComponentsAlgorithm.findStronglyConnectedComponents(dg)); - List strata = StratificationAlgorithm.calculateStratification(cg); - - Predicate a = Predicates.getPredicate("a", 0); - Predicate b = Predicates.getPredicate("b", 0); - Predicate c = Predicates.getPredicate("c", 0); - - assertTrue(predicateIsBeforePredicateInOrder(a, b, strata)); - assertTrue(predicateIsBeforePredicateInOrder(b, c, strata)); - assertTrue(predicateIsBeforePredicateInOrder(a, c, strata)); - - assertEquals(3, strata.size()); - } - -} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/DummyGrounder.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithBasicProgram.java similarity index 87% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/DummyGrounder.java rename to alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithBasicProgram.java index fe2cb6f8c..a298cb6eb 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/DummyGrounder.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; @@ -51,43 +54,38 @@ 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.rules.Rule; -import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; 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.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.substitutions.BasicSubstitution; 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.programs.atoms.RuleAtom; -import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRules; /** * Represents a small ASP program {@code { c :- a, b. a. b. }}. * * Copyright (c) 2016, the Alpha Team. */ -public class DummyGrounder implements Grounder { +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; @@ -95,15 +93,15 @@ public class DummyGrounder 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 Rule ruleABC = Rules.newRule(Heads.newNormalHead(atomCC), Arrays.asList(atomAA.toLiteral(), atomBB.toLiteral())); - private static Atom rule1 = new RuleAtom(InternalRule.fromNormalRule(Rules.toNormalRule(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 DummyGrounder(AtomStore atomStore) { + public GrounderMockWithBasicProgram(AtomStore atomStore) { this(atomStore, p -> true); } - public DummyGrounder(AtomStore atomStore, java.util.function.Predicate filter) { + public GrounderMockWithBasicProgram(AtomStore atomStore, java.util.function.Predicate filter) { this.atomStore = atomStore; this.filter = filter; Arrays.asList(atomAA, atomBB, rule1, atomCC).forEach(atomStore::putIfAbsent); @@ -172,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(); @@ -191,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/ChoiceGrounder.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithChoice.java similarity index 83% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceGrounder.java rename to alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/GrounderMockWithChoice.java index 530d54944..d2d22c212 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/ChoiceGrounder.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 @@ -32,6 +32,7 @@ import static at.ac.tuwien.kr.alpha.core.common.NoGood.headFirst; import static at.ac.tuwien.kr.alpha.core.common.NoGoodTest.fromOldLiterals; import static java.util.Arrays.asList; +import static java.util.Collections.singleton; import java.util.Arrays; import java.util.Collections; @@ -43,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; @@ -50,34 +54,30 @@ 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.rules.Rule; -import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; 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.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.substitutions.BasicSubstitution; 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.programs.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.core.programs.atoms.RuleAtom; -import at.ac.tuwien.kr.alpha.core.programs.rules.InternalRule; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRules; /** - * Represents a small ASP program with choices {@code { aa :- not bb. bb :- not aa. }}. + * Represents a small ASP program with choices {@code { aa :- not bb. bb :- not aa. }}. */ -public class ChoiceGrounder implements Grounder { +public class GrounderMockWithChoice implements Grounder { public static final Set EXPECTED = new HashSet<>(asList( new AnswerSetBuilder() .predicate("aa") .build(), new AnswerSetBuilder() .predicate("bb") - .build())); + .build() + )); private static final int ATOM_AA = 1; private static final int ATOM_BB = 2; @@ -93,7 +93,7 @@ public class ChoiceGrounder implements Grounder { private static final int BRULE_BB = 14; // { -_br2, -aa } private static final int CHOICE_EN_BR1 = 15; // { -_en_br1 } private static final int CHOICE_EN_BR2 = 16; // { -_en_br2 } - private static final int CHOICE_DIS_BR1 = 17; // { -_dis_br1, bb} + 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))), @@ -103,21 +103,22 @@ public class ChoiceGrounder implements Grounder { 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()); + 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)).collect(entriesToMap()); + 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)).collect(entriesToMap()); + 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 Rule ruleAA = Rules.newRule(Heads.newNormalHead(atomAA), - Collections.singletonList(Atoms.newBasicAtom(Predicates.getPredicate("bb", 0)).toLiteral(false))); - private static Rule ruleBB = Rules.newRule(Heads.newNormalHead(atomBB), - Collections.singletonList(Atoms.newBasicAtom(Predicates.getPredicate("aa", 0)).toLiteral(false))); - private static Atom rule1 = new RuleAtom(InternalRule.fromNormalRule(Rules.toNormalRule(ruleAA)), new BasicSubstitution()); - private static Atom rule2 = new RuleAtom(InternalRule.fromNormalRule(Rules.toNormalRule(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); @@ -127,11 +128,11 @@ public class ChoiceGrounder implements Grounder { private final java.util.function.Predicate filter; - public ChoiceGrounder(AtomStore atomStore) { + public GrounderMockWithChoice(AtomStore atomStore) { this(atomStore, p -> true); } - public ChoiceGrounder(AtomStore atomStore, java.util.function.Predicate filter) { + public GrounderMockWithChoice(AtomStore atomStore, java.util.function.Predicate filter) { this.atomStore = atomStore; this.filter = filter; Arrays.asList(atomAA, atomBB, rule1, rule2, atomEnBR1, atomEnBR2, atomDisBR1, atomDisBR2).forEach(atomStore::putIfAbsent); @@ -155,11 +156,11 @@ public AnswerSet assignmentToAnswerSet(Iterable trueAtoms) { Map> predicateInstances = new HashMap<>(); for (Predicate trueAtomPredicate : trueAtomPredicates) { BasicAtom basicAtom = Atoms.newBasicAtom(trueAtomPredicate); - predicateInstances.put(trueAtomPredicate, new TreeSet<>(Collections.singleton(basicAtom))); + predicateInstances.put(trueAtomPredicate, new TreeSet<>(singleton(basicAtom))); } // Note: This grounder only deals with 0-ary predicates, i.e., every atom is a predicate and there is - // only one predicate instance representing 0 terms. + // only one predicate instance representing 0 terms. return AnswerSets.newAnswerSet(trueAtomPredicates, predicateInstances); } @@ -209,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/NaiveGrounderTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/NaiveGrounderTest.java index 1f1ca1d9b..74ce484f3 100644 --- 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 @@ -25,7 +25,6 @@ */ package at.ac.tuwien.kr.alpha.core.grounder; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.atom; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -36,6 +35,10 @@ 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; @@ -43,7 +46,7 @@ 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.ASPCore2Program; +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; @@ -100,14 +103,14 @@ public void resetRuleIdGenerator() { */ @Test public void groundRuleAlreadyGround() { - ASPCore2Program program = PROGRAM_PARSER.parse("a :- not b. " + InputProgram program = PROGRAM_PARSER.parse("a :- not b. " + "b :- not a. " + "c :- b."); NormalProgram normal = NORMALIZE_TRANSFORM.apply(program); - CompiledProgram prog = new StratifiedEvaluation().apply(AnalyzedProgram.analyzeNormalProgram(normal)); + CompiledProgram prog = new StratifiedEvaluation(null, false).apply(AnalyzedProgram.analyzeNormalProgram(normal)); AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance("naive", prog, atomStore, true); + 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"))); @@ -121,15 +124,15 @@ public void groundRuleAlreadyGround() { */ @Test public void groundRuleWithLongerBodyAlreadyGround() { - ASPCore2Program program = PROGRAM_PARSER.parse("a :- not b. " + 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().apply(AnalyzedProgram.analyzeNormalProgram(normal)); + InternalProgram prog = new StratifiedEvaluation(null, false).apply(AnalyzedProgram.analyzeNormalProgram(normal)); AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance("naive", prog, atomStore, true); + 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); @@ -147,14 +150,14 @@ public void groundRuleWithLongerBodyAlreadyGround() { */ @Test public void groundConstraintAlreadyGround() { - ASPCore2Program program = PROGRAM_PARSER.parse("a :- not b. " + InputProgram program = PROGRAM_PARSER.parse("a :- not b. " + "b :- not a. " + ":- b."); NormalProgram normal = NORMALIZE_TRANSFORM.apply(program); - InternalProgram prog = new StratifiedEvaluation().apply(AnalyzedProgram.analyzeNormalProgram(normal)); + InternalProgram prog = new StratifiedEvaluation(null, false).apply(AnalyzedProgram.analyzeNormalProgram(normal)); AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance("naive", prog, atomStore, true); + 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()))); @@ -189,7 +192,7 @@ public void noDeadEndWithPermissiveGrounderHeuristicForQ1() { } /** - * Tests the method {@link NaiveGrounder#getGroundInstantiations(InternalRule, RuleGroundingOrder, Substitution, Assignment)} on a + * Tests the method {@link NaiveGrounder#getGroundInstantiations)} on a * predefined program: * * p1(1). q1(1).
@@ -218,8 +221,7 @@ private void testDeadEnd(String predicateNameOfStartingLiteral, RuleGroundingOrd PROGRAM_PARSER.parse(aspStr))); AtomStore atomStore = new AtomStoreImpl(); - NaiveGrounder grounder = (NaiveGrounder) GrounderFactory.getInstance("naive", program, atomStore, p -> true, - GrounderHeuristicsConfiguration.permissive(), true); + 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)"; @@ -237,7 +239,7 @@ private void testDeadEnd(String predicateNameOfStartingLiteral, RuleGroundingOrd @Test public void testGroundingOfRuleSwitchedOffByFalsePositiveBody() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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); @@ -245,7 +247,7 @@ public void testGroundingOfRuleSwitchedOffByFalsePositiveBody() { @Test public void testGroundingOfRuleNotSwitchedOffByTruePositiveBody() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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); @@ -254,7 +256,7 @@ public void testGroundingOfRuleNotSwitchedOffByTruePositiveBody() { @Test @Disabled("Currently, rule grounding is not switched off by a true negative body atom") public void testGroundingOfRuleSwitchedOffByTrueNegativeBody() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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); @@ -262,7 +264,7 @@ public void testGroundingOfRuleSwitchedOffByTrueNegativeBody() { @Test public void testGroundingOfRuleNotSwitchedOffByFalseNegativeBody() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + InputProgram program = PROGRAM_PARSER.parse("a(1). " + "c(X) :- a(X), not b(X). " + "b(X) :- something(X). "); @@ -270,21 +272,20 @@ public void testGroundingOfRuleNotSwitchedOffByFalseNegativeBody() { } /** - * Tests if {@link NaiveGrounder#getGroundInstantiations(InternalRule, RuleGroundingOrder, Substitution, Assignment)} + * 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(ASPCore2Program program, int ruleID, Literal startingLiteral, int startingInstance, ThriceTruth bTruth, + 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) GrounderFactory.getInstance("naive", internalPrg, atomStore, p -> true, - GrounderHeuristicsConfiguration.permissive(), true); + NaiveGrounder grounder = (NaiveGrounder) new GrounderFactory(GrounderHeuristicsConfiguration.permissive(), true).createGrounder(internalPrg, atomStore, p -> true); - int b = atomStore.putIfAbsent(atom("b", 1)); + int b = atomStore.putIfAbsent(Atoms.newBasicAtom(Predicates.getPredicate("b", 1), Terms.newConstant(1))); currentAssignment.growForMaxAtomId(); currentAssignment.assign(b, bTruth); @@ -299,7 +300,7 @@ private void testIfGrounderGroundsRule(ASPCore2Program program, int ruleID, Lite @Test public void testPermissiveGrounderHeuristicTolerance_0_reject() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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)); @@ -307,7 +308,7 @@ public void testPermissiveGrounderHeuristicTolerance_0_reject() { @Test public void testPermissiveGrounderHeuristicTolerance_1_accept() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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)); @@ -315,7 +316,7 @@ public void testPermissiveGrounderHeuristicTolerance_1_accept() { @Test public void testPermissiveGrounderHeuristicTolerance_1_reject() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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)); @@ -323,7 +324,7 @@ public void testPermissiveGrounderHeuristicTolerance_1_reject() { @Test public void testPermissiveGrounderHeuristicTolerance_2_accept() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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)); @@ -331,7 +332,7 @@ public void testPermissiveGrounderHeuristicTolerance_2_accept() { @Test public void testPermissiveGrounderHeuristicTolerance_1_accept_two_substitutions() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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, @@ -340,7 +341,7 @@ public void testPermissiveGrounderHeuristicTolerance_1_accept_two_substitutions( @Test public void testPermissiveGrounderHeuristicTolerance_1_accept_accept_two_substitutions_with_different_remaining_tolerances() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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)); @@ -348,7 +349,7 @@ public void testPermissiveGrounderHeuristicTolerance_1_accept_accept_two_substit @Test public void testPermissiveGrounderHeuristicTolerance_2_reject() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). " + 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)); @@ -356,20 +357,20 @@ public void testPermissiveGrounderHeuristicTolerance_2_reject() { @Test public void testPermissiveGrounderHeuristicTolerance_2_accept_multiple_facts_of_same_variable() { - ASPCore2Program program = PROGRAM_PARSER.parse("a(1). b(1). " + 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(ASPCore2Program program, int ruleID, Literal startingLiteral, int startingInstance, int tolerance, + 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(InternalRule, RuleGroundingOrder, Substitution, Assignment)} + * 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: @@ -386,13 +387,13 @@ private void testPermissiveGrounderHeuristicTolerance(ASPCore2Program program, i * 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(ASPCore2Program program, int ruleID, Literal startingLiteral, int startingInstance, int tolerance, + 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) GrounderFactory.getInstance("naive", internalPrg, atomStore, p -> true, heuristicConfiguration, true); + 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++) { @@ -457,4 +458,12 @@ private void assertExistsNoGoodContaining(Collection noGoods, int litera 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 index 501978758..eb0a06392 100644 --- 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 @@ -25,15 +25,10 @@ */ package at.ac.tuwien.kr.alpha.core.grounder; -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.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.ASPCore2Program; +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; @@ -47,8 +42,12 @@ 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 org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests {@link NoGoodGenerator} @@ -66,12 +65,12 @@ public class NoGoodGeneratorTest { private static final VariableTerm Y = Terms.newVariable("Y"); /** - * Calls {@link NoGoodGenerator#collectNegLiterals(InternalRule, Substitution)}, which puts the atom occurring + * 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() { - ASPCore2Program input = PARSER.parse("p(a,b). " + 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); @@ -79,7 +78,7 @@ public void collectNeg_ContainsOnlyPositiveLiterals() { CompiledRule rule = program.getRules().get(1); AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance("naive", program, atomStore, true); + Grounder grounder = new GrounderFactory(new GrounderHeuristicsConfiguration(), true).createGrounder(program, atomStore); NoGoodGenerator noGoodGenerator = ((NaiveGrounder) grounder).noGoodGenerator; Substitution substitution = new BasicSubstitution(); substitution.put(X, A); 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 index efae731d9..a59a958d3 100644 --- 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 @@ -32,7 +32,7 @@ import org.junit.jupiter.api.Test; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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; @@ -78,7 +78,7 @@ public void mergeUnifierIntoLeft() { private BasicAtom parseAtom(String atom) { ProgramParser programParser = new ProgramParserImpl(); - ASPCore2Program program = programParser.parse(atom + "."); + 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/parser/ParserTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/parser/ParserTest.java index 3c4da3aaa..676ce858b 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 @@ -27,41 +27,40 @@ */ package at.ac.tuwien.kr.alpha.core.parser; -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.channels.ReadableByteChannel; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -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; - -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; 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.ModuleAtom; 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.literals.ModuleLiteral; +import at.ac.tuwien.kr.alpha.api.programs.modules.Module; +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.Head; 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.api.programs.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestCase; 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.Util; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.channels.ReadableByteChannel; +import java.util.*; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; /** * Copyright (c) 2016, the Alpha Team. @@ -70,10 +69,10 @@ 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 {}" - + "}"; + + ":- 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. } }"; @@ -87,11 +86,35 @@ public class ParserTest { 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 static final String MODULE_SIMPLE = "#module aSimpleModule(input/1 => {out1/2, out2/3}) { p(a). p(b). q(X) :- p(X). }"; + + private static final String MODULE_OUTPUT_ALL = "#module mod(in/1 => {*}) { a(X). b(X) :- a(X).}"; + + private static final String MODULE_WITH_REGULAR_STMTS = "p(a). p(b). q(X) :- p(X). #module aSimpleModule(input/1 => {out1/2, out2/3}) { p(a). p(b). q(X) :- p(X). }"; + + private static final String MODULE_MULTIPLE_DEFINITIONS = "a. b(5). #module aSimpleModule(input/1 => {out1/2, out2/3}) { p(a). p(b). q(X) :- p(X). } q(Y) :- r(S, Y), t(S). #module anotherModule(input/1 => {out1/2, out2/3}) { p(a). p(b). q(X) :- p(X). }"; + + private static final String MODULE_LITERAL = "p(a). q(b). r(X) :- p(X), q(Y), #mod[X, Y](X)."; + + private static final String MODULE_LITERAL_WITH_NUM_ANSWER_SETS = ":- r(1), q(B, 1). r(X) :- p(X), q(Y), #mod{4}[X, Y](X)."; + + private static final String MODULE_LITERAL_NO_INPUT = "a(X) :- #something(X)."; + + private static final String MODULE_LITERAL_NO_INPUT_WITH_NUM_ANSWER_SETS = "a(X) :- #something{4}(X)."; + + private static final String MODULE_LITERAL_NO_OUTPUT = "a(X) :- #something[X]."; + + private static final String MODULE_LITERAL_NO_OUTPUT_WITH_NUM_ANSWER_SETS = "a(X) :- #something{4}[X]."; + + private static final String LIST_AGGREGATE = "stuff_list(LST) :- LST = #list{X : stuff(X)}."; + + private static final String LIST_AGGREGATE_TUPLE = "stuff_list(LST) :- LST = #list{stuff_tuple(X,Y) : stuff(X,Y)}."; + private final ProgramParserImpl parser = new ProgramParserImpl(); @Test public void parseFact() { - ASPCore2Program parsedProgram = parser.parse("p(a,b)."); + InputProgram parsedProgram = parser.parse("p(a,b)."); assertEquals(1, parsedProgram.getFacts().size(), "Program contains one fact."); assertEquals("p", parsedProgram.getFacts().get(0).getPredicate().getName(), "Predicate name of fact is p."); @@ -102,7 +125,7 @@ public void parseFact() { @Test public void parseFactWithFunctionTerms() { - ASPCore2Program parsedProgram = parser.parse("p(f(a),g(h(Y)))."); + InputProgram parsedProgram = parser.parse("p(f(a),g(h(Y)))."); assertEquals(1, parsedProgram.getFacts().size(), "Program contains one fact."); assertEquals("p", parsedProgram.getFacts().get(0).getPredicate().getName(), "Predicate name of fact is p."); @@ -113,7 +136,7 @@ public void parseFactWithFunctionTerms() { @Test public void parseSmallProgram() { - ASPCore2Program parsedProgram = parser.parse( + InputProgram parsedProgram = parser.parse( "a :- b, not d." + System.lineSeparator() + "c(X) :- p(X,a,_), q(Xaa,xaa)." + System.lineSeparator() + ":- f(Y)."); @@ -130,7 +153,7 @@ public void parseBadSyntax() { @Test public void parseBuiltinAtom() { - ASPCore2Program parsedProgram = parser.parse("a :- p(X), X != Y, q(Y)."); + InputProgram parsedProgram = parser.parse("a :- p(X), X != Y, q(Y)."); assertEquals(1, parsedProgram.getRules().size()); assertEquals(3, parsedProgram.getRules().get(0).getBody().size()); } @@ -145,31 +168,31 @@ public void parseProgramWithDisjunctionInHead() { @Test public void parseInterval() { - ASPCore2Program parsedProgram = parser.parse("fact(2..5). p(X) :- q(a, 3 .. X)."); + InputProgram parsedProgram = parser.parse("fact(2..5). p(X) :- q(a, 3 .. X)."); IntervalTerm factInterval = (IntervalTerm) parsedProgram.getFacts().get(0).getTerms().get(0); - assertTrue(factInterval.equals(Terms.newIntervalTerm(Terms.newConstant(2), Terms.newConstant(5)))); + assertEquals(factInterval, Terms.newIntervalTerm(Terms.newConstant(2), Terms.newConstant(5))); IntervalTerm bodyInterval = (IntervalTerm) parsedProgram.getRules().get(0).getBody().stream().findFirst().get().getTerms().get(1); - assertTrue(bodyInterval.equals(Terms.newIntervalTerm(Terms.newConstant(3), Terms.newVariable("X")))); + assertEquals(bodyInterval, Terms.newIntervalTerm(Terms.newConstant(3), Terms.newVariable("X"))); } @Test public void parseChoiceRule() { - ASPCore2Program parsedProgram = parser.parse("dom(1). dom(2). { a ; b } :- dom(X)."); + InputProgram parsedProgram = parser.parse("dom(1). dom(2). { a ; b } :- dom(X)."); ChoiceHead choiceHead = (ChoiceHead) parsedProgram.getRules().get(0).getHead(); assertEquals(2, choiceHead.getChoiceElements().size()); - assertTrue(choiceHead.getChoiceElements().get(0).getChoiceAtom().toString().equals("a")); - assertTrue(choiceHead.getChoiceElements().get(1).getChoiceAtom().toString().equals("b")); - assertEquals(null, choiceHead.getLowerBound()); - assertEquals(null, choiceHead.getUpperBound()); + assertEquals("a", choiceHead.getChoiceElements().get(0).getChoiceAtom().toString()); + assertEquals("b", choiceHead.getChoiceElements().get(1).getChoiceAtom().toString()); + assertNull(choiceHead.getLowerBound()); + assertNull(choiceHead.getUpperBound()); } @Test public void parseChoiceRuleBounded() { - ASPCore2Program parsedProgram = parser.parse("dom(1). dom(2). 1 < { a: p(v,w), not r; b } <= 13 :- dom(X). foo."); + InputProgram parsedProgram = parser.parse("dom(1). dom(2). 1 < { a: p(v,w), not r; b } <= 13 :- dom(X). foo."); ChoiceHead choiceHead = (ChoiceHead) parsedProgram.getRules().get(0).getHead(); assertEquals(2, choiceHead.getChoiceElements().size()); - assertTrue(choiceHead.getChoiceElements().get(0).getChoiceAtom().toString().equals("a")); - assertTrue(choiceHead.getChoiceElements().get(1).getChoiceAtom().toString().equals("b")); + assertEquals("a", choiceHead.getChoiceElements().get(0).getChoiceAtom().toString()); + assertEquals("b", choiceHead.getChoiceElements().get(1).getChoiceAtom().toString()); List conditionalLiterals = choiceHead.getChoiceElements().get(0).getConditionLiterals(); assertEquals(2, conditionalLiterals.size()); assertFalse(conditionalLiterals.get(0).isNegated()); @@ -215,7 +238,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)."); @@ -225,7 +248,7 @@ public void parseEnumerationDirective() { @Test public void cardinalityAggregate() { - ASPCore2Program parsedProgram = parser.parse("num(K) :- K <= #count {X,Y,Z : p(X,Y,Z) }, dom(K)."); + InputProgram parsedProgram = parser.parse("num(K) :- K <= #count {X,Y,Z : p(X,Y,Z) }, dom(K)."); Optional optionalBodyElement = parsedProgram.getRules().get(0).getBody().stream().filter((lit) -> lit instanceof AggregateLiteral).findFirst(); assertTrue(optionalBodyElement.isPresent()); Literal bodyElement = optionalBodyElement.get(); @@ -244,7 +267,7 @@ public void cardinalityAggregate() { @Test public void stringWithEscapedQuotes() throws IOException { CharStream stream = CharStreams.fromStream(ParserTest.class.getResourceAsStream("/escaped_quotes.asp")); - ASPCore2Program prog = parser.parse(stream); + InputProgram prog = parser.parse(stream); assertEquals(1, prog.getFacts().size()); Atom stringAtom = prog.getFacts().get(0); String stringWithQuotes = stringAtom.getTerms().get(0).toString(); @@ -253,7 +276,7 @@ public void stringWithEscapedQuotes() throws IOException { @Test public void unitTestExpectUnsat() { - ASPCore2Program prog = parser.parse(UNIT_TEST_EXPECT_UNSAT); + InputProgram prog = parser.parse(UNIT_TEST_EXPECT_UNSAT); assertEquals(1, prog.getTestCases().size()); TestCase tc = prog.getTestCases().get(0); assertEquals("expected_unsat", tc.getName()); @@ -263,7 +286,7 @@ public void unitTestExpectUnsat() { @Test public void unitTestBasicTest() { - ASPCore2Program prog = parser.parse(UNIT_TEST_BASIC_TEST); + InputProgram prog = parser.parse(UNIT_TEST_BASIC_TEST); assertEquals(1, prog.getTestCases().size()); TestCase tc = prog.getTestCases().get(0); assertEquals("ensure_a", tc.getName()); @@ -274,7 +297,7 @@ public void unitTestBasicTest() { @Test public void unitTestMultipleAsserts() { - ASPCore2Program prog = parser.parse(UNIT_TEST_MORE_ASSERTIONS); + InputProgram prog = parser.parse(UNIT_TEST_MORE_ASSERTIONS); assertEquals(1, prog.getTestCases().size()); TestCase tc = prog.getTestCases().get(0); assertEquals("ensure_a", tc.getName()); @@ -286,7 +309,7 @@ public void unitTestMultipleAsserts() { @Test public void unitTestMoreTCs() { - ASPCore2Program prog = parser.parse(UNIT_TEST_MORE_TCS); + InputProgram prog = parser.parse(UNIT_TEST_MORE_TCS); assertEquals(2, prog.getTestCases().size()); TestCase tc1 = prog.getTestCases().get(0); assertEquals("ensure_a", tc1.getName()); @@ -296,7 +319,7 @@ public void unitTestMoreTCs() { @Test public void unitTestKeywordsAsIds() { - ASPCore2Program prog = parser.parse(UNIT_TEST_KEYWORDS_AS_IDS); + InputProgram prog = parser.parse(UNIT_TEST_KEYWORDS_AS_IDS); assertEquals(1, prog.getTestCases().size()); TestCase tc = prog.getTestCases().get(0); assertEquals("test", tc.getName()); @@ -305,4 +328,223 @@ public void unitTestKeywordsAsIds() { assertEquals(Assertion.Mode.FOR_ALL, tc.getAssertions().get(0).getMode()); } + @Test + public void simpleModule() { + InputProgram prog = parser.parse(MODULE_SIMPLE); + List modules = prog.getModules(); + assertFalse(modules.isEmpty()); + assertEquals(1, modules.size()); + Module module = modules.get(0); + assertEquals("aSimpleModule", module.getName()); + Predicate inputSpec = module.getInputSpec(); + assertEquals("input", inputSpec.getName()); + assertEquals(1, inputSpec.getArity()); + Set outputSpec = module.getOutputSpec(); + assertEquals(2, outputSpec.size()); + assertTrue(outputSpec.contains(Predicates.getPredicate("out1", 2))); + assertTrue(outputSpec.contains(Predicates.getPredicate("out2", 3))); + InputProgram implementation = module.getImplementation(); + assertEquals(2, implementation.getFacts().size()); + assertEquals(1, implementation.getRules().size()); + } + + @Test + public void moduleOutputAll() { + InputProgram prog = parser.parse(MODULE_OUTPUT_ALL); + List modules = prog.getModules(); + assertFalse(modules.isEmpty()); + assertEquals(1, modules.size()); + Module module = modules.get(0); + assertEquals("mod", module.getName()); + Predicate inputSpec = module.getInputSpec(); + assertEquals("in", inputSpec.getName()); + assertEquals(1, inputSpec.getArity()); + assertTrue(module.getOutputSpec().isEmpty()); + InputProgram implementation = module.getImplementation(); + assertEquals(1, implementation.getFacts().size()); + assertEquals(1, implementation.getRules().size()); + } + + @Test + public void moduleAndRegularStmts() { + InputProgram prog = parser.parse(MODULE_WITH_REGULAR_STMTS); + assertEquals(2, prog.getFacts().size()); + assertEquals(1, prog.getRules().size()); + List modules = prog.getModules(); + assertFalse(modules.isEmpty()); + assertEquals(1, modules.size()); + Module module = modules.get(0); + assertEquals("aSimpleModule", module.getName()); + Predicate inputSpec = module.getInputSpec(); + assertEquals("input", inputSpec.getName()); + assertEquals(1, inputSpec.getArity()); + Set outputSpec = module.getOutputSpec(); + assertEquals(2, outputSpec.size()); + assertTrue(outputSpec.contains(Predicates.getPredicate("out1", 2))); + assertTrue(outputSpec.contains(Predicates.getPredicate("out2", 3))); + InputProgram implementation = module.getImplementation(); + assertEquals(2, implementation.getFacts().size()); + assertEquals(1, implementation.getRules().size()); + } + + @Test + public void multipleModuleDefinitions() { + InputProgram prog = parser.parse(MODULE_MULTIPLE_DEFINITIONS); + assertEquals(2, prog.getFacts().size()); + assertEquals(1, prog.getRules().size()); + + List modules = prog.getModules(); + assertFalse(modules.isEmpty()); + assertEquals(2, modules.size()); + } + + @Test + public void invalidNestedModule() { + assertThrows(IllegalStateException.class, () -> + parser.parse("#module aSimpleModule(input/1 => {out1/2, out2/3}) { p(a). p(b). #module anotherModule(input/1 => {out1/2, out2/3}) { p(a). p(b). } }")); + } + + @Test + public void invalidNestedTest() { + assertThrows(IllegalStateException.class, () -> + parser.parse("#module mod(foo/1 => {*}) { #test test(expect: 1) { given { b. } assertForAll { :- a. } } }")); + } + + @Test + public void moduleLiteral() { + InputProgram prog = parser.parse(MODULE_LITERAL); + assertEquals(2, prog.getFacts().size()); + assertEquals(1, prog.getRules().size()); + Rule rule = prog.getRules().get(0); + assertEquals(3, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).count()); + ModuleLiteral moduleLiteral = (ModuleLiteral) rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).findFirst().get(); + assertEquals("mod", moduleLiteral.getAtom().getModuleName()); + assertEquals(2, moduleLiteral.getAtom().getInput().size()); + assertEquals(1, moduleLiteral.getAtom().getOutput().size()); + assertEquals(ModuleAtom.ModuleInstantiationMode.ALL, moduleLiteral.getAtom().getInstantiationMode()); + } + + @Test + public void moduleLiteralWithNumAnswerSets() { + InputProgram prog = parser.parse(MODULE_LITERAL_WITH_NUM_ANSWER_SETS); + assertEquals(2, prog.getRules().size()); + Optional> ruleWithModuleLiteral = prog.getRules().stream().filter(rule -> rule.getBody().stream().anyMatch(lit -> lit instanceof ModuleLiteral)).findFirst(); + assertTrue(ruleWithModuleLiteral.isPresent()); + Rule rule = ruleWithModuleLiteral.get(); + assertEquals(3, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).count()); + Optional optModuleLiteral = rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).findFirst(); + assertTrue(optModuleLiteral.isPresent()); + ModuleLiteral moduleLiteral = (ModuleLiteral) optModuleLiteral.get(); + assertEquals("mod", moduleLiteral.getAtom().getModuleName()); + assertEquals(2, moduleLiteral.getAtom().getInput().size()); + assertEquals(1, moduleLiteral.getAtom().getOutput().size()); + assertTrue(moduleLiteral.getAtom().getInstantiationMode().requestedAnswerSets().isPresent()); + assertEquals(4, moduleLiteral.getAtom().getInstantiationMode().requestedAnswerSets().get()); + } + + @Test + public void moduleLiteralNoInput() { + InputProgram prog = parser.parse(MODULE_LITERAL_NO_INPUT); + assertEquals(1, prog.getRules().size()); + Rule rule = prog.getRules().get(0); + assertEquals(1, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).count()); + ModuleLiteral moduleLiteral = (ModuleLiteral) rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).findFirst().get(); + assertEquals("something", moduleLiteral.getAtom().getModuleName()); + assertTrue(moduleLiteral.getAtom().getInput().isEmpty()); + assertEquals(1, moduleLiteral.getAtom().getOutput().size()); + assertEquals(ModuleAtom.ModuleInstantiationMode.ALL, moduleLiteral.getAtom().getInstantiationMode()); + } + + @Test + public void moduleLiteralNoInputWithNumAnswerSets() { + InputProgram prog = parser.parse(MODULE_LITERAL_NO_INPUT_WITH_NUM_ANSWER_SETS); + assertEquals(1, prog.getRules().size()); + Rule rule = prog.getRules().get(0); + assertEquals(1, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).count()); + ModuleLiteral moduleLiteral = (ModuleLiteral) rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).findFirst().get(); + assertEquals("something", moduleLiteral.getAtom().getModuleName()); + assertTrue(moduleLiteral.getAtom().getInput().isEmpty()); + assertEquals(1, moduleLiteral.getAtom().getOutput().size()); + assertTrue(moduleLiteral.getAtom().getInstantiationMode().requestedAnswerSets().isPresent()); + assertEquals(4, moduleLiteral.getAtom().getInstantiationMode().requestedAnswerSets().get()); + } + + @Test + public void moduleLiteralNoOutput() { + InputProgram prog = parser.parse(MODULE_LITERAL_NO_OUTPUT); + assertEquals(1, prog.getRules().size()); + Rule rule = prog.getRules().get(0); + assertEquals(1, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).count()); + ModuleLiteral moduleLiteral = (ModuleLiteral) rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).findFirst().get(); + assertEquals("something", moduleLiteral.getAtom().getModuleName()); + assertEquals(1, moduleLiteral.getAtom().getInput().size()); + assertTrue(moduleLiteral.getAtom().getOutput().isEmpty()); + assertFalse(moduleLiteral.getAtom().getInstantiationMode().requestedAnswerSets().isPresent()); + assertEquals(ModuleAtom.ModuleInstantiationMode.ALL, moduleLiteral.getAtom().getInstantiationMode()); + } + + @Test + public void moduleLiteralNoOutputWithNumAnswerSets() { + InputProgram prog = parser.parse(MODULE_LITERAL_NO_OUTPUT_WITH_NUM_ANSWER_SETS); + assertEquals(1, prog.getRules().size()); + Rule rule = prog.getRules().get(0); + assertEquals(1, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).count()); + ModuleLiteral moduleLiteral = (ModuleLiteral) rule.getBody().stream().filter(lit -> lit instanceof ModuleLiteral).findFirst().get(); + assertEquals("something", moduleLiteral.getAtom().getModuleName()); + assertEquals(1, moduleLiteral.getAtom().getInput().size()); + assertTrue(moduleLiteral.getAtom().getOutput().isEmpty()); + assertTrue(moduleLiteral.getAtom().getInstantiationMode().requestedAnswerSets().isPresent()); + assertEquals(4, moduleLiteral.getAtom().getInstantiationMode().requestedAnswerSets().get()); + } + + @Test + public void listAggregate() { + InputProgram prog = parser.parse(LIST_AGGREGATE); + assertEquals(1, prog.getRules().size()); + Rule rule = prog.getRules().get(0); + assertEquals(1, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof AggregateLiteral).count()); + AggregateLiteral aggregateLiteral = (AggregateLiteral) rule.getBody().stream().filter(lit -> lit instanceof AggregateLiteral).findFirst().get(); + AggregateAtom aggregateAtom = aggregateLiteral.getAtom(); + assertEquals(ComparisonOperators.EQ, aggregateAtom.getLowerBoundOperator()); + assertEquals(Terms.newVariable("LST"), aggregateAtom.getLowerBoundTerm()); + assertEquals(AggregateAtom.AggregateFunctionSymbol.LIST, aggregateAtom.getAggregateFunction()); + assertEquals(1, aggregateAtom.getAggregateElements().size()); + AggregateAtom.AggregateElement aggregateElement = aggregateAtom.getAggregateElements().get(0); + assertEquals(1, aggregateElement.getElementTerms().size()); + Term elementTerm = aggregateElement.getElementTerms().get(0); + assertEquals(Terms.newVariable("X"), elementTerm); + assertEquals(1, aggregateElement.getElementLiterals().size()); + Literal elementLiteral = aggregateElement.getElementLiterals().get(0); + assertEquals(Atoms.newBasicAtom(Predicates.getPredicate("stuff", 1), Terms.newVariable("X")).toLiteral(), elementLiteral); + } + + @Test + public void listAggregateWithTuples() { + InputProgram prog = parser.parse(LIST_AGGREGATE_TUPLE); + assertEquals(1, prog.getRules().size()); + Rule rule = prog.getRules().get(0); + assertEquals(1, rule.getBody().size()); + assertEquals(1, rule.getBody().stream().filter(lit -> lit instanceof AggregateLiteral).count()); + AggregateLiteral aggregateLiteral = (AggregateLiteral) rule.getBody().stream().filter(lit -> lit instanceof AggregateLiteral).findFirst().get(); + AggregateAtom aggregateAtom = aggregateLiteral.getAtom(); + assertEquals(ComparisonOperators.EQ, aggregateAtom.getLowerBoundOperator()); + assertEquals(Terms.newVariable("LST"), aggregateAtom.getLowerBoundTerm()); + assertEquals(AggregateAtom.AggregateFunctionSymbol.LIST, aggregateAtom.getAggregateFunction()); + assertEquals(1, aggregateAtom.getAggregateElements().size()); + AggregateAtom.AggregateElement aggregateElement = aggregateAtom.getAggregateElements().get(0); + assertEquals(1, aggregateElement.getElementTerms().size()); + Term elementTerm = aggregateElement.getElementTerms().get(0); + assertEquals(Terms.newFunctionTerm("stuff_tuple", Terms.newVariable("X"), Terms.newVariable("Y")), elementTerm); + assertEquals(1, aggregateElement.getElementLiterals().size()); + Literal elementLiteral = aggregateElement.getElementLiterals().get(0); + assertEquals(Atoms.newBasicAtom(Predicates.getPredicate("stuff", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), elementLiteral); + } + } 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 index 1c0c26b57..ac961bebe 100644 --- 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 @@ -1,9 +1,5 @@ package at.ac.tuwien.kr.alpha.core.programs.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.HashMap; import java.util.HashSet; @@ -15,16 +11,18 @@ 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.ASPCore2Program; +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.core.externals.Externals; +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}. * @@ -58,56 +56,56 @@ public static final Set>> extWithOutput(int in) { @Test public void testIsBasicAtomGround() { - ASPCore2Program p = parser.parse("bla(blubb, foo(bar))."); + InputProgram p = parser.parse("bla(blubb, foo(bar))."); Atom a = p.getFacts().get(0); assertBasicAtomGround(a, true); - ASPCore2Program p1 = parser.parse("foo(1, 2, 3, \"bar\")."); + InputProgram p1 = parser.parse("foo(1, 2, 3, \"bar\")."); Atom a1 = p1.getFacts().get(0); assertBasicAtomGround(a1, true); - ASPCore2Program p2 = parser.parse("foo(BAR)."); + InputProgram p2 = parser.parse("foo(BAR)."); Atom a2 = p2.getFacts().get(0); assertBasicAtomGround(a2, false); - ASPCore2Program p3 = parser.parse("foo(b, a, r(\"bla\", BLUBB))."); + InputProgram p3 = parser.parse("foo(b, a, r(\"bla\", BLUBB))."); Atom a3 = p3.getFacts().get(0); assertBasicAtomGround(a3, false); } @Test public void testAreBasicAtomsEqual() { - ASPCore2Program p1 = parser.parse("bla(blubb, foo(bar)). bla(blubb, foo(bar))."); + 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); - ASPCore2Program p2 = parser.parse("foo(1, 2, 3, \"bar\"). foo(1, 2, 3, \"bar\")."); + 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); - ASPCore2Program p3 = parser.parse("foo(BAR). foo(BAR)."); + InputProgram p3 = parser.parse("foo(BAR). foo(BAR)."); Atom a5 = p3.getFacts().get(0); Atom a6 = p3.getFacts().get(1); assertEquals(a5, a6); - ASPCore2Program p4 = parser.parse("foo(b, a, r(\"bla\", BLUBB)). foo(b, a, r(\"bla\", BLUBB))."); + 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); - 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); } @Test public void testIsExternalAtomGround() { - ASPCore2Program p1 = parser.parse("a :- &isFoo[1].", externals); + InputProgram p1 = parser.parse("a :- &isFoo[1].", externals); Atom ext1 = p1.getRules().get(0).getBody().stream().findFirst().get().getAtom(); assertExternalAtomGround(ext1, true); - ASPCore2Program p2 = parser.parse("a :- &isFoo[bar(1)].", externals); + InputProgram p2 = parser.parse("a :- &isFoo[bar(1)].", externals); Atom ext2 = p2.getRules().get(0).getBody().stream().findFirst().get().getAtom(); assertExternalAtomGround(ext2, true); - ASPCore2Program p3 = parser.parse("a :- &isFoo[BLA].", externals); + InputProgram p3 = parser.parse("a :- &isFoo[BLA].", externals); Atom ext3 = p3.getRules().get(0).getBody().stream().findFirst().get().getAtom(); assertExternalAtomGround(ext3, false); } @@ -115,21 +113,21 @@ public void testIsExternalAtomGround() { @Test @SuppressWarnings("unlikely-arg-type") public void testAreExternalAtomsEqual() { - ASPCore2Program p1 = parser.parse("a :- &isFoo[1].", externals); + InputProgram p1 = parser.parse("a :- &isFoo[1].", externals); Atom ext1 = p1.getRules().get(0).getBody().stream().findFirst().get().getAtom(); - ASPCore2Program p2 = parser.parse("a :- &isFoo[1].", externals); + 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); - 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 public void testExternalHasOutput() { - ASPCore2Program p = parser.parse("a:- &extWithOutput[1](OUT).", externals); + 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()); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/atoms/RuleAtomTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtomTest.java similarity index 97% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/atoms/RuleAtomTest.java rename to alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtomTest.java index 56e64c4ef..e89317207 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/atoms/RuleAtomTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/atoms/RuleAtomTest.java @@ -1,7 +1,10 @@ -package at.ac.tuwien.kr.alpha.core.atoms; +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; @@ -18,17 +21,13 @@ 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.parser.ProgramParserImpl; -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; /** * Copyright (c) 2022, the Alpha Team. */ public class RuleAtomTest { - private static final ProgramParser PARSER = new ProgramParserImpl(); + 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); 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 d7ff68a37..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 @@ -12,11 +12,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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.core.externals.Externals; +import at.ac.tuwien.kr.alpha.commons.externals.Externals; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; public class ProgramTransformationTest { @@ -44,11 +44,11 @@ private static String readTestResource(String resource) throws IOException { } private , O extends Program> void genericTransformationTest(ProgramTransformation transform, - Function prepareFunc, String resourceSet) { + Function prepareFunc, String resourceSet) { try { String inputCode = ProgramTransformationTest.readTestResource(resourceSet + ".in"); String expectedResult = ProgramTransformationTest.readTestResource(resourceSet + ".out"); - ASPCore2Program inputProg = PARSER.parse(inputCode, Externals.scan(ProgramTransformationTest.class)); + InputProgram inputProg = PARSER.parse(inputCode, Externals.scan(ProgramTransformationTest.class)); I transformInput = prepareFunc.apply(inputProg); String beforeTransformProg = transformInput.toString(); O transformedProg = transform.apply(transformInput); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluationRegressionTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluationRegressionTest.java deleted file mode 100644 index 8715675b0..000000000 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluationRegressionTest.java +++ /dev/null @@ -1,262 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.programs.transformation; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.function.Consumer; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -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.ASPCore2Program; -import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; -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.Grounder; -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.AnalyzedProgram; -import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.solver.SolverFactory; -import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; - -public class StratifiedEvaluationRegressionTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(StratifiedEvaluationRegressionTest.class); - - private static final String STRATIFIED_NEG_ASP = "base(X) :- req(X), not incomp(X).\n" - + "depend_base(X, Y) :- base(X), base(Y).\n" - + "dep_b_hlp(X) :- depend_base(X, _).\n" - + "fallback_base(X) :- base(X), not dep_b_hlp(X).\n" - + "depend_further(X) :- depend_base(_, X).\n" - + "depend_further(X) :- fallback_base(X)."; - - private static final String BASIC_TEST_ASP = "a. b:- a."; - private static final String BASIC_MULTI_INSTANCE_ASP = "p(a). p(b). q(X) :- p(X)."; - private static final String BASIC_NEGATION_ASP = "p(a). q(b). p(c). q(d). r(c). s(X, Y) :- p(X), q(Y), not r(X)."; - private static final String PART_STRATIFIED_ASP = "p(a). q(a). p(b). m(c). n(d).\n" + "r(X) :- p(X), q(X).\n" + "s(X, Y, Z) :- r(X), m(Y), n(Z).\n" - + "t(X, Y) :- p(X), q(X), p(Y), not q(Y).\n" + "either(X) :- t(X, _), not or(X).\n" + "or(X) :- t(X, _), not either(X)."; - private static final String POSITIVE_RECURSION_ASP = "num(0).\n" + "max_num(10).\n" + "num(S) :- num(N), S = N + 1, S <= M, max_num(M)."; - private static final String EMPTY_PROG_ASP = ""; - private static final String FACTS_ONLY_ASP = "a. b. c. p(a). q(b, c). r(c, c, a). s(b)."; - private static final String STRATIFIED_NO_FACTS_ASP = STRATIFIED_NEG_ASP; - private static final String STRATIFIED_W_FACTS_ASP = "req(a). req(b). incomp(b).\n" + STRATIFIED_NEG_ASP; - private static final String EQUALITY_ASP = "equal :- 1 = 1."; - private static final String EQUALITY_WITH_VAR_ASP = "a(1). a(2). a(3). b(X) :- a(X), X = 1. c(X) :- a(X), X = 2. d(X) :- X = 3, a(X)."; - - private static final ImmutablePair, Consumer>> BASIC_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramBasic, StratifiedEvaluationRegressionTest::verifyAnswerSetsBasic); - private static final ImmutablePair, Consumer>> BASIC_MULTI_INSTANCE_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramBasicMultiInstance, StratifiedEvaluationRegressionTest::verifyAnswerSetsBasicMultiInstance); - private static final ImmutablePair, Consumer>> BASIC_NEGATION_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramBasicNegation, StratifiedEvaluationRegressionTest::verifyAnswerSetsBasicNegation); - private static final ImmutablePair, Consumer>> PART_STRATIFIED_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramPartStratified, StratifiedEvaluationRegressionTest::verifyAnswerSetsPartStratified); - private static final ImmutablePair, Consumer>> POSITIVE_RECURSIVE_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramPositiveRecursive, StratifiedEvaluationRegressionTest::verifyAnswerSetsPositiveRecursive); - private static final ImmutablePair, Consumer>> EMPTY_PROG_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramEmptyProg, StratifiedEvaluationRegressionTest::verifyAnswerSetsEmptyProg); - private static final ImmutablePair, Consumer>> FACTS_ONLY_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramFactsOnly, StratifiedEvaluationRegressionTest::verifyAnswerSetsFactsOnly); - private static final ImmutablePair, Consumer>> STRATIFIED_NO_FACTS_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramStratNoFacts, StratifiedEvaluationRegressionTest::verifyAnswerSetsStratNoFacts); - private static final ImmutablePair, Consumer>> STRATIFIED_W_FACTS_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramStratWithFacts, StratifiedEvaluationRegressionTest::verifyAnswerSetsStratWithFacts); - private static final ImmutablePair, Consumer>> EQUALITY_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramEquality, StratifiedEvaluationRegressionTest::verifyAnswerSetsEquality); - private static final ImmutablePair, Consumer>> EQUALITY_WITH_VAR_VERIFIERS = new ImmutablePair<>( - StratifiedEvaluationRegressionTest::verifyProgramEqualityWithVar, StratifiedEvaluationRegressionTest::verifyAnswerSetsEqualityWithVar); - - public static List params() { - List, Consumer>>>> testCases = new ArrayList<>(); - List paramList = new ArrayList<>(); - testCases.add(new ImmutablePair<>(BASIC_TEST_ASP, BASIC_VERIFIERS)); - testCases.add(new ImmutablePair<>(BASIC_MULTI_INSTANCE_ASP, BASIC_MULTI_INSTANCE_VERIFIERS)); - testCases.add(new ImmutablePair<>(BASIC_NEGATION_ASP, BASIC_NEGATION_VERIFIERS)); - testCases.add(new ImmutablePair<>(PART_STRATIFIED_ASP, PART_STRATIFIED_VERIFIERS)); - testCases.add(new ImmutablePair<>(POSITIVE_RECURSION_ASP, POSITIVE_RECURSIVE_VERIFIERS)); - testCases.add(new ImmutablePair<>(EMPTY_PROG_ASP, EMPTY_PROG_VERIFIERS)); - testCases.add(new ImmutablePair<>(FACTS_ONLY_ASP, FACTS_ONLY_VERIFIERS)); - testCases.add(new ImmutablePair<>(STRATIFIED_NO_FACTS_ASP, STRATIFIED_NO_FACTS_VERIFIERS)); - testCases.add(new ImmutablePair<>(STRATIFIED_W_FACTS_ASP, STRATIFIED_W_FACTS_VERIFIERS)); - testCases.add(new ImmutablePair<>(EQUALITY_ASP, EQUALITY_VERIFIERS)); - testCases.add(new ImmutablePair<>(EQUALITY_WITH_VAR_ASP, EQUALITY_WITH_VAR_VERIFIERS)); - - testCases.forEach((pair) -> paramList.add(Arguments.of(pair.left, pair.right.left, pair.right.right))); - return paramList; - } - - @ParameterizedTest - @MethodSource("at.ac.tuwien.kr.alpha.core.programs.transformation.StratifiedEvaluationRegressionTest#params") - public void runTest(String aspString, Consumer programVerifier, Consumer> resultVerifier) { - // Parse and pre-evaulate program - ProgramParser parser = new ProgramParserImpl(); - ASPCore2Program prog = parser.parse(aspString); - AnalyzedProgram analyzed = AnalyzedProgram - .analyzeNormalProgram(new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG).apply(prog)); - CompiledProgram evaluated = new StratifiedEvaluation().apply(analyzed); - // Verify stratified evaluation result - programVerifier.accept(evaluated); - // Solve remaining program - AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance("naive", evaluated, atomStore, false); - Solver solver = SolverFactory.getInstance(new SystemConfig(), atomStore, grounder); - Set answerSets = solver.collectSet(); - resultVerifier.accept(answerSets); - } - - private static void verifyProgramBasic(CompiledProgram evaluated) { - TestUtils.assertFactsContainedInProgram(evaluated, TestUtils.basicAtomWithSymbolicTerms("a"), TestUtils.basicAtomWithSymbolicTerms("b")); - assertEquals(2, evaluated.getFacts().size()); - assertTrue(evaluated.getRules().size() == 0); - } - - private static void verifyAnswerSetsBasic(Set answerSets) { - TestUtils.assertAnswerSetsEqual("a, b", answerSets); - } - - private static void verifyProgramBasicMultiInstance(CompiledProgram evaluated) { - TestUtils.assertFactsContainedInProgram(evaluated, TestUtils.basicAtomWithSymbolicTerms("q", "a"), TestUtils.basicAtomWithSymbolicTerms("q", "b")); - assertTrue(evaluated.getRules().size() == 0); - } - - private static void verifyAnswerSetsBasicMultiInstance(Set answerSets) { - TestUtils.assertAnswerSetsEqual("p(a), p(b), q(a), q(b)", answerSets); - } - - private static void verifyProgramBasicNegation(CompiledProgram evaluated) { - TestUtils.assertFactsContainedInProgram(evaluated, TestUtils.basicAtomWithSymbolicTerms("s", "a", "b"), - TestUtils.basicAtomWithSymbolicTerms("s", "a", "d")); - assertEquals(7, evaluated.getFacts().size()); - assertEquals(0, evaluated.getRules().size()); - } - - private static void verifyAnswerSetsBasicNegation(Set answerSets) { - TestUtils.assertAnswerSetsEqual("p(a), q(b), p(c), q(d), r(c), s(a,b), s(a,d)", answerSets); - } - - private static void verifyProgramPartStratified(CompiledProgram evaluated) { - TestUtils.assertFactsContainedInProgram(evaluated, TestUtils.basicAtomWithSymbolicTerms("p", "a"), TestUtils.basicAtomWithSymbolicTerms("q", "a"), - TestUtils.basicAtomWithSymbolicTerms("p", "b"), - TestUtils.basicAtomWithSymbolicTerms("m", "c"), TestUtils.basicAtomWithSymbolicTerms("n", "d"), TestUtils.basicAtomWithSymbolicTerms("r", "a"), - TestUtils.basicAtomWithSymbolicTerms("s", "a", "c", "d"), - TestUtils.basicAtomWithSymbolicTerms("t", "a", "b")); - LOGGER.debug("part stratified evaluated prog is:\n{}", evaluated.toString()); - assertEquals(2, evaluated.getRules().size()); - } - - private static void verifyAnswerSetsPartStratified(Set answerSets) { - TestUtils.assertAnswerSetsEqual(new String[] {"p(a), q(a), p(b), m(c), n(d), r(a), s(a,c,d), t(a,b), either(a)", - "p(a), q(a), p(b), m(c), n(d), r(a), s(a,c,d), t(a,b), or(a)" }, answerSets); - } - - private static void verifyProgramPositiveRecursive(CompiledProgram evaluated) { - Predicate num = Predicates.getPredicate("num", 1); - TestUtils.assertFactsContainedInProgram(evaluated, Atoms.newBasicAtom(Predicates.getPredicate("max_num", 1), Terms.newConstant(10)), - Atoms.newBasicAtom(num, Terms.newConstant(0)), - Atoms.newBasicAtom(num, Terms.newConstant(1)), Atoms.newBasicAtom(num, Terms.newConstant(2)), - Atoms.newBasicAtom(num, Terms.newConstant(3)), Atoms.newBasicAtom(num, Terms.newConstant(4)), - Atoms.newBasicAtom(num, Terms.newConstant(5)), Atoms.newBasicAtom(num, Terms.newConstant(6)), - Atoms.newBasicAtom(num, Terms.newConstant(7)), Atoms.newBasicAtom(num, Terms.newConstant(8)), - Atoms.newBasicAtom(num, Terms.newConstant(9)), Atoms.newBasicAtom(num, Terms.newConstant(10))); - LOGGER.debug("Recursive program evaluated is:\n{}", evaluated.toString()); - assertEquals(0, evaluated.getRules().size()); - } - - private static void verifyAnswerSetsPositiveRecursive(Set answerSets) { - TestUtils.assertAnswerSetsEqual("max_num(10), num(0), num(1), num(2), num(3), num(4), num(5), num(6), num(7), num(8), num(9), num(10)", answerSets); - } - - private static void verifyProgramEmptyProg(CompiledProgram evaluated) { - assertTrue(evaluated.getRules().isEmpty()); - assertTrue(evaluated.getRulesById().isEmpty()); - assertTrue(evaluated.getPredicateDefiningRules().isEmpty()); - assertTrue(evaluated.getFacts().isEmpty()); - assertTrue(evaluated.getFactsByPredicate().isEmpty()); - } - - private static void verifyAnswerSetsEmptyProg(Set answerSets) { - assertEquals(1, answerSets.size()); - assertTrue(answerSets.iterator().next().isEmpty()); - } - - private static void verifyProgramFactsOnly(CompiledProgram evaluated) { - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("a"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("b"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("c"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("p", "a"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("q", "b", "c"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("r", "c", "c", "a"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("s", "b"))); - } - - private static void verifyAnswerSetsFactsOnly(Set answerSets) { - TestUtils.assertAnswerSetsEqual("a, b, c, p(a), q(b,c), r(c,c,a), s(b)", answerSets); - } - - private static void verifyProgramStratNoFacts(CompiledProgram evaluated) { - assertTrue(evaluated.getFacts().isEmpty()); - } - - private static void verifyAnswerSetsStratNoFacts(Set answerSets) { - assertEquals(1, answerSets.size()); - assertTrue(answerSets.iterator().next().isEmpty()); - } - - private static void verifyProgramStratWithFacts(CompiledProgram evaluated) { - // rules should all be taken care of at this point - assertTrue(evaluated.getRules().isEmpty()); - assertTrue(evaluated.getRulesById().isEmpty()); - assertTrue(evaluated.getPredicateDefiningRules().isEmpty()); - - // facts should be the full answer set - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("req", "a"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("req", "b"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("incomp", "b"))); - - // below facts from stratified evaluation - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("base", "a"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("depend_base", "a", "a"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("dep_b_hlp", "a"))); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("depend_further", "a"))); - } - - private static void verifyAnswerSetsStratWithFacts(Set answerSets) { - TestUtils.assertAnswerSetsEqual("req(a), req(b), incomp(b), base(a), depend_base(a,a), dep_b_hlp(a), depend_further(a)", answerSets); - } - - private static void verifyProgramEquality(CompiledProgram evaluated) { - assertEquals(0, evaluated.getRules().size()); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("equal"))); - } - - private static void verifyAnswerSetsEquality(Set answerSets) { - TestUtils.assertAnswerSetsEqual("equal", answerSets); - } - - private static void verifyProgramEqualityWithVar(CompiledProgram evaluated) { - assertEquals(0, evaluated.getRules().size()); - assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newConstant(1)))); - assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("c", 1), Terms.newConstant(2)))); - assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("d", 1), Terms.newConstant(3)))); - } - - private static void verifyAnswerSetsEqualityWithVar(Set answerSets) { - TestUtils.assertAnswerSetsEqual("a(1), a(2), a(3), b(1), c(2), d(3)", answerSets); - } - -} 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 index 96a4c6e11..f4ec2ce48 100644 --- 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 @@ -10,6 +10,7 @@ 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; @@ -24,7 +25,6 @@ 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.core.test.util.RuleParser; public class AggregateRewritingRuleAnalysisTest { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/rules/RuleGroundingInfoTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/rules/RuleGroundingInfoTest.java new file mode 100644 index 000000000..6edbd02ed --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/rules/RuleGroundingInfoTest.java @@ -0,0 +1,200 @@ +/* + * 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.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.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; +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. + */ +public class RuleGroundingInfoTest { + + @Test + public void groundingOrder() { + // r1 := h(X,C) :- p(X,Y), q(A,B), r(Y,A), s(C). + 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(), + Atoms.newBasicAtom(Predicates.getPredicate("r", 2), Terms.newVariable("Y"), Terms.newVariable("A")).toLiteral(), + Atoms.newBasicAtom(Predicates.getPredicate("s", 1), Terms.newVariable("C")).toLiteral()); + RuleGroundingInfo rgo1 = new RuleGroundingInfoImpl(r1); + rgo1.computeGroundingOrders(); + 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 = 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(), + Atoms.newBasicAtom(Predicates.getPredicate("r1", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(), + Atoms.newBasicAtom(Predicates.getPredicate("r1", 2), Terms.newVariable("A"), Terms.newVariable("X")).toLiteral(), + Atoms.newBasicAtom(Predicates.getPredicate("r1", 2), Terms.newVariable("A"), Terms.newVariable("Y")).toLiteral()); + RuleGroundingInfo rgo2 = new RuleGroundingInfoImpl(r2); + rgo2.computeGroundingOrders(); + assertEquals(4, rgo2.getStartingLiterals().size()); + + // r3 := p(a) :- b = 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(); + assertTrue(rgo3.hasFixedInstantiation()); + } + + /** + * Tests that an exception is thrown when trying to compute grounding orders for a rule that is not safe due to cyclic dependencies between + * body variables. + */ + @Test + public void groundingOrderUnsafe() { + assertThrows(RuntimeException.class, () -> { + // rule := h(X, Z) :- Y = X + 1, X = Z + 1, Z = Y - 2. + CompiledRule rule = CompiledRules.newCompiledRule( + Heads.newNormalHead(Atoms.newBasicAtom(Predicates.getPredicate("h", 2), Terms.newVariable("X"), Terms.newVariable("Z"))), + Atoms.newComparisonAtom( + Terms.newVariable("Y"), + Terms.newArithmeticTerm(Terms.newVariable("Y"), ArithmeticOperator.PLUS, Terms.newConstant(1)), + ComparisonOperators.EQ).toLiteral(), + Atoms.newComparisonAtom( + Terms.newVariable("X"), + Terms.newArithmeticTerm(Terms.newVariable("Z"), ArithmeticOperator.PLUS, Terms.newConstant(1)), + ComparisonOperators.EQ).toLiteral(), + Atoms.newComparisonAtom( + Terms.newVariable("Z"), + Terms.newArithmeticTerm(Terms.newVariable("Y"), ArithmeticOperator.MINUS, Terms.newConstant(2)), + ComparisonOperators.EQ).toLiteral()); + computeGroundingOrdersForRule(rule); + }); + } + + @Test + public void testPositionFromWhichAllVarsAreBound_ground() { + // rule := a :- b, not c. + 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); + assertEquals(0, rgo0.getFixedGroundingOrder().getPositionFromWhichAllVarsAreBound()); + } + + @Test + public void testPositionFromWhichAllVarsAreBound_simpleNonGround() { + // rule := a(X) :- b(X), not c(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); + assertEquals(1, rgo0.getStartingLiterals().size()); + for (Literal startingLiteral : rgo0.getStartingLiterals()) { + assertEquals(0, rgo0.orderStartingFrom(startingLiteral).getPositionFromWhichAllVarsAreBound()); + } + } + + @Test + public void testPositionFromWhichAllVarsAreBound_longerSimpleNonGround() { + // rule := a(X) :- b(X), c(X), d(X), not e(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(), + Atoms.newBasicAtom(Predicates.getPredicate("e", 1), Terms.newVariable("X")).toLiteral(false)); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(rule); + assertEquals(3, rgo0.getStartingLiterals().size()); + for (Literal startingLiteral : rgo0.getStartingLiterals()) { + assertEquals(0, rgo0.orderStartingFrom(startingLiteral).getPositionFromWhichAllVarsAreBound()); + } + } + + @Test + public void testToString_longerSimpleNonGround() { + // rule := a(X) :- b(X), c(X), d(X), not e(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(), + Atoms.newBasicAtom(Predicates.getPredicate("e", 1), Terms.newVariable("X")).toLiteral(false)); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(rule); + 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() { + // rule := a(X) :- b(X), c(X, Y), d(X, Z), not e(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(), + Atoms.newBasicAtom(Predicates.getPredicate("e", 1), Terms.newVariable("X")).toLiteral(false)); + RuleGroundingInfo rgo0 = computeGroundingOrdersForRule(rule); + final Literal litBX = Atoms.newBasicAtom(Predicates.getPredicate("b", 1), Terms.newVariable("X")).toLiteral(); + final Literal litCXY = Atoms.newBasicAtom(Predicates.getPredicate("c", 2), Terms.newVariable("X"), Terms.newVariable("Y")).toLiteral(); + final Literal litDXZ = Atoms.newBasicAtom(Predicates.getPredicate("d", 2), Terms.newVariable("X"), Terms.newVariable("Z")).toLiteral(); + assertTrue(2 <= rgo0.orderStartingFrom(litBX).getPositionFromWhichAllVarsAreBound()); + assertTrue(1 <= rgo0.orderStartingFrom(litCXY).getPositionFromWhichAllVarsAreBound()); + assertTrue(1 <= rgo0.orderStartingFrom(litDXZ).getPositionFromWhichAllVarsAreBound()); + } + + private RuleGroundingInfo computeGroundingOrdersForRule(CompiledRule rule) { + RuleGroundingInfo rgo = new RuleGroundingInfoImpl(rule); + rgo.computeGroundingOrders(); + return rgo; + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AntecedentTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AntecedentTest.java deleted file mode 100644 index a2cb52826..000000000 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AntecedentTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.solver; - -import java.util.HashSet; - -public class AntecedentTest { - - /** - * Tests whether two Antecedent objects have the same reason literals (irrespective of their order). - * Note that both Antecedents are assumed to contain no duplicate literals. - * @param l left Antecedent. - * @param r right Antecedent - * @return true iff both Antecedents contain the same literals. - */ - public static boolean antecedentsEquals(Antecedent l, Antecedent r) { - if (l == r) { - return true; - } - if (l != null && r != null && l.getReasonLiterals().length == r.getReasonLiterals().length) { - HashSet lSet = new HashSet<>(); - for (int literal : l.getReasonLiterals()) { - lSet.add(literal); - } - for (int literal : r.getReasonLiterals()) { - if (!lSet.contains(literal)) { - return false; - } - } - return true; - } - return false; - } -} \ No newline at end of file diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ArithmeticTermsTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ArithmeticTermsTest.java deleted file mode 100644 index b232ba659..000000000 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ArithmeticTermsTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.solver; - -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSet; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSetsWithBase; - -/** - * Tests ASP programs containing arithmetic terms at arbitrary positions. - * - * Copyright (c) 2020, the Alpha Team. - */ -public class ArithmeticTermsTest { - - @RegressionTest - public void testArithmeticTermInHead(RegressionTestConfig cfg) { - String program = "dom(1). dom(2)." - + "p(X+3) :- dom(X)."; - assertRegressionTestAnswerSet(cfg, program, "dom(1),dom(2),p(4),p(5)"); - } - - @RegressionTest - public void testArithmeticTermInRule(RegressionTestConfig cfg) { - String program = "dom(1). dom(2)." - + "p(Y+4) :- dom(X+1), dom(X), Y=X, X=Y."; - assertRegressionTestAnswerSet(cfg, program, "dom(1),dom(2),p(5)"); - } - - @RegressionTest - public void testArithmeticTermInChoiceRule(RegressionTestConfig cfg) { - String program = "cycle_max(4). cycle(1)." + - "{ cycle(N+1) } :- cycle(N), cycle_max(K), N buildConfigs() { - // Check whether we are running in a CI environment. - boolean ci = Boolean.valueOf(System.getenv("CI")); - - //@formatter:off - String[] solvers = ci ? new String[]{DEFAULT_SOLVER_NAME, "naive" } : new String[]{DEFAULT_SOLVER_NAME }; - String grounder = DEFAULT_GROUNDER_NAME; - String[] atomStores = ci ? new String[]{DEFAULT_ATOM_STORE, "naive" } : new String[]{DEFAULT_ATOM_STORE }; - String[] heuristics = ci ? nonDeprecatedHeuristics() : new String[]{"NAIVE", DEFAULT_BRANCHING_HEURISTIC }; - String[] gtcValues = new String[]{DEFAULT_GROUNDER_TOLERANCE, "permissive" }; - String gtrValue = DEFAULT_GROUNDER_TOLERANCE; - boolean[] disableInstanceRemovalValues = 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 - - // NOTE: - // It is handy to set the seed for reproducing bugs. However, the reverse is also sometimes needed: - // A test case fails, now what was the seed that "caused" it? To allow this, we need full control over - // the seed, so we generate one in any case. - // If your test case fails you can inspect the property called "seed" of AbstractSolverTests and extract - // its value. - String seedProperty = System.getProperty("seed", ci ? "0" : ""); - long seed = seedProperty.isEmpty() ? (new Random().nextLong()) : Long.valueOf(seedProperty); - - List configsToTest = new ArrayList<>(); - for (String solverName : solvers) { - for (String atomStoreName : atomStores) { - for (String branchingHeuristicName : heuristics) { - for (String grounderTolerance : gtcValues) { - for (boolean disableInstanceRemoval : disableInstanceRemovalValues) { - for (boolean evaluateStratified : evaluateStratifiedValues) { - for (boolean enableDebugChecks : enableDebugChecksValues) { - configsToTest.add(new RegressionTestConfig( - solverName, grounder, atomStoreName, Heuristic.valueOf(branchingHeuristicName), - seed, enableDebugChecks, grounderTolerance, gtrValue, disableInstanceRemoval, evaluateStratified, - true, true)); - } - } - } - } - } - } - } - return configsToTest; - - } - - /** - * Provides {@link RegressionTestConfig}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. - * - * @return - */ - 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) { - configsToTest.add( - new RegressionTestConfig( - DEFAULT_SOLVER_NAME, DEFAULT_GROUNDER_NAME, DEFAULT_ATOM_STORE, Heuristic.valueOf(DEFAULT_BRANCHING_HEURISTIC), - 0, DEFAULT_ENABLE_DEBUG_CHECKS, DEFAULT_GROUNDER_TOLERANCE, DEFAULT_GROUNDER_TOLERANCE, DEFAULT_DISABLE_INSTANCE_REMOVAL, - evalStratified, - useSortingGrid, supportNegativeElements)); - } - } - } - - return configsToTest; - } - - public static List provideConfigs() { - List retVal = new ArrayList<>(); - for (RegressionTestConfig cfg : buildConfigs()) { - retVal.add(Arguments.of(cfg)); - } - return retVal; - } - - public static List provideAggregateTestConfigs() { - List retVal = new ArrayList<>(); - for (RegressionTestConfig cfg : buildConfigsForAggregateTests()) { - retVal.add(Arguments.of(cfg)); - } - return retVal; - } - - private static final String[] nonDeprecatedHeuristics() { - final List nonDeprecatedHeuristicsNames = new ArrayList<>(); - for (Field field : Heuristic.class.getFields()) { - if (field.getAnnotation(Deprecated.class) == null) { - nonDeprecatedHeuristicsNames.add(field.getName()); - } - } - return nonDeprecatedHeuristicsNames.toArray(new String[] {}); - } -} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/TestableChoiceManager.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/TestableChoiceManager.java deleted file mode 100644 index 50eaa2443..000000000 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/TestableChoiceManager.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2017-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.solver; - -import org.apache.commons.lang3.tuple.Pair; - -import java.util.Map; -import java.util.Set; - -/** - * This class is only here to make {@link ChoiceManager#addChoiceInformation(Pair)} public so that unit tests can access it. - * - * Copyright (c) 2017 Siemens AG - * - */ -public class TestableChoiceManager extends ChoiceManager { - - public TestableChoiceManager(WritableAssignment assignment, NoGoodStore store) { - super(assignment, store); - } - - @Override - public void addChoiceInformation(Pair, Map> choiceAtoms, Map> headsToBodies) { - super.addChoiceInformation(choiceAtoms, headsToBodies); - } - -} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignmentTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignmentTest.java index 72100a72b..1c9265d3d 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignmentTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignmentTest.java @@ -27,18 +27,6 @@ */ package at.ac.tuwien.kr.alpha.core.solver; -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.IntIterator; -import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; - 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; @@ -48,6 +36,19 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +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.IntIterator; +import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; + /** * Copyright (c) 2018-2020, the Alpha Team. */ 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 a3bd04475..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 @@ -29,27 +29,30 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Arrays; import java.util.Collection; -import java.util.function.Function; +import java.util.List; 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.config.SystemConfig; -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.commons.Predicates; 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.programs.transformation.NormalizeProgramTransformation; +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.TestableChoiceManager; import at.ac.tuwien.kr.alpha.core.solver.TrailAssignment; import at.ac.tuwien.kr.alpha.core.solver.WritableAssignment; @@ -63,30 +66,39 @@ */ public class AlphaHeuristicTestAssumptions { - private final ProgramParser parser = new ProgramParserImpl(); - private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); - private final Function parseAndPreprocess = (str) -> { - return InternalProgram.fromNormalProgram(normalizer.apply(parser.parse(str))); - }; - private Grounder grounder; private WritableAssignment assignment; - private TestableChoiceManager choiceManager; + private ChoiceManager choiceManager; private AtomStore atomStore; @BeforeEach public void setUp() { - String testProgram = "" - + "b1." - + "b2." - + "{b3}." - + "{b4}." - + "h :- b1, b2, not b3, not b4."; - CompiledProgram internalProgram = parseAndPreprocess.apply(testProgram); + /* program := + * b1. b2. + * b3 :- not nb3. + * nb3 :- not b3. + * b4 :- not nb4. + * nb4 :- not b4. + * h :- b1, b2, not b3, not b4. + */ + List facts = Arrays.asList(Atoms.newBasicAtom(Predicates.getPredicate("b1", 0)), Atoms.newBasicAtom(Predicates.getPredicate("b2", 0))); + List rules = Arrays.asList( + 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), + Atoms.newBasicAtom(Predicates.getPredicate("b4", 0)).toLiteral(false)) + ); + CompiledProgram program = new InternalProgram(rules, facts); + atomStore = new AtomStoreImpl(); - grounder = new NaiveGrounder(internalProgram, atomStore, true); + grounder = new NaiveGrounder(program, atomStore, true); assignment = new TrailAssignment(atomStore); - choiceManager = new TestableChoiceManager(assignment, new NaiveNoGoodStore(assignment)); + choiceManager = new ChoiceManager(assignment, new NaiveNoGoodStore(assignment)); } @Test diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearnerTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearnerTest.java index b7ea7ef40..229f78755 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearnerTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/learning/GroundConflictNoGoodLearnerTest.java @@ -1,7 +1,6 @@ package at.ac.tuwien.kr.alpha.core.solver.learning; import static at.ac.tuwien.kr.alpha.core.common.NoGoodTest.fromOldLiterals; -import static at.ac.tuwien.kr.alpha.core.solver.AntecedentTest.antecedentsEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -71,7 +70,7 @@ public void smallConflictNonTrivial1UIP() { assertNotNull(conflictCause); Antecedent violatedNoGood = conflictCause.getAntecedent(); assertNotNull(violatedNoGood); - assertTrue(antecedentsEquals(violatedNoGood, n5.asAntecedent()) || antecedentsEquals(violatedNoGood, n7.asAntecedent())); + assertTrue(TestUtils.antecedentsEquals(violatedNoGood, n5.asAntecedent()) || TestUtils.antecedentsEquals(violatedNoGood, n7.asAntecedent())); GroundConflictNoGoodLearner.ConflictAnalysisResult analysisResult = learner.analyzeConflictingNoGood(conflictCause.getAntecedent()); NoGood learnedNoGood = analysisResult.learnedNoGood; assertEquals(new NoGood(fromOldLiterals(1, -8)), learnedNoGood); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/AnswerSetsParser.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/AnswerSetsParser.java deleted file mode 100644 index b78ebc20c..000000000 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/AnswerSetsParser.java +++ /dev/null @@ -1,44 +0,0 @@ -package at.ac.tuwien.kr.alpha.core.test.util; - -import java.util.Collections; -import java.util.Set; - -import org.antlr.v4.runtime.BailErrorStrategy; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.RecognitionException; -import org.antlr.v4.runtime.atn.PredictionMode; -import org.antlr.v4.runtime.misc.ParseCancellationException; - -import at.ac.tuwien.kr.alpha.api.AnswerSet; -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; - -public class AnswerSetsParser { - - private static final ParseTreeVisitor VISITOR = new ParseTreeVisitor(Collections.emptyMap(), false); - - public static Set parse(String s) { - try { - return parse(CharStreams.fromString(s)); - } catch (RecognitionException | ParseCancellationException e) { - // If there were issues parsing the given string, we - // throw something that suggests that the input string - // is malformed. - throw new IllegalArgumentException("Could not parse answer sets.", e); - } - } - - public static Set parse(CharStream stream) { - final ASPCore2Parser parser = new ASPCore2Parser(new CommonTokenStream(new ASPCore2Lexer(stream))); - - // Try SLL parsing mode (faster but may terminate incorrectly). - parser.getInterpreter().setPredictionMode(PredictionMode.SLL); - parser.removeErrorListeners(); - parser.setErrorHandler(new BailErrorStrategy()); - - return VISITOR.translate(parser.answer_sets()); - } -} 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 bd0c358c1..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 @@ -2,29 +2,19 @@ import static java.util.Collections.emptySet; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.StringJoiner; import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.junit.jupiter.api.Assumptions; -import org.junit.jupiter.api.function.Executable; - import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.Solver; -import at.ac.tuwien.kr.alpha.api.config.Heuristic; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; -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.Program; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; @@ -34,17 +24,9 @@ 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.common.NoGood; -import at.ac.tuwien.kr.alpha.core.grounder.Grounder; -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.AnalyzedProgram; -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.programs.transformation.StratifiedEvaluation; -import at.ac.tuwien.kr.alpha.core.solver.RegressionTestConfig; -import at.ac.tuwien.kr.alpha.core.solver.SolverFactory; +import at.ac.tuwien.kr.alpha.core.solver.Antecedent; +import at.ac.tuwien.kr.alpha.test.AnswerSetsParser; public class TestUtils { @@ -55,25 +37,30 @@ public static void fillAtomStore(AtomStore atomStore, int numberOfAtomsToFill) { } } - public static Atom atom(String predicateName, String... termStrings) { - Term[] terms = new Term[termStrings.length]; - for (int i = 0; i < termStrings.length; i++) { - String termString = termStrings[i]; - if (StringUtils.isAllUpperCase(termString.substring(0, 1))) { - terms[i] = Terms.newVariable(termString); - } else { - terms[i] = Terms.newConstant(termString); - } + /** + * Tests whether two Antecedent objects have the same reason literals (irrespective of their order). + * Note that both Antecedents are assumed to contain no duplicate literals. + * @param l left Antecedent. + * @param r right Antecedent + * @return true iff both Antecedents contain the same literals. + */ + public static boolean antecedentsEquals(Antecedent l, Antecedent r) { + if (l == r) { + return true; } - return Atoms.newBasicAtom(Predicates.getPredicate(predicateName, terms.length), terms); - } - - public 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]); + if (l != null && r != null && l.getReasonLiterals().length == r.getReasonLiterals().length) { + HashSet lSet = new HashSet<>(); + for (int literal : l.getReasonLiterals()) { + lSet.add(literal); + } + for (int literal : r.getReasonLiterals()) { + if (!lSet.contains(literal)) { + return false; + } + } + return true; } - return Atoms.newBasicAtom(Predicates.getPredicate(predicateName, terms.length), terms); + return false; } public static void printNoGoods(AtomStore atomStore, Collection noGoods) { @@ -154,66 +141,4 @@ public static BasicAtom basicAtomWithSymbolicTerms(String predicate, String... c return Atoms.newBasicAtom(pred, trms); } - private static Solver buildSolverFromSystemConfig(ASPCore2Program prog, SystemConfig cfg) { - AtomStore atomStore = new AtomStoreImpl(); - NormalProgram normalProg = new NormalizeProgramTransformation(cfg.getAggregateRewritingConfig()).apply(prog); - InternalProgram preprocessed = cfg.isEvaluateStratifiedPart() ? new StratifiedEvaluation().apply(AnalyzedProgram.analyzeNormalProgram(normalProg)) - : InternalProgram.fromNormalProgram(normalProg); - return SolverFactory.getInstance(cfg, atomStore, GrounderFactory.getInstance(cfg.getGrounderName(), preprocessed, atomStore, cfg.isDebugInternalChecks())); - } - - public static Solver buildSolverForRegressionTest(ASPCore2Program prog, RegressionTestConfig cfg) { - return buildSolverFromSystemConfig(prog, cfg.toSystemConfig()); - } - - public static Solver buildSolverForRegressionTest(String prog, RegressionTestConfig cfg) { - return buildSolverFromSystemConfig(new ProgramParserImpl().parse(prog), cfg.toSystemConfig()); - } - - public static Solver buildSolverForRegressionTest(AtomStore atomStore, Grounder grounder, RegressionTestConfig cfg) { - SystemConfig systemCfg = cfg.toSystemConfig(); - return SolverFactory.getInstance(systemCfg, atomStore, grounder); - } - - public static Set collectRegressionTestAnswerSets(ASPCore2Program prog, RegressionTestConfig cfg) { - return buildSolverForRegressionTest(prog, cfg).collectSet(); - } - - public static Set collectRegressionTestAnswerSets(String aspstr, RegressionTestConfig cfg) { - ASPCore2Program prog = new ProgramParserImpl().parse(aspstr); - return collectRegressionTestAnswerSets(prog, cfg); - } - - public static void assertRegressionTestAnswerSet(RegressionTestConfig cfg, String program, String answerSet) { - Set actualAnswerSets = collectRegressionTestAnswerSets(program, cfg); - TestUtils.assertAnswerSetsEqual(answerSet, actualAnswerSets); - } - - public static void assertRegressionTestAnswerSets(RegressionTestConfig cfg, String program, String... answerSets) { - Set actualAnswerSets = collectRegressionTestAnswerSets(program, cfg); - TestUtils.assertAnswerSetsEqual(answerSets, actualAnswerSets); - } - - public static void assertRegressionTestAnswerSetsWithBase(RegressionTestConfig cfg, String program, String base, String... answerSets) { - Set actualAnswerSets = collectRegressionTestAnswerSets(program, cfg); - TestUtils.assertAnswerSetsEqualWithBase(base, answerSets, actualAnswerSets); - } - - public static void runWithTimeout(RegressionTestConfig cfg, long baseTimeout, long timeoutFactor, Executable action) { - long timeout = cfg.isDebugChecks() ? timeoutFactor * baseTimeout : baseTimeout; - assertTimeoutPreemptively(Duration.ofMillis(timeout), action); - } - - public static void ignoreTestForNaiveSolver(RegressionTestConfig cfg) { - Assumptions.assumeFalse(cfg.getSolverName().equals("naive")); - } - - public static void ignoreTestForNonDefaultDomainIndependentHeuristics(RegressionTestConfig cfg) { - Assumptions.assumeTrue(cfg.getBranchingHeuristic() == Heuristic.VSIDS); - } - - public static void ignoreTestForSimplifiedSumAggregates(RegressionTestConfig cfg) { - Assumptions.assumeTrue(cfg.isSupportNegativeSumElements()); - } - } 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 new file mode 100644 index 000000000..cce21dafa --- /dev/null +++ b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AlphaAssertions.java @@ -0,0 +1,75 @@ +package at.ac.tuwien.kr.alpha.test; + + +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 static java.util.Collections.emptySet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AlphaAssertions { + + public static void assertAnswerSetsEqual(Set expected, Set actual) { + if (expected == null) { + if (actual != null) { + throw new AssertionError("Expected answer sets are null, but actual are not!"); + } + } + try { + assertEquals(expected, actual); + } catch (AssertionError e) { + Set expectedMinusActual = new LinkedHashSet<>(expected); + expectedMinusActual.removeAll(actual); + Set actualMinusExpected = new LinkedHashSet<>(actual); + actualMinusExpected.removeAll(expected); + String setDiffs = "Expected and actual answer sets do not agree, differences are:\nExpected \\ Actual:\n" + expectedMinusActual + + "\nActual \\ Expected:\n" + actualMinusExpected; + throw new AssertionError(setDiffs + e.getMessage(), e); + } + } + + public static void assertAnswerSetsEqual(String[] expected, Set actual) { + if (expected.length == 0) { + assertAnswerSetsEqual(emptySet(), actual); + return; + } + StringJoiner joiner = new StringJoiner("} {", "{", "}"); + Arrays.stream(expected).forEach(joiner::add); + assertAnswerSetsEqual(AnswerSetsParser.parse(joiner.toString()), actual); + } + + public static void assertAnswerSetsEqual(String expectedAnswerSet, Set actual) { + assertAnswerSetsEqual(AnswerSetsParser.parse("{ " + expectedAnswerSet + " }"), actual); + } + + public static void assertAnswerSetsEqualWithBase(String base, String[] expectedAnswerSets, Set actual) { + base = base.trim(); + if (!base.endsWith(",")) { + base += ", "; + } + + for (int i = 0; i < expectedAnswerSets.length; i++) { + expectedAnswerSets[i] = base + expectedAnswerSets[i]; + // Remove trailing ",". + expectedAnswerSets[i] = expectedAnswerSets[i].trim(); + if (expectedAnswerSets[i].endsWith(",")) { + expectedAnswerSets[i] = expectedAnswerSets[i].substring(0, expectedAnswerSets[i].length() - 1); + } + } + assertAnswerSetsEqual(expectedAnswerSets, actual); + } + + public static void assertFactsContainedInProgram(Program prog, Atom... facts) { + for (Atom fact : facts) { + assertTrue(prog.getFacts().contains(fact)); + } + } + +} diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AnswerSetsParser.java b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AnswerSetsParser.java similarity index 98% rename from alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AnswerSetsParser.java rename to alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AnswerSetsParser.java index 93515666b..34f60e7c5 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/AnswerSetsParser.java +++ b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/AnswerSetsParser.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.api.impl; +package at.ac.tuwien.kr.alpha.test; import java.util.Collections; import java.util.Set; 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-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/RuleParser.java b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/RuleParser.java similarity index 80% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/RuleParser.java rename to alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/RuleParser.java index 5381de504..d66576a44 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/test/util/RuleParser.java +++ b/alpha-core/src/testFixtures/java/at/ac/tuwien/kr/alpha/test/RuleParser.java @@ -1,6 +1,6 @@ -package at.ac.tuwien.kr.alpha.core.test.util; +package at.ac.tuwien.kr.alpha.test; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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.rules.Rule; import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; @@ -10,7 +10,7 @@ public class RuleParser { public static Rule parse(String str) { ProgramParser parser = new ProgramParserImpl(); - ASPCore2Program prog = parser.parse(str); + InputProgram prog = parser.parse(str); if (!prog.getFacts().isEmpty()) { throw new IllegalArgumentException("Expected exactly one rule and no facts!"); } diff --git a/alpha-core/benchmarks/omiga/omiga-testcases.tar.gz b/alpha-solver/benchmarks/omiga/omiga-testcases.tar.gz similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases.tar.gz rename to alpha-solver/benchmarks/omiga/omiga-testcases.tar.gz diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/3col/3col-10-18.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/3col/3col-10-18.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/3col/3col-10-18.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/3col/3col-10-18.txt diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/3col/3col-20-38.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/3col/3col-20-38.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/3col/3col-20-38.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/3col/3col-20-38.txt diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-30.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-30.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-30.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-30.txt diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-50.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-50.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-50.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/cutedge/cutedge-100-50.txt diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/locstrat/locstrat-200.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/locstrat/locstrat-200.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/locstrat/locstrat-200.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/locstrat/locstrat-200.txt diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/locstrat/locstrat-400.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/locstrat/locstrat-400.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/locstrat/locstrat-400.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/locstrat/locstrat-400.txt diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/reach/reach-1.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/reach/reach-1.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/reach/reach-1.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/reach/reach-1.txt diff --git a/alpha-core/benchmarks/omiga/omiga-testcases/reach/reach-4.txt b/alpha-solver/benchmarks/omiga/omiga-testcases/reach/reach-4.txt similarity index 100% rename from alpha-core/benchmarks/omiga/omiga-testcases/reach/reach-4.txt rename to alpha-solver/benchmarks/omiga/omiga-testcases/reach/reach-4.txt diff --git a/alpha-core/benchmarks/siemens/racks/racks.lp b/alpha-solver/benchmarks/siemens/racks/racks.lp similarity index 100% rename from alpha-core/benchmarks/siemens/racks/racks.lp rename to alpha-solver/benchmarks/siemens/racks/racks.lp diff --git a/alpha-solver/build.gradle.kts b/alpha-solver/build.gradle.kts index b0c59c197..aff85c7cc 100644 --- a/alpha-solver/build.gradle.kts +++ b/alpha-solver/build.gradle.kts @@ -6,6 +6,8 @@ dependencies { api(project(":alpha-api")) api(project(":alpha-commons")) implementation(project(":alpha-core")) + + testImplementation(testFixtures(project(":alpha-core"))) } tasks.test { 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 new file mode 100644 index 000000000..9905d39f5 --- /dev/null +++ b/alpha-solver/src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaFactory.java @@ -0,0 +1,99 @@ +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.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 class AlphaFactory { + + protected ProgramTransformation newProgramNormalizer(AggregateRewritingConfig aggregateCfg) { + return new NormalizeProgramTransformation(aggregateCfg); + } + + protected Supplier newStratifiedEvaluationFactory(ActionImplementationProvider actionImplementationProvider, + boolean generateActionWitnesses) { + return () -> new StratifiedEvaluation(new ActionExecutionServiceImpl(actionImplementationProvider), generateActionWitnesses); + } + + protected GrounderFactory newGrounderFactory(SystemConfig cfg) { + GrounderHeuristicsConfiguration grounderHeuristicsCfg = GrounderHeuristicsConfiguration.getInstance(cfg.getGrounderToleranceConstraints(), + cfg.getGrounderToleranceRules()); + grounderHeuristicsCfg.setAccumulatorEnabled(cfg.isGrounderAccumulatorEnabled()); + return new GrounderFactory( + grounderHeuristicsCfg, + cfg.isDebugInternalChecks()); + } + + protected SolverFactory newSolverFactory(SystemConfig cfg) { + SolverConfig solverCfg = new SolverConfig(); + solverCfg.setDisableJustifications(cfg.isDisableJustificationSearch()); + solverCfg.setDisableNogoodDeletion(cfg.isDisableNoGoodDeletion()); + solverCfg.setEnableDebugChecks(cfg.isDebugInternalChecks()); + solverCfg.setRandomSeed(cfg.getSeed()); + solverCfg.setHeuristicsConfiguration( + HeuristicsConfiguration.builder() + .setHeuristic(cfg.getBranchingHeuristic()) + .setMomsStrategy(cfg.getMomsStrategy()) + .setReplayChoices(cfg.getReplayChoices()) + .build()); + 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(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 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 8534b91b4..342d38ecc 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 @@ -32,10 +32,8 @@ import at.ac.tuwien.kr.alpha.api.DebugSolvingContext; import at.ac.tuwien.kr.alpha.api.Solver; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; -import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; 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.ASPCore2Program; +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.ProgramParser; @@ -44,21 +42,18 @@ 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.ASPCore2ProgramBuilder; +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.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.commons.util.Util; 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.Grounder; 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.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.transformation.NormalizeProgramTransformation; +import at.ac.tuwien.kr.alpha.core.programs.transformation.ModuleLinker; +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; @@ -76,6 +71,7 @@ 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; @@ -83,29 +79,35 @@ public class AlphaImpl implements Alpha { private static final Logger LOGGER = LoggerFactory.getLogger(AlphaImpl.class); - private final SystemConfig config; // Config is initialized with default values. - private final ProgramParser parser = new ProgramParserImpl(); - + private final ProgramParser parser; + private final ProgramTransformation programNormalization; + private final Supplier stratifiedEvaluationFactory; + private final GrounderFactory grounderFactory; + private final SolverFactory solverFactory; private final TestRunner testRunner; - private final Reifier reifier = new Reifier(() -> { - IdGenerator idGen = new IntIdGenerator(0); - return () -> Terms.newConstant(idGen.getNextId()); - }); - - - public AlphaImpl(SystemConfig cfg) { - this.config = cfg; + private final Reifier reifier; + private final boolean sortAnswerSets; + + AlphaImpl(ProgramParser parser, ProgramTransformation programNormalization, + Supplier stratifiedEvaluationFactory, + GrounderFactory grounderFactory, + SolverFactory solverFactory, + Reifier reifier, + boolean sortAnswerSets) { + this.parser = parser; + this.programNormalization = programNormalization; + this.stratifiedEvaluationFactory = stratifiedEvaluationFactory; + this.grounderFactory = grounderFactory; + this.solverFactory = solverFactory; + this.reifier = reifier; this.testRunner = new TestRunner(this); - } - - public AlphaImpl() { - this(new SystemConfig()); + this.sortAnswerSets = sortAnswerSets; } @Override - public ASPCore2Program readProgram(InputConfig cfg) throws IOException { - ASPCore2ProgramBuilder prgBuilder = Programs.builder(); - ASPCore2Program tmpProg; + public InputProgram readProgram(InputConfig cfg) throws IOException { + InputProgramBuilder prgBuilder = Programs.builder(); + InputProgram tmpProg; if (!cfg.getFiles().isEmpty()) { tmpProg = readProgramFiles(cfg.isLiterate(), cfg.getPredicateMethods(), cfg.getFiles()); prgBuilder.accumulate(tmpProg); @@ -118,14 +120,14 @@ public ASPCore2Program readProgram(InputConfig cfg) throws IOException { } @Override - public ASPCore2Program readProgramFiles(boolean literate, Map externals, List paths) throws IOException { - return readProgramFiles(literate, externals, paths.stream().map(Paths::get).collect(Collectors.toList()).toArray(new Path[] {})); + 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[]{})); } @Override - public ASPCore2Program readProgramFiles(boolean literate, Map externals, Path... paths) throws IOException { - ASPCore2ProgramBuilder prgBuilder = Programs.builder(); - ASPCore2Program tmpProg; + public InputProgram readProgramFiles(boolean literate, Map externals, Path... paths) throws IOException { + InputProgramBuilder prgBuilder = Programs.builder(); + InputProgram tmpProg; for (Path path : paths) { InputStream stream; if (!literate) { @@ -140,29 +142,36 @@ public ASPCore2Program readProgramFiles(boolean literate, Map externals) { + public InputProgram readProgramString(String aspString, Map externals) { return parser.parse(aspString, externals); } @Override - public ASPCore2Program readProgramString(String aspString) { + public InputProgram readProgramString(String aspString) { return readProgramString(aspString, Collections.emptyMap()); } @Override - public NormalProgram normalizeProgram(ASPCore2Program program) { - return new NormalizeProgramTransformation(config.getAggregateRewritingConfig()).apply(program); + 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 programNormalization.apply(program); } @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { LOGGER.debug("Preprocessing InternalProgram!"); - InternalProgram retVal = InternalProgram.fromNormalProgram(program); - if (config.isEvaluateStratifiedPart()) { - AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); - retVal = new StratifiedEvaluation().apply(analyzed); - } - return retVal; + NormalProgram linkedProgram = new ModuleLinker(this).apply(program); + AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(linkedProgram); + return stratifiedEvaluationFactory.get().apply(analyzed); } /** @@ -170,7 +179,7 @@ InternalProgram performProgramPreprocessing(NormalProgram program) { * program analysis and normalization aren't of interest. */ @Override - public Stream solve(ASPCore2Program program) { + public Stream solve(InputProgram program) { return solve(program, InputConfig.DEFAULT_FILTER); } @@ -179,7 +188,7 @@ public Stream solve(ASPCore2Program program) { * details of the program analysis and normalization aren't of interest. */ @Override - public Stream solve(ASPCore2Program program, java.util.function.Predicate filter) { + public Stream solve(InputProgram program, java.util.function.Predicate filter) { NormalProgram normalized = normalizeProgram(program); return solve(normalized, filter); } @@ -201,41 +210,33 @@ 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) { Stream retVal = prepareSolverFor(program, filter).stream(); - return config.isSortAnswerSets() ? retVal.sorted() : retVal; + return sortAnswerSets ? retVal.sorted() : retVal; } /** * 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. * @return a solver (and accompanying grounder) instance pre-loaded with the given program. */ private Solver prepareSolverFor(CompiledProgram program, java.util.function.Predicate filter) { - String grounderName = config.getGrounderName(); - boolean doDebugChecks = config.isDebugInternalChecks(); - - GrounderHeuristicsConfiguration grounderHeuristicConfiguration = GrounderHeuristicsConfiguration - .getInstance(config.getGrounderToleranceConstraints(), config.getGrounderToleranceRules()); - grounderHeuristicConfiguration.setAccumulatorEnabled(config.isGrounderAccumulatorEnabled()); - AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance(grounderName, program, atomStore, filter, grounderHeuristicConfiguration, doDebugChecks); - - return SolverFactory.getInstance(config, atomStore, grounder); + Grounder grounder = grounderFactory.createGrounder(program, atomStore, filter); + return solverFactory.createSolver(grounder, atomStore); } @Override - public DebugSolvingContext prepareDebugSolve(ASPCore2Program program) { + public DebugSolvingContext prepareDebugSolve(InputProgram program) { return prepareDebugSolve(program, InputConfig.DEFAULT_FILTER); } @@ -245,7 +246,7 @@ public DebugSolvingContext prepareDebugSolve(NormalProgram program) { } @Override - public DebugSolvingContext prepareDebugSolve(final ASPCore2Program program, java.util.function.Predicate filter) { + public DebugSolvingContext prepareDebugSolve(final InputProgram program, java.util.function.Predicate filter) { return prepareDebugSolve(normalizeProgram(program), filter); } @@ -253,13 +254,10 @@ public DebugSolvingContext prepareDebugSolve(final ASPCore2Program program, java public DebugSolvingContext prepareDebugSolve(final NormalProgram program, java.util.function.Predicate filter) { final DependencyGraph depGraph; final ComponentGraph compGraph; - final AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(program); + NormalProgram linkedProgram = new ModuleLinker(this).apply(program); + final AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(linkedProgram); final NormalProgram preprocessed; - if (this.config.isEvaluateStratifiedPart()) { - 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); @@ -294,7 +292,7 @@ public ComponentGraph getComponentGraph() { } @Override - public Solver prepareSolverFor(ASPCore2Program program, java.util.function.Predicate filter) { + public Solver prepareSolverFor(InputProgram program, java.util.function.Predicate filter) { return prepareSolverFor(normalizeProgram(program), filter); } @@ -304,12 +302,12 @@ public Solver prepareSolverFor(NormalProgram program, java.util.function.Predica } @Override - public Set reify(ASPCore2Program program) { + public Set reify(InputProgram program) { return reifier.reifyProgram(program); } @Override - public TestResult test(ASPCore2Program program) { + 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 index 2ac4bce95..48735f7e1 100644 --- 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 @@ -2,7 +2,7 @@ import at.ac.tuwien.kr.alpha.api.Alpha; import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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; @@ -27,7 +27,7 @@ class TestRunner { this.alpha = alpha; } - TestResult test(ASPCore2Program program) { + TestResult test(InputProgram program) { LOGGER.info("Running unit tests.."); NormalProgram programUnderTest = alpha.normalizeProgram(program); List testCaseResults = program.getTestCases().stream() @@ -40,7 +40,7 @@ private TestResult.TestCaseResult runTestCase(NormalProgram programUnderTest, Te 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()); + NormalProgram prog = Programs.newNormalProgram(programUnderTest.getRules(), facts, programUnderTest.getInlineDirectives(), programUnderTest.getModules()); Set answerSets; try { answerSets = alpha.solve(prog).collect(Collectors.toSet()); @@ -103,7 +103,7 @@ private List evaluateAssertion(Set answerSets, Assertion asse } private boolean answerSetSatisfiesAssertion(AnswerSet as, Assertion assertion) { - ASPCore2Program verifierWithInput = Programs.builder(assertion.getVerifier()).addFacts(new ArrayList<>(as.asFacts())).build(); + 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..cf9d627f7 --- /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!\n", 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!\n", dummyFileContent.toString()); + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateLiteralSplittingTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateLiteralSplittingTest.java similarity index 96% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateLiteralSplittingTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateLiteralSplittingTest.java index 13df2386e..9481ebc5f 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateLiteralSplittingTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateLiteralSplittingTest.java @@ -1,15 +1,15 @@ -package at.ac.tuwien.kr.alpha.core.programs.transformation.aggregates; +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.programs.rules.Rule; -import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; -import at.ac.tuwien.kr.alpha.core.test.util.RuleParser; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class AggregateLiteralSplittingTest { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalizationTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateOperatorNormalizationTest.java similarity index 96% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalizationTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateOperatorNormalizationTest.java index 3b8870c04..72ecd207b 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateOperatorNormalizationTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateOperatorNormalizationTest.java @@ -1,10 +1,4 @@ -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.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; +package at.ac.tuwien.kr.alpha; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; @@ -17,7 +11,11 @@ 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.programs.terms.Terms; -import at.ac.tuwien.kr.alpha.core.test.util.RuleParser; +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.*; public class AggregateOperatorNormalizationTest { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingContextTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingContextTest.java similarity index 96% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingContextTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingContextTest.java index 969f26412..e872f081e 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingContextTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingContextTest.java @@ -1,17 +1,7 @@ -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.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; +package at.ac.tuwien.kr.alpha; import at.ac.tuwien.kr.alpha.api.ComparisonOperator; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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.rules.Rule; import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; @@ -19,7 +9,17 @@ import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; 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; public class AggregateRewritingContextTest { @@ -58,7 +58,7 @@ public class AggregateRewritingContextTest { //@formatter:on private static final AggregateRewritingContext rewritingContextForAspString(String asp) { - ASPCore2Program program = new ProgramParserImpl().parse(asp); + InputProgram program = new ProgramParserImpl().parse(asp); AggregateRewritingContext ctx = new AggregateRewritingContext(); for (Rule rule : program.getRules()) { ctx.registerRule(rule); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingTest.java similarity index 81% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingTest.java index 288b52fbd..6fa33a5ba 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/aggregates/AggregateRewritingTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/AggregateRewritingTest.java @@ -1,47 +1,27 @@ -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.assertTrue; - -import java.util.List; -import java.util.function.Function; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; +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.Solver; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; -import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; +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.api.programs.ProgramParser; +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 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.Grounder; -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.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.SolverFactory; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; -public class AggregateRewritingTest { +import java.util.List; +import java.util.SortedSet; +import java.util.function.Function; +import java.util.stream.Collectors; - private static final ProgramParser PARSER = new ProgramParserImpl(); - private static final Function> NORMALIZE_AND_SOLVE = (str) -> { - SystemConfig cfg = new SystemConfig(); - ASPCore2Program prog = PARSER.parse(str); - NormalProgram normalized = new NormalizeProgramTransformation(cfg.getAggregateRewritingConfig()).apply(prog); - CompiledProgram compiled = InternalProgram.fromNormalProgram(normalized); - AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance("naive", compiled, atomStore, cfg.isDebugInternalChecks()); - Solver solver = SolverFactory.getInstance(cfg, atomStore, grounder); - return solver.collectList(); - }; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AggregateRewritingTest { //@formatter:off // Smoke-test case for "X <= #count{...}" aggregate @@ -97,11 +77,22 @@ public class AggregateRewritingTest { "p(1..10)." + "q :- X = #count { Y : p( Y ) }, X = #count { Z : p( Z ) }," + " Y = #count { X : p( X ) }, 1 <= #count { X : p( X ) }, Z = #max { W : p( W ) }."; + + private static final String LIST_COLLECT = + "p(1). p(2). p(3)." + + " q(X) :- X = #list{ Y : p(Y) }."; //@formatter:on + // Use an alpha instance with default config for all test cases + private final Alpha alpha = AlphaFactory.newAlpha(); + private final Function> solve = (asp) -> { + InputProgram prog = alpha.readProgramString(asp); + return alpha.solve(prog).collect(Collectors.toList()); + }; + @Test public void countLeSortingGridSimple() { - List answerSets = NORMALIZE_AND_SOLVE.apply(CNT_LE1_ASP); + List answerSets = solve.apply(CNT_LE1_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate thing = Predicates.getPredicate("thing", 1); @@ -123,7 +114,7 @@ public void countLeSortingGridSimple() { @Test public void countEqSimple() { - List answerSets = NORMALIZE_AND_SOLVE.apply(CNT_EQ1_ASP); + List answerSets = solve.apply(CNT_EQ1_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate thing = Predicates.getPredicate("thing", 1); @@ -141,7 +132,7 @@ public void countEqSimple() { @Test public void countLeCountingGridSimple() { - List answerSets = NORMALIZE_AND_SOLVE.apply(CNT_LE1_ASP); + List answerSets = solve.apply(CNT_LE1_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate thing = Predicates.getPredicate("thing", 1); @@ -163,7 +154,7 @@ public void countLeCountingGridSimple() { @Test public void countEqGlobalVars() { - List answerSets = NORMALIZE_AND_SOLVE.apply(VERTEX_DEGREE_ASP); + List answerSets = solve.apply(VERTEX_DEGREE_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate vertexDegree = Predicates.getPredicate("graph_vertex_degree", 3); @@ -182,7 +173,7 @@ public void countEqGlobalVars() { @Test // Test "count eq" and "max eq" together with global vars public void graphVerticesOfMaxDegree() { - List answerSets = NORMALIZE_AND_SOLVE.apply(NUM_MAX_DEGREE_VERTICES_ASP); + List answerSets = solve.apply(NUM_MAX_DEGREE_VERTICES_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate maxDegreeVertices = Predicates.getPredicate("graph_max_degree_vertices", 3); @@ -196,7 +187,7 @@ public void graphVerticesOfMaxDegree() { @Test public void greaterMin() { - List answerSets = NORMALIZE_AND_SOLVE.apply(MIN_GT1_ASP); + List answerSets = solve.apply(MIN_GT1_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate greaterMin = Predicates.getPredicate("greater_min_acceptable", 1); @@ -210,7 +201,7 @@ public void greaterMin() { @Test public void sumEquals1() { - List answerSets = NORMALIZE_AND_SOLVE.apply(SUM_EQ1_ASP); + List answerSets = solve.apply(SUM_EQ1_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate sumThings = Predicates.getPredicate("sum_things", 1); @@ -224,7 +215,7 @@ public void sumEquals1() { @Test public void sumLessOrEqual1() { - List answerSets = NORMALIZE_AND_SOLVE.apply(SUM_LE1_ASP); + List answerSets = solve.apply(SUM_LE1_ASP); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate boundLe = Predicates.getPredicate("bound_le_sum", 1); @@ -238,7 +229,7 @@ public void sumLessOrEqual1() { @Test @Disabled("Open issue, as dependency analysis includes cyclic output-dependency, which it should not.") public void setComplexEqualityWithGlobals() { - List answerSets = NORMALIZE_AND_SOLVE.apply(COMPLEX_EQUALITY_WITH_GLOBALS); + List answerSets = solve.apply(COMPLEX_EQUALITY_WITH_GLOBALS); assertEquals(1, answerSets.size()); AnswerSet answerSet = answerSets.get(0); Predicate q = Predicates.getPredicate("q", 0); @@ -249,4 +240,18 @@ public void setComplexEqualityWithGlobals() { assertTrue(answerSet.getPredicateInstances(q).contains(Atoms.newBasicAtom(q))); } + @Test + public void listCollect() { + List answerSets = solve.apply(LIST_COLLECT); + assertEquals(1, answerSets.size()); + AnswerSet answerSet = answerSets.get(0); + Predicate q = Predicates.getPredicate("q", 1); + SortedSet instances = answerSet.getPredicateInstances(q); + assertEquals(1, instances.size()); + Atom instance = instances.first(); + assertEquals(1, instance.getTerms().size()); + Term term = instance.getTerms().get(0); + assertEquals(Terms.asListTerm(List.of(Terms.newConstant(1), Terms.newConstant(2), Terms.newConstant(3))), term); + } + } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewritingTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ArithmeticTermsRewritingTest.java similarity index 95% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewritingTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ArithmeticTermsRewritingTest.java index e92589302..3c6e195de 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/ArithmeticTermsRewritingTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/ArithmeticTermsRewritingTest.java @@ -1,15 +1,4 @@ -package at.ac.tuwien.kr.alpha.core.programs.transformation; - -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; +package at.ac.tuwien.kr.alpha; import at.ac.tuwien.kr.alpha.api.common.fixedinterpretations.PredicateInterpretation; import at.ac.tuwien.kr.alpha.api.externals.Predicate; @@ -21,10 +10,21 @@ 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.programs.Programs; import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; -import at.ac.tuwien.kr.alpha.core.externals.Externals; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +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. diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/FixedInterpretationLiteralsTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/FixedInterpretationLiteralsTest.java similarity index 94% rename from alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/FixedInterpretationLiteralsTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/FixedInterpretationLiteralsTest.java index 690e39777..530040d78 100644 --- a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/api/impl/FixedInterpretationLiteralsTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/FixedInterpretationLiteralsTest.java @@ -1,30 +1,22 @@ -package at.ac.tuwien.kr.alpha.api.impl; - -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; +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.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.programs.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; +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.programs.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.programs.terms.Terms; -import at.ac.tuwien.kr.alpha.core.externals.AspStandardLibrary; -import at.ac.tuwien.kr.alpha.core.externals.Externals; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; public class FixedInterpretationLiteralsTest { @@ -79,7 +71,7 @@ public static Set>> connection(String dummy) { private Map externals; public FixedInterpretationLiteralsTest() { - this.alpha = new AlphaImpl(); + this.alpha = AlphaFactory.newAlpha(); this.externals = new HashMap<>(); this.externals.putAll(Externals.scan(AspStandardLibrary.class)); this.externals.putAll(Externals.scan(FixedInterpretationLiteralsTest.class)); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleToStringTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleToStringTest.java similarity index 93% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleToStringTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleToStringTest.java index 828f6f922..f099fb724 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/grounder/RuleToStringTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/RuleToStringTest.java @@ -23,15 +23,9 @@ * 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; -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.ASPCore2Program; +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.rules.Rule; import at.ac.tuwien.kr.alpha.api.programs.rules.heads.Head; @@ -39,10 +33,12 @@ 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 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(); @@ -97,7 +93,7 @@ private void constructNonGroundRuleAndCheckToString(String textualRule) { } private Rule parseSingleRule(String rule) { - ASPCore2Program program = parser.parse(rule); + InputProgram program = parser.parse(rule); List> rules = program.getRules(); assertEquals(1, rules.size(), "Number of rules"); return rules.get(0); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluationTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/StratifiedEvaluationTest.java similarity index 51% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluationTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/StratifiedEvaluationTest.java index 2cf6b1337..7c6c5fdae 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/StratifiedEvaluationTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/StratifiedEvaluationTest.java @@ -25,70 +25,52 @@ * 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.transformation; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; - -import org.junit.jupiter.api.Test; +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.Solver; +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.programs.ASPCore2Program; +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; 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.commons.Predicates; +import at.ac.tuwien.kr.alpha.commons.externals.Externals; 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.substitutions.Instance; -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.externals.Externals; -import at.ac.tuwien.kr.alpha.core.grounder.Grounder; -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.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.solver.SolverFactory; -import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; +import org.junit.jupiter.api.Test; -public class StratifiedEvaluationTest { +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; - private final ProgramParser parser = new ProgramParserImpl(); - private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); - private final StratifiedEvaluation evaluator = new StratifiedEvaluation(); - private final Function parseAndEvaluate = (str) -> { - return evaluator.apply(AnalyzedProgram.analyzeNormalProgram(normalizer.apply(parser.parse(str)))); - }; +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; + +public class StratifiedEvaluationTest { - private final Function> solveCompiledProg = (prog) -> { - AtomStore atomStore = new AtomStoreImpl(); - Grounder grounder = GrounderFactory.getInstance("naive", prog, atomStore, false); - Solver solver = SolverFactory.getInstance(new SystemConfig(), atomStore, grounder); - return solver.collectSet(); - }; + // Alpha instance with default configuration (evolog support and stratified evaluation enabled) + private final Alpha alpha = AlphaFactory.newAlpha(); + /** + * Verifies that facts are not duplicated by stratified evaluation. + */ @Test public void testDuplicateFacts() { String aspStr = "p(a). p(b). q(b). q(X) :- p(X)."; - CompiledProgram evaluated = parseAndEvaluate.apply(aspStr); - Instance qOfB = new Instance(TestUtils.basicAtomWithSymbolicTerms("q", "b").getTerms()); - Set facts = evaluated.getFactsByPredicate().get(Predicates.getPredicate("q", 1)); + DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(alpha.readProgramString(aspStr)); + NormalProgram evaluated = dbgInfo.getPreprocessedProgram(); + BasicAtom qOfB = Atoms.newBasicAtom(Predicates.getPredicate("q", 1), Terms.newSymbolicConstant("b")); int numQOfB = 0; - for (Instance at : facts) { - if (at.equals(qOfB)) { + for (Atom fact : evaluated.getFacts()) { + if (fact.equals(qOfB)) { numQOfB++; } } @@ -98,41 +80,39 @@ public void testDuplicateFacts() { @Test public void testEqualityWithConstantTerms() { String aspStr = "equal :- 1 = 1."; - CompiledProgram evaluated = parseAndEvaluate.apply(aspStr); - Atom equal = TestUtils.basicAtomWithSymbolicTerms("equal"); + DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(alpha.readProgramString(aspStr)); + NormalProgram evaluated = dbgInfo.getPreprocessedProgram(); + Atom equal = Atoms.newBasicAtom(Predicates.getPredicate("equal", 0)); assertTrue(evaluated.getFacts().contains(equal)); } @Test public void testEqualityWithVarTerms() { String aspStr = "a(1). a(2). a(3). b(X) :- a(X), X = 1. c(X) :- a(X), X = 2. d(X) :- X = 3, a(X)."; - CompiledProgram evaluated = parseAndEvaluate.apply(aspStr); - Set answerSets = solveCompiledProg.apply(evaluated); - TestUtils.assertAnswerSetsEqual("a(1), a(2), a(3), b(1), c(2), d(3)", answerSets); + Set answerSets = alpha.solve(alpha.readProgramString(aspStr)).collect(Collectors.toSet()); + assertAnswerSetsEqual("a(1), a(2), a(3), b(1), c(2), d(3)", answerSets); } @Test public void testNonGroundableRule() { String asp = "p(a). q(a, b). s(X, Y) :- p(X), q(X, Y), r(Y)."; - CompiledProgram evaluated = parseAndEvaluate.apply(asp); - Set answerSets = solveCompiledProg.apply(evaluated); - TestUtils.assertAnswerSetsEqual("p(a), q(a,b)", answerSets); + Set answerSets = alpha.solve(alpha.readProgramString(asp)).collect(Collectors.toSet()); + assertAnswerSetsEqual("p(a), q(a,b)", answerSets); } + @Test public void testCountAggregate() { String asp = "a. b :- 1 <= #count { 1 : a }."; - CompiledProgram evaluated = parseAndEvaluate.apply(asp); - Set answerSets = solveCompiledProg.apply(evaluated); - TestUtils.assertAnswerSetsEqual("a, b", answerSets); + Set answerSets = alpha.solve(alpha.readProgramString(asp)).collect(Collectors.toSet()); + assertAnswerSetsEqual("a, b", answerSets); } @Test public void testIntervalFact() { String asp = "a(1..3)."; - CompiledProgram evaluated = parseAndEvaluate.apply(asp); - Set answerSets = solveCompiledProg.apply(evaluated); - TestUtils.assertAnswerSetsEqual("a(1), a(2), a(3)", answerSets); + Set answerSets = alpha.solve(alpha.readProgramString(asp)).collect(Collectors.toSet()); + assertAnswerSetsEqual("a(1), a(2), a(3)", answerSets); } @Test @@ -141,18 +121,18 @@ public void testAggregateSpecial() { + "{ chosenThing(X) : thing(X) }.\n" + "chosenSomething :- chosenThing(X).\n" + ":- not chosenSomething.\n" + ":- chosenThing(X), chosenThing(Y), X != Y.\n" + "allThings :- 3 <= #count{ X : thing(X)}. \n" + "chosenMaxThing :- allThings, chosenThing(3).\n" + ":- not chosenMaxThing."; - CompiledProgram evaluated = parseAndEvaluate.apply(asp); - assertTrue(evaluated.getFacts().contains(TestUtils.basicAtomWithSymbolicTerms("allThings"))); - Set answerSets = solveCompiledProg.apply(evaluated); - TestUtils.assertAnswerSetsEqual("allThings, thing(1), thing(2), thing(3), chosenMaxThing, chosenSomething, chosenThing(3)", answerSets); + DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(alpha.readProgramString(asp)); + NormalProgram evaluated = dbgInfo.getPreprocessedProgram(); + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("allThings", 0)))); + Set answerSets = dbgInfo.getSolver().collectSet(); + assertAnswerSetsEqual("allThings, thing(1), thing(2), thing(3), chosenMaxThing, chosenSomething, chosenThing(3)", answerSets); } @Test public void testNegatedFixedInterpretationLiteral() { String asp = "stuff(1). stuff(2). smallStuff(X) :- stuff(X), not X > 1."; - CompiledProgram evaluated = parseAndEvaluate.apply(asp); - Set answerSets = solveCompiledProg.apply(evaluated); - TestUtils.assertAnswerSetsEqual("stuff(1), stuff(2), smallStuff(1)", answerSets); + Set answerSets = alpha.solve(alpha.readProgramString(asp)).collect(Collectors.toSet()); + assertAnswerSetsEqual("stuff(1), stuff(2), smallStuff(1)", answerSets); } @SuppressWarnings("unused") @@ -161,16 +141,14 @@ 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]."; Map externals = new HashMap<>(); externals.put("sayTrue", Externals.processPredicateMethod(this.getClass().getMethod("sayTrue", Object.class))); - ProgramParser parserWithExternals = new ProgramParserImpl(); - AnalyzedProgram analyzed = AnalyzedProgram.analyzeNormalProgram(normalizer.apply(parserWithExternals.parse(asp, externals))); - CompiledProgram evaluated = new StratifiedEvaluation().apply(analyzed); - Set answerSets = solveCompiledProg.apply(evaluated); - TestUtils.assertAnswerSetsEqual("claimedTruth(bla), truth(bla)", answerSets); + Set answerSets = alpha.solve(alpha.readProgramString(asp, externals)).collect(Collectors.toSet()); + assertAnswerSetsEqual("claimedTruth(bla), truth(bla)", answerSets); } /** @@ -179,8 +157,11 @@ public void testNegatedExternalLiteral() throws Exception { */ @Test public void testPartnerUnitsProblemTopologicalOrder() throws IOException { - ASPCore2Program prg = parser.parse(StratifiedEvaluationTest.class.getResourceAsStream("/partial-eval/pup_topological_order.asp")); - CompiledProgram evaluated = new StratifiedEvaluation().apply(AnalyzedProgram.analyzeNormalProgram(normalizer.apply(prg))); + InputProgram prg = alpha.readProgramStream( + StratifiedEvaluationTest.class.getResourceAsStream("/partial-eval/pup_topological_order.asp"), + new HashMap<>()); + DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(prg); + NormalProgram evaluated = dbgInfo.getPreprocessedProgram(); assertTrue(evaluated.getRules().isEmpty(), "Not all rules eliminated by stratified evaluation"); assertEquals(57, evaluated.getFacts().size()); } @@ -191,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 @@ -200,51 +187,48 @@ public void testNegatedLiteralInRecursiveRule() throws IOException { + "inc_value(4), inc_value(5), inc_value(6), inc_value(7), " + "inc_value(8)"; //@formatter:on - ASPCore2Program prog = new ProgramParserImpl().parse( + InputProgram prog = alpha.readProgramStream( StratifiedEvaluationTest.class.getResourceAsStream("/partial-eval/recursive_w_negated_condition.asp"), new HashMap<>()); // Run stratified evaluation and solve - CompiledProgram inputStratEval = new StratifiedEvaluation().apply(AnalyzedProgram.analyzeNormalProgram(normalizer.apply(prog))); - Set asStrat = solveCompiledProg.apply(inputStratEval); - TestUtils.assertAnswerSetsEqual(expectedAnswerSet, asStrat); - - // Solve without stratified evaluation - CompiledProgram inputNoStratEval = InternalProgram.fromNormalProgram(normalizer.apply(prog)); - Set as = solveCompiledProg.apply(inputNoStratEval); - TestUtils.assertAnswerSetsEqual(expectedAnswerSet, as); + 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 - CompiledProgram evaluated = parseAndEvaluate.apply(asp); + DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(alpha.readProgramString(asp)); + NormalProgram evaluated = dbgInfo.getPreprocessedProgram(); Predicate rank = Predicates.getPredicate("thing_rank", 2); BasicAtom rank1 = Atoms.newBasicAtom(rank, Terms.newSymbolicConstant("a"), Terms.newConstant(1)); BasicAtom rank2 = Atoms.newBasicAtom(rank, Terms.newSymbolicConstant("b"), Terms.newConstant(2)); 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 9a774a18b..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 @@ -32,8 +32,7 @@ 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.ASPCore2Program; -import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; +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; @@ -43,18 +42,18 @@ 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.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.programs.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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.common.fixedinterpretations.MethodPredicateInterpretation; -import at.ac.tuwien.kr.alpha.core.externals.AspStandardLibrary; -import at.ac.tuwien.kr.alpha.core.externals.Externals; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; +import at.ac.tuwien.kr.alpha.test.AnswerSetsParser; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -147,10 +146,10 @@ public static boolean thinger(Thingy thingy) { @Test public void withExternal() throws Exception { - Alpha alpha = new AlphaImpl(); + Alpha alpha = AlphaFactory.newAlpha(); InputConfig inputCfg = InputConfig.forString("a :- &isOne[1]."); inputCfg.addPredicateMethod("isOne", Externals.processPredicateMethod(this.getClass().getMethod("isOne", int.class))); - ASPCore2Program program = alpha.readProgram(inputCfg); + InputProgram program = alpha.readProgram(inputCfg); Set actual = alpha.solve(program).collect(Collectors.toSet()); Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("a").build())); assertEquals(expected, actual); @@ -158,20 +157,20 @@ public void withExternal() throws Exception { @Test public void addsFacts() { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); Thingy a = new Thingy(); Thingy b = new Thingy(); List things = asList(a, b); - ASPCore2Program program = Programs.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 = new AlphaImpl(); + 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()); @@ -182,10 +181,10 @@ public void withExternalTypeConflict() { @Test public void smallGraph() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig inputCfg = InputConfig.forString("node(1). node(2). node(3). a :- &connected[1,2]."); inputCfg.addPredicateMethod("connected", Externals.processPredicate((Integer a, Integer b) -> (a == 1 && b == 2) || (b == 2 || b == 3))); - ASPCore2Program program = system.readProgram(inputCfg); + InputProgram program = system.readProgram(inputCfg); Set actual = system.solve(program).collect(Collectors.toSet()); Set expected = AnswerSetsParser.parse("{ a, node(1), node(2), node(3) }"); @@ -194,12 +193,12 @@ public void smallGraph() throws Exception { @Test public void filterOutput() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig inputCfg = InputConfig.forString("node(1). node(2). outgoing13(X) :- node(X), &getLargeGraphEdges(13,X)."); inputCfg.addPredicateMethod("getLargeGraphEdges", Externals.processPredicate(() -> new HashSet<>(asList(asList(Terms.newConstant(1), Terms.newConstant(2)), asList(Terms.newConstant(2), Terms.newConstant(1)), asList(Terms.newConstant(13), Terms.newConstant(1)))))); - ASPCore2Program program = system.readProgram(inputCfg); + InputProgram program = system.readProgram(inputCfg); Set actual = system.solve(program).collect(Collectors.toSet()); Set expected = AnswerSetsParser.parse("{ node(1), node(2), outgoing13(1) }"); assertEquals(expected, actual); @@ -207,10 +206,10 @@ public void filterOutput() throws Exception { @Test public void supplier() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("node(1). a :- &bestNode(X), node(X)."); cfg.addPredicateMethod("bestNode", Externals.processPredicate(() -> singleton(singletonList(Terms.newConstant(1))))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set expected = AnswerSetsParser.parse("{ node(1), a }"); Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -224,10 +223,10 @@ public static Set>> bestNode() { @Test public void noInput() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("node(1). a :- &bestNode(X), node(X)."); cfg.addPredicateMethod("bestNode", Externals.processPredicateMethod(this.getClass().getMethod("bestNode"))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set expected = AnswerSetsParser.parse("{ node(1), a }"); Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -237,10 +236,10 @@ public void noInput() throws Exception { @Test public void smallGraphWithWrongType() { assertThrows(IllegalArgumentException.class, () -> { - Alpha system = new AlphaImpl(); + 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))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); system.solve(prog).collect(Collectors.toSet()); }); @@ -263,10 +262,10 @@ public static Set>> coolNode(int node) { @Test @Disabled("Test program is not safe (external lacking output variables). This should throw some exception.") public void smallGraphNoNeighbors() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("noNeighbors(2) :- not &neighbors[2]."); cfg.addPredicateMethod("neighbors", Externals.processPredicateMethod(this.getClass().getMethod("neighbors", int.class))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set expected = AnswerSetsParser.parse("{ noNeighbors(2) }"); Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -275,10 +274,10 @@ public void smallGraphNoNeighbors() throws Exception { @Test public void smallGraphCoolNode() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("node(1..2). in(X) :- node(X), &coolNode[X]."); cfg.addPredicateMethod("coolNode", Externals.processPredicateMethod(this.getClass().getMethod("coolNode", int.class))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set actual = system.solve(prog).collect(Collectors.toSet()); Set expected = AnswerSetsParser.parse("{ in(1), node(1), node(2) }"); @@ -287,10 +286,10 @@ public void smallGraphCoolNode() throws Exception { @Test public void smallGraphSingleNeighbor() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("node(1..3). in(1,X) :- &neighbors[1](X), node(X)."); cfg.addPredicateMethod("neighbors", Externals.processPredicateMethod(this.getClass().getMethod("neighbors", int.class))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set expected = AnswerSetsParser.parse("{ in(1,2), in(1,3), node(1), node(2), node(3) }"); Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -300,10 +299,10 @@ public void smallGraphSingleNeighbor() throws Exception { @Test @Disabled("Test program is not safe (external lacking output variables). This should throw some exception.") public void smallGraphSingleNeighborNoTerm() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("success :- &neighbors[1], not &neighbors[2]."); cfg.addPredicateMethod("neighbors", Externals.processPredicateMethod(this.getClass().getMethod("neighbors", int.class))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set expected = AnswerSetsParser.parse("{ success }"); Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -331,13 +330,13 @@ public void withExternalSubtype() throws Exception { 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 = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); - ASPCore2Program prog = Programs.newASPCore2Program(singletonList(rule), emptyList(), Programs.newInlineDirectives()); + 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())); @@ -346,10 +345,10 @@ public void withExternalSubtype() throws Exception { @Test public void withExternalViaAnnotation() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("a :- &isOne[1]."); cfg.addPredicateMethods(Externals.scan(this.getClass())); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set actual = system.solve(prog).collect(Collectors.toSet()); Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("a").build())); @@ -372,10 +371,10 @@ public void errorDuplicateExternal() { @Test public void withNativeExternal() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("a :- &isTwo[2]."); cfg.addPredicateMethod("isTwo", Externals.processPredicate((Integer t) -> t == 2)); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); Set actual = system.solve(prog).collect(Collectors.toSet()); Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("a").build())); @@ -385,10 +384,10 @@ public void withNativeExternal() throws Exception { @Test @Disabled("External atom has state, which is not allowed. Caching of calls makes the number of invocations wrong.") public void withExternalInvocationCounted1() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("a :- &isOne[1], &isOne[1]."); cfg.addPredicateMethod("isOne", Externals.processPredicateMethod(this.getClass().getMethod("isOne", int.class))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); int before = invocations; Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -403,10 +402,10 @@ public void withExternalInvocationCounted1() throws Exception { @Test @Disabled("External atom has state, which is not allowed. Caching of calls makes the number of invocations wrong.") public void withExternalInvocationCounted2() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("a. b :- &isOne[1], &isOne[2]."); cfg.addPredicateMethod("isOne", Externals.processPredicateMethod(this.getClass().getMethod("isOne", int.class))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); int before = invocations; Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -421,10 +420,10 @@ public void withExternalInvocationCounted2() throws Exception { @Test @Disabled("External atom has state, which is not allowed. Caching of calls makes the number of invocations wrong.") public void withExternalInvocationCounted3() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); InputConfig cfg = InputConfig.forString("a :- &isOne[1], not &isOne[2]."); cfg.addPredicateMethod("isOne", Externals.processPredicateMethod(this.getClass().getMethod("isOne", int.class))); - ASPCore2Program prog = system.readProgram(cfg); + InputProgram prog = system.readProgram(cfg); int before = invocations; Set actual = system.solve(prog).collect(Collectors.toSet()); @@ -439,8 +438,8 @@ public void withExternalInvocationCounted3() throws Exception { @Test @SuppressWarnings("unchecked") public void programWithExternalStringStuff() throws IOException { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgram(InputConfig.forString(STRINGSTUFF_ASP)); + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgram(InputConfig.forString(STRINGSTUFF_ASP)); Set answerSets = alpha.solve(prog).collect(Collectors.toSet()); // Verify every result string has length 6 and contains "foo" for (AnswerSet as : answerSets) { @@ -455,8 +454,8 @@ public void programWithExternalStringStuff() throws IOException { @Test @SuppressWarnings("unchecked") public void withNegatedExternal() throws IOException { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgram(InputConfig.forString(NEGATED_EXTERNAL_ASP)); + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgram(InputConfig.forString(NEGATED_EXTERNAL_ASP)); Set answerSets = alpha.solve(prog).collect(Collectors.toSet()); assertEquals(31, answerSets.size()); // Verify every result string has length 6 and contains "foo" @@ -473,8 +472,8 @@ public void withNegatedExternal() throws IOException { @Test public void reifyInput() { String aspInput = "p(X) :- q(X), not r(X)."; - Alpha system = new AlphaImpl(); - ASPCore2Program input = system.readProgramString(aspInput); + Alpha system = AlphaFactory.newAlpha(); + InputProgram input = system.readProgramString(aspInput); Set reified = system.reify(input); Set reifiedPredicates = reified.stream() @@ -493,7 +492,7 @@ public void reifyInput() { @Test public void basicUsage() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); Set actual = system.solve(system.readProgram(InputConfig.forString("p(a)."))).collect(Collectors.toSet()); Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("p").symbolicInstance("a").build())); assertEquals(expected, actual); @@ -501,7 +500,7 @@ public void basicUsage() throws Exception { @Test public void basicUsageWithString() throws Exception { - Alpha system = new AlphaImpl(); + Alpha system = AlphaFactory.newAlpha(); Set actual = system.solve(system.readProgram(InputConfig.forString("p(\"a\")."))).collect(Collectors.toSet()); Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("p").instance("a").build())); assertEquals(expected, actual); @@ -513,59 +512,26 @@ public void basicUsageWithString() throws Exception { @Test public void filterTest() { String progstr = "a. b. c. d :- c. e(a, b) :- d."; - Alpha system = new AlphaImpl(); - ASPCore2Program prog = system.readProgramString(progstr); + Alpha system = AlphaFactory.newAlpha(); + InputProgram prog = system.readProgramString(progstr); Set actual = system.solve(prog, (p) -> p.equals(Predicates.getPredicate("a", 0)) || p.equals(Predicates.getPredicate("e", 2))) .collect(Collectors.toSet()); Set expected = new HashSet<>(singletonList(new AnswerSetBuilder().predicate("a").predicate("e").symbolicInstance("a", "b").build())); 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 = new AlphaImpl(cfg); - ASPCore2Program 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!"); - } - - /** - * 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 = new AlphaImpl(cfg); - ASPCore2Program 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!"); - } - @Test public void passingUnitTestExpectUnsat() { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgramString(UNIT_TEST_EXPECT_UNSAT); + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram prog = alpha.readProgramString(UNIT_TEST_EXPECT_UNSAT); TestResult testResult = alpha.test(prog); assertTrue(testResult.isSuccess()); } @Test public void passingUnitTestBasicTest() { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgramString(UNIT_TEST_BASIC_TEST); + 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()); @@ -579,8 +545,8 @@ public void passingUnitTestBasicTest() { @Test public void passingUnitTestMultipleAssertions() { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgramString(UNIT_TEST_MORE_ASSERTIONS); + 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()); @@ -594,8 +560,8 @@ public void passingUnitTestMultipleAssertions() { @Test public void passingUnitTestMultipleTestCases() { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgramString(UNIT_TEST_MORE_TCS); + 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()); @@ -603,8 +569,8 @@ public void passingUnitTestMultipleTestCases() { @Test public void failingAssertionUnitTest() { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgramString(UNIT_TEST_FAILING_ASSERTION); + 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()); @@ -618,8 +584,8 @@ public void failingAssertionUnitTest() { @Test public void failingAnswerSetCountUnitTest() { - Alpha alpha = new AlphaImpl(); - ASPCore2Program prog = alpha.readProgramString(UNIT_TEST_FAILING_COUNT); + 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()); @@ -678,19 +644,18 @@ public void problematicRun_3col_1119718541727902_sorted_400() throws IOException * -DebugEnableInternalChecks -q -g naive -s default -sort -n 400 -i 3col-20-38.txt */ SystemConfig cfg = new SystemConfig(); - cfg.setGrounderName("naive"); cfg.setSolverName("default"); cfg.setNogoodStoreName("alpharoaming"); cfg.setDebugInternalChecks(true); cfg.setSeed(1119718541727902L); - final Alpha system = new AlphaImpl(cfg); + final Alpha system = AlphaFactory.newAlpha(cfg); final Path path = Paths.get("src", "test", "resources", "PreviouslyProblematic").resolve("3col-20-38.txt"); InputConfig inputCfg = new InputConfig(); List files = new ArrayList<>(); files.add(path.toString()); inputCfg.setFiles(files); - ASPCore2Program prog = system.readProgram(inputCfg); + InputProgram prog = system.readProgram(inputCfg); assertFalse(system.solve(prog).sorted().limit(400).collect(Collectors.toList()).isEmpty()); } @@ -698,29 +663,29 @@ public void problematicRun_3col_1119718541727902_sorted_400() throws IOException private void problematicRun(String program, long seed, int limit) throws IOException { final Path base = Paths.get("src", "test", "resources", "PreviouslyProblematic"); SystemConfig cfg = new SystemConfig(); - cfg.setGrounderName("naive"); cfg.setSolverName("default"); cfg.setNogoodStoreName("alpharoaming"); cfg.setDebugInternalChecks(true); cfg.setSeed(seed); - final Alpha system = new AlphaImpl(cfg); + final Alpha system = AlphaFactory.newAlpha(cfg); InputConfig inputCfg = new InputConfig(); List files = new ArrayList<>(); files.add(base.resolve(program).toString()); inputCfg.setFiles(files); - ASPCore2Program prog = system.readProgram(inputCfg); + 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(); - ASPCore2ProgramBuilder bld = Programs.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))); - ASPCore2Program parsedProgram = bld.build(); + InputProgram parsedProgram = bld.build(); SystemConfig config = new SystemConfig(); config.setSolverName("default"); @@ -729,11 +694,10 @@ 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)); - Alpha alpha = new AlphaImpl(config); + 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 index 4ec2ea622..4131b6f52 100644 --- 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 @@ -33,7 +33,7 @@ */ public class ReificationTest { - private final Alpha alpha = new AlphaImpl(); + private final Alpha alpha = AlphaFactory.newAlpha(); private static final Map> CMP_OP_IDS; diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/e2etests/End2EndTests.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/e2etests/End2EndTests.java new file mode 100644 index 000000000..31ad7d731 --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/e2etests/End2EndTests.java @@ -0,0 +1,73 @@ +package at.ac.tuwien.kr.alpha.e2etests; + +import at.ac.tuwien.kr.alpha.api.Alpha; +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.tests.Assertion; +import at.ac.tuwien.kr.alpha.api.programs.tests.TestResult; +import at.ac.tuwien.kr.alpha.commons.programs.Programs; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Runs tests written in ASP from a given set of files. + * Dynamic tests generated by this class use Alpha's default configuration. + * A test fails when any ASP test in the corresponding fileset fails. + */ +public class End2EndTests { + + private static final String E2E_TESTS_DIR = "/e2e-tests/"; + + private static void runAspTests(String testName, String... fileset) { + Alpha alpha = AlphaFactory.newAlpha(); + Programs.InputProgramBuilder programBuilder = Programs.builder(); + for (String file : fileset) { + try (InputStream is = End2EndTests.class.getResourceAsStream(file)) { + programBuilder.accumulate(alpha.readProgramStream(is)); + } catch (IOException ex) { + throw new RuntimeException("Failed to read test file: " + file, ex); + } + } + InputProgram program = programBuilder.build(); + TestResult testResult = alpha.test(program); + if (!testResult.isSuccess()) { + StringBuilder msgBuilder = new StringBuilder("Test ").append(testName).append(" failed:").append(System.lineSeparator()); + testResult.getTestCaseResults().stream().filter(Predicate.not(TestResult.TestCaseResult::isSuccess)).forEach(tcResult -> { + msgBuilder.append("Assertion failures for test case ").append(tcResult.getTestCaseName()).append(": ").append(System.lineSeparator()); + if (tcResult.answerSetCountVerificationResult().isPresent()) { + msgBuilder.append(tcResult.answerSetCountVerificationResult().get()).append(System.lineSeparator()); + } + for (Map.Entry> assertionError : tcResult.getAssertionErrors().entrySet()) { + for (String errMsg : assertionError.getValue()) { + msgBuilder.append("Assertion failed: ").append(assertionError.getKey()).append(", error = ").append(errMsg).append(System.lineSeparator()); + } + } + }); + fail(msgBuilder.toString()); + } + } + + private static DynamicTest alphaEnd2EndTest(String testName, String... fileset) { + return DynamicTest.dynamicTest(testName, () -> runAspTests(testName, fileset)); + } + + @TestFactory + Stream alphaEnd2EndTests() { + return Stream.of( + alphaEnd2EndTest("3-Coloring", E2E_TESTS_DIR + "3col.asp"), + alphaEnd2EndTest("modules-basic", E2E_TESTS_DIR + "modules-basic.evl"), + alphaEnd2EndTest("neighboring-vertices-list", E2E_TESTS_DIR + "neighboring-vertices-list.evl"), + alphaEnd2EndTest("bin-packing", E2E_TESTS_DIR + "bin-packing.evl", E2E_TESTS_DIR + "bin-packing.test.evl") + ); + } + +} diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AggregatesTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/AggregatesTest.java similarity index 76% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AggregatesTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/AggregatesTest.java index 62542ba2d..f0f3508e2 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AggregatesTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/AggregatesTest.java @@ -23,84 +23,87 @@ * 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.solver; +package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSet; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSets; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSetsWithBase; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.ignoreTestForNaiveSolver; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.ignoreTestForSimplifiedSumAggregates; +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.ignoreTestForNaiveSolver; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.ignoreTestForSimplifiedSumAggregates; + +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.regressiontests.util.AggregateRegressionTest; /** * Tests if correct answer sets for programs containing aggregates are computed. */ +// TODO This is a functional test and should not be run with standard unit tests public class AggregatesTest { private static final String LS = System.lineSeparator(); @AggregateRegressionTest - public void aggregateCountLeGroundPositive(RegressionTestConfig cfg) { + public void aggregateCountLeGroundPositive(SystemConfig cfg) { String program = "a." + LS + "b :- 1 <= #count { 1 : a }."; - assertRegressionTestAnswerSet(cfg, program, "a,b"); + assertRegressionTestAnswerSets(cfg, program, "a,b"); } @AggregateRegressionTest - public void aggregateCountEqSingleElementPositive(RegressionTestConfig cfg) { + public void aggregateCountEqSingleElementPositive(SystemConfig cfg) { String program = "thing(1..3)." + "cnt_things(N) :- N = #count{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "thing(1), thing(2), thing(3), cnt_things(3)"); + assertRegressionTestAnswerSets(cfg, program, "thing(1), thing(2), thing(3), cnt_things(3)"); } @AggregateRegressionTest - public void aggregateCountEqEmptySetPositive(RegressionTestConfig cfg) { + public void aggregateCountEqEmptySetPositive(SystemConfig cfg) { String program = "cnt_things(N) :- N = #count{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "cnt_things(0)"); + assertRegressionTestAnswerSets(cfg, program, "cnt_things(0)"); } @AggregateRegressionTest - public void aggregateCountLeEmptySetPositive(RegressionTestConfig cfg) { + public void aggregateCountLeEmptySetPositive(SystemConfig cfg) { String program = "zero_leq_cnt :- 0 <= #count{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "zero_leq_cnt"); + assertRegressionTestAnswerSets(cfg, program, "zero_leq_cnt"); } @AggregateRegressionTest - public void aggregateSumEqEmptySetPositive(RegressionTestConfig cfg) { + public void aggregateSumEqEmptySetPositive(SystemConfig cfg) { String program = "sum_things(S) :- S = #sum{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "sum_things(0)"); + assertRegressionTestAnswerSets(cfg, program, "sum_things(0)"); } @AggregateRegressionTest - public void aggregateSumEqNegativeSum(RegressionTestConfig cfg) { + public void aggregateSumEqNegativeSum(SystemConfig cfg) { ignoreTestForSimplifiedSumAggregates(cfg); String program = "thing(-1). thing(-2). thing(-3). sum_things(S) :- S = #sum{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "thing(-1), thing(-2), thing(-3), sum_things(-6)"); + assertRegressionTestAnswerSets(cfg, program, "thing(-1), thing(-2), thing(-3), sum_things(-6)"); } @AggregateRegressionTest - public void aggregateSumEqMixedElementsSum(RegressionTestConfig cfg) { + public void aggregateSumEqMixedElementsSum(SystemConfig cfg) { ignoreTestForSimplifiedSumAggregates(cfg); String program = "thing(-1). thing(6). thing(-3). sum_things(S) :- S = #sum{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "thing(-1), thing(6), thing(-3), sum_things(2)"); + assertRegressionTestAnswerSets(cfg, program, "thing(-1), thing(6), thing(-3), sum_things(2)"); } @AggregateRegressionTest - public void aggregateSumLeEmptySetPositive(RegressionTestConfig cfg) { + public void aggregateSumLeEmptySetPositive(SystemConfig cfg) { String program = "zero_leq_sum :- 0 <= #sum{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "zero_leq_sum"); + assertRegressionTestAnswerSets(cfg, program, "zero_leq_sum"); } @AggregateRegressionTest - public void aggregateSumLeNegativeSum(RegressionTestConfig cfg) { + public void aggregateSumLeNegativeSum(SystemConfig cfg) { ignoreTestForSimplifiedSumAggregates(cfg); String program = "thing(-3). thing(4). " + "minus_three_leq_sum :- -3 <= #sum{X : thing(X)}." + "two_gt_sum :- 2 > #sum{X : thing(X)}."; - assertRegressionTestAnswerSet(cfg, program, "thing(-3), thing(4), minus_three_leq_sum, two_gt_sum"); + assertRegressionTestAnswerSets(cfg, program, "thing(-3), thing(4), minus_three_leq_sum, two_gt_sum"); } @AggregateRegressionTest - public void aggregateSumLeNegativeElementsWithChoice(RegressionTestConfig cfg) { + public void aggregateSumLeNegativeElementsWithChoice(SystemConfig cfg) { ignoreTestForSimplifiedSumAggregates(cfg); String program = "thing(3). thing(-5). thing(5). " + "{summed_up_thing(X) : thing(X)}. " @@ -118,7 +121,7 @@ public void aggregateSumLeNegativeElementsWithChoice(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateCountLeWithChoicePositive(RegressionTestConfig cfg) { + public void aggregateCountLeWithChoicePositive(SystemConfig cfg) { String program = "potential_thing(1..4). " + "{ thing(N) : potential_thing(N)}." + "two_things_chosen :- thing(N1), thing(N2), N1 != N2." @@ -137,7 +140,7 @@ public void aggregateCountLeWithChoicePositive(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateCountEqWithChoicePositive(RegressionTestConfig cfg) { + public void aggregateCountEqWithChoicePositive(SystemConfig cfg) { String program = "potential_thing(1..4). " + "{ thing(N) : potential_thing(N)}." + "two_things_chosen :- thing(N1), thing(N2), N1 != N2." @@ -156,7 +159,7 @@ public void aggregateCountEqWithChoicePositive(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateSumEqWithChoicePositive(RegressionTestConfig cfg) { + public void aggregateSumEqWithChoicePositive(SystemConfig cfg) { String program = "potential_thing(1..4). " + "{ thing(N) : potential_thing(N)}." + "two_things_chosen :- thing(N1), thing(N2), N1 != N2." @@ -175,7 +178,7 @@ public void aggregateSumEqWithChoicePositive(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateSumEqOverMixedValuesWithChoicePositive(RegressionTestConfig cfg) { + public void aggregateSumEqOverMixedValuesWithChoicePositive(SystemConfig cfg) { ignoreTestForSimplifiedSumAggregates(cfg); String program = "potential_thing(-2). potential_thing(-1). potential_thing(0). potential_thing(1). " + "{ thing(N) : potential_thing(N)}." @@ -195,7 +198,7 @@ public void aggregateSumEqOverMixedValuesWithChoicePositive(RegressionTestConfig } @AggregateRegressionTest - public void aggregateSumBetweenNegative(RegressionTestConfig cfg) { + public void aggregateSumBetweenNegative(SystemConfig cfg) { String program = "potential_thing(1..4). " + "{ thing(N) : potential_thing(N)}." + "two_things_chosen :- thing(N1), thing(N2), N1 != N2." @@ -214,7 +217,7 @@ public void aggregateSumBetweenNegative(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateMaxNegative(RegressionTestConfig cfg) { + public void aggregateMaxNegative(SystemConfig cfg) { String program = "potential_thing(1..4). " + "{ thing(N) : potential_thing(N) }." + "one_chosen :- thing(_)." @@ -222,12 +225,12 @@ public void aggregateMaxNegative(RegressionTestConfig cfg) { + ":- thing(N1), thing(N2), N1 != N2." + "max_chosen :- thing(X), not X < #max{M : potential_thing(M)}." + ":- not max_chosen."; - assertRegressionTestAnswerSet(cfg, program, + assertRegressionTestAnswerSets(cfg, program, "potential_thing(1), potential_thing(2), potential_thing(3), potential_thing(4), one_chosen, max_chosen, thing(4)"); } @AggregateRegressionTest - public void aggregateCountGroundNegative(RegressionTestConfig cfg) { + public void aggregateCountGroundNegative(SystemConfig cfg) { String program = "{a}." + LS + "b :- not c." + LS + "c :- 1 <= #count { 1 : a }."; @@ -235,7 +238,7 @@ public void aggregateCountGroundNegative(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateCountNonGroundPositive(RegressionTestConfig cfg) { + public void aggregateCountNonGroundPositive(SystemConfig cfg) { String program = "n(1..3)." + LS + "{x(N)} :- n(N)." + LS + "min(3)." + LS @@ -246,7 +249,7 @@ public void aggregateCountNonGroundPositive(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateCountNonGroundLowerAndUpper(RegressionTestConfig cfg) { + public void aggregateCountNonGroundLowerAndUpper(SystemConfig cfg) { String program = "n(1..3)." + LS + "{x(N)} :- n(N)." + LS + "min(2)." + LS @@ -260,14 +263,14 @@ public void aggregateCountNonGroundLowerAndUpper(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateSumGroundLower(RegressionTestConfig cfg) { + public void aggregateSumGroundLower(SystemConfig cfg) { String program = "a." + LS + "b :- 5 <= #sum { 2 : a; 3 }."; - assertRegressionTestAnswerSet(cfg, program, "a,b"); + assertRegressionTestAnswerSets(cfg, program, "a,b"); } @AggregateRegressionTest - public void aggregateSumNonGroundLowerAndUpper(RegressionTestConfig cfg) { + public void aggregateSumNonGroundLowerAndUpper(SystemConfig cfg) { String program = "n(1..3)." + LS + "{x(N)} :- n(N)." + LS + "min(3)." + LS @@ -281,7 +284,7 @@ public void aggregateSumNonGroundLowerAndUpper(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateSumNonGroundLower(RegressionTestConfig cfg) { + public void aggregateSumNonGroundLower(SystemConfig cfg) { String program = "n(1..3)." + LS + "{x(N)} :- n(N)." + LS + "min(3)." + LS @@ -293,7 +296,7 @@ public void aggregateSumNonGroundLower(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateSumComputed(RegressionTestConfig cfg) { + public void aggregateSumComputed(SystemConfig cfg) { ignoreTestForNaiveSolver(cfg); // Do not run this test case with the naive solver. String program = "n(1..3)." + LS + "{x(N)} :- n(N)." + LS @@ -313,7 +316,7 @@ public void aggregateSumComputed(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateCountGlobalVariable(RegressionTestConfig cfg) { + public void aggregateCountGlobalVariable(SystemConfig cfg) { String program = "box(1..2)." + LS + "in(1,1)." + LS + "in(1,2)." + LS @@ -324,7 +327,7 @@ public void aggregateCountGlobalVariable(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateSumGlobalVariable(RegressionTestConfig cfg) { + public void aggregateSumGlobalVariable(SystemConfig cfg) { String program = "box(1..2)." + LS + "item_size(I,I) :- I=1..2." + LS + "in(1,1)." + LS @@ -336,35 +339,35 @@ public void aggregateSumGlobalVariable(RegressionTestConfig cfg) { } @AggregateRegressionTest - public void aggregateRightHandTermCountGreater(RegressionTestConfig cfg) { + public void aggregateRightHandTermCountGreater(SystemConfig cfg) { String program = "p(1)." + "p(2)." + "q :- #count { N : p(N) } > 1."; - assertRegressionTestAnswerSet(cfg, program, "p(1), p(2), q"); + assertRegressionTestAnswerSets(cfg, program, "p(1), p(2), q"); } @AggregateRegressionTest - public void aggregateRightHandTermCountEqAssigning(RegressionTestConfig cfg) { + public void aggregateRightHandTermCountEqAssigning(SystemConfig cfg) { String program = "p(1)." + "p(2)." + "q :- #count { N : p(N) } = 2."; - assertRegressionTestAnswerSet(cfg, program, "p(1), p(2), q"); + assertRegressionTestAnswerSets(cfg, program, "p(1), p(2), q"); } @AggregateRegressionTest - public void aggregateRightHandTermCountNeqAssigning(RegressionTestConfig cfg) { + public void aggregateRightHandTermCountNeqAssigning(SystemConfig cfg) { String program = "p(1)." + "p(2)." + "q :- #count { N : p(N) } != 1."; - assertRegressionTestAnswerSet(cfg, program, "p(1), p(2), q"); + assertRegressionTestAnswerSets(cfg, program, "p(1), p(2), q"); } @AggregateRegressionTest - public void aggregateRightHandTermCountLt(RegressionTestConfig cfg) { + public void aggregateRightHandTermCountLt(SystemConfig cfg) { String program = "p(1)." + "p(2)." + "q :- #count { N : p(N) } < 3."; - assertRegressionTestAnswerSet(cfg, program, "p(1), p(2), q"); + assertRegressionTestAnswerSets(cfg, program, "p(1), p(2), q"); } } diff --git a/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ArithmeticTermsTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ArithmeticTermsTest.java new file mode 100644 index 000000000..a7c5b5577 --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ArithmeticTermsTest.java @@ -0,0 +1,59 @@ +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 at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; + +/** + * Tests ASP programs containing arithmetic terms at arbitrary positions. + * + * Copyright (c) 2020, the Alpha Team. + */ +// TODO This is a functional test and should not be run with standard unit tests +public class ArithmeticTermsTest { + + @RegressionTest + public void testArithmeticTermInHead(SystemConfig cfg) { + String program = "dom(1). dom(2)." + + "p(X+3) :- dom(X)."; + assertRegressionTestAnswerSets(cfg, program, "dom(1),dom(2),p(4),p(5)"); + } + + @RegressionTest + public void testArithmeticTermInRule(SystemConfig cfg) { + String program = "dom(1). dom(2)." + + "p(Y+4) :- dom(X+1), dom(X), Y=X, X=Y."; + assertRegressionTestAnswerSets(cfg, program, "dom(1),dom(2),p(5)"); + } + + @RegressionTest + public void testArithmeticTermInChoiceRule(SystemConfig cfg) { + String program = "cycle_max(4). cycle(1)." + + "{ cycle(N+1) } :- cycle(N), cycle_max(K), NTowers of Hanoi). * */ public class HanoiTowerTest { @@ -62,49 +63,49 @@ public class HanoiTowerTest { @RegressionTest @Disabled("disabled to save resources during CI") - public void testInstance1(RegressionTestConfig cfg) { + public void testInstance1(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testHanoiTower(1, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testInstance2(RegressionTestConfig cfg) { + public void testInstance2(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testHanoiTower(2, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testInstance3(RegressionTestConfig cfg) { + public void testInstance3(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testHanoiTower(3, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testInstance4(RegressionTestConfig cfg) { + public void testInstance4(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testHanoiTower(4, cfg)); } @RegressionTest - public void testSimple(RegressionTestConfig cfg) { - TestUtils.ignoreTestForNaiveSolver(cfg); - TestUtils.ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); + public void testSimple(SystemConfig cfg) { + ignoreTestForNaiveSolver(cfg); + ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testHanoiTower("simple", cfg)); } - private void testHanoiTower(int instance, RegressionTestConfig cfg) throws IOException { + private void testHanoiTower(int instance, SystemConfig cfg) throws IOException { testHanoiTower(String.valueOf(instance), cfg); } - private void testHanoiTower(String instance, RegressionTestConfig cfg) throws IOException { - ASPCore2Program prog = new ProgramParserImpl().parse( + private void testHanoiTower(String instance, SystemConfig cfg) throws IOException { + InputProgram prog = new ProgramParserImpl().parse( Paths.get("src", "test", "resources", "HanoiTower_Alpha.asp"), Paths.get("src", "test", "resources", "HanoiTower_instances", instance + ".asp")); - Solver solver = TestUtils.buildSolverForRegressionTest(prog, cfg); + Solver solver = buildSolverForRegressionTest(prog, cfg); Optional answerSet = solver.stream().findFirst(); assertTrue(answerSet.isPresent()); checkGoal(prog, answerSet.get()); @@ -115,7 +116,7 @@ private void testHanoiTower(String instance, RegressionTestConfig cfg) throws IO * for every goal/3 * fact in the input there is a corresponding on/3 atom in the output. */ - private void checkGoal(ASPCore2Program parsedProgram, AnswerSet answerSet) { + private void checkGoal(InputProgram parsedProgram, AnswerSet answerSet) { Predicate ongoal = Predicates.getPredicate("ongoal", 2); Predicate on = Predicates.getPredicate("on", 3); int steps = getSteps(parsedProgram); @@ -131,11 +132,11 @@ private void checkGoal(ASPCore2Program parsedProgram, AnswerSet answerSet) { } } - private int getSteps(ASPCore2Program parsedProgram) { + 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-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/HeadBodyTransformationTests.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HeadBodyTransformationTests.java similarity index 65% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/HeadBodyTransformationTests.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HeadBodyTransformationTests.java index 07839eda8..07f80ac83 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/HeadBodyTransformationTests.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/HeadBodyTransformationTests.java @@ -23,8 +23,10 @@ * 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.solver; +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 static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -34,14 +36,14 @@ 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.programs.ASPCore2Program; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; - +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.programs.InputProgram; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; /** * Tests rule transformations described in the following research paper, and their effects on performance: * @@ -55,131 +57,131 @@ public class HeadBodyTransformationTests { @RegressionTest - public void testProgramB_N1(RegressionTestConfig cfg) { + public void testProgramB_N1(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(1), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(1), cfg)); } @RegressionTest - public void testProgramB_Transformed_N1(RegressionTestConfig cfg) { + public void testProgramB_Transformed_N1(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(1), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(1), cfg)); } @RegressionTest - public void testProgramA_N1(RegressionTestConfig cfg) { + public void testProgramA_N1(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(1), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(1), cfg)); } @RegressionTest - public void testProgramA_Transformed_N1(RegressionTestConfig cfg) { + public void testProgramA_Transformed_N1(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(1), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(1), cfg)); } @RegressionTest - public void testProgramB_N2(RegressionTestConfig cfg) { + public void testProgramB_N2(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(2), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(2), cfg)); } @RegressionTest - public void testProgramB_Transformed_N2(RegressionTestConfig cfg) { + public void testProgramB_Transformed_N2(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(2), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(2), cfg)); } @RegressionTest - public void testProgramA_N2(RegressionTestConfig cfg) { + public void testProgramA_N2(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(2), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(2), cfg)); } @RegressionTest - public void testProgramA_Transformed_N2(RegressionTestConfig cfg) { + public void testProgramA_Transformed_N2(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(2), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(2), cfg)); } @RegressionTest - public void testProgramB_N4(RegressionTestConfig cfg) { + public void testProgramB_N4(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(4), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(4), cfg)); } @RegressionTest - public void testProgramB_Transformed_N4(RegressionTestConfig cfg) { + public void testProgramB_Transformed_N4(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(4), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(4), cfg)); } @RegressionTest - public void testProgramA_N4(RegressionTestConfig cfg) { + public void testProgramA_N4(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(4), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(4), cfg)); } @RegressionTest - public void testProgramA_Transformed_N4(RegressionTestConfig cfg) { + public void testProgramA_Transformed_N4(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(4), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(4), cfg)); } @RegressionTest - public void testProgramB_N8(RegressionTestConfig cfg) { + public void testProgramB_N8(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(8), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(8), cfg)); } @RegressionTest - public void testProgramB_Transformed_N8(RegressionTestConfig cfg) { + public void testProgramB_Transformed_N8(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(8), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(8), cfg)); } @RegressionTest - public void testProgramA_N8(RegressionTestConfig cfg) { + public void testProgramA_N8(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(8), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(8), cfg)); } @RegressionTest - public void testProgramA_Transformed_N8(RegressionTestConfig cfg) { + public void testProgramA_Transformed_N8(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(8), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(8), cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testProgramB_N16(RegressionTestConfig cfg) { + public void testProgramB_N16(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(16), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB(16), cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testProgramB_Transformed_N16(RegressionTestConfig cfg) { + public void testProgramB_Transformed_N16(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(16), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramB_TransformationB(16), cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testProgramA_N16(RegressionTestConfig cfg) { + public void testProgramA_N16(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(16), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA(16), cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testProgramA_Transformed_N16(RegressionTestConfig cfg) { + public void testProgramA_Transformed_N16(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(16), cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(constructProgramA_TransformationA(16), cfg)); } - private void test(ASPCore2Program program, RegressionTestConfig cfg) { - Solver solver = TestUtils.buildSolverForRegressionTest(program, cfg); + private void test(InputProgram program, SystemConfig cfg) { + Solver solver = buildSolverForRegressionTest(program, cfg); Optional answerSet = solver.stream().findFirst(); assertFalse(answerSet.isPresent()); } @@ -189,7 +191,7 @@ private void test(ASPCore2Program program, RegressionTestConfig cfg) { * * @param n */ - private ASPCore2Program constructProgramB(int n) { + private InputProgram constructProgramB(int n) { int numberOfRules = 3 * n + 1; List strRules = new ArrayList<>(numberOfRules); strRules.add("x :- not x."); @@ -203,7 +205,7 @@ private ASPCore2Program constructProgramB(int n) { * * @param n */ - private ASPCore2Program constructProgramB_TransformationB(int n) { + private InputProgram constructProgramB_TransformationB(int n) { int numberOfRules = 6 * n + 2; List strRules = new ArrayList<>(numberOfRules); strRules.add("b_notX :- not x."); @@ -218,7 +220,7 @@ private ASPCore2Program constructProgramB_TransformationB(int n) { * * @param n */ - private ASPCore2Program constructProgramA(int n) { + private InputProgram constructProgramA(int n) { int numberOfRules = 4 * n + 1; List strRules = new ArrayList<>(numberOfRules); strRules.add(createXCRule(n)); @@ -232,7 +234,7 @@ private ASPCore2Program constructProgramA(int n) { * * @param n */ - private ASPCore2Program constructProgramA_TransformationA(int n) { + private InputProgram constructProgramA_TransformationA(int n) { int numberOfRules = 7 * n + 2; List strRules = new ArrayList<>(numberOfRules); strRules.addAll(createXCRules_TransformationA(n)); @@ -241,10 +243,10 @@ private ASPCore2Program constructProgramA_TransformationA(int n) { return checkNumberOfRulesAndParse(strRules, numberOfRules); } - private ASPCore2Program checkNumberOfRulesAndParse(List strRules, int numberOfRules) { + private InputProgram checkNumberOfRulesAndParse(List strRules, int numberOfRules) { assertEquals(numberOfRules, strRules.size()); String strProgram = strRules.stream().collect(Collectors.joining(System.lineSeparator())); - ASPCore2Program parsedProgram = new ProgramParserImpl().parse(strProgram); + InputProgram parsedProgram = new ProgramParserImpl().parse(strProgram); assertEquals(numberOfRules, parsedProgram.getRules().size()); return parsedProgram; } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/OmigaBenchmarksTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/OmigaBenchmarksTest.java similarity index 50% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/OmigaBenchmarksTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/OmigaBenchmarksTest.java index 4962ddc4c..9ae96e5cd 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/OmigaBenchmarksTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/OmigaBenchmarksTest.java @@ -23,91 +23,98 @@ * 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.solver; +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 java.io.IOException; import java.nio.file.Files; 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.core.parser.ProgramParserImpl; -import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +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 public class OmigaBenchmarksTest { @SuppressWarnings("unused") private static final Logger LOGGER = LoggerFactory.getLogger(OmigaBenchmarksTest.class); - private static final int DEBUG_TIMEOUT_FACTOR = 15; + private static final int DEBUG_TIMEOUT_FACTOR = 20; @RegressionTest - public void test3Col_10_18(RegressionTestConfig cfg) { + public void test3Col_10_18(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("3col", "3col-10-18.txt", cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("3col", "3col-10-18.txt", cfg)); } @RegressionTest - public void test3Col_20_38(RegressionTestConfig cfg) { + public void test3Col_20_38(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("3col", "3col-20-38.txt", cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("3col", "3col-20-38.txt", cfg)); } @RegressionTest - public void testCutedge_100_30(RegressionTestConfig cfg) { + public void testCutedge_100_30(SystemConfig cfg) { long timeout = 15000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("cutedge", "cutedge-100-30.txt", cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("cutedge", "cutedge-100-30.txt", cfg)); } @RegressionTest - public void testCutedge_100_50(RegressionTestConfig cfg) { + public void testCutedge_100_50(SystemConfig cfg) { long timeout = 15000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("cutedge", "cutedge-100-50.txt", cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("cutedge", "cutedge-100-50.txt", cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testLocstrat_200(RegressionTestConfig cfg) { + public void testLocstrat_200(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("locstrat", "locstrat-200.txt", cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("locstrat", "locstrat-200.txt", cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testLocstrat_400(RegressionTestConfig cfg) { + public void testLocstrat_400(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("locstrat", "locstrat-400.txt", cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("locstrat", "locstrat-400.txt", cfg)); } @RegressionTest - public void testReach_1(RegressionTestConfig cfg) { - long timeout = 15000L; - TestUtils.ignoreTestForNaiveSolver(cfg); - TestUtils.ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("reach", "reach-1.txt", cfg)); + public void testReach_1(SystemConfig cfg) { + long timeout = 20000L; + ignoreTestForNaiveSolver(cfg); + ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("reach", "reach-1.txt", cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testReach_4(RegressionTestConfig cfg) { + public void testReach_4(SystemConfig cfg) { long timeout = 10000L; - TestUtils.runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("reach", "reach-4.txt", cfg)); + runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test("reach", "reach-4.txt", cfg)); } - private void test(String folder, String aspFileName, RegressionTestConfig cfg) throws IOException { + private void test(String folder, String aspFileName, SystemConfig cfg) throws IOException { @SuppressWarnings("unused") - Optional answerSet = TestUtils - .buildSolverForRegressionTest( - new ProgramParserImpl().parse(Files.newInputStream(Paths.get("benchmarks", "omiga", "omiga-testcases", folder, aspFileName))), cfg) - .stream().findFirst(); + Optional answerSet = buildSolverForRegressionTest( + new ProgramParserImpl().parse(Files.newInputStream(Paths.get("benchmarks", "omiga", "omiga-testcases", folder, aspFileName))), cfg) + .stream().findFirst(); // System.out.println(answerSet); // TODO: check correctness of answer set } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/PartSubpartConfigurationTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/PartSubpartConfigurationTest.java similarity index 83% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/PartSubpartConfigurationTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/PartSubpartConfigurationTest.java index f39a9434a..d559b2971 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/PartSubpartConfigurationTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/PartSubpartConfigurationTest.java @@ -23,10 +23,10 @@ * 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.solver; +package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.collectRegressionTestAnswerSets; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.runWithTimeout; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.collectRegressionTestAnswerSets; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; import static org.junit.jupiter.api.Assertions.assertFalse; import java.util.ArrayList; @@ -36,70 +36,74 @@ import org.junit.jupiter.api.Disabled; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; + /** * Tests {@link AbstractSolver} using some configuration test cases in which subparts are assigned to parts. * */ +// TODO This is a functional test and should not be run with standard unit tests public class PartSubpartConfigurationTest { private static final int DEBUG_TIMEOUT_FACTOR = 5; @RegressionTest - public void testN2(RegressionTestConfig cfg) { + public void testN2(SystemConfig cfg) { long timeout = 1000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(2, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN4(RegressionTestConfig cfg) { + public void testN4(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(4, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN8(RegressionTestConfig cfg) { + public void testN8(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(8, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN16(RegressionTestConfig cfg) { + public void testN16(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(16, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN32(RegressionTestConfig cfg) { + public void testN32(SystemConfig cfg) { long timeout = 61000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(32, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN60(RegressionTestConfig cfg) { + public void testN60(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(60, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN75(RegressionTestConfig cfg) { + public void testN75(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(75, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN100(RegressionTestConfig cfg) { + public void testN100(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPartSubpart(100, cfg)); } - private void testPartSubpart(int n, RegressionTestConfig cfg) { + private void testPartSubpart(int n, SystemConfig cfg) { List rules = new ArrayList<>(); for (int i = 1; i <= n; i++) { rules.add(String.format("n(%d).", i)); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/PigeonHoleTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/PigeonHoleTest.java similarity index 82% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/PigeonHoleTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/PigeonHoleTest.java index d444d5a7e..73070b487 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/PigeonHoleTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/PigeonHoleTest.java @@ -23,11 +23,11 @@ * 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.solver; +package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.collectRegressionTestAnswerSets; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.ignoreTestForNonDefaultDomainIndependentHeuristics; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.runWithTimeout; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.collectRegressionTestAnswerSets; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.ignoreTestForNonDefaultDomainIndependentHeuristics; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; @@ -38,58 +38,61 @@ 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.regressiontests.util.RegressionTest; /** * Tests {@link AbstractSolver} using some pigeon-hole test cases (see https://en.wikipedia.org/wiki/Pigeonhole_principle). */ +// TODO This is a functional test and should not be run with standard unit tests public class PigeonHoleTest { private static final long DEBUG_TIMEOUT_FACTOR = 5; @RegressionTest - public void test2Pigeons2Holes(RegressionTestConfig cfg) { + public void test2Pigeons2Holes(SystemConfig cfg) { long timeout = 5000L; ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(2, 2, cfg)); } @RegressionTest - public void test3Pigeons2Holes(RegressionTestConfig cfg) { + public void test3Pigeons2Holes(SystemConfig cfg) { long timeout = 5000L; ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(3, 2, cfg)); } @RegressionTest - public void test2Pigeons3Holes(RegressionTestConfig cfg) { + public void test2Pigeons3Holes(SystemConfig cfg) { long timeout = 5000L; ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(2, 3, cfg)); } @RegressionTest - public void test3Pigeons3Holes(RegressionTestConfig cfg) { + public void test3Pigeons3Holes(SystemConfig cfg) { long timeout = 10000L; ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(3, 3, cfg)); } @RegressionTest - public void test4Pigeons3Holes(RegressionTestConfig cfg) { + public void test4Pigeons3Holes(SystemConfig cfg) { long timeout = 10000L; ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(4, 3, cfg)); } @RegressionTest - public void test3Pigeons4Holes(RegressionTestConfig cfg) { + public void test3Pigeons4Holes(SystemConfig cfg) { long timeout = 10000L; ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(3, 4, cfg)); } @RegressionTest - public void test4Pigeons4Holes(RegressionTestConfig cfg) { + public void test4Pigeons4Holes(SystemConfig cfg) { long timeout = 10000L; ignoreTestForNonDefaultDomainIndependentHeuristics(cfg); runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(4, 4, cfg)); @@ -97,42 +100,42 @@ public void test4Pigeons4Holes(RegressionTestConfig cfg) { @RegressionTest @Disabled("disabled to save resources during CI") - public void test10Pigeons10Holes(RegressionTestConfig cfg) { + public void test10Pigeons10Holes(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(10, 10, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void test19Pigeons20Holes(RegressionTestConfig cfg) { + public void test19Pigeons20Holes(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(19, 20, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void test28Pigeons30Holes(RegressionTestConfig cfg) { + public void test28Pigeons30Holes(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(28, 30, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void test37Pigeons40Holes(RegressionTestConfig cfg) { + public void test37Pigeons40Holes(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(37, 40, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void test46Pigeons50Holes(RegressionTestConfig cfg) { + public void test46Pigeons50Holes(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(46, 50, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void test55Pigeons60Holes(RegressionTestConfig cfg) { + public void test55Pigeons60Holes(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testPigeonsHoles(55, 60, cfg)); } @@ -140,7 +143,7 @@ public void test55Pigeons60Holes(RegressionTestConfig cfg) { /** * Tries to solve the problem of assigning P pigeons to H holes. */ - private void testPigeonsHoles(int pigeons, int holes, RegressionTestConfig cfg) { + private void testPigeonsHoles(int pigeons, int holes, SystemConfig cfg) { List rules = new ArrayList<>(); rules.add("pos(P,H) :- pigeon(P), hole(H), not negpos(P,H)."); rules.add("negpos(P,H) :- pigeon(P), hole(H), not pos(P,H)."); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/RacksTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/RacksTest.java similarity index 79% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/RacksTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/RacksTest.java index 1ea2b88ca..7fd811e8a 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/RacksTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/RacksTest.java @@ -23,39 +23,42 @@ * 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.solver; +package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.runWithTimeout; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.runWithTimeout; import java.io.IOException; 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; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; -import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +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 @Disabled("disabled to save resources during CI") public class RacksTest { private static final long DEBUG_TIMEOUT_FACTOR = 5; @RegressionTest - public void testRacks(RegressionTestConfig cfg) { + public void testRacks(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> test(cfg)); } - private void test(RegressionTestConfig cfg) throws IOException { + private void test(SystemConfig cfg) throws IOException { CharStream programInputStream = CharStreams.fromPath( Paths.get("benchmarks", "siemens", "racks", "racks.lp")); Solver solver = buildSolverForRegressionTest(new ProgramParserImpl().parse(programInputStream), cfg); diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/SolverStatisticsTests.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverStatisticsTests.java similarity index 77% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/SolverStatisticsTests.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverStatisticsTests.java index 1afed713b..b2bea6687 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/SolverStatisticsTests.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverStatisticsTests.java @@ -23,9 +23,9 @@ * 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.solver; +package at.ac.tuwien.kr.alpha.regressiontests; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.buildSolverForRegressionTest; +import static at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestUtils.buildSolverForRegressionTest; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeTrue; @@ -36,10 +36,14 @@ import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; import at.ac.tuwien.kr.alpha.api.StatisticsReportingSolver; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; 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.DummyGrounder; +import at.ac.tuwien.kr.alpha.core.solver.DefaultSolver; +import at.ac.tuwien.kr.alpha.core.solver.NoGoodCounter; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; +// TODO This is a functional test and should not be run with standard unit tests public class SolverStatisticsTests { private AtomStore atomStore; @@ -50,32 +54,33 @@ public void setUp() { } @RegressionTest - public void checkStatsStringZeroChoices(RegressionTestConfig cfg) { + public void checkStatsStringZeroChoices(SystemConfig cfg) { Solver solver = buildSolverForRegressionTest("a.", cfg); assumeTrue(solver instanceof StatisticsReportingSolver); collectAnswerSetsAndCheckStats(solver, 1, 0, 0, 0, 0, 0, 0, 0); } @RegressionTest - public void checkStatsStringOneChoice(RegressionTestConfig cfg) { + public void checkStatsStringOneChoice(SystemConfig cfg) { Solver solver = buildSolverForRegressionTest("a :- not b. b :- not a.", cfg); assumeTrue(solver instanceof StatisticsReportingSolver); collectAnswerSetsAndCheckStats(solver, 2, 1, 1, 1, 1, 0, 0, 0); } - @RegressionTest - public void checkNoGoodCounterStatsByTypeUsingDummyGrounder(RegressionTestConfig cfg) { - Solver solver = buildSolverForRegressionTest(atomStore, new DummyGrounder(atomStore), cfg); - assumeTrue(solver instanceof StatisticsReportingSolver); - collectAnswerSetsAndCheckNoGoodCounterStatsByType(solver, 4, 0, 0, 0); - } + // TODO Why are these tests config-dependent if they use a grounder mock and seem rather like unit tests on solver statistics? + // @RegressionTest + // public void checkNoGoodCounterStatsByTypeUsingDummyGrounder(SystemConfig cfg) { + // Solver solver = buildSolverForRegressionTest(atomStore, new GrounderMockWithBasicProgram(atomStore), cfg); + // assumeTrue(solver instanceof StatisticsReportingSolver); + // collectAnswerSetsAndCheckNoGoodCounterStatsByType(solver, 4, 0, 0, 0); + // } - @RegressionTest - public void checkNoGoodCounterStatsByCardinalityUsingDummyGrounder(RegressionTestConfig cfg) { - Solver solver = buildSolverForRegressionTest(atomStore, new DummyGrounder(atomStore), cfg); - assumeTrue(solver instanceof StatisticsReportingSolver); - collectAnswerSetsAndCheckNoGoodCounterStatsByCardinality(solver, 2, 1, 1); - } + // @RegressionTest + // public void checkNoGoodCounterStatsByCardinalityUsingDummyGrounder(SystemConfig cfg) { + // Solver solver = buildSolverForRegressionTest(atomStore, new GrounderMockWithBasicProgram(atomStore), cfg); + // assumeTrue(solver instanceof StatisticsReportingSolver); + // collectAnswerSetsAndCheckNoGoodCounterStatsByCardinality(solver, 2, 1, 1); + // } private void collectAnswerSetsAndCheckStats(Solver solver, int expectedNumberOfAnswerSets, int expectedNumberOfGuesses, int expectedTotalNumberOfBacktracks, int expectedNumberOfBacktracksWithinBackjumps, int expectedNumberOfBackjumps, int expectedNumberOfMBTs, int expectedNumberOfConflictsAfterClosing, int expectedNumberOfDeletedNoGoods) { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/SolverTests.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverTests.java similarity index 77% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/SolverTests.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverTests.java index c0bfdd991..65556fc3e 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/SolverTests.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/SolverTests.java @@ -25,26 +25,12 @@ * 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.solver; - -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSet; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSets; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.assertRegressionTestAnswerSetsWithBase; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.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; +package at.ac.tuwien.kr.alpha.regressiontests; import at.ac.tuwien.kr.alpha.api.AnswerSet; import at.ac.tuwien.kr.alpha.api.Solver; -import at.ac.tuwien.kr.alpha.api.programs.ASPCore2Program; +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.programs.terms.ConstantTerm; @@ -53,11 +39,14 @@ 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.core.common.AtomStore; -import at.ac.tuwien.kr.alpha.core.common.AtomStoreImpl; -import at.ac.tuwien.kr.alpha.core.grounder.ChoiceGrounder; -import at.ac.tuwien.kr.alpha.core.grounder.DummyGrounder; -import at.ac.tuwien.kr.alpha.core.test.util.AnswerSetsParser; +import at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTest; +import at.ac.tuwien.kr.alpha.test.AnswerSetsParser; + +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 { @@ -74,12 +63,12 @@ public int compareTo(Thingy o) { } @RegressionTest - public void testObjectProgram(RegressionTestConfig cfg) { + public void testObjectProgram(SystemConfig cfg) { final Thingy thingy = new Thingy(); final Atom fact = Atoms.newBasicAtom(Predicates.getPredicate("foo", 1), Terms.newConstant(thingy)); - final ASPCore2Program program = Programs.newASPCore2Program( + final InputProgram program = Programs.newInputProgram( Collections.emptyList(), Collections.singletonList(fact), Programs.newInlineDirectives() @@ -91,8 +80,8 @@ public void testObjectProgram(RegressionTestConfig cfg) { } @RegressionTest - public void testFactsOnlyProgram(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void testFactsOnlyProgram(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "p(a). p(b). foo(13). foo(16). q(a). q(c).", @@ -101,8 +90,8 @@ public void testFactsOnlyProgram(RegressionTestConfig cfg) { } @RegressionTest - public void testSimpleRule(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void testSimpleRule(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "p(a). p(b). r(X) :- p(X).", @@ -111,8 +100,8 @@ public void testSimpleRule(RegressionTestConfig cfg) { } @RegressionTest - public void testSimpleRuleWithGroundPart(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void testSimpleRuleWithGroundPart(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "p(1)." + "p(2)." + @@ -123,8 +112,8 @@ public void testSimpleRuleWithGroundPart(RegressionTestConfig cfg) { } @RegressionTest - public void testProgramZeroArityPredicates(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void testProgramZeroArityPredicates(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "a. p(X) :- b, r(X).", @@ -133,7 +122,7 @@ public void testProgramZeroArityPredicates(RegressionTestConfig cfg) { } @RegressionTest - public void testChoiceGroundProgram(RegressionTestConfig cfg) { + public void testChoiceGroundProgram(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "a :- not b. b :- not a.", @@ -144,7 +133,7 @@ public void testChoiceGroundProgram(RegressionTestConfig cfg) { } @RegressionTest - public void testChoiceProgramNonGround(RegressionTestConfig cfg) { + public void testChoiceProgramNonGround(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "dom(1). dom(2). dom(3)." + @@ -165,7 +154,7 @@ public void testChoiceProgramNonGround(RegressionTestConfig cfg) { } @RegressionTest - public void choiceProgram3Way(RegressionTestConfig cfg) { + public void choiceProgram3Way(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "a :- not b, not c." + @@ -179,12 +168,12 @@ public void choiceProgram3Way(RegressionTestConfig cfg) { } @RegressionTest - public void emptyProgramYieldsEmptyAnswerSet(RegressionTestConfig cfg) { + public void emptyProgramYieldsEmptyAnswerSet(SystemConfig cfg) { assertRegressionTestAnswerSets(cfg, "", ""); } @RegressionTest - public void chooseMultipleAnswerSets(RegressionTestConfig cfg) { + public void chooseMultipleAnswerSets(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "a :- not nota." + @@ -206,8 +195,8 @@ public void chooseMultipleAnswerSets(RegressionTestConfig cfg) { } @RegressionTest - public void builtinAtoms(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void builtinAtoms(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "dom(1). dom(2). dom(3). dom(4). dom(5)." + "p(X) :- dom(X), X = 4." + @@ -218,8 +207,8 @@ public void builtinAtoms(RegressionTestConfig cfg) { } @RegressionTest - public void builtinAtomsGroundRule(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void builtinAtomsGroundRule(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "a :- 13 != 4." + "b :- 2 != 3, 2 = 3." + @@ -231,8 +220,8 @@ public void builtinAtomsGroundRule(RegressionTestConfig cfg) { @RegressionTest - public void choiceProgramConstraintSimple(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void choiceProgramConstraintSimple(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "fact(a).\n" + "choice(either, X) :- fact(X), not choice(or, X).\n" + @@ -244,8 +233,8 @@ public void choiceProgramConstraintSimple(RegressionTestConfig cfg) { } @RegressionTest - public void choiceProgramConstraintSimple2(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void choiceProgramConstraintSimple2(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "fact(a).\n" + "desired(either).\n" + @@ -258,7 +247,7 @@ public void choiceProgramConstraintSimple2(RegressionTestConfig cfg) { } @RegressionTest - public void choiceProgramConstraint(RegressionTestConfig cfg) { + public void choiceProgramConstraint(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "eq(1,1)." + @@ -284,7 +273,7 @@ public void choiceProgramConstraint(RegressionTestConfig cfg) { } @RegressionTest - public void choiceProgramConstraintPermutation(RegressionTestConfig cfg) { + public void choiceProgramConstraintPermutation(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "eq(1,1)." + @@ -310,8 +299,8 @@ public void choiceProgramConstraintPermutation(RegressionTestConfig cfg) { } @RegressionTest - public void simpleNoPropagation(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void simpleNoPropagation(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "val(1,1)." + "val(2,2)." + @@ -322,7 +311,7 @@ public void simpleNoPropagation(RegressionTestConfig cfg) { } @RegressionTest - public void choiceAndPropagationAfterwards(RegressionTestConfig cfg) { + public void choiceAndPropagationAfterwards(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "node(a)." + @@ -341,7 +330,7 @@ public void choiceAndPropagationAfterwards(RegressionTestConfig cfg) { } @RegressionTest - public void choiceAndConstraints(RegressionTestConfig cfg) { + public void choiceAndConstraints(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "node(a)." + @@ -360,13 +349,13 @@ public void choiceAndConstraints(RegressionTestConfig cfg) { } @RegressionTest - public void testUnsatisfiableProgram(RegressionTestConfig cfg) { + public void testUnsatisfiableProgram(SystemConfig cfg) { assertRegressionTestAnswerSets(cfg, "p(a). p(b). :- p(a), p(b)."); } @RegressionTest - public void testFunctionTermEquality(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void testFunctionTermEquality(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "r1(f(a,b)). r2(f(a,b)). a :- r1(X), r2(Y), X = Y.", @@ -375,7 +364,7 @@ public void testFunctionTermEquality(RegressionTestConfig cfg) { } @RegressionTest - public void builtinInequality(RegressionTestConfig cfg) { + public void builtinInequality(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "location(a1)." + @@ -398,7 +387,7 @@ public void builtinInequality(RegressionTestConfig cfg) { } @RegressionTest - public void choiceConstraintsInequality(RegressionTestConfig cfg) { + public void choiceConstraintsInequality(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "assign(L, R) :- not nassign(L, R), possible(L, R)." + @@ -456,7 +445,7 @@ public void choiceConstraintsInequality(RegressionTestConfig cfg) { } @RegressionTest - public void sameVariableTwiceInAtom(RegressionTestConfig cfg) { + public void sameVariableTwiceInAtom(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "p(a, a)." + @@ -467,7 +456,7 @@ public void sameVariableTwiceInAtom(RegressionTestConfig cfg) { } @RegressionTest - public void sameVariableTwiceInAtomConstraint(RegressionTestConfig cfg) { + public void sameVariableTwiceInAtomConstraint(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "p(a, a)." + @@ -476,7 +465,7 @@ public void sameVariableTwiceInAtomConstraint(RegressionTestConfig cfg) { } @RegressionTest - public void noPositiveSelfFounding(RegressionTestConfig cfg) { + public void noPositiveSelfFounding(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "a :- b." + @@ -486,7 +475,7 @@ public void noPositiveSelfFounding(RegressionTestConfig cfg) { } @RegressionTest - public void noPositiveCycleSelfFoundingChoice(RegressionTestConfig cfg) { + public void noPositiveCycleSelfFoundingChoice(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "c :- not d." + @@ -498,8 +487,8 @@ public void noPositiveCycleSelfFoundingChoice(RegressionTestConfig cfg) { } @RegressionTest - public void conflictFromUnaryNoGood(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void conflictFromUnaryNoGood(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "d(b)." + "sel(X) :- not nsel(X), d(X)." + @@ -512,7 +501,7 @@ public void conflictFromUnaryNoGood(RegressionTestConfig cfg) { } @RegressionTest - public void intervalsInFacts(RegressionTestConfig cfg) { + public void intervalsInFacts(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "a." + @@ -549,7 +538,7 @@ public void intervalsInFacts(RegressionTestConfig cfg) { } @RegressionTest - public void intervalInRules(RegressionTestConfig cfg) { + public void intervalInRules(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "a :- 3 = 1..4 ." + @@ -570,7 +559,7 @@ public void intervalInRules(RegressionTestConfig cfg) { } @RegressionTest - public void emptyIntervals(RegressionTestConfig cfg) { + public void emptyIntervals(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "p(3..1)." + @@ -581,7 +570,7 @@ public void emptyIntervals(RegressionTestConfig cfg) { } @RegressionTest - public void intervalInFunctionTermsInRules(RegressionTestConfig cfg) { + public void intervalInFunctionTermsInRules(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "a :- q(f(1..3,g(4..5)))." + @@ -606,8 +595,8 @@ public void intervalInFunctionTermsInRules(RegressionTestConfig cfg) { } @RegressionTest - public void groundAtomInRule(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void groundAtomInRule(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "p :- dom(X), q, q2." + "dom(1)." + @@ -622,7 +611,7 @@ public void groundAtomInRule(RegressionTestConfig cfg) { } @RegressionTest - public void simpleChoiceRule(RegressionTestConfig cfg) { + public void simpleChoiceRule(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "{ a; b; c} :- d." + @@ -641,7 +630,7 @@ public void simpleChoiceRule(RegressionTestConfig cfg) { } @RegressionTest - public void conditionalChoiceRule(RegressionTestConfig cfg) { + public void conditionalChoiceRule(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "dom(1..3)." + @@ -665,7 +654,7 @@ public void conditionalChoiceRule(RegressionTestConfig cfg) { } @RegressionTest - public void doubleChoiceRule(RegressionTestConfig cfg) { + public void doubleChoiceRule(SystemConfig cfg) { Solver solver = buildSolverForRegressionTest("{ a }. { a }.", cfg); // Make sure that no superfluous answer sets that only differ on hidden atoms occur. List actual = solver.collectList(); @@ -674,8 +663,8 @@ public void doubleChoiceRule(RegressionTestConfig cfg) { } @RegressionTest - public void simpleArithmetics(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void simpleArithmetics(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "eight(X) :- X = 4 + 5 - 1." + "three(X) :- X = Z, Y = 1..10, Z = Y / 3, Z > 2, Z < 4.", @@ -684,8 +673,8 @@ public void simpleArithmetics(RegressionTestConfig cfg) { } @RegressionTest - public void arithmeticsMultiplicationBeforeAddition(RegressionTestConfig cfg) { - assertRegressionTestAnswerSet( + public void arithmeticsMultiplicationBeforeAddition(SystemConfig cfg) { + assertRegressionTestAnswerSets( cfg, "seven(X) :- 1+2 * 3 = X.", @@ -696,7 +685,7 @@ public void arithmeticsMultiplicationBeforeAddition(RegressionTestConfig cfg) { * Tests the fix for issue #101 */ @RegressionTest - public void involvedUnsatisfiableProgram(RegressionTestConfig cfg) { + public void involvedUnsatisfiableProgram(SystemConfig cfg) { assertRegressionTestAnswerSets( cfg, "x :- c1, c2, not x." + @@ -711,7 +700,7 @@ public void involvedUnsatisfiableProgram(RegressionTestConfig cfg) { } @RegressionTest - public void instanceEnumerationAtom(RegressionTestConfig cfg) { + public void instanceEnumerationAtom(SystemConfig cfg) { Set answerSets = buildSolverForRegressionTest("# enumeration_predicate_is enum." + "dom(1). dom(2). dom(3)." + "p(X) :- dom(X)." + @@ -728,7 +717,7 @@ public void instanceEnumerationAtom(RegressionTestConfig cfg) { } @RegressionTest - public void instanceEnumerationArbitraryTerms(RegressionTestConfig cfg) { + public void instanceEnumerationArbitraryTerms(SystemConfig cfg) { Set answerSets = buildSolverForRegressionTest("# enumeration_predicate_is enum." + "dom(a). dom(f(a,b)). dom(d)." + "p(X) :- dom(X)." + @@ -745,7 +734,7 @@ public void instanceEnumerationArbitraryTerms(RegressionTestConfig cfg) { } @RegressionTest - public void instanceEnumerationMultipleIdentifiers(RegressionTestConfig cfg) { + public void instanceEnumerationMultipleIdentifiers(SystemConfig cfg) { Set answerSets = buildSolverForRegressionTest("# enumeration_predicate_is enum." + "dom(a). dom(b). dom(c). dom(d)." + "p(X) :- dom(X)." + @@ -765,15 +754,15 @@ public void instanceEnumerationMultipleIdentifiers(RegressionTestConfig 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; } @@ -783,7 +772,7 @@ private void assertEnumerationPositions(SortedSet positions, int numPositi } @RegressionTest - public void smallCardinalityAggregate(RegressionTestConfig cfg) { + public void smallCardinalityAggregate(SystemConfig cfg) { assertRegressionTestAnswerSetsWithBase( cfg, "dom(1..3)." + @@ -804,16 +793,17 @@ public void smallCardinalityAggregate(RegressionTestConfig cfg) { ); } - @RegressionTest - public void dummyGrounder(RegressionTestConfig cfg) { - AtomStore atomStore = new AtomStoreImpl(); - assertEquals(DummyGrounder.EXPECTED, buildSolverForRegressionTest(atomStore, new DummyGrounder(atomStore), cfg).collectSet()); - } - - @RegressionTest - public void choiceGrounder(RegressionTestConfig cfg) { - AtomStore atomStore = new AtomStoreImpl(); - assertEquals(ChoiceGrounder.EXPECTED, buildSolverForRegressionTest(atomStore, new ChoiceGrounder(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 new file mode 100644 index 000000000..ada29162d --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/StratifiedEvaluationRegressionTest.java @@ -0,0 +1,293 @@ +package at.ac.tuwien.kr.alpha.regressiontests; + +import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertAnswerSetsEqual; +import static at.ac.tuwien.kr.alpha.test.AlphaAssertions.assertFactsContainedInProgram; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +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; +import org.junit.jupiter.params.provider.MethodSource; +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; +import at.ac.tuwien.kr.alpha.api.Solver; +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; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.commons.Predicates; + +// TODO This is a functional test and should not be run with standard unit tests +public class StratifiedEvaluationRegressionTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(StratifiedEvaluationRegressionTest.class); + + //@formatter:off + private static final String STRATIFIED_NEG_ASP = "base(X) :- req(X), not incomp(X).\n" + + "depend_base(X, Y) :- base(X), base(Y).\n" + + "dep_b_hlp(X) :- depend_base(X, _).\n" + + "fallback_base(X) :- base(X), not dep_b_hlp(X).\n" + + "depend_further(X) :- depend_base(_, X).\n" + + "depend_further(X) :- fallback_base(X)."; + + private static final String BASIC_TEST_ASP = "a. b:- a."; + private static final String BASIC_MULTI_INSTANCE_ASP = "p(a). p(b). q(X) :- p(X)."; + private static final String BASIC_NEGATION_ASP = "p(a). q(b). p(c). q(d). r(c). s(X, Y) :- p(X), q(Y), not r(X)."; + private static final String PART_STRATIFIED_ASP = + "p(a). q(a). p(b). m(c). n(d).\n" + + "r(X) :- p(X), q(X).\n" + + "s(X, Y, Z) :- r(X), m(Y), n(Z).\n" + + "t(X, Y) :- p(X), q(X), p(Y), not q(Y).\n" + + "either(X) :- t(X, _), not or(X).\n" + + "or(X) :- t(X, _), not either(X)."; + private static final String POSITIVE_RECURSION_ASP = + "num(0).\n" + + "max_num(10).\n" + + "num(S) :- num(N), S = N + 1, S <= M, max_num(M)."; + private static final String EMPTY_PROG_ASP = ""; + private static final String FACTS_ONLY_ASP = "a. b. c. p(a). q(b, c). r(c, c, a). s(b)."; + private static final String STRATIFIED_NO_FACTS_ASP = STRATIFIED_NEG_ASP; + private static final String STRATIFIED_W_FACTS_ASP = "req(a). req(b). incomp(b).\n" + STRATIFIED_NEG_ASP; + private static final String EQUALITY_ASP = "equal :- 1 = 1."; + private static final String EQUALITY_WITH_VAR_ASP = "a(1). a(2). a(3). b(X) :- a(X), X = 1. c(X) :- a(X), X = 2. d(X) :- X = 3, a(X)."; + + private static final ImmutablePair, Consumer>> BASIC_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramBasic, StratifiedEvaluationRegressionTest::verifyAnswerSetsBasic); + private static final ImmutablePair, Consumer>> BASIC_MULTI_INSTANCE_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramBasicMultiInstance, StratifiedEvaluationRegressionTest::verifyAnswerSetsBasicMultiInstance); + private static final ImmutablePair, Consumer>> BASIC_NEGATION_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramBasicNegation, StratifiedEvaluationRegressionTest::verifyAnswerSetsBasicNegation); + private static final ImmutablePair, Consumer>> PART_STRATIFIED_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramPartStratified, StratifiedEvaluationRegressionTest::verifyAnswerSetsPartStratified); + private static final ImmutablePair, Consumer>> POSITIVE_RECURSIVE_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramPositiveRecursive, StratifiedEvaluationRegressionTest::verifyAnswerSetsPositiveRecursive); + private static final ImmutablePair, Consumer>> EMPTY_PROG_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramEmptyProg, StratifiedEvaluationRegressionTest::verifyAnswerSetsEmptyProg); + private static final ImmutablePair, Consumer>> FACTS_ONLY_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramFactsOnly, StratifiedEvaluationRegressionTest::verifyAnswerSetsFactsOnly); + private static final ImmutablePair, Consumer>> STRATIFIED_NO_FACTS_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramStratNoFacts, StratifiedEvaluationRegressionTest::verifyAnswerSetsStratNoFacts); + private static final ImmutablePair, Consumer>> STRATIFIED_W_FACTS_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramStratWithFacts, StratifiedEvaluationRegressionTest::verifyAnswerSetsStratWithFacts); + private static final ImmutablePair, Consumer>> EQUALITY_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramEquality, StratifiedEvaluationRegressionTest::verifyAnswerSetsEquality); + private static final ImmutablePair, Consumer>> EQUALITY_WITH_VAR_VERIFIERS = new ImmutablePair<>( + StratifiedEvaluationRegressionTest::verifyProgramEqualityWithVar, StratifiedEvaluationRegressionTest::verifyAnswerSetsEqualityWithVar); + + public static List params() { + List, Consumer>>>> testCases = new ArrayList<>(); + List paramList = new ArrayList<>(); + testCases.add(new ImmutablePair<>(BASIC_TEST_ASP, BASIC_VERIFIERS)); + testCases.add(new ImmutablePair<>(BASIC_MULTI_INSTANCE_ASP, BASIC_MULTI_INSTANCE_VERIFIERS)); + testCases.add(new ImmutablePair<>(BASIC_NEGATION_ASP, BASIC_NEGATION_VERIFIERS)); + testCases.add(new ImmutablePair<>(PART_STRATIFIED_ASP, PART_STRATIFIED_VERIFIERS)); + testCases.add(new ImmutablePair<>(POSITIVE_RECURSION_ASP, POSITIVE_RECURSIVE_VERIFIERS)); + testCases.add(new ImmutablePair<>(EMPTY_PROG_ASP, EMPTY_PROG_VERIFIERS)); + testCases.add(new ImmutablePair<>(FACTS_ONLY_ASP, FACTS_ONLY_VERIFIERS)); + testCases.add(new ImmutablePair<>(STRATIFIED_NO_FACTS_ASP, STRATIFIED_NO_FACTS_VERIFIERS)); + testCases.add(new ImmutablePair<>(STRATIFIED_W_FACTS_ASP, STRATIFIED_W_FACTS_VERIFIERS)); + testCases.add(new ImmutablePair<>(EQUALITY_ASP, EQUALITY_VERIFIERS)); + testCases.add(new ImmutablePair<>(EQUALITY_WITH_VAR_ASP, EQUALITY_WITH_VAR_VERIFIERS)); + + testCases.forEach((pair) -> paramList.add(Arguments.of(pair.left, pair.right.left, pair.right.right))); + return paramList; + } + //@formatter:on + + @ParameterizedTest + @MethodSource("at.ac.tuwien.kr.alpha.regressiontests.StratifiedEvaluationRegressionTest#params") + public void runTest(String aspString, Consumer programVerifier, + Consumer> resultVerifier) { + LOGGER.debug("Testing ASP String {}", aspString); + // Parse and pre-evaluate program + // Alpha instance with default config, stratified evaluation enabled + Alpha alpha = AlphaFactory.newAlpha(); + InputProgram input = alpha.readProgramString(aspString); + DebugSolvingContext dbgInfo = alpha.prepareDebugSolve(input); + NormalProgram evaluated = dbgInfo.getPreprocessedProgram(); + // Verify stratified evaluation result + programVerifier.accept(evaluated); + // Solve remaining program + Solver solver = dbgInfo.getSolver(); + Set answerSets = solver.collectSet(); + resultVerifier.accept(answerSets); + } + + 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().isEmpty()); + } + + private static void verifyAnswerSetsBasic(Set answerSets) { + assertAnswerSetsEqual("a, b", answerSets); + } + + 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().isEmpty()); + } + + private static void verifyAnswerSetsBasicMultiInstance(Set answerSets) { + assertAnswerSetsEqual("p(a), p(b), q(a), q(b)", answerSets); + } + + private static void verifyProgramBasicNegation(NormalProgram evaluated) { + assertFactsContainedInProgram(evaluated, + Atoms.newBasicAtom(Predicates.getPredicate("s", 2), Terms.newSymbolicConstant("a"), + Terms.newSymbolicConstant("b")), + Atoms.newBasicAtom(Predicates.getPredicate("s", 2), Terms.newSymbolicConstant("a"), + Terms.newSymbolicConstant("d"))); + assertEquals(7, evaluated.getFacts().size()); + assertEquals(0, evaluated.getRules().size()); + } + + private static void verifyAnswerSetsBasicNegation(Set answerSets) { + assertAnswerSetsEqual("p(a), q(b), p(c), q(d), r(c), s(a,b), s(a,d)", answerSets); + } + + private static void verifyProgramPartStratified(NormalProgram evaluated) { + LOGGER.debug("part stratified evaluated prog is:\n{}", evaluated.toString()); + assertFactsContainedInProgram(evaluated, + Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newSymbolicConstant("a")), + Atoms.newBasicAtom(Predicates.getPredicate("q", 1), Terms.newSymbolicConstant("a")), + Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newSymbolicConstant("b")), + Atoms.newBasicAtom(Predicates.getPredicate("m", 1), Terms.newSymbolicConstant("c")), + Atoms.newBasicAtom(Predicates.getPredicate("n", 1), Terms.newSymbolicConstant("d")), + Atoms.newBasicAtom(Predicates.getPredicate("r", 1), Terms.newSymbolicConstant("a")), + Atoms.newBasicAtom(Predicates.getPredicate("s", 3), Terms.newSymbolicConstant("a"), + Terms.newSymbolicConstant("c"), Terms.newSymbolicConstant("d")), + Atoms.newBasicAtom(Predicates.getPredicate("t", 2), Terms.newSymbolicConstant("a"), + Terms.newSymbolicConstant("b"))); + assertEquals(2, evaluated.getRules().size()); + } + + private static void verifyAnswerSetsPartStratified(Set answerSets) { + assertAnswerSetsEqual(new String[] {"p(a), q(a), p(b), m(c), n(d), r(a), s(a,c,d), t(a,b), either(a)", + "p(a), q(a), p(b), m(c), n(d), r(a), s(a,c,d), t(a,b), or(a)" }, answerSets); + } + + private static void verifyProgramPositiveRecursive(NormalProgram evaluated) { + Predicate num = Predicates.getPredicate("num", 1); + assertFactsContainedInProgram(evaluated, + Atoms.newBasicAtom(Predicates.getPredicate("max_num", 1), Terms.newConstant(10)), + Atoms.newBasicAtom(num, Terms.newConstant(0)), Atoms.newBasicAtom(num, Terms.newConstant(1)), + Atoms.newBasicAtom(num, Terms.newConstant(2)), Atoms.newBasicAtom(num, Terms.newConstant(3)), + Atoms.newBasicAtom(num, Terms.newConstant(4)), Atoms.newBasicAtom(num, Terms.newConstant(5)), + Atoms.newBasicAtom(num, Terms.newConstant(6)), Atoms.newBasicAtom(num, Terms.newConstant(7)), + Atoms.newBasicAtom(num, Terms.newConstant(8)), Atoms.newBasicAtom(num, Terms.newConstant(9)), + Atoms.newBasicAtom(num, Terms.newConstant(10))); + LOGGER.debug("Recursive program evaluated is:\n{}", evaluated.toString()); + assertEquals(0, evaluated.getRules().size()); + } + + private static void verifyAnswerSetsPositiveRecursive(Set answerSets) { + assertAnswerSetsEqual( + "max_num(10), num(0), num(1), num(2), num(3), num(4), num(5), num(6), num(7), num(8), num(9), num(10)", + answerSets); + } + + private static void verifyProgramEmptyProg(NormalProgram evaluated) { + assertTrue(evaluated.getRules().isEmpty()); + assertTrue(evaluated.getFacts().isEmpty()); + } + + private static void verifyAnswerSetsEmptyProg(Set answerSets) { + assertEquals(1, answerSets.size()); + assertTrue(answerSets.iterator().next().isEmpty()); + } + + private static void verifyProgramFactsOnly(NormalProgram evaluated) { + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("a", 0)))); + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("b", 0)))); + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("c", 0)))); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("p", 1), Terms.newSymbolicConstant("a")))); + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("q", 2), + Terms.newSymbolicConstant("b"), Terms.newSymbolicConstant("c")))); + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("r", 3), + Terms.newSymbolicConstant("c"), Terms.newSymbolicConstant("c"), Terms.newSymbolicConstant("a")))); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("s", 1), Terms.newSymbolicConstant("b")))); + } + + private static void verifyAnswerSetsFactsOnly(Set answerSets) { + assertAnswerSetsEqual("a, b, c, p(a), q(b,c), r(c,c,a), s(b)", answerSets); + } + + private static void verifyProgramStratNoFacts(NormalProgram evaluated) { + assertTrue(evaluated.getFacts().isEmpty()); + } + + private static void verifyAnswerSetsStratNoFacts(Set answerSets) { + assertEquals(1, answerSets.size()); + assertTrue(answerSets.iterator().next().isEmpty()); + } + + private static void verifyProgramStratWithFacts(NormalProgram evaluated) { + // rules should all be taken care of at this point + assertTrue(evaluated.getRules().isEmpty()); + + // facts should be the full answer set + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("req", 1), Terms.newSymbolicConstant("a")))); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("req", 1), Terms.newSymbolicConstant("b")))); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("incomp", 1), Terms.newSymbolicConstant("b")))); + + // below facts from stratified evaluation + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("base", 1), Terms.newSymbolicConstant("a")))); + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("depend_base", 2), + Terms.newSymbolicConstant("a"), Terms.newSymbolicConstant("a")))); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("dep_b_hlp", 1), Terms.newSymbolicConstant("a")))); + assertTrue(evaluated.getFacts().contains( + Atoms.newBasicAtom(Predicates.getPredicate("depend_further", 1), Terms.newSymbolicConstant("a")))); + } + + private static void verifyAnswerSetsStratWithFacts(Set answerSets) { + assertAnswerSetsEqual("req(a), req(b), incomp(b), base(a), depend_base(a,a), dep_b_hlp(a), depend_further(a)", + answerSets); + } + + private static void verifyProgramEquality(NormalProgram evaluated) { + assertEquals(0, evaluated.getRules().size()); + assertTrue(evaluated.getFacts().contains(Atoms.newBasicAtom(Predicates.getPredicate("equal", 0)))); + } + + private static void verifyAnswerSetsEquality(Set answerSets) { + assertAnswerSetsEqual("equal", answerSets); + } + + private static void verifyProgramEqualityWithVar(NormalProgram evaluated) { + assertEquals(0, evaluated.getRules().size()); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("a", 1), Terms.newConstant(1)))); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("c", 1), Terms.newConstant(2)))); + assertTrue(evaluated.getFacts() + .contains(Atoms.newBasicAtom(Predicates.getPredicate("d", 1), Terms.newConstant(3)))); + } + + private static void verifyAnswerSetsEqualityWithVar(Set answerSets) { + assertAnswerSetsEqual("a(1), a(2), a(3), b(1), c(2), d(3)", answerSets); + } + +} \ No newline at end of file diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringRandomGraphTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringRandomGraphTest.java similarity index 82% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringRandomGraphTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringRandomGraphTest.java index b39232c8c..1740d5133 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringRandomGraphTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringRandomGraphTest.java @@ -23,93 +23,95 @@ * 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.solver; - -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.runWithTimeout; +package at.ac.tuwien.kr.alpha.regressiontests; 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.programs.ASPCore2Program; +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.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.programs.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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 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; @RegressionTest - public void testV3E3(RegressionTestConfig cfg) { + public void testV3E3(SystemConfig cfg) { long timeout = 1000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(3, 3, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testV10E18(RegressionTestConfig cfg) { + public void testV10E18(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(10, 18, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testV20E38(RegressionTestConfig cfg) { + public void testV20E38(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(20, 38, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testV30E48(RegressionTestConfig cfg) { + public void testV30E48(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(30, 48, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testV200E300(RegressionTestConfig cfg) { + public void testV200E300(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(200, 300, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testV300E200(RegressionTestConfig cfg) { + public void testV300E200(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(300, 200, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testV300E300(RegressionTestConfig cfg) { + public void testV300E300(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(300, 300, cfg)); } - private void testThreeColouring(int nVertices, int nEdges, RegressionTestConfig cfg) { - ASPCore2Program tmpPrg = new ProgramParserImpl().parse( + private void testThreeColouring(int nVertices, int nEdges, SystemConfig cfg) { + InputProgram tmpPrg = new ProgramParserImpl().parse( "blue(N) :- v(N), not red(N), not green(N)." + "red(N) :- v(N), not blue(N), not green(N)." + "green(N) :- v(N), not red(N), not blue(N)." + ":- e(N1,N2), blue(N1), blue(N2)." + ":- e(N1,N2), red(N1), red(N2)." + ":- e(N1,N2), green(N1), green(N2)."); - ASPCore2ProgramBuilder prgBuilder = Programs.builder(tmpPrg); + InputProgramBuilder prgBuilder = Programs.builder(tmpPrg); prgBuilder.addFacts(createVertices(nVertices)); prgBuilder.addFacts(createEdges(nVertices, nEdges)); - ASPCore2Program program = prgBuilder.build(); + InputProgram program = prgBuilder.build(); maybeShuffle(program); @SuppressWarnings("unused") @@ -120,7 +122,7 @@ private void testThreeColouring(int nVertices, int nEdges, RegressionTestConfig } @SuppressWarnings("unused") - private void maybeShuffle(ASPCore2Program program) { + private void maybeShuffle(InputProgram program) { // TODO: switch on if different rule orderings in the encoding are desired (e.g. for benchmarking purposes) // FIXME since InputProgram is immutable this needs to be reworked a bit if used diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringTestWithRandom.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringTestWithRandom.java similarity index 83% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringTestWithRandom.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringTestWithRandom.java index e0ff335a6..7af25b780 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringTestWithRandom.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringTestWithRandom.java @@ -23,10 +23,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.solver; - -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.runWithTimeout; +package at.ac.tuwien.kr.alpha.regressiontests; import java.util.ArrayList; import java.util.Collections; @@ -34,23 +31,28 @@ 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.programs.ASPCore2Program; +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.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.programs.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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 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: @@ -61,137 +63,137 @@ public class ThreeColouringTestWithRandom { private static final long DEBUG_TIMEOUT_FACTOR = 5; @RegressionTest - public void testN3(RegressionTestConfig cfg) { + public void testN3(SystemConfig cfg) { long timeout = 3000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(3, false, 0, cfg)); } @RegressionTest - public void testN4(RegressionTestConfig cfg) { + public void testN4(SystemConfig cfg) { long timeout = 4000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(4, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN5(RegressionTestConfig cfg) { + public void testN5(SystemConfig cfg) { long timeout = 5000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(5, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN6(RegressionTestConfig cfg) { + public void testN6(SystemConfig cfg) { long timeout = 6000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(6, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN7(RegressionTestConfig cfg) { + public void testN7(SystemConfig cfg) { long timeout = 7000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(7, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN8(RegressionTestConfig cfg) { + public void testN8(SystemConfig cfg) { long timeout = 8000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(8, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN9(RegressionTestConfig cfg) { + public void testN9(SystemConfig cfg) { long timeout = 9000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(9, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN10(RegressionTestConfig cfg) { + public void testN10(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(10, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN10Random0(RegressionTestConfig cfg) { + public void testN10Random0(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(10, true, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN10Random1(RegressionTestConfig cfg) { + public void testN10Random1(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(10, true, 1, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN10Random2(RegressionTestConfig cfg) { + public void testN10Random2(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(10, true, 2, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN10Random3(RegressionTestConfig cfg) { + public void testN10Random3(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(10, true, 3, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN19(RegressionTestConfig cfg) { + public void testN19(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(19, false, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN19Random0(RegressionTestConfig cfg) { + public void testN19Random0(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(19, true, 0, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN19Random1(RegressionTestConfig cfg) { + public void testN19Random1(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(19, true, 1, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN19Random2(RegressionTestConfig cfg) { + public void testN19Random2(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(19, true, 2, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN19Random3(RegressionTestConfig cfg) { + public void testN19Random3(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(19, true, 3, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN101(RegressionTestConfig cfg) { + public void testN101(SystemConfig cfg) { long timeout = 10000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(101, false, 0, cfg)); } - private void testThreeColouring(int n, boolean shuffle, int seed, RegressionTestConfig cfg) { - ASPCore2Program tmpPrg = new ProgramParserImpl() + 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)."); - ASPCore2ProgramBuilder prgBuilder = Programs.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)); - ASPCore2Program program = prgBuilder.build(); + InputProgram program = prgBuilder.build(); Solver solver = buildSolverForRegressionTest(program, cfg); @SuppressWarnings("unused") diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringWheelTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringWheelTest.java similarity index 82% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringWheelTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringWheelTest.java index 370e6fbd0..a3ad1c447 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/ThreeColouringWheelTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/ThreeColouringWheelTest.java @@ -23,32 +23,34 @@ * 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.solver; - -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.buildSolverForRegressionTest; -import static at.ac.tuwien.kr.alpha.core.test.util.TestUtils.runWithTimeout; +package at.ac.tuwien.kr.alpha.regressiontests; 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.programs.ASPCore2Program; +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.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.programs.Programs; -import at.ac.tuwien.kr.alpha.commons.programs.Programs.ASPCore2ProgramBuilder; +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 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. @@ -59,55 +61,55 @@ public class ThreeColouringWheelTest { private static final long DEBUG_TIMEOUT_FACTOR = 5; @RegressionTest - public void testN4(RegressionTestConfig cfg) { + public void testN4(SystemConfig cfg) { long timeout = 1000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(4, cfg)); } @RegressionTest - public void testN5(RegressionTestConfig cfg) { + public void testN5(SystemConfig cfg) { long timeout = 1000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(5, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN6(RegressionTestConfig cfg) { + public void testN6(SystemConfig cfg) { long timeout = 6000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(6, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN3(RegressionTestConfig cfg) { + public void testN3(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(3, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN7(RegressionTestConfig cfg) { + public void testN7(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(7, cfg)); } @RegressionTest @Disabled("disabled to save resources during CI") - public void testN11(RegressionTestConfig cfg) { + public void testN11(SystemConfig cfg) { long timeout = 60000L; runWithTimeout(cfg, timeout, DEBUG_TIMEOUT_FACTOR, () -> testThreeColouring(11, cfg)); } - private void testThreeColouring(int n, RegressionTestConfig cfg) { - ASPCore2Program tmpPrg = new ProgramParserImpl().parse( + private void testThreeColouring(int n, 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)."); - ASPCore2ProgramBuilder prgBuilder = Programs.builder(tmpPrg); + InputProgramBuilder prgBuilder = Programs.builder(tmpPrg); prgBuilder.addFacts(createColors("red", "blue", "green")); prgBuilder.addFacts(createVertices(n)); prgBuilder.addFacts(createEdges(n)); - ASPCore2Program program = prgBuilder.build(); + InputProgram program = prgBuilder.build(); maybeShuffle(program); @@ -121,7 +123,7 @@ private void testThreeColouring(int n, RegressionTestConfig cfg) { } @SuppressWarnings("unused") - private void maybeShuffle(ASPCore2Program program) { + private void maybeShuffle(InputProgram program) { // FIXME since InputProgram is immutable this needs to be reworked a bit if used // No shuffling here. } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AggregateRegressionTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/AggregateRegressionTest.java similarity index 71% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AggregateRegressionTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/AggregateRegressionTest.java index 8b12f3866..ee4b07305 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/AggregateRegressionTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/AggregateRegressionTest.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.core.solver; +package at.ac.tuwien.kr.alpha.regressiontests.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -11,7 +11,7 @@ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @ParameterizedTest -@MethodSource("at.ac.tuwien.kr.alpha.core.solver.RegressionTestConfigProvider#provideAggregateTestConfigs") +@MethodSource("at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestConfigProvider#provideAggregateTestConfigs") public @interface AggregateRegressionTest { } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/RegressionTest.java b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTest.java similarity index 72% rename from alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/RegressionTest.java rename to alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTest.java index f6f3e28a2..4b5b6f3cd 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/solver/RegressionTest.java +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTest.java @@ -1,4 +1,4 @@ -package at.ac.tuwien.kr.alpha.core.solver; +package at.ac.tuwien.kr.alpha.regressiontests.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -11,7 +11,7 @@ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @ParameterizedTest -@MethodSource("at.ac.tuwien.kr.alpha.core.solver.RegressionTestConfigProvider#provideConfigs") +@MethodSource("at.ac.tuwien.kr.alpha.regressiontests.util.RegressionTestConfigProvider#provideConfigs") public @interface RegressionTest { - + } 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 new file mode 100644 index 000000000..93a5e3ad7 --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestConfigProvider.java @@ -0,0 +1,148 @@ +package at.ac.tuwien.kr.alpha.regressiontests.util; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.junit.jupiter.params.provider.Arguments; + +import at.ac.tuwien.kr.alpha.api.config.AggregateRewritingConfig; +import at.ac.tuwien.kr.alpha.api.config.Heuristic; +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; + +public class RegressionTestConfigProvider { + + private static final String DEFAULT_SOLVER_NAME = "default"; + private static final String DEFAULT_NOGOOD_STORE = "alpharoaming"; + private static final String DEFAULT_BRANCHING_HEURISTIC = "VSIDS"; + private static final String DEFAULT_GROUNDER_TOLERANCE = "strict"; + private static final boolean DEFAULT_DISABLE_INSTANCE_REMOVAL = false; + private static final boolean DEFAULT_ENABLE_DEBUG_CHECKS = false; + + /** + * 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. + * + * @return + */ + private static List buildConfigs() { + // Check whether we are running in a CI environment. + boolean ci = Boolean.valueOf(System.getenv("CI")); + + //@formatter:off + String[] solvers = ci ? new String[]{DEFAULT_SOLVER_NAME, "naive" } : new String[]{DEFAULT_SOLVER_NAME }; + String[] nogoodStores = ci ? new String[]{DEFAULT_NOGOOD_STORE, "naive" } : new String[]{DEFAULT_NOGOOD_STORE }; + String[] heuristics = ci ? nonDeprecatedHeuristics() : new String[]{"NAIVE", DEFAULT_BRANCHING_HEURISTIC }; + 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[] enableDebugChecksValues = new boolean[]{DEFAULT_ENABLE_DEBUG_CHECKS, true }; + //@formatter:on + + // NOTE: + // It is handy to set the seed for reproducing bugs. However, the reverse is also sometimes needed: + // A test case fails, now what was the seed that "caused" it? To allow this, we need full control over + // the seed, so we generate one in any case. + // If your test case fails you can inspect the property called "seed" of AbstractSolverTests and extract + // its value. + String seedProperty = System.getProperty("seed", ci ? "0" : ""); + long seed = seedProperty.isEmpty() ? (new Random().nextLong()) : Long.valueOf(seedProperty); + + List configsToTest = new ArrayList<>(); + for (String solverName : solvers) { + for (String nogoodStoreName : nogoodStores) { + for (String branchingHeuristicName : heuristics) { + for (String grounderToleranceConstraints : gtcValues) { + for (boolean grounderAccumulatorEnabled : grounderAccumulatorValues) { + 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); + } + } + } + } + } + } + return configsToTest; + + } + + /** + * 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. + * + * @return + */ + private static List buildConfigsForAggregateTests() { + List configsToTest = new ArrayList<>(); + boolean[] useSortingGridValues = new boolean[] {true, false }; + boolean[] supportNegativeSumElementsValues = new boolean[] {true, false }; + + 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; + } + + public static List provideConfigs() { + List retVal = new ArrayList<>(); + for (SystemConfig cfg : buildConfigs()) { + retVal.add(Arguments.of(cfg)); + } + return retVal; + } + + public static List provideAggregateTestConfigs() { + List retVal = new ArrayList<>(); + for (SystemConfig cfg : buildConfigsForAggregateTests()) { + retVal.add(Arguments.of(cfg)); + } + return retVal; + } + + private static String[] nonDeprecatedHeuristics() { + final List nonDeprecatedHeuristicsNames = new ArrayList<>(); + for (Field field : Heuristic.class.getFields()) { + if (field.getAnnotation(Deprecated.class) == null) { + nonDeprecatedHeuristicsNames.add(field.getName()); + } + } + return nonDeprecatedHeuristicsNames.toArray(new String[] {}); + } + +} 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 new file mode 100644 index 000000000..c4301385b --- /dev/null +++ b/alpha-solver/src/test/java/at/ac/tuwien/kr/alpha/regressiontests/util/RegressionTestUtils.java @@ -0,0 +1,82 @@ +package at.ac.tuwien.kr.alpha.regressiontests.util; + +import at.ac.tuwien.kr.alpha.api.Alpha; +import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.Solver; +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.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 { + + private RegressionTestUtils() { + throw new AssertionError("Cannot instantiate utility class!"); + } + + public static void runWithTimeout(SystemConfig cfg, long baseTimeout, long timeoutFactor, Executable action) { + long timeout = cfg.isDebugInternalChecks() ? timeoutFactor * baseTimeout : baseTimeout; + assertTimeoutPreemptively(Duration.ofMillis(timeout), action); + } + + public static Solver buildSolverForRegressionTest(String programString, SystemConfig cfg) { + Alpha alpha = AlphaFactory.newAlpha(cfg); + InputProgram program = alpha.readProgramString(programString); + return alpha.prepareSolverFor(program, InputConfig.DEFAULT_FILTER); + } + + public static Solver buildSolverForRegressionTest(InputProgram program, SystemConfig cfg) { + Alpha alpha = AlphaFactory.newAlpha(cfg); + return alpha.prepareSolverFor(program, InputConfig.DEFAULT_FILTER); + } + + public static Set collectRegressionTestAnswerSets(String program, SystemConfig cfg) { + Alpha alpha = AlphaFactory.newAlpha(cfg); + InputProgram in = alpha.readProgramString(program); + return alpha.solve(in).collect(Collectors.toSet()); + } + + public static Set collectRegressionTestAnswerSets(InputProgram program, SystemConfig cfg) { + return AlphaFactory.newAlpha(cfg) + .solve(program) + .collect(Collectors.toSet()); + } + + private static Set solveForConfig(String programString, SystemConfig cfg) { + Alpha alpha = AlphaFactory.newAlpha(cfg); + InputProgram program = alpha.readProgramString(programString); + return alpha.solve(program).collect(Collectors.toSet()); + } + + public static void assertRegressionTestAnswerSets(SystemConfig cfg, String programString, String... expectedAnswerSets) { + assertAnswerSetsEqual(expectedAnswerSets, solveForConfig(programString, cfg)); + } + + public static void assertRegressionTestAnswerSetsWithBase(SystemConfig cfg, String programString, String base, String... expectedAnswerSets) { + assertAnswerSetsEqualWithBase(base, expectedAnswerSets, solveForConfig(programString, cfg)); + } + + public static void ignoreTestForNaiveSolver(SystemConfig cfg) { + Assumptions.assumeFalse(cfg.getSolverName().equals("naive")); + } + + public static void ignoreTestForSimplifiedSumAggregates(SystemConfig cfg) { + Assumptions.assumeTrue(cfg.getAggregateRewritingConfig().isSupportNegativeValuesInSums()); + } + + public static void ignoreTestForNonDefaultDomainIndependentHeuristics(SystemConfig cfg) { + Assumptions.assumeTrue(cfg.getBranchingHeuristic() == Heuristic.VSIDS); + } + +} 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/alpha-solver/src/test/resources/e2e-tests/3col.asp b/alpha-solver/src/test/resources/e2e-tests/3col.asp new file mode 100644 index 000000000..8b7620cde --- /dev/null +++ b/alpha-solver/src/test/resources/e2e-tests/3col.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). + } +} \ No newline at end of file diff --git a/alpha-solver/src/test/resources/e2e-tests/bin-packing.evl b/alpha-solver/src/test/resources/e2e-tests/bin-packing.evl new file mode 100644 index 000000000..53b410fc0 --- /dev/null +++ b/alpha-solver/src/test/resources/e2e-tests/bin-packing.evl @@ -0,0 +1,66 @@ +%%% Module Bin-Packing %%% +% +% This module solves instances of the bin-packing decision problem: +% Given a set of bins, described as terms bin(B, SIZE), and items, described as terms item(I, SIZE), +% the module calculates all assignments of items to bins, such that all items are packed and no +% bin size is exceeded. Each answer set corresponds to one valid assignment. +% +% Input: a fact "instance(BIN_LST, ITEM_LST)", where +% - BIN_LST is a list of terms of form bin(B, SIZE), +% - and ITEM_LST is a list of terms of form item(I, SIZE) +% +%%% +#module bin_packing(instance/2 => {item_packed/2}) { + % Unpack input lists. + bin_element(E, TAIL) :- instance(lst(E, TAIL), _). + bin_element(E, TAIL) :- bin_element(_, lst(E, TAIL)). + bin(B, S) :- bin_element(bin(B, S), _). + + item_element(E, TAIL) :- instance(_, lst(E, TAIL)). + item_element(E, TAIL) :- item_element(_, lst(E, TAIL)). + item(I, S) :- item_element(item(I, S), _). + + % For every item, guess an assignment to each bin. + { item_packed(I, B) : bin(B, _) } :- item(I, _). + % An item may only be assigned to one bin at a time + :- item_packed(I, B1), item_packed(I, B2), B1 != B2. + + % We must not exceed the capacity of any bin. + capacity_used(B, C) :- C = #sum{S : item(I, S), item_packed(I, B)}, bin(B, _). + :- capacity_used(B, C), C > S, bin(B, S). + + % Every item must be packed. + item_packed_somewhere(I) :- item_packed(I, _). + :- item(I, _), not item_packed_somewhere(I). +} + + +%%% Bin-Packing Valuation %%% +% +% Given a Bin-Packing instance and a satisfying assignment, +% calculates a numeric value for the given assignment. +% The value is the sum of the capacities of all bins used in the assignment. +% Intuitively, we calculate the cost in total storage capacity of a given bin assignment. +% +%%% +#module bin_packing_valuation(instance_with_assignment/3 => {assignment_value/1}) { + %% Unpack input + % Extract bins from bin list + bin_element(E, TAIL) :- instance_with_assignment(lst(E, TAIL), _, _). + bin_element(E, TAIL) :- bin_element(_, lst(E, TAIL)). + bin(B, S) :- bin_element(bin(B, S), _). + + % Extract items from item list + item_element(E, TAIL) :- instance_with_assignment(_, lst(E, TAIL), _). + item_element(E, TAIL) :- item_element(_, lst(E, TAIL)). + item(I, S) :- item_element(item(I, S), _). + + % Extract individual item assignments + assignment_element(E, TAIL) :- instance_with_assignment(_, _, lst(E, TAIL)). + assignment_element(E, TAIL) :- assignment_element(_, lst(E, TAIL)). + assigned(I, B) :- assignment_element(item_packed(I, B), _). + + % Get all bins that are used in the assignment + bin_used(B) :- assigned(_, B). + assignment_value(V) :- V = #sum{ S : bin(B, S), bin_used(B)}. +} \ No newline at end of file diff --git a/alpha-solver/src/test/resources/e2e-tests/bin-packing.test.evl b/alpha-solver/src/test/resources/e2e-tests/bin-packing.test.evl new file mode 100644 index 000000000..c7279dbc0 --- /dev/null +++ b/alpha-solver/src/test/resources/e2e-tests/bin-packing.test.evl @@ -0,0 +1,89 @@ +%%% Unit tests for bin_packing module + +instance(BINS, ITEMS) :- BINS = #list{bin(B, S) : bin(B, S)}, ITEMS = #list{item(I, S) : item(I, S)}. +instance_with_assignment(BINS, ITEMS, ASSGN) :- instance(BINS, ITEMS), #bin_packing[BINS, ITEMS](ASSGN). +bin_assignment(A) :- instance_with_assignment(_, _, A). +assignment_valuation_result(A, V) :- instance_with_assignment(B, I, A), #bin_packing_valuation[B, I, A](V). +assignment_value(A, V) :- assignment_valuation_result(A, lst(assignment_value(V), lst_empty)). + +#test singleBinPositiveCase(expect: 1) { + given { + bin(a, 10). + + item(x, 3). + item(y, 2). + item(z, 4). + + } + assertForAll { + % There is excatly one assignment + assignment_found :- bin_assignment(_). + :- not assignment_found. + :- bin_assignment(A1), bin_assignment(A2), A1 != A2. + + % Every item is in a bin + assignment_element(lst(E, TAIL), E, TAIL) :- bin_assignment(lst(E, TAIL)). + assignment_element(ASSGN, E, TAIL) :- assignment_element(ASSGN, _, lst(E, TAIL)). + assigned(I, B, A) :- assignment_element(A, item_packed(I, B), _). + item_assigned(A, I) :- item(I, _), assigned(I, _, A). + :- bin_assignment(A), item(I, _), not item_assigned(A, I). + + % In no assignment, any bin capacity is exceeded + capacity_used(A, B, C) :- C = #sum{S : item(I, S), item_assigned(I, B, A)}, bin_assignment(A), bin(B, _). + :- bin_assignment(A), bin(B, S), capacity_used(A, B, C), C > S. + + % The single assignment has value 10 + :- bin_assignment(A), not assignment_value(A, 10). + } +} + +#test singleBinNegativeCase(expect: 1) { + given { + bin(a, 7). + + item(x, 3). + item(y, 2). + item(z, 4). + } + assertForAll { + % There is no assignment + assignment_found :- bin_assignment(_). + :- assignment_found. + } +} + +#test twoBinsTwoAssignments(expect: 1) { + given { + bin(a, 6). + bin(b, 4). + + item(x, 3). + item(y, 2). + item(z, 4). + + } + assertForAll { + % There are exactly two assignments + num_assignments(N) :- N = #count{ A : bin_assignment(A)}. + assignment_found :- bin_assignment(_). + :- num_assignments(N), N != 2. + + % Every item is in a bin + assignment_element(lst(E, TAIL), E, TAIL) :- bin_assignment(lst(E, TAIL)). + assignment_element(ASSGN, E, TAIL) :- assignment_element(ASSGN, _, lst(E, TAIL)). + assigned(I, B, A) :- assignment_element(A, item_packed(I, B), _). + item_assigned(A, I) :- item(I, _), assigned(I, _, A). + :- bin_assignment(A), item(I, _), not item_assigned(A, I). + + % In no assignment, any bin capacity is exceeded + capacity_used(A, B, C) :- C = #sum{S : item(I, S), item_assigned(I, B, A)}, bin_assignment(A), bin(B, _). + :- bin_assignment(A), bin(B, S), capacity_used(A, B, C), C > S. + + % There is an assignment in which items y and z are in bin a. + y_and_z_in_a :- bin_assignment(A), assigned(y, a, A), assigned(z, a, A). + :- not y_and_z_in_a. + + % Both assignments have value 10 + :- bin_assignment(A), not assignment_value(A, 10). + } +} \ No newline at end of file diff --git a/alpha-solver/src/test/resources/e2e-tests/modules-basic.evl b/alpha-solver/src/test/resources/e2e-tests/modules-basic.evl new file mode 100644 index 000000000..86dcca7c2 --- /dev/null +++ b/alpha-solver/src/test/resources/e2e-tests/modules-basic.evl @@ -0,0 +1,83 @@ +%%% Module 3col %%% +% +% Calculates 3-colorings of a given graph. +% Graph is expected to be represented as a function term with following +% structure: graph(list(V, TAIL), list(E, TAIL)), where list(V, TAIL) +% and list(E, TAIL) are vertex- and edge-lists. +% +%%% +#module threecol(graph/2 => {col/2}) { + % Unwrap input + vertex_element(V, TAIL) :- graph(list(V, TAIL), _). + vertex_element(V, TAIL) :- vertex_element(_, list(V, TAIL)). + vertex(V) :- vertex_element(V, _). + edge_element(E, TAIL) :- graph(_, list(E, TAIL)). + edge_element(E, TAIL) :- edge_element(_, list(E, TAIL)). + edge(V1, V2) :- edge_element(edge(V1, V2), _). + + % Make sure edges are symmetric + edge(V2, V1) :- edge(V1, V2). + + % Guess colors + 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). + + % Filter invalid guesses + :- 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). + + col(V, red) :- red(V). + col(V, blue) :- blue(V). + col(V, green) :- green(V). +} + +%%% Main program %%% +% +% This program uses the module "3col" to determine 3-colorability and actual colorings of a graph +% +%%% + +%% pack vertices into a vertex list +vertex_element(E) :- vertex(E). +% First, establish ordering of elements (which we need to establish the order within the list) +vertex_element_less(N, K) :- vertex_element(N), vertex_element(K), N < K. +vertex_element_not_predecessor(N, K) :- vertex_element_less(N, I), vertex_element_less(I, K). +vertex_element_predecessor(N, K) :- vertex_element_less(N, K), not vertex_element_not_predecessor(N, K). +vertex_element_has_predecessor(N) :- vertex_element_predecessor(_, N). +% Now build the list as a recursively nested function term +vertex_lst_element(IDX, list(N, list_empty)) :- vertex_element(N), not vertex_element_has_predecessor(N), IDX = 0. +vertex_lst_element(IDX, list(N, list(K, TAIL))) :- vertex_element(N), vertex_element_predecessor(K, N), vertex_lst_element(PREV_IDX, list(K, TAIL)), IDX = PREV_IDX + 1. +has_next_vertex_element(IDX) :- vertex_lst_element(IDX, _), NEXT_IDX = IDX + 1, vertex_lst_element(NEXT_IDX, _). +vertex_lst(LIST) :- vertex_lst_element(IDX, LIST), not has_next_vertex_element(IDX). + +%% pack edges into an edge list +edge_element(edge(V1, V2)) :- edge(V1, V2). +% First, establish ordering of elements (which we need to establish the order within the list) +edge_element_less(N, K) :- edge_element(N), edge_element(K), N < K. +edge_element_not_predecessor(N, K) :- edge_element_less(N, I), edge_element_less(I, K). +edge_element_predecessor(N, K) :- edge_element_less(N, K), not edge_element_not_predecessor(N, K). +edge_element_has_predecessor(N) :- edge_element_predecessor(_, N). +% Now build the list as a recursively nested function term +edge_lst_element(IDX, list(N, list_empty)) :- edge_element(N), not edge_element_has_predecessor(N), IDX = 0. +edge_lst_element(IDX, list(N, list(K, TAIL))) :- edge_element(N), edge_element_predecessor(K, N), edge_lst_element(PREV_IDX, list(K, TAIL)), IDX = PREV_IDX + 1. +has_next_edge_element(IDX) :- edge_lst_element(IDX, _), NEXT_IDX = IDX + 1, edge_lst_element(NEXT_IDX, _). +edge_lst(LIST) :- edge_lst_element(IDX, LIST), not has_next_edge_element(IDX). + +coloring(COL) :- vertex_lst(VERTEX_LST), edge_lst(EDGE_LST), #threecol[VERTEX_LST, EDGE_LST](COL). + +#test smokeTest(expect: >0) { + given { + vertex(a). + vertex(b). + vertex(c). + edge(a, b). + edge(b, c). + edge(c, a). + } + assertForAll { + coloring_found :- coloring(_). + :- not coloring_found. + } +} \ No newline at end of file diff --git a/alpha-solver/src/test/resources/e2e-tests/neighboring-vertices-list.evl b/alpha-solver/src/test/resources/e2e-tests/neighboring-vertices-list.evl new file mode 100644 index 000000000..149a02a3f --- /dev/null +++ b/alpha-solver/src/test/resources/e2e-tests/neighboring-vertices-list.evl @@ -0,0 +1,45 @@ +% Graph is undirected +edge(Y, X) :- edge(X, Y). + +%% Generate list of neighboring vertices for each vertex in the graph +neighbor(V, N) :- vertex(V), vertex(N), edge(V, N). +neighbors(V, LST) :- vertex(V), LST = #list{ N : neighbor(V, N)}. + +#test lineGraph(expect: 1) { + given { + vertex(1). vertex(2). edge(1, 2). + } + assertForAll { + :- not neighbors(1, lst(2, lst_empty)). + :- not neighbors(2, lst(1, lst_empty)). + } +} + +#test network(expect: 1) { + given { + vertex(1..8). + + edge(1, 2). + edge(1, 3). + edge(1, 4). + edge(2, 5). + edge(1, 3). + edge(1, 4). + edge(2, 5). + edge(3, 6). + edge(4, 7). + edge(5, 8). + edge(6, 8). + edge(7, 8). + } + assertForAll { + :- not neighbors(1, lst(2, lst(3, lst(4, lst_empty)))). + :- not neighbors(2, lst(1, lst(5, lst_empty))). + :- not neighbors(3, lst(1, lst(6, lst_empty))). + :- not neighbors(4, lst(1, lst(7, lst_empty))). + :- not neighbors(5, lst(2, lst(8, lst_empty))). + :- not neighbors(6, lst(3, lst(8, lst_empty))). + :- not neighbors(7, lst(4, lst(8, lst_empty))). + :- not neighbors(8, lst(5, lst(6, lst(7, lst_empty)))). + } +} \ No newline at end of file diff --git a/alpha-core/src/test/resources/partial-eval/pup_topological_order.asp b/alpha-solver/src/test/resources/partial-eval/pup_topological_order.asp similarity index 100% rename from alpha-core/src/test/resources/partial-eval/pup_topological_order.asp rename to alpha-solver/src/test/resources/partial-eval/pup_topological_order.asp diff --git a/alpha-core/src/test/resources/partial-eval/recursive_w_negated_condition.asp b/alpha-solver/src/test/resources/partial-eval/recursive_w_negated_condition.asp similarity index 100% rename from alpha-core/src/test/resources/partial-eval/recursive_w_negated_condition.asp rename to alpha-solver/src/test/resources/partial-eval/recursive_w_negated_condition.asp 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 69fe7a74a..eb65b0a59 100644 --- a/buildSrc/src/main/kotlin/alpha.java-common-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/alpha.java-common-conventions.gradle.kts @@ -6,6 +6,7 @@ plugins { id("jacoco") id("checkstyle") id("maven-publish") + id("java-test-fixtures") } repositories { @@ -36,6 +37,10 @@ dependencies { // Logging for tests 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/evolog/greet-me.evl b/examples/evolog/greet-me.evl new file mode 100644 index 000000000..8bf5bdcda --- /dev/null +++ b/examples/evolog/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/evolog/hello-world.evl b/examples/evolog/hello-world.evl new file mode 100644 index 000000000..4cede8ed1 --- /dev/null +++ b/examples/evolog/hello-world.evl @@ -0,0 +1,2 @@ +hello_text("Hello World!"). +hello_result(R) : @streamWrite[STDOUT, TEXT] = R :- hello_text(TEXT), &stdout(STDOUT). \ No newline at end of file diff --git a/examples/evolog/write_something.evl b/examples/evolog/write_something.evl new file mode 100644 index 000000000..cb113762b --- /dev/null +++ b/examples/evolog/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).