From 67c4148c6241d48ecfd7451dae2c6db9d45253d9 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Thu, 28 Oct 2021 12:03:11 +0200 Subject: [PATCH 01/56] added SimplePreprocessing ProgramTransformation --- .../transformation/SimplePreprocessing.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java new file mode 100644 index 000000000..6f84520c9 --- /dev/null +++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java @@ -0,0 +1,63 @@ +package at.ac.tuwien.kr.alpha.grounder.transformation; + +import at.ac.tuwien.kr.alpha.common.atoms.Atom; +import at.ac.tuwien.kr.alpha.common.atoms.Literal; +import at.ac.tuwien.kr.alpha.common.program.NormalProgram; +import at.ac.tuwien.kr.alpha.common.rule.NormalRule; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Simplifies a normal input program by deleting redundant rules. + */ + +public class SimplePreprocessing extends ProgramTransformation{ + + @Override + public NormalProgram apply(NormalProgram inputProgram) { + + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + + Iterator ruleIterator = srcRules.iterator(); + + while(ruleIterator.hasNext()) { + NormalRule rule = ruleIterator.next(); + boolean redundantRule = false; + + Atom headAtom = rule.getHead().getAtom(); + Set body = rule.getBody(); + Set positiveBody = rule.getPositiveBody(); + Set negativeBody = rule.getNegativeBody(); + + //implements s3: deletes rule if body contains head atom + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.getAtom().equals(headAtom)) { + redundantRule = true; + break; + } + } + + //implements s2: deletes rule if body contains both positive and negative literal of an atom + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + if (negativeBody.contains(positiveLiteral.negate())) { + redundantRule = true; + break; + } + } + + //implements s0: delete duplicate rules + if (!redundantRule && !transformedRules.contains(rule)) { + transformedRules.add(rule); + } + } + return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + } +} From a10011822809205f34136bd7d3a6f1ecec699ca6 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 14:47:12 +0100 Subject: [PATCH 02/56] added preprocesssing steps in SimplePreprocessing, removal of a literal in InternalRule --- .../kr/alpha/common/rule/InternalRule.java | 11 ++ .../kr/alpha/grounder/NaiveGrounder.java | 12 +- .../grounder/ProgramAnalyzingGrounder.java | 4 +- .../structure/AnalyzeUnjustified.java | 24 +-- .../transformation/SimplePreprocessing.java | 154 +++++++++++++++--- ...eralizedDependencyDrivenPyroHeuristic.java | 2 +- 6 files changed, 159 insertions(+), 48 deletions(-) diff --git a/src/main/java/at/ac/tuwien/kr/alpha/common/rule/InternalRule.java b/src/main/java/at/ac/tuwien/kr/alpha/common/rule/InternalRule.java index a6e21a6d3..2d89fcaf4 100644 --- a/src/main/java/at/ac/tuwien/kr/alpha/common/rule/InternalRule.java +++ b/src/main/java/at/ac/tuwien/kr/alpha/common/rule/InternalRule.java @@ -136,4 +136,15 @@ public int getRuleId() { return this.ruleId; } + public InternalRule removeLiteral(Literal literal) { + Atom headAtom = this.getHeadAtom(); + List newBody = new ArrayList<>(this.getBody().size()); + for (Literal bodyLiteral : this.getBody()) { + if(!literal.equals(bodyLiteral)) { + newBody.add(bodyLiteral); + } + } + return new InternalRule(new NormalHead(headAtom), newBody); + } + } diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/NaiveGrounder.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/NaiveGrounder.java index 8a54946a4..c7fb322bf 100644 --- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/NaiveGrounder.java +++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/NaiveGrounder.java @@ -312,7 +312,7 @@ protected HashMap bootstrap() { } @Override - public Map getNoGoods(Assignment currentAssignment) { + public Map getNoGoods(Assignment assignment) { // In first call, prepare facts and ground rules. final Map newNoGoods = fixedRules != null ? bootstrap() : new LinkedHashMap<>(); @@ -351,7 +351,7 @@ public Map getNoGoods(Assignment currentAssignment) { nonGroundRule, nonGroundRule.getGroundingOrders().orderStartingFrom(firstBindingAtom.startingLiteral), unifier, - currentAssignment); + assignment); groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), newNoGoods); } @@ -411,7 +411,7 @@ public int register(NoGood noGood) { // Ideally, this method should be private. It's only visible because NaiveGrounderTest needs to access it. BindingResult getGroundInstantiations(InternalRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, - Assignment currentAssignment) { + Assignment assignment) { int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint()); if (tolerance < 0) { tolerance = Integer.MAX_VALUE; @@ -420,7 +420,7 @@ BindingResult getGroundInstantiations(InternalRule rule, RuleGroundingOrder grou // Update instantiationStrategy with current assignment. // Note: Actually the assignment could be an instance variable of the grounder (shared with solver), // but this would have a larger impact on grounder/solver communication design as a whole. - instantiationStrategy.setCurrentAssignment(currentAssignment); + instantiationStrategy.setCurrentAssignment(assignment); BindingResult bindingResult = bindNextAtomInRule(groundingOrder, 0, tolerance, tolerance, partialSubstitution); if (LOGGER.isDebugEnabled()) { for (int i = 0; i < bindingResult.size(); i++) { @@ -599,8 +599,8 @@ public boolean isFact(Atom atom) { } @Override - public Set justifyAtom(int atomToJustify, Assignment currentAssignment) { - Set literals = analyzeUnjustified.analyze(atomToJustify, currentAssignment); + public Set justifyAtom(int atomToJustify, Assignment assignment) { + Set literals = analyzeUnjustified.analyze(atomToJustify, assignment); // Remove facts from justification before handing it over to the solver. for (Iterator iterator = literals.iterator(); iterator.hasNext();) { Literal literal = iterator.next(); diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/ProgramAnalyzingGrounder.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/ProgramAnalyzingGrounder.java index 0ff1f153e..1e0179c5d 100644 --- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/ProgramAnalyzingGrounder.java +++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/ProgramAnalyzingGrounder.java @@ -15,10 +15,10 @@ public interface ProgramAnalyzingGrounder extends Grounder { /** * Justifies the absence of an atom, i.e., returns reasons why the atom is not TRUE given the assignment. * @param atomToJustify the atom to justify. - * @param currentAssignment the current assignment. + * @param assignment the current assignment. * @return a set of literals who jointly imply the atomToJustify not being TRUE. */ - Set justifyAtom(int atomToJustify, Assignment currentAssignment); + Set justifyAtom(int atomToJustify, Assignment assignment); /** * Returns true iff the given atom is known to the grounder as a fact (hence not occurring in any assignment). diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/structure/AnalyzeUnjustified.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/structure/AnalyzeUnjustified.java index 658429f70..7dcadb691 100644 --- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/structure/AnalyzeUnjustified.java +++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/structure/AnalyzeUnjustified.java @@ -52,7 +52,7 @@ public AnalyzeUnjustified(InternalProgram programAnalysis, AtomStore atomStore, private Map> assignedAtoms; - public Set analyze(int atomToJustify, Assignment currentAssignment) { + public Set analyze(int atomToJustify, Assignment assignment) { padDepth = 0; Atom atom = atomStore.get(atomToJustify); if (!(atom instanceof BasicAtom)) { @@ -67,7 +67,7 @@ public Set analyze(int atomToJustify, Assignment currentAssignment) { //@formatter:on assignedAtoms = new LinkedHashMap<>(); for (int i = 1; i <= atomStore.getMaxAtomId(); i++) { - ThriceTruth truth = currentAssignment.getTruth(i); + ThriceTruth truth = assignment.getTruth(i); if (truth == null) { continue; } @@ -75,11 +75,11 @@ public Set analyze(int atomToJustify, Assignment currentAssignment) { assignedAtoms.putIfAbsent(assignedAtom.getPredicate(), new ArrayList<>()); assignedAtoms.get(assignedAtom.getPredicate()).add(assignedAtom); } - return analyze((BasicAtom) atom, currentAssignment); + return analyze((BasicAtom) atom, assignment); } - private Set analyze(BasicAtom atom, Assignment currentAssignment) { - log(pad("Starting analyze, current assignment is: {}"), currentAssignment); + private Set analyze(BasicAtom atom, Assignment assignment) { + log(pad("Starting analyze, current assignment is: {}"), assignment); LinkedHashSet vL = new LinkedHashSet<>(); LinkedHashSet vToDo = new LinkedHashSet<>(Collections.singleton(new LitSet(atom, new LinkedHashSet<>()))); LinkedHashSet vDone = new LinkedHashSet<>(); @@ -90,7 +90,7 @@ private Set analyze(BasicAtom atom, Assignment currentAssignment) { log(""); log("Treating now: {}", x); vDone.add(x); - ReturnExplainUnjust unjustRet = explainUnjust(x, currentAssignment); + ReturnExplainUnjust unjustRet = explainUnjust(x, assignment); log("Additional ToDo: {}", unjustRet.vToDo); // Check each new LitSet if it does not already occur as done. for (LitSet todoLitSet : unjustRet.vToDo) { @@ -103,7 +103,7 @@ private Set analyze(BasicAtom atom, Assignment currentAssignment) { return vL; } - private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment) { + private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { padDepth += 2; log("Begin explainUnjust(): {}", x); Atom p = x.getAtom(); @@ -150,7 +150,7 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment log("Considering: {}", lg); if (atomStore.contains(lg)) { int atomId = atomStore.get(lg); - if (!currentAssignment.getTruth(atomId).toBoolean()) { + if (!assignment.getTruth(atomId).toBoolean()) { log("{} is not assigned TRUE or MBT. Skipping.", lg); continue; } @@ -187,14 +187,14 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment } } log("Calling UnjustCover() for positive body."); - ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, currentAssignment)); + ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, assignment)); } log("End explainUnjust()."); padDepth -= 2; return ret; } - private Set unjustCover(List vB, Set vY, Set vN, Assignment currentAssignment) { + private Set unjustCover(List vB, Set vY, Set vN, Assignment assignment) { padDepth += 2; log("Begin UnjustCoverFixed()"); log("Finding unjustified body literals in: {} / {} excluded {}", vB, vY, vN); @@ -228,7 +228,7 @@ private Set unjustCover(List vB, Set vY, Set log("Checking atom: {}", atom); if (atomStore.contains(atom)) { int atomId = atomStore.get(atom); - if (currentAssignment.getTruth(atomId) != ThriceTruth.TRUE) { + if (assignment.getTruth(atomId) != ThriceTruth.TRUE) { log("Atom is not TRUE. Skipping."); continue; } @@ -274,7 +274,7 @@ private Set unjustCover(List vB, Set vY, Set } ArrayList newB = new ArrayList<>(vB); newB.remove(chosenLiteralPos); - ret.addAll(unjustCover(newB, vYp, vN, currentAssignment)); + ret.addAll(unjustCover(newB, vYp, vN, assignment)); log("Literal set(s) to treat: {}", ret); } log("End unjustCover()."); diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java index 6f84520c9..9e7ffb750 100644 --- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java +++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java @@ -2,8 +2,9 @@ import at.ac.tuwien.kr.alpha.common.atoms.Atom; import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.NormalProgram; -import at.ac.tuwien.kr.alpha.common.rule.NormalRule; +import at.ac.tuwien.kr.alpha.common.program.InternalProgram; +import at.ac.tuwien.kr.alpha.common.rule.InternalRule; +import at.ac.tuwien.kr.alpha.grounder.Unification; import java.util.ArrayList; import java.util.Iterator; @@ -11,21 +12,19 @@ import java.util.Set; /** - * Simplifies a normal input program by deleting redundant rules. + * Simplifies an internal input program by deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation{ +public class SimplePreprocessing extends ProgramTransformation{ @Override - public NormalProgram apply(NormalProgram inputProgram) { - - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - Iterator ruleIterator = srcRules.iterator(); + public InternalProgram apply(InternalProgram inputProgram) { + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + Iterator ruleIterator = srcRules.iterator(); while(ruleIterator.hasNext()) { - NormalRule rule = ruleIterator.next(); + InternalRule rule = ruleIterator.next(); boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); @@ -33,31 +32,132 @@ public NormalProgram apply(NormalProgram inputProgram) { Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); - //implements s3: deletes rule if body contains head atom - Iterator literalIterator = body.iterator(); + if (checkForHeadInBody(body,headAtom)) { + redundantRule = true; + } + if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + redundantRule = true; + } + //implements s0: delete duplicate rules + if (!(redundantRule || transformedRules.contains(rule))) { + transformedRules.add(rule); + } + } + deleteConflictingRules(transformedRules, inputProgram.getFacts()); + + simplifyRules(transformedRules, inputProgram.getFacts()); + + return new InternalProgram(transformedRules, inputProgram.getFacts()); + } + + /** + * This method checks if a rule contains a literal in both the positive and the negative body. + * implements s2 + */ + private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + //TODO: implement literal.equals() + if (negativeBody.contains(positiveLiteral.negate())) { + return true; + } + } + return false; + } + + /** + * This method checks if the head atom occurs in the rule's body. + * implements s3 + */ + private boolean checkForHeadInBody(Set body, Atom headAtom) { + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + //TODO: implement atom.equals() + if (literal.getAtom().equals(headAtom)) { + return true; + } + } + return false; + } + + /** + * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * implements s9 + */ + private List deleteConflictingRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); + while(literalIterator.hasNext()) { Literal literal = literalIterator.next(); - if (literal.getAtom().equals(headAtom)) { - redundantRule = true; - break; + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + } + else { + if (isDerivable(literal, rules)) { + transformedRules.add(rule); + } } } + } + return transformedRules; + } + + + /** + * This method removes literals from rule bodies, that are already facts (when positive) + * or not derivable (when negated). + * implements s10 + */ + private List simplifyRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); - //implements s2: deletes rule if body contains both positive and negative literal of an atom - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - if (negativeBody.contains(positiveLiteral.negate())) { - redundantRule = true; - break; + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + else transformedRules.add(rule.removeLiteral(literal)); + } + else { + if (!isDerivable(literal, rules)) { + transformedRules.add(rule.removeLiteral(literal)); + } + else transformedRules.add(rule); } } + } + return transformedRules; + } - //implements s0: delete duplicate rules - if (!redundantRule && !transformedRules.contains(rule)) { - transformedRules.add(rule); + + /** + * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * implements s5 conditions + */ + private boolean isDerivable(Literal literal, List rules){ + Iterator ruleIterator = rules.iterator(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + return true; } } - return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return false; } } diff --git a/src/main/java/at/ac/tuwien/kr/alpha/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java b/src/main/java/at/ac/tuwien/kr/alpha/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java index e8deefa8b..5b2af4415 100644 --- a/src/main/java/at/ac/tuwien/kr/alpha/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java +++ b/src/main/java/at/ac/tuwien/kr/alpha/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java @@ -45,7 +45,7 @@ public class GeneralizedDependencyDrivenPyroHeuristic extends GeneralizedDependencyDrivenHeuristic { public GeneralizedDependencyDrivenPyroHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random, - BodyActivityType bodyActivityType) { + BodyActivityType bodyActivityType) { super(assignment, choiceManager, decayPeriod, decayFactor, random, bodyActivityType); } From aa83c73c90e8612be76b84695e6b50e8813cc3db Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 15:29:36 +0100 Subject: [PATCH 03/56] refactored SimplePreprocessing loops --- .../transformation/SimplePreprocessing.java | 121 ++++++++---------- 1 file changed, 53 insertions(+), 68 deletions(-) diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java index 9e7ffb750..3a705c9da 100644 --- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java +++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/transformation/SimplePreprocessing.java @@ -5,6 +5,7 @@ import at.ac.tuwien.kr.alpha.common.program.InternalProgram; import at.ac.tuwien.kr.alpha.common.rule.InternalRule; import at.ac.tuwien.kr.alpha.grounder.Unification; +import org.apache.poi.util.Internal; import java.util.ArrayList; import java.util.Iterator; @@ -12,7 +13,7 @@ import java.util.Set; /** - * Simplifies an internal input program by deleting redundant rules. + * Simplifies an internal input program by simplifying and deleting redundant rules. */ public class SimplePreprocessing extends ProgramTransformation{ @@ -21,31 +22,42 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = new ArrayList<>(inputProgram.getRules()); List transformedRules = new ArrayList<>(); - Iterator ruleIterator = srcRules.iterator(); - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); + for (InternalRule rule : srcRules) { boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); Set body = rule.getBody(); Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); + InternalRule simplifiedRule = null; - if (checkForHeadInBody(body,headAtom)) { + //implements s0: delete duplicate rules + if (transformedRules.contains(rule)) { //TODO: Add InternalRule.equals() redundantRule = true; } - if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + //implemnts s2 + if (checkForConflictingBodyLiterals(positiveBody, negativeBody)) { redundantRule = true; } - //implements s0: delete duplicate rules - if (!(redundantRule || transformedRules.contains(rule))) { + //implements s3 + if (checkForHeadInBody(body, headAtom)) { + redundantRule = true; + } + //implements s9 + if(checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { + redundantRule = true; + } + //implements s10 + simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); + if(simplifiedRule != null) { + rule = simplifiedRule; + } + + if(!redundantRule) { transformedRules.add(rule); } } - deleteConflictingRules(transformedRules, inputProgram.getFacts()); - - simplifyRules(transformedRules, inputProgram.getFacts()); return new InternalProgram(transformedRules, inputProgram.getFacts()); } @@ -55,10 +67,7 @@ public InternalProgram apply(InternalProgram inputProgram) { * implements s2 */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - //TODO: implement literal.equals() + for (Literal positiveLiteral : positiveBody) { if (negativeBody.contains(positiveLiteral.negate())) { return true; } @@ -71,10 +80,8 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { - Iterator literalIterator = body.iterator(); - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - //TODO: implement atom.equals() + for (Literal literal : body) { + //TODO: implement Atom.equals() if (literal.getAtom().equals(headAtom)) { return true; } @@ -82,79 +89,57 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { return false; } + /** - * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. * implements s9 */ - private List deleteConflictingRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } + private boolean checkForUnreachableLiterals (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + return false; } - else { - if (isDerivable(literal, rules)) { - transformedRules.add(rule); - } + } else { + if (isDerivable(literal, rules)) { + return false; } } } - return transformedRules; + return true; } /** - * This method removes literals from rule bodies, that are already facts (when positive) + * This method checks for literals from rule bodies, that are already facts (when positive) * or not derivable (when negated). * implements s10 */ - private List simplifyRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } - else transformedRules.add(rule.removeLiteral(literal)); - } - else { - if (!isDerivable(literal, rules)) { - transformedRules.add(rule.removeLiteral(literal)); - } - else transformedRules.add(rule); - } + private InternalRule checkForSimplifiableRule (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return null; + } else return rule.removeLiteral(literal); + } else { + if (!isDerivable(literal, rules)) { + return rule.removeLiteral(literal); + } else return null; } } - return transformedRules; + return null; } + + /** * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. * implements s5 conditions */ private boolean isDerivable(Literal literal, List rules){ - Iterator ruleIterator = rules.iterator(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + for (InternalRule rule : rules) { + if (Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { return true; } } From 2a2038c4a024052924bebb0563e3f30a2753faca Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Thu, 28 Oct 2021 12:03:11 +0200 Subject: [PATCH 04/56] added SimplePreprocessing ProgramTransformation --- .../transformation/SimplePreprocessing.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java new file mode 100644 index 000000000..6f84520c9 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -0,0 +1,63 @@ +package at.ac.tuwien.kr.alpha.grounder.transformation; + +import at.ac.tuwien.kr.alpha.common.atoms.Atom; +import at.ac.tuwien.kr.alpha.common.atoms.Literal; +import at.ac.tuwien.kr.alpha.common.program.NormalProgram; +import at.ac.tuwien.kr.alpha.common.rule.NormalRule; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Simplifies a normal input program by deleting redundant rules. + */ + +public class SimplePreprocessing extends ProgramTransformation{ + + @Override + public NormalProgram apply(NormalProgram inputProgram) { + + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + + Iterator ruleIterator = srcRules.iterator(); + + while(ruleIterator.hasNext()) { + NormalRule rule = ruleIterator.next(); + boolean redundantRule = false; + + Atom headAtom = rule.getHead().getAtom(); + Set body = rule.getBody(); + Set positiveBody = rule.getPositiveBody(); + Set negativeBody = rule.getNegativeBody(); + + //implements s3: deletes rule if body contains head atom + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.getAtom().equals(headAtom)) { + redundantRule = true; + break; + } + } + + //implements s2: deletes rule if body contains both positive and negative literal of an atom + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + if (negativeBody.contains(positiveLiteral.negate())) { + redundantRule = true; + break; + } + } + + //implements s0: delete duplicate rules + if (!redundantRule && !transformedRules.contains(rule)) { + transformedRules.add(rule); + } + } + return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + } +} From b959d31d963542c60eaed1f5fd17791c6ee43849 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 14:47:12 +0100 Subject: [PATCH 05/56] added preprocesssing steps in SimplePreprocessing, removal of a literal in InternalRule --- .../kr/alpha/core/grounder/NaiveGrounder.java | 163 +++++++++--------- .../grounder/ProgramAnalyzingGrounder.java | 4 +- .../structure/AnalyzeUnjustified.java | 24 +-- .../transformation/SimplePreprocessing.java | 154 ++++++++++++++--- .../kr/alpha/core/rules/InternalRule.java | 11 ++ ...eralizedDependencyDrivenPyroHeuristic.java | 2 +- 6 files changed, 233 insertions(+), 125 deletions(-) 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 1e498d50d..6dd46430c 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 @@ -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. - *

+ * 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 @@ -25,10 +25,15 @@ * 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.grounder; -import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.Util.oops; +import static at.ac.tuwien.kr.alpha.common.Literals.atomOf; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; @@ -43,39 +48,31 @@ import java.util.SortedSet; import java.util.TreeSet; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; -import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.AnswerSets; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.commons.util.Util; -import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; -import at.ac.tuwien.kr.alpha.core.common.Assignment; -import at.ac.tuwien.kr.alpha.core.common.AtomStore; -import at.ac.tuwien.kr.alpha.core.common.IntIterator; -import at.ac.tuwien.kr.alpha.core.common.NoGood; -import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; -import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; -import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; -import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.Util; +import at.ac.tuwien.kr.alpha.common.AnswerSet; +import at.ac.tuwien.kr.alpha.common.Assignment; +import at.ac.tuwien.kr.alpha.common.AtomStore; +import at.ac.tuwien.kr.alpha.common.BasicAnswerSet; +import at.ac.tuwien.kr.alpha.common.IntIterator; +import at.ac.tuwien.kr.alpha.common.NoGood; +import at.ac.tuwien.kr.alpha.common.NoGoodInterface; +import at.ac.tuwien.kr.alpha.common.Predicate; +import at.ac.tuwien.kr.alpha.common.atoms.Atom; +import at.ac.tuwien.kr.alpha.common.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.common.atoms.Literal; +import at.ac.tuwien.kr.alpha.common.program.InternalProgram; +import at.ac.tuwien.kr.alpha.common.rule.InternalRule; +import at.ac.tuwien.kr.alpha.common.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.grounder.atoms.ChoiceAtom; +import at.ac.tuwien.kr.alpha.grounder.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.grounder.bridges.Bridge; +import at.ac.tuwien.kr.alpha.grounder.heuristics.GrounderHeuristicsConfiguration; +import at.ac.tuwien.kr.alpha.grounder.instantiation.AssignmentStatus; +import at.ac.tuwien.kr.alpha.grounder.instantiation.BindingResult; +import at.ac.tuwien.kr.alpha.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; +import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiationResult; +import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiator; +import at.ac.tuwien.kr.alpha.grounder.structure.AnalyzeUnjustified; /** * A semi-naive grounder. @@ -90,14 +87,14 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final NogoodRegistry registry = new NogoodRegistry(); final NoGoodGenerator noGoodGenerator; private final ChoiceRecorder choiceRecorder; - private final CompiledProgram program; + private final InternalProgram program; private final AnalyzeUnjustified analyzeUnjustified; private final Map> factsFromProgram; private final Map> rulesUsingPredicateWorkingMemory = new HashMap<>(); - private final Map knownNonGroundRules; + private final Map knownNonGroundRules; - private ArrayList fixedRules = new ArrayList<>(); + private ArrayList fixedRules = new ArrayList<>(); private LinkedHashSet removeAfterObtainingNewNoGoods = new LinkedHashSet<>(); private final boolean debugInternalChecks; @@ -108,16 +105,16 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final LiteralInstantiator ruleInstantiator; private final DefaultLazyGroundingInstantiationStrategy instantiationStrategy; - public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { + public NaiveGrounder(InternalProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, + private NaiveGrounder(InternalProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, + NaiveGrounder(InternalProgram program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; @@ -133,7 +130,7 @@ private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeur this.initializeFactsAndRules(); - final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); + final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); choiceRecorder = new ChoiceRecorder(atomStore); noGoodGenerator = new NoGoodGenerator(atomStore, choiceRecorder, factsFromProgram, this.program, uniqueGroundRulePerGroundHead); @@ -162,7 +159,7 @@ private void initializeFactsAndRules() { workingMemory.initialize(ChoiceAtom.ON); // Initialize rules and constraints in working memory. - for (CompiledRule nonGroundRule : program.getRulesById().values()) { + for (InternalRule nonGroundRule : program.getRulesById().values()) { // Create working memories for all predicates occurring in the rule. for (Predicate predicate : nonGroundRule.getOccurringPredicates()) { // FIXME: this also contains interval/builtin predicates that are not needed. @@ -170,30 +167,30 @@ private void initializeFactsAndRules() { } // If the rule has fixed ground instantiations, it is not registered but grounded once like facts. - if (nonGroundRule.getGroundingInfo().hasFixedInstantiation()) { + if (nonGroundRule.getGroundingOrders().fixedInstantiation()) { fixedRules.add(nonGroundRule); continue; } // Register each starting literal at the corresponding working memory. - for (Literal literal : nonGroundRule.getGroundingInfo().getStartingLiterals()) { + for (Literal literal : nonGroundRule.getGroundingOrders().getStartingLiterals()) { registerLiteralAtWorkingMemory(literal, nonGroundRule); } } } - private Set getRulesWithUniqueHead() { + private Set getRulesWithUniqueHead() { // FIXME: below optimisation (adding support nogoods if there is only one rule instantiation per unique atom over the interpretation) could // be done as a transformation (adding a non-ground constraint corresponding to the nogood that is generated by the grounder). // Record all unique rule heads. - final Set uniqueGroundRulePerGroundHead = new HashSet<>(); + final Set uniqueGroundRulePerGroundHead = new HashSet<>(); - for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { + for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { if (headDefiningRules.getValue().size() != 1) { continue; } - CompiledRule nonGroundRule = headDefiningRules.getValue().iterator().next(); + InternalRule nonGroundRule = headDefiningRules.getValue().iterator().next(); // Check that all variables of the body also occur in the head (otherwise grounding is not unique). Atom headAtom = nonGroundRule.getHeadAtom(); @@ -224,7 +221,7 @@ private Set getRulesWithUniqueHead() { * * @param nonGroundRule the rule in which the literal occurs. */ - private void registerLiteralAtWorkingMemory(Literal literal, CompiledRule nonGroundRule) { + private void registerLiteralAtWorkingMemory(Literal literal, InternalRule nonGroundRule) { if (literal.isNegated()) { throw new RuntimeException("Literal to register is negated. Should not happen."); } @@ -278,15 +275,15 @@ public AnswerSet assignmentToAnswerSet(Iterable trueAtoms) { predicateInstances.putIfAbsent(factPredicate, new TreeSet<>()); for (Instance factInstance : facts.getValue()) { SortedSet instances = predicateInstances.get(factPredicate); - instances.add(Atoms.newBasicAtom(factPredicate, factInstance.terms)); + instances.add(new BasicAtom(factPredicate, factInstance.terms)); } } if (knownPredicates.isEmpty()) { - return AnswerSets.EMPTY_SET; + return BasicAnswerSet.EMPTY; } - return AnswerSets.newAnswerSet(knownPredicates, predicateInstances); + return new BasicAnswerSet(knownPredicates, predicateInstances); } /** @@ -302,10 +299,10 @@ protected HashMap bootstrap() { workingMemory.addInstances(predicate, true, factsFromProgram.get(predicate)); } - for (CompiledRule nonGroundRule : fixedRules) { + for (InternalRule nonGroundRule : fixedRules) { // Generate NoGoods for all rules that have a fixed grounding. - RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingInfo().getFixedGroundingOrder(); - BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new BasicSubstitution(), null); + RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingOrders().getFixedGroundingOrder(); + BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new Substitution(), null); groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), groundNogoods); } @@ -337,14 +334,14 @@ public Map getNoGoods(Assignment currentAssignment) { for (FirstBindingAtom firstBindingAtom : firstBindingAtoms) { // Use the recently added instances from the modified working memory to construct an initial substitution - CompiledRule nonGroundRule = firstBindingAtom.rule; + InternalRule nonGroundRule = firstBindingAtom.rule; // Generate substitutions from each recent instance. for (Instance instance : modifiedWorkingMemory.getRecentlyAddedInstances()) { // Check instance if it matches with the atom. - final Substitution unifier = BasicSubstitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, - BasicSubstitution.EMPTY_SUBSTITUTION); + final Substitution unifier = Substitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, + Substitution.EMPTY_SUBSTITUTION); if (unifier == null) { continue; @@ -352,7 +349,7 @@ public Map getNoGoods(Assignment currentAssignment) { final BindingResult bindingResult = getGroundInstantiations( nonGroundRule, - nonGroundRule.getGroundingInfo().orderStartingFrom(firstBindingAtom.startingLiteral), + nonGroundRule.getGroundingOrders().orderStartingFrom(firstBindingAtom.startingLiteral), unifier, currentAssignment); @@ -400,7 +397,7 @@ public Map getNoGoods(Assignment currentAssignment) { * @param substitutions the substitutions to be applied. * @param newNoGoods a set of nogoods to which newly generated nogoods will be added. */ - private void groundAndRegister(final CompiledRule nonGroundRule, final List substitutions, final Map newNoGoods) { + private void groundAndRegister(final InternalRule nonGroundRule, final List substitutions, final Map newNoGoods) { for (Substitution substitution : substitutions) { List generatedNoGoods = noGoodGenerator.generateNoGoodsFromGroundSubstitution(nonGroundRule, substitution); registry.register(generatedNoGoods, newNoGoods); @@ -438,13 +435,13 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou } /** - * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrderImpl, int, int, int, BasicSubstitution)}. - * - * Takes an ImmutablePair of a {@link BasicSubstitution} and an accompanying {@link AssignmentStatus} and calls + * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrder, int, int, int, Substitution)}. + * + * Takes an ImmutablePair of a {@link Substitution} and an accompanying {@link AssignmentStatus} and calls * bindNextAtomInRule for the next literal in the grounding order. * If the assignment status for the last bound literal was {@link AssignmentStatus#UNASSIGNED}, the remainingTolerance * parameter is decreased by 1. If the remaining tolerance drops below zero, this method returns an empty {@link BindingResult}. - * + * * @param groundingOrder * @param orderPosition * @param originalTolerance @@ -494,12 +491,12 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding //@formatter:off /** - * Computes ground substitutions for a literal based on a {@link RuleGroundingOrderImpl} and a {@link BasicSubstitution}. - * + * Computes ground substitutions for a literal based on a {@link RuleGroundingOrder} and a {@link Substitution}. + * * Computes ground substitutions for the literal at position orderPosition of groundingOrder * Actual substitutions are computed by this grounder's {@link LiteralInstantiator}. - * - * @param groundingOrder a {@link RuleGroundingOrderImpl} representing the body literals of a rule in the + * + * @param groundingOrder a {@link RuleGroundingOrder} representing the body literals of a rule in the * sequence in which the should be bound during grounding. * @param orderPosition the current position within groundingOrder, indicates which literal should be bound * @param originalTolerance the original tolerance of the used grounding heuristic @@ -588,7 +585,7 @@ public void forgetAssignment(int[] atomIds) { } @Override - public CompiledRule getNonGroundRule(Integer ruleId) { + public InternalRule getNonGroundRule(Integer ruleId) { return knownNonGroundRules.get(ruleId); } @@ -620,8 +617,8 @@ public Set justifyAtom(int atomToJustify, Assignment currentAssignment) /** * Checks that every nogood not marked as {@link NoGoodInterface.Type#INTERNAL} contains only - * atoms which are not {@link PredicateImpl#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). - * + * atoms which are not {@link Predicate#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). + * * @param newNoGoods */ private void checkTypesOfNoGoods(Collection newNoGoods) { @@ -638,10 +635,10 @@ private void checkTypesOfNoGoods(Collection newNoGoods) { } private static class FirstBindingAtom { - final CompiledRule rule; + final InternalRule rule; final Literal startingLiteral; - FirstBindingAtom(CompiledRule rule, Literal startingLiteral) { + FirstBindingAtom(InternalRule rule, Literal startingLiteral) { this.rule = rule; this.startingLiteral = startingLiteral; } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java index d64388123..12960995a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java @@ -15,10 +15,10 @@ public interface ProgramAnalyzingGrounder extends Grounder { /** * Justifies the absence of an atom, i.e., returns reasons why the atom is not TRUE given the assignment. * @param atomToJustify the atom to justify. - * @param currentAssignment the current assignment. + * @param assignment the current assignment. * @return a set of literals who jointly imply the atomToJustify not being TRUE. */ - Set justifyAtom(int atomToJustify, Assignment currentAssignment); + Set justifyAtom(int atomToJustify, Assignment assignment); /** * Returns true iff the given atom is known to the grounder as a fact (hence not occurring in any assignment). diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java index cb12167db..c04c9578c 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java @@ -54,7 +54,7 @@ public AnalyzeUnjustified(CompiledProgram programAnalysis, AtomStore atomStore, private Map> assignedAtoms; - public Set analyze(int atomToJustify, Assignment currentAssignment) { + public Set analyze(int atomToJustify, Assignment assignment) { padDepth = 0; Atom atom = atomStore.get(atomToJustify); if (!(atom instanceof BasicAtom)) { @@ -69,7 +69,7 @@ public Set analyze(int atomToJustify, Assignment currentAssignment) { //@formatter:on assignedAtoms = new LinkedHashMap<>(); for (int i = 1; i <= atomStore.getMaxAtomId(); i++) { - ThriceTruth truth = currentAssignment.getTruth(i); + ThriceTruth truth = assignment.getTruth(i); if (truth == null) { continue; } @@ -77,11 +77,11 @@ public Set analyze(int atomToJustify, Assignment currentAssignment) { assignedAtoms.putIfAbsent(assignedAtom.getPredicate(), new ArrayList<>()); assignedAtoms.get(assignedAtom.getPredicate()).add(assignedAtom); } - return analyze((BasicAtom) atom, currentAssignment); + return analyze((BasicAtom) atom, assignment); } - private Set analyze(BasicAtom atom, Assignment currentAssignment) { - log(pad("Starting analyze, current assignment is: {}"), currentAssignment); + private Set analyze(BasicAtom atom, Assignment assignment) { + log(pad("Starting analyze, current assignment is: {}"), assignment); LinkedHashSet vL = new LinkedHashSet<>(); LinkedHashSet vToDo = new LinkedHashSet<>(Collections.singleton(new LitSet(atom, new LinkedHashSet<>()))); LinkedHashSet vDone = new LinkedHashSet<>(); @@ -92,7 +92,7 @@ private Set analyze(BasicAtom atom, Assignment currentAssignment) { log(""); log("Treating now: {}", x); vDone.add(x); - ReturnExplainUnjust unjustRet = explainUnjust(x, currentAssignment); + ReturnExplainUnjust unjustRet = explainUnjust(x, assignment); log("Additional ToDo: {}", unjustRet.vToDo); // Check each new LitSet if it does not already occur as done. for (LitSet todoLitSet : unjustRet.vToDo) { @@ -105,7 +105,7 @@ private Set analyze(BasicAtom atom, Assignment currentAssignment) { return vL; } - private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment) { + private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { padDepth += 2; log("Begin explainUnjust(): {}", x); Atom p = x.getAtom(); @@ -151,7 +151,7 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment log("Considering: {}", lg); if (atomStore.contains(lg)) { int atomId = atomStore.get(lg); - if (!currentAssignment.getTruth(atomId).toBoolean()) { + if (!assignment.getTruth(atomId).toBoolean()) { log("{} is not assigned TRUE or MBT. Skipping.", lg); continue; } @@ -188,14 +188,14 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment } } log("Calling UnjustCover() for positive body."); - ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, currentAssignment)); + ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, assignment)); } log("End explainUnjust()."); padDepth -= 2; return ret; } - private Set unjustCover(List vB, Set vY, Set vN, Assignment currentAssignment) { + private Set unjustCover(List vB, Set vY, Set vN, Assignment assignment) { padDepth += 2; log("Begin UnjustCoverFixed()"); log("Finding unjustified body literals in: {} / {} excluded {}", vB, vY, vN); @@ -228,7 +228,7 @@ private Set unjustCover(List vB, Set vY, Set log("Checking atom: {}", atom); if (atomStore.contains(atom)) { int atomId = atomStore.get(atom); - if (currentAssignment.getTruth(atomId) != ThriceTruth.TRUE) { + if (assignment.getTruth(atomId) != ThriceTruth.TRUE) { log("Atom is not TRUE. Skipping."); continue; } @@ -274,7 +274,7 @@ private Set unjustCover(List vB, Set vY, Set } ArrayList newB = new ArrayList<>(vB); newB.remove(chosenLiteralPos); - ret.addAll(unjustCover(newB, vYp, vN, currentAssignment)); + ret.addAll(unjustCover(newB, vYp, vN, assignment)); log("Literal set(s) to treat: {}", ret); } log("End unjustCover()."); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 6f84520c9..9e7ffb750 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -2,8 +2,9 @@ import at.ac.tuwien.kr.alpha.common.atoms.Atom; import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.NormalProgram; -import at.ac.tuwien.kr.alpha.common.rule.NormalRule; +import at.ac.tuwien.kr.alpha.common.program.InternalProgram; +import at.ac.tuwien.kr.alpha.common.rule.InternalRule; +import at.ac.tuwien.kr.alpha.grounder.Unification; import java.util.ArrayList; import java.util.Iterator; @@ -11,21 +12,19 @@ import java.util.Set; /** - * Simplifies a normal input program by deleting redundant rules. + * Simplifies an internal input program by deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation{ +public class SimplePreprocessing extends ProgramTransformation{ @Override - public NormalProgram apply(NormalProgram inputProgram) { - - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - Iterator ruleIterator = srcRules.iterator(); + public InternalProgram apply(InternalProgram inputProgram) { + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + Iterator ruleIterator = srcRules.iterator(); while(ruleIterator.hasNext()) { - NormalRule rule = ruleIterator.next(); + InternalRule rule = ruleIterator.next(); boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); @@ -33,31 +32,132 @@ public NormalProgram apply(NormalProgram inputProgram) { Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); - //implements s3: deletes rule if body contains head atom - Iterator literalIterator = body.iterator(); + if (checkForHeadInBody(body,headAtom)) { + redundantRule = true; + } + if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + redundantRule = true; + } + //implements s0: delete duplicate rules + if (!(redundantRule || transformedRules.contains(rule))) { + transformedRules.add(rule); + } + } + deleteConflictingRules(transformedRules, inputProgram.getFacts()); + + simplifyRules(transformedRules, inputProgram.getFacts()); + + return new InternalProgram(transformedRules, inputProgram.getFacts()); + } + + /** + * This method checks if a rule contains a literal in both the positive and the negative body. + * implements s2 + */ + private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + //TODO: implement literal.equals() + if (negativeBody.contains(positiveLiteral.negate())) { + return true; + } + } + return false; + } + + /** + * This method checks if the head atom occurs in the rule's body. + * implements s3 + */ + private boolean checkForHeadInBody(Set body, Atom headAtom) { + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + //TODO: implement atom.equals() + if (literal.getAtom().equals(headAtom)) { + return true; + } + } + return false; + } + + /** + * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * implements s9 + */ + private List deleteConflictingRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); + while(literalIterator.hasNext()) { Literal literal = literalIterator.next(); - if (literal.getAtom().equals(headAtom)) { - redundantRule = true; - break; + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + } + else { + if (isDerivable(literal, rules)) { + transformedRules.add(rule); + } } } + } + return transformedRules; + } + + + /** + * This method removes literals from rule bodies, that are already facts (when positive) + * or not derivable (when negated). + * implements s10 + */ + private List simplifyRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); - //implements s2: deletes rule if body contains both positive and negative literal of an atom - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - if (negativeBody.contains(positiveLiteral.negate())) { - redundantRule = true; - break; + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + else transformedRules.add(rule.removeLiteral(literal)); + } + else { + if (!isDerivable(literal, rules)) { + transformedRules.add(rule.removeLiteral(literal)); + } + else transformedRules.add(rule); } } + } + return transformedRules; + } - //implements s0: delete duplicate rules - if (!redundantRule && !transformedRules.contains(rule)) { - transformedRules.add(rule); + + /** + * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * implements s5 conditions + */ + private boolean isDerivable(Literal literal, List rules){ + Iterator ruleIterator = rules.iterator(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + return true; } } - return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return false; } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index 9a72fca12..aaa15c5fa 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -143,4 +143,15 @@ public int getRuleId() { return this.ruleId; } + public InternalRule removeLiteral(Literal literal) { + Atom headAtom = this.getHeadAtom(); + List newBody = new ArrayList<>(this.getBody().size()); + for (Literal bodyLiteral : this.getBody()) { + if(!literal.equals(bodyLiteral)) { + newBody.add(bodyLiteral); + } + } + return new InternalRule(new NormalHead(headAtom), newBody); + } + } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java index f4c8e71f7..586dc3598 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java @@ -45,7 +45,7 @@ public class GeneralizedDependencyDrivenPyroHeuristic extends GeneralizedDependencyDrivenHeuristic { public GeneralizedDependencyDrivenPyroHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random, - BodyActivityType bodyActivityType) { + BodyActivityType bodyActivityType) { super(assignment, choiceManager, decayPeriod, decayFactor, random, bodyActivityType); } From acfd478d14c55140a2ae1e6b7bee8914d25d4432 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 15:29:36 +0100 Subject: [PATCH 06/56] refactored SimplePreprocessing loops --- .../transformation/SimplePreprocessing.java | 121 ++++++++---------- 1 file changed, 53 insertions(+), 68 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 9e7ffb750..3a705c9da 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -5,6 +5,7 @@ import at.ac.tuwien.kr.alpha.common.program.InternalProgram; import at.ac.tuwien.kr.alpha.common.rule.InternalRule; import at.ac.tuwien.kr.alpha.grounder.Unification; +import org.apache.poi.util.Internal; import java.util.ArrayList; import java.util.Iterator; @@ -12,7 +13,7 @@ import java.util.Set; /** - * Simplifies an internal input program by deleting redundant rules. + * Simplifies an internal input program by simplifying and deleting redundant rules. */ public class SimplePreprocessing extends ProgramTransformation{ @@ -21,31 +22,42 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = new ArrayList<>(inputProgram.getRules()); List transformedRules = new ArrayList<>(); - Iterator ruleIterator = srcRules.iterator(); - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); + for (InternalRule rule : srcRules) { boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); Set body = rule.getBody(); Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); + InternalRule simplifiedRule = null; - if (checkForHeadInBody(body,headAtom)) { + //implements s0: delete duplicate rules + if (transformedRules.contains(rule)) { //TODO: Add InternalRule.equals() redundantRule = true; } - if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + //implemnts s2 + if (checkForConflictingBodyLiterals(positiveBody, negativeBody)) { redundantRule = true; } - //implements s0: delete duplicate rules - if (!(redundantRule || transformedRules.contains(rule))) { + //implements s3 + if (checkForHeadInBody(body, headAtom)) { + redundantRule = true; + } + //implements s9 + if(checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { + redundantRule = true; + } + //implements s10 + simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); + if(simplifiedRule != null) { + rule = simplifiedRule; + } + + if(!redundantRule) { transformedRules.add(rule); } } - deleteConflictingRules(transformedRules, inputProgram.getFacts()); - - simplifyRules(transformedRules, inputProgram.getFacts()); return new InternalProgram(transformedRules, inputProgram.getFacts()); } @@ -55,10 +67,7 @@ public InternalProgram apply(InternalProgram inputProgram) { * implements s2 */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - //TODO: implement literal.equals() + for (Literal positiveLiteral : positiveBody) { if (negativeBody.contains(positiveLiteral.negate())) { return true; } @@ -71,10 +80,8 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { - Iterator literalIterator = body.iterator(); - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - //TODO: implement atom.equals() + for (Literal literal : body) { + //TODO: implement Atom.equals() if (literal.getAtom().equals(headAtom)) { return true; } @@ -82,79 +89,57 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { return false; } + /** - * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. * implements s9 */ - private List deleteConflictingRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } + private boolean checkForUnreachableLiterals (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + return false; } - else { - if (isDerivable(literal, rules)) { - transformedRules.add(rule); - } + } else { + if (isDerivable(literal, rules)) { + return false; } } } - return transformedRules; + return true; } /** - * This method removes literals from rule bodies, that are already facts (when positive) + * This method checks for literals from rule bodies, that are already facts (when positive) * or not derivable (when negated). * implements s10 */ - private List simplifyRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } - else transformedRules.add(rule.removeLiteral(literal)); - } - else { - if (!isDerivable(literal, rules)) { - transformedRules.add(rule.removeLiteral(literal)); - } - else transformedRules.add(rule); - } + private InternalRule checkForSimplifiableRule (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return null; + } else return rule.removeLiteral(literal); + } else { + if (!isDerivable(literal, rules)) { + return rule.removeLiteral(literal); + } else return null; } } - return transformedRules; + return null; } + + /** * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. * implements s5 conditions */ private boolean isDerivable(Literal literal, List rules){ - Iterator ruleIterator = rules.iterator(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + for (InternalRule rule : rules) { + if (Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { return true; } } From bce28379cf78257112cf9fc39332a680df679f0d Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 21 Dec 2021 16:22:13 +0100 Subject: [PATCH 07/56] merged with master branch and fixed merging problems --- .../kr/alpha/core/grounder/NaiveGrounder.java | 225 +++++++------- ...ultLazyGroundingInstantiationStrategy.java | 1 - .../transformation/SimplePreprocessing.java | 279 +++++++++--------- .../kr/alpha/core/rules/CompiledRule.java | 3 + .../kr/alpha/core/rules/InternalRule.java | 21 +- .../SimplePreprocessingTest.java | 19 ++ 6 files changed, 295 insertions(+), 253 deletions(-) create mode 100644 alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java 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 c7fb322bf..2d9320abd 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 @@ -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. - * + * 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 @@ -25,54 +25,57 @@ * 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.grounder; - -import static at.ac.tuwien.kr.alpha.Util.oops; -import static at.ac.tuwien.kr.alpha.common.Literals.atomOf; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collection; -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.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import at.ac.tuwien.kr.alpha.Util; -import at.ac.tuwien.kr.alpha.common.AnswerSet; -import at.ac.tuwien.kr.alpha.common.Assignment; -import at.ac.tuwien.kr.alpha.common.AtomStore; -import at.ac.tuwien.kr.alpha.common.BasicAnswerSet; -import at.ac.tuwien.kr.alpha.common.IntIterator; -import at.ac.tuwien.kr.alpha.common.NoGood; -import at.ac.tuwien.kr.alpha.common.NoGoodInterface; -import at.ac.tuwien.kr.alpha.common.Predicate; -import at.ac.tuwien.kr.alpha.common.atoms.Atom; -import at.ac.tuwien.kr.alpha.common.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.InternalProgram; -import at.ac.tuwien.kr.alpha.common.rule.InternalRule; -import at.ac.tuwien.kr.alpha.common.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.grounder.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.grounder.atoms.RuleAtom; -import at.ac.tuwien.kr.alpha.grounder.bridges.Bridge; -import at.ac.tuwien.kr.alpha.grounder.heuristics.GrounderHeuristicsConfiguration; -import at.ac.tuwien.kr.alpha.grounder.instantiation.AssignmentStatus; -import at.ac.tuwien.kr.alpha.grounder.instantiation.BindingResult; -import at.ac.tuwien.kr.alpha.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; -import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiationResult; -import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiator; -import at.ac.tuwien.kr.alpha.grounder.structure.AnalyzeUnjustified; + package at.ac.tuwien.kr.alpha.core.grounder; + + import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; + import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; + + import java.util.ArrayList; + import java.util.Collection; + 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.Set; + import java.util.SortedSet; + import java.util.TreeSet; + + import org.apache.commons.lang3.tuple.ImmutablePair; + import org.apache.commons.lang3.tuple.Pair; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + + import at.ac.tuwien.kr.alpha.api.AnswerSet; + import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; + import at.ac.tuwien.kr.alpha.api.grounder.Substitution; + import at.ac.tuwien.kr.alpha.api.programs.Predicate; + import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; + import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; + import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; + import at.ac.tuwien.kr.alpha.commons.AnswerSets; + import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; + import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; + import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; + import at.ac.tuwien.kr.alpha.commons.util.Util; + import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; + import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; + import at.ac.tuwien.kr.alpha.core.common.Assignment; + import at.ac.tuwien.kr.alpha.core.common.AtomStore; + import at.ac.tuwien.kr.alpha.core.common.IntIterator; + import at.ac.tuwien.kr.alpha.core.common.NoGood; + import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; + import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; + import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; + import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; + import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; /** * A semi-naive grounder. @@ -87,14 +90,14 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final NogoodRegistry registry = new NogoodRegistry(); final NoGoodGenerator noGoodGenerator; private final ChoiceRecorder choiceRecorder; - private final InternalProgram program; + private final CompiledProgram program; private final AnalyzeUnjustified analyzeUnjustified; private final Map> factsFromProgram; private final Map> rulesUsingPredicateWorkingMemory = new HashMap<>(); - private final Map knownNonGroundRules; + private final Map knownNonGroundRules; - private ArrayList fixedRules = new ArrayList<>(); + private ArrayList fixedRules = new ArrayList<>(); private LinkedHashSet removeAfterObtainingNewNoGoods = new LinkedHashSet<>(); private final boolean debugInternalChecks; @@ -105,17 +108,17 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final LiteralInstantiator ruleInstantiator; private final DefaultLazyGroundingInstantiationStrategy instantiationStrategy; - public NaiveGrounder(InternalProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { + public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(InternalProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, - Bridge... bridges) { + private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, + Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(InternalProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, + GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; @@ -130,7 +133,7 @@ private NaiveGrounder(InternalProgram program, AtomStore atomStore, GrounderHeur this.initializeFactsAndRules(); - final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); + final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); choiceRecorder = new ChoiceRecorder(atomStore); noGoodGenerator = new NoGoodGenerator(atomStore, choiceRecorder, factsFromProgram, this.program, uniqueGroundRulePerGroundHead); @@ -159,7 +162,7 @@ private void initializeFactsAndRules() { workingMemory.initialize(ChoiceAtom.ON); // Initialize rules and constraints in working memory. - for (InternalRule nonGroundRule : program.getRulesById().values()) { + for (CompiledRule nonGroundRule : program.getRulesById().values()) { // Create working memories for all predicates occurring in the rule. for (Predicate predicate : nonGroundRule.getOccurringPredicates()) { // FIXME: this also contains interval/builtin predicates that are not needed. @@ -167,30 +170,30 @@ private void initializeFactsAndRules() { } // If the rule has fixed ground instantiations, it is not registered but grounded once like facts. - if (nonGroundRule.getGroundingOrders().fixedInstantiation()) { + if (nonGroundRule.getGroundingInfo().hasFixedInstantiation()) { fixedRules.add(nonGroundRule); continue; } // Register each starting literal at the corresponding working memory. - for (Literal literal : nonGroundRule.getGroundingOrders().getStartingLiterals()) { + for (Literal literal : nonGroundRule.getGroundingInfo().getStartingLiterals()) { registerLiteralAtWorkingMemory(literal, nonGroundRule); } } } - private Set getRulesWithUniqueHead() { + private Set getRulesWithUniqueHead() { // FIXME: below optimisation (adding support nogoods if there is only one rule instantiation per unique atom over the interpretation) could // be done as a transformation (adding a non-ground constraint corresponding to the nogood that is generated by the grounder). // Record all unique rule heads. - final Set uniqueGroundRulePerGroundHead = new HashSet<>(); + final Set uniqueGroundRulePerGroundHead = new HashSet<>(); - for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { + for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { if (headDefiningRules.getValue().size() != 1) { continue; } - InternalRule nonGroundRule = headDefiningRules.getValue().iterator().next(); + CompiledRule nonGroundRule = headDefiningRules.getValue().iterator().next(); // Check that all variables of the body also occur in the head (otherwise grounding is not unique). Atom headAtom = nonGroundRule.getHeadAtom(); @@ -218,10 +221,10 @@ private Set getRulesWithUniqueHead() { /** * Registers a starting literal of a NonGroundRule at its corresponding working memory. - * + * * @param nonGroundRule the rule in which the literal occurs. */ - private void registerLiteralAtWorkingMemory(Literal literal, InternalRule nonGroundRule) { + private void registerLiteralAtWorkingMemory(Literal literal, CompiledRule nonGroundRule) { if (literal.isNegated()) { throw new RuntimeException("Literal to register is negated. Should not happen."); } @@ -275,20 +278,20 @@ public AnswerSet assignmentToAnswerSet(Iterable trueAtoms) { predicateInstances.putIfAbsent(factPredicate, new TreeSet<>()); for (Instance factInstance : facts.getValue()) { SortedSet instances = predicateInstances.get(factPredicate); - instances.add(new BasicAtom(factPredicate, factInstance.terms)); + instances.add(Atoms.newBasicAtom(factPredicate, factInstance.terms)); } } if (knownPredicates.isEmpty()) { - return BasicAnswerSet.EMPTY; + return AnswerSets.EMPTY_SET; } - return new BasicAnswerSet(knownPredicates, predicateInstances); + return AnswerSets.newAnswerSet(knownPredicates, predicateInstances); } /** * Prepares facts of the input program for joining and derives all NoGoods representing ground rules. May only be called once. - * + * * @return */ protected HashMap bootstrap() { @@ -299,10 +302,10 @@ protected HashMap bootstrap() { workingMemory.addInstances(predicate, true, factsFromProgram.get(predicate)); } - for (InternalRule nonGroundRule : fixedRules) { + for (CompiledRule nonGroundRule : fixedRules) { // Generate NoGoods for all rules that have a fixed grounding. - RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingOrders().getFixedGroundingOrder(); - BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new Substitution(), null); + RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingInfo().getFixedGroundingOrder(); + BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new BasicSubstitution(), null); groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), groundNogoods); } @@ -312,7 +315,7 @@ protected HashMap bootstrap() { } @Override - public Map getNoGoods(Assignment assignment) { + public Map getNoGoods(Assignment currentAssignment) { // In first call, prepare facts and ground rules. final Map newNoGoods = fixedRules != null ? bootstrap() : new LinkedHashMap<>(); @@ -334,14 +337,14 @@ public Map getNoGoods(Assignment assignment) { for (FirstBindingAtom firstBindingAtom : firstBindingAtoms) { // Use the recently added instances from the modified working memory to construct an initial substitution - InternalRule nonGroundRule = firstBindingAtom.rule; + CompiledRule nonGroundRule = firstBindingAtom.rule; // Generate substitutions from each recent instance. for (Instance instance : modifiedWorkingMemory.getRecentlyAddedInstances()) { // Check instance if it matches with the atom. - final Substitution unifier = Substitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, - Substitution.EMPTY_SUBSTITUTION); + final Substitution unifier = BasicSubstitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, + BasicSubstitution.EMPTY_SUBSTITUTION); if (unifier == null) { continue; @@ -349,9 +352,9 @@ public Map getNoGoods(Assignment assignment) { final BindingResult bindingResult = getGroundInstantiations( nonGroundRule, - nonGroundRule.getGroundingOrders().orderStartingFrom(firstBindingAtom.startingLiteral), + nonGroundRule.getGroundingInfo().orderStartingFrom(firstBindingAtom.startingLiteral), unifier, - assignment); + currentAssignment); groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), newNoGoods); } @@ -397,7 +400,7 @@ public Map getNoGoods(Assignment assignment) { * @param substitutions the substitutions to be applied. * @param newNoGoods a set of nogoods to which newly generated nogoods will be added. */ - private void groundAndRegister(final InternalRule nonGroundRule, final List substitutions, final Map newNoGoods) { + private void groundAndRegister(final CompiledRule nonGroundRule, final List substitutions, final Map newNoGoods) { for (Substitution substitution : substitutions) { List generatedNoGoods = noGoodGenerator.generateNoGoodsFromGroundSubstitution(nonGroundRule, substitution); registry.register(generatedNoGoods, newNoGoods); @@ -410,8 +413,8 @@ public int register(NoGood noGood) { } // Ideally, this method should be private. It's only visible because NaiveGrounderTest needs to access it. - BindingResult getGroundInstantiations(InternalRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, - Assignment assignment) { + BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, + Assignment currentAssignment) { int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint()); if (tolerance < 0) { tolerance = Integer.MAX_VALUE; @@ -420,7 +423,7 @@ BindingResult getGroundInstantiations(InternalRule rule, RuleGroundingOrder grou // Update instantiationStrategy with current assignment. // Note: Actually the assignment could be an instance variable of the grounder (shared with solver), // but this would have a larger impact on grounder/solver communication design as a whole. - instantiationStrategy.setCurrentAssignment(assignment); + instantiationStrategy.setCurrentAssignment(currentAssignment); BindingResult bindingResult = bindNextAtomInRule(groundingOrder, 0, tolerance, tolerance, partialSubstitution); if (LOGGER.isDebugEnabled()) { for (int i = 0; i < bindingResult.size(); i++) { @@ -435,13 +438,13 @@ BindingResult getGroundInstantiations(InternalRule rule, RuleGroundingOrder grou } /** - * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrder, int, int, int, Substitution)}. - * - * Takes an ImmutablePair of a {@link Substitution} and an accompanying {@link AssignmentStatus} and calls + * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrderImpl, int, int, int, BasicSubstitution)}. + * + * Takes an ImmutablePair of a {@link BasicSubstitution} and an accompanying {@link AssignmentStatus} and calls * bindNextAtomInRule for the next literal in the grounding order. * If the assignment status for the last bound literal was {@link AssignmentStatus#UNASSIGNED}, the remainingTolerance * parameter is decreased by 1. If the remaining tolerance drops below zero, this method returns an empty {@link BindingResult}. - * + * * @param groundingOrder * @param orderPosition * @param originalTolerance @@ -451,7 +454,7 @@ BindingResult getGroundInstantiations(InternalRule rule, RuleGroundingOrder grou * tolerance is less than zero. */ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - ImmutablePair lastLiteralBindingResult) { + ImmutablePair lastLiteralBindingResult) { Substitution substitution = lastLiteralBindingResult.left; AssignmentStatus lastBoundLiteralAssignmentStatus = lastLiteralBindingResult.right; switch (lastBoundLiteralAssignmentStatus) { @@ -475,13 +478,13 @@ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int ord } private BindingResult advanceAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { groundingOrder.considerUntilCurrentEnd(); return bindNextAtomInRule(groundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution); } private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { RuleGroundingOrder modifiedGroundingOrder = groundingOrder.pushBack(orderPosition); if (modifiedGroundingOrder == null) { return BindingResult.empty(); @@ -491,12 +494,12 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding //@formatter:off /** - * Computes ground substitutions for a literal based on a {@link RuleGroundingOrder} and a {@link Substitution}. - * + * Computes ground substitutions for a literal based on a {@link RuleGroundingOrderImpl} and a {@link BasicSubstitution}. + * * Computes ground substitutions for the literal at position orderPosition of groundingOrder * Actual substitutions are computed by this grounder's {@link LiteralInstantiator}. - * - * @param groundingOrder a {@link RuleGroundingOrder} representing the body literals of a rule in the + * + * @param groundingOrder a {@link RuleGroundingOrderImpl} representing the body literals of a rule in the * sequence in which the should be bound during grounding. * @param orderPosition the current position within groundingOrder, indicates which literal should be bound * @param originalTolerance the original tolerance of the used grounding heuristic @@ -506,7 +509,7 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding */ //@formatter:on private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition); if (currentLiteral == null) { LOGGER.trace("No more literals found in grounding order, therefore stopping binding!"); @@ -585,7 +588,7 @@ public void forgetAssignment(int[] atomIds) { } @Override - public InternalRule getNonGroundRule(Integer ruleId) { + public CompiledRule getNonGroundRule(Integer ruleId) { return knownNonGroundRules.get(ruleId); } @@ -599,8 +602,8 @@ public boolean isFact(Atom atom) { } @Override - public Set justifyAtom(int atomToJustify, Assignment assignment) { - Set literals = analyzeUnjustified.analyze(atomToJustify, assignment); + public Set justifyAtom(int atomToJustify, Assignment currentAssignment) { + Set literals = analyzeUnjustified.analyze(atomToJustify, currentAssignment); // Remove facts from justification before handing it over to the solver. for (Iterator iterator = literals.iterator(); iterator.hasNext();) { Literal literal = iterator.next(); @@ -617,8 +620,8 @@ public Set justifyAtom(int atomToJustify, Assignment assignment) { /** * Checks that every nogood not marked as {@link NoGoodInterface.Type#INTERNAL} contains only - * atoms which are not {@link Predicate#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). - * + * atoms which are not {@link PredicateImpl#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). + * * @param newNoGoods */ private void checkTypesOfNoGoods(Collection newNoGoods) { @@ -635,13 +638,13 @@ private void checkTypesOfNoGoods(Collection newNoGoods) { } private static class FirstBindingAtom { - final InternalRule rule; + final CompiledRule rule; final Literal startingLiteral; - FirstBindingAtom(InternalRule rule, Literal startingLiteral) { + FirstBindingAtom(CompiledRule rule, Literal startingLiteral) { this.rule = rule; this.startingLiteral = startingLiteral; } } -} +} \ No newline at end of file diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java index 621e4616b..e54f9d627 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java @@ -37,7 +37,6 @@ import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.grounder.IndexedInstanceStorage; -import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; import at.ac.tuwien.kr.alpha.core.grounder.WorkingMemory; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 3a705c9da..b8ce81cf9 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -1,14 +1,18 @@ -package at.ac.tuwien.kr.alpha.grounder.transformation; - -import at.ac.tuwien.kr.alpha.common.atoms.Atom; -import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.InternalProgram; -import at.ac.tuwien.kr.alpha.common.rule.InternalRule; -import at.ac.tuwien.kr.alpha.grounder.Unification; -import org.apache.poi.util.Internal; +package at.ac.tuwien.kr.alpha.core.programs.transformation; + +import at.ac.tuwien.kr.alpha.api.programs.Program; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.rules.Rule; +import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.core.grounder.Unification; +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.InputProgram; +import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -16,133 +20,132 @@ * Simplifies an internal input program by simplifying and deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation{ - - @Override - public InternalProgram apply(InternalProgram inputProgram) { - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - for (InternalRule rule : srcRules) { - boolean redundantRule = false; - - Atom headAtom = rule.getHead().getAtom(); - Set body = rule.getBody(); - Set positiveBody = rule.getPositiveBody(); - Set negativeBody = rule.getNegativeBody(); - InternalRule simplifiedRule = null; - - //implements s0: delete duplicate rules - if (transformedRules.contains(rule)) { //TODO: Add InternalRule.equals() - redundantRule = true; - } - //implemnts s2 - if (checkForConflictingBodyLiterals(positiveBody, negativeBody)) { - redundantRule = true; - } - //implements s3 - if (checkForHeadInBody(body, headAtom)) { - redundantRule = true; - } - //implements s9 - if(checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { - redundantRule = true; - } - //implements s10 - simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); - if(simplifiedRule != null) { - rule = simplifiedRule; - } - - if(!redundantRule) { - transformedRules.add(rule); - } - } - - return new InternalProgram(transformedRules, inputProgram.getFacts()); - } - - /** - * This method checks if a rule contains a literal in both the positive and the negative body. - * implements s2 - */ - private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - for (Literal positiveLiteral : positiveBody) { - if (negativeBody.contains(positiveLiteral.negate())) { - return true; - } - } - return false; - } - - /** - * This method checks if the head atom occurs in the rule's body. - * implements s3 - */ - private boolean checkForHeadInBody(Set body, Atom headAtom) { - for (Literal literal : body) { - //TODO: implement Atom.equals() - if (literal.getAtom().equals(headAtom)) { - return true; - } - } - return false; - } - - - /** - * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. - * implements s9 - */ - private boolean checkForUnreachableLiterals (List rules, InternalRule rule, List facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - return false; - } - } else { - if (isDerivable(literal, rules)) { - return false; - } - } - } - return true; - } - - - /** - * This method checks for literals from rule bodies, that are already facts (when positive) - * or not derivable (when negated). - * implements s10 - */ - private InternalRule checkForSimplifiableRule (List rules, InternalRule rule, List facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return null; - } else return rule.removeLiteral(literal); - } else { - if (!isDerivable(literal, rules)) { - return rule.removeLiteral(literal); - } else return null; - } - } - return null; - } - - - - - /** - * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. - * implements s5 conditions - */ - private boolean isDerivable(Literal literal, List rules){ - for (InternalRule rule : rules) { - if (Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { - return true; - } - } - return false; - } +public class SimplePreprocessing extends ProgramTransformation { + + @Override + public CompiledProgram apply(CompiledProgram inputProgram) { + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + + for (CompiledRule rule : srcRules) { + boolean redundantRule = false; + + Atom headAtom = rule.getHead().getAtom(); + Set body = rule.getBody(); + Set positiveBody = rule.getPositiveBody(); + Set negativeBody = rule.getNegativeBody(); + CompiledRule simplifiedRule = null; + + //implements s0: delete duplicate rules + if (transformedRules.contains(rule)) { + redundantRule = true; + } + //implements s2 + if (!redundantRule && checkForConflictingBodyLiterals(positiveBody, negativeBody)) { + redundantRule = true; + } + //implements s3 + if (!redundantRule && checkForHeadInBody(body, headAtom)) { + redundantRule = true; + } + //implements s9 + if (!redundantRule && checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { + redundantRule = true; + } + //implements s10 + simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); + if (simplifiedRule != null) { + rule = simplifiedRule; + } + + if(!redundantRule) { + transformedRules.add(rule); + } + } + + if(inputProgram.getClass() == InternalProgram.class) { + return new InternalProgram(transformedRules, inputProgram.getFacts()); + } + else { + return new AnalyzedProgram(transformedRules, inputProgram.getFacts()); + } + } + + /** + * This method checks if a rule contains a literal in both the positive and the negative body. + * implements s2 + */ + private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { + for (Literal positiveLiteral : positiveBody) { + if (negativeBody.contains(positiveLiteral.negate())) { + return true; + } + } + return false; + } + + /** + * This method checks if the head atom occurs in the rule's body. + * implements s3 + */ + private boolean checkForHeadInBody(Set body, Atom headAtom) { + for (Literal literal : body) { + if (literal.getAtom().equals(headAtom)) { + return true; + } + } + return false; + } + + /** + * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. + * implements s9 + */ + private boolean checkForUnreachableLiterals (List rules, CompiledRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + return false; + } + } else { + if (isDerivable(literal, rules)) { + return false; + } + } + } + return true; + } + + /** + * This method checks for literals from rule bodies, that are already facts (when positive) + * or not derivable (when negated). + * implements s10 + */ + private CompiledRule checkForSimplifiableRule (List rules, CompiledRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return null; + } else return rule.returnCopyWithoutLiteral(literal); + } else { + if (!isDerivable(literal, rules)) { + return rule.returnCopyWithoutLiteral(literal); + } else return null; + } + } + return null; + } + + /** + * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * implements s5 conditions + */ + private boolean isDerivable(Literal literal, List rules){ + for (Rule rule : rules) { + if (Unification.unifyAtoms(literal.getAtom(), rule.getHead().getAtom()) != null) { + return true; + } + } + return false; + } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java index b15dfbc41..754e0fe3d 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java @@ -3,6 +3,7 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfo; @@ -17,4 +18,6 @@ public interface CompiledRule extends NormalRule { CompiledRule renameVariables(String str); boolean isGround(); + + CompiledRule returnCopyWithoutLiteral(Literal literal); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index aaa15c5fa..70c05b5e1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -29,7 +29,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import com.google.common.annotations.VisibleForTesting; import at.ac.tuwien.kr.alpha.api.programs.Predicate; @@ -143,15 +145,28 @@ public int getRuleId() { return this.ruleId; } - public InternalRule removeLiteral(Literal literal) { - Atom headAtom = this.getHeadAtom(); + public InternalRule returnCopyWithoutLiteral(Literal literal) { + BasicAtom headAtom = this.getHeadAtom(); List newBody = new ArrayList<>(this.getBody().size()); for (Literal bodyLiteral : this.getBody()) { if(!literal.equals(bodyLiteral)) { newBody.add(bodyLiteral); } } - return new InternalRule(new NormalHead(headAtom), newBody); + return new InternalRule(Heads.newNormalHead(headAtom), newBody); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InternalRule that = (InternalRule) o; + + return Objects.equals(occurringPredicates, that.occurringPredicates); } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java new file mode 100644 index 000000000..c04f2e6b5 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -0,0 +1,19 @@ +package at.ac.tuwien.kr.alpha.core.programs.transformation; + +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +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 java.util.function.Function; + +public class SimplePreprocessingTest { + + private final ProgramParser parser = new ProgramParserImpl(); + private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + private final SimplePreprocessing evaluator = new SimplePreprocessing(); + private final Function parseAndEvaluate = (str) -> { + return evaluator.apply(AnalyzedProgram.analyzeNormalProgram(normalizer.apply(parser.parse(str)))); + }; +} From ea34af81b453080d774de508b9b496ad5731e51f Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 18 Jan 2022 15:42:42 +0100 Subject: [PATCH 08/56] refactored and fixed bugs in SimplePreprocessing, added tests --- .../kr/alpha/core/grounder/NaiveGrounder.java | 12 +- .../kr/alpha/core/grounder/Unification.java | 8 +- .../transformation/SimplePreprocessing.java | 198 +++++++++++------- .../kr/alpha/core/rules/InternalRule.java | 25 +-- ...eralizedDependencyDrivenPyroHeuristic.java | 2 +- .../SimplePreprocessingTest.java | 88 +++++++- .../tuwien/kr/alpha/api/impl/AlphaImpl.java | 5 +- 7 files changed, 226 insertions(+), 112 deletions(-) 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 2d9320abd..299a80bfb 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 @@ -113,12 +113,12 @@ public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debug } private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, - Bridge... bridges) { + Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; @@ -414,7 +414,7 @@ public int register(NoGood noGood) { // Ideally, this method should be private. It's only visible because NaiveGrounderTest needs to access it. BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, - Assignment currentAssignment) { + Assignment currentAssignment) { int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint()); if (tolerance < 0) { tolerance = Integer.MAX_VALUE; @@ -454,7 +454,7 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou * tolerance is less than zero. */ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - ImmutablePair lastLiteralBindingResult) { + ImmutablePair lastLiteralBindingResult) { Substitution substitution = lastLiteralBindingResult.left; AssignmentStatus lastBoundLiteralAssignmentStatus = lastLiteralBindingResult.right; switch (lastBoundLiteralAssignmentStatus) { @@ -478,7 +478,7 @@ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int ord } private BindingResult advanceAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { groundingOrder.considerUntilCurrentEnd(); return bindNextAtomInRule(groundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution); } @@ -509,7 +509,7 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding */ //@formatter:on private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition); if (currentLiteral == null) { LOGGER.trace("No more literals found in grounding order, therefore stopping binding!"); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java index ab2647942..819890808 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java @@ -65,10 +65,10 @@ public static Unifier instantiate(Atom general, Atom specific) { private static Unifier unifyAtoms(Atom left, Atom right, boolean keepLeftAsIs) { Set leftOccurringVariables = left.getOccurringVariables(); - Set rightOccurringVaribles = right.getOccurringVariables(); - boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVaribles.size(); - Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVaribles; - Set largerSet = leftSmaller ? rightOccurringVaribles : leftOccurringVariables; + Set rightOccurringVariables = right.getOccurringVariables(); + boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); + Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; + Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; for (VariableTerm variableTerm : smallerSet) { if (largerSet.contains(variableTerm)) { throw oops("Left and right atom share variables."); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index b8ce81cf9..5c216fb9f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -1,79 +1,78 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import at.ac.tuwien.kr.alpha.api.programs.Program; +import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; import at.ac.tuwien.kr.alpha.core.grounder.Unification; -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.InputProgram; -import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; +import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; + +import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; /** * Simplifies an internal input program by simplifying and deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation { +public class SimplePreprocessing extends ProgramTransformation { @Override - public CompiledProgram apply(CompiledProgram inputProgram) { - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - for (CompiledRule rule : srcRules) { - boolean redundantRule = false; - - Atom headAtom = rule.getHead().getAtom(); - Set body = rule.getBody(); - Set positiveBody = rule.getPositiveBody(); - Set negativeBody = rule.getNegativeBody(); - CompiledRule simplifiedRule = null; - - //implements s0: delete duplicate rules - if (transformedRules.contains(rule)) { - redundantRule = true; - } - //implements s2 - if (!redundantRule && checkForConflictingBodyLiterals(positiveBody, negativeBody)) { - redundantRule = true; - } - //implements s3 - if (!redundantRule && checkForHeadInBody(body, headAtom)) { - redundantRule = true; - } - //implements s9 - if (!redundantRule && checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { - redundantRule = true; + public NormalProgram apply(NormalProgram inputProgram) { + List srcRules = inputProgram.getRules(); + Set facts = new LinkedHashSet<>(inputProgram.getFacts()); + boolean modified = true; + while (modified) { + modified = false; + //implements s0 by using a Set (deleting duplicate rules) + Set newRules = new LinkedHashSet<>(); + for (NormalRule rule : srcRules) { + //s9 + if (checkForNonDerivableLiterals(rule, srcRules, facts)) { + continue; + } + //s10 + NormalRule simplifiedRule = simplifyRule(rule, srcRules, facts); + if (simplifiedRule == null) { + continue; + } + else if (simplifiedRule.getBody().isEmpty()) { + facts.add(simplifiedRule.getHeadAtom()); + modified = true; + continue; + } else { + if(!simplifiedRule.equals(rule)) { + modified = true; + rule = simplifiedRule; + } + } + newRules.add(rule); } - //implements s10 - simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); - if (simplifiedRule != null) { - rule = simplifiedRule; + srcRules = new LinkedList<>(newRules); + } + Set newRules = new LinkedHashSet<>(); + for (NormalRule rule: srcRules) { + //s2 + if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { + continue; } - - if(!redundantRule) { - transformedRules.add(rule); + //s3 + if (checkForHeadInBody(rule.getBody(), rule.getHeadAtom())) { + continue; } + newRules.add(rule); } - - if(inputProgram.getClass() == InternalProgram.class) { - return new InternalProgram(transformedRules, inputProgram.getFacts()); - } - else { - return new AnalyzedProgram(transformedRules, inputProgram.getFacts()); - } + return new NormalProgramImpl(new LinkedList<>(newRules),new LinkedList<>(facts),inputProgram.getInlineDirectives()); } /** * This method checks if a rule contains a literal in both the positive and the negative body. * implements s2 + * @return true if the rule contains conflicting literals, false otherwise */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { for (Literal positiveLiteral : positiveBody) { @@ -87,6 +86,7 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { for (Literal literal : body) { @@ -98,54 +98,100 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { } /** - * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. + * This method checks rules for bodies containing non-derivable literals or negated literals, that are facts. * implements s9 + * @param rule the rule to check + * @param rules the rules from which the literals should be derivable from + * @param facts the facts from which the literals should be derivable from + * @return true if the rule is non-derivable, false if it is derivable */ - private boolean checkForUnreachableLiterals (List rules, CompiledRule rule, List facts) { + private boolean checkForNonDerivableLiterals(NormalRule rule, List rules, Set facts) { for (Literal literal : rule.getBody()) { if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - return false; + if (facts.contains(literal.getAtom())) { + return true; } } else { - if (isDerivable(literal, rules)) { - return false; + if (isNonDerivable(literal, rules)) { + return true; } } } - return true; + return false; } /** - * This method checks for literals from rule bodies, that are already facts (when positive) - * or not derivable (when negated). + * This method checks for literals from rule bodies, that are already facts or non-derivable. * implements s10 + * @param rule the rule to check + * @param rules the rules from which the literals should be derivable from + * @param facts the facts from which the literals should be derivable from + * @return the possibly shortened rule or null, if the rule is not derivable */ - private CompiledRule checkForSimplifiableRule (List rules, CompiledRule rule, List facts) { + private NormalRule simplifyRule(NormalRule rule, List rules, Set facts) { for (Literal literal : rule.getBody()) { if (literal.isNegated()) { if (facts.contains(literal.getAtom())) { return null; - } else return rule.returnCopyWithoutLiteral(literal); - } else { - if (!isDerivable(literal, rules)) { - return rule.returnCopyWithoutLiteral(literal); - } else return null; + } + else if (isNonDerivable(literal, rules)) { + return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); + } + } + else { + if (isNonDerivable(literal, rules)) { + return null; + } + else if (facts.contains(literal.getAtom())) { + return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); + } } } - return null; + return rule; } /** - * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * This method checks whether a literal is non-derivable, i.e. it is not unifiable with the head atom of a rule. * implements s5 conditions + * @param literal the literal to check + * @param rules the rules from which the literal should be derivable from + * @return true if the literal is not derivable, false otherwise */ - private boolean isDerivable(Literal literal, List rules){ - for (Rule rule : rules) { - if (Unification.unifyAtoms(literal.getAtom(), rule.getHead().getAtom()) != null) { - return true; + private boolean isNonDerivable(Literal literal, List rules) { + for (NormalRule rule : rules) { + boolean hasSharedVariable = false; + Set leftOccurringVariables = literal.getAtom().getOccurringVariables(); + Set rightOccurringVariables = rule.getHeadAtom().getOccurringVariables(); + boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); + Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; + Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; + for (VariableTerm variableTerm : smallerSet) { + if (largerSet.contains(variableTerm)) { + hasSharedVariable = true; + break; + } + } + if (!hasSharedVariable) { + if(Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { + return false; + } } } - return false; + return true; + } + + /** + * Returns a copy of the rule with the specified literal removed + ** @return the rule without the specified literal + */ + private NormalRule removeLiteralFromRule(NormalRule rule, Literal literal) { + BasicAtom headAtom = rule.getHeadAtom(); + List newBody = new LinkedList<>(); + for (Literal bodyLiteral : rule.getBody()) { + if (!literal.equals(bodyLiteral)) { + newBody.add(bodyLiteral); + } + } + return new NormalRuleImpl(Heads.newNormalHead(headAtom), newBody); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index 70c05b5e1..38ca6b6f1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -29,11 +29,8 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import com.google.common.annotations.VisibleForTesting; - import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; @@ -145,28 +142,22 @@ public int getRuleId() { return this.ruleId; } + /** + * Returns a copy of the rule with the specified literal removed, or null if the new rule would have an empty body. + * @return the rule without the specified literal, null if no body remains. + */ public InternalRule returnCopyWithoutLiteral(Literal literal) { BasicAtom headAtom = this.getHeadAtom(); List newBody = new ArrayList<>(this.getBody().size()); for (Literal bodyLiteral : this.getBody()) { - if(!literal.equals(bodyLiteral)) { + if (!literal.equals(bodyLiteral)) { newBody.add(bodyLiteral); } } - return new InternalRule(Heads.newNormalHead(headAtom), newBody); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; + if (newBody.isEmpty()) { + return null; } - InternalRule that = (InternalRule) o; - - return Objects.equals(occurringPredicates, that.occurringPredicates); + return new InternalRule(Heads.newNormalHead(headAtom), newBody); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java index 586dc3598..2fe6a59f8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java @@ -45,7 +45,7 @@ public class GeneralizedDependencyDrivenPyroHeuristic extends GeneralizedDependencyDrivenHeuristic { public GeneralizedDependencyDrivenPyroHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random, - BodyActivityType bodyActivityType) { + BodyActivityType bodyActivityType) { super(assignment, choiceManager, decayPeriod, decayFactor, random, bodyActivityType); } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index c04f2e6b5..48b5e723c 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -1,19 +1,93 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; +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.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +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 org.junit.jupiter.api.Test; +import java.util.Set; import java.util.function.Function; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class SimplePreprocessingTest { - private final ProgramParser parser = new ProgramParserImpl(); - private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); - private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private final Function parseAndEvaluate = (str) -> { - return evaluator.apply(AnalyzedProgram.analyzeNormalProgram(normalizer.apply(parser.parse(str)))); - }; + private final ProgramParser parser = new ProgramParserImpl(); + private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + private final SimplePreprocessing evaluator = new SimplePreprocessing(); + private final Function parseAndEvaluate = (str) -> { + return evaluator.apply(normalizer.apply(parser.parse(str))); + }; + + 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(); + }; + + @Test + public void testDuplicateRules() { + String aspStr1 = "a :- b. a :- b. b."; + String aspStr2 = "a :- b. b."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + @Test + public void testConflictingBodyLiterals() { + String aspStr1 = "a :- b, not b. b :- c."; + String aspStr2 = " b :- c."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + @Test + public void testHeadInBody() { + String aspStr1 = "a :- a, not b. b :- c."; + String aspStr2 = " b :- c."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + //@Test + public void testNonDerivableLiterals() { + String aspStr1 = "a :- not b. b :- c. d. e :- not d."; + String aspStr2 = "a :- not b. d."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + //@Test + public void testSimplifiedRules() { + String aspStr1 = "a :- b, not c. b. c :- not a. e :- a, not d."; + String aspStr2 = "a :- not c. b. c :- not a."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + @Test + public void testNonGroundProgram() { + String aspStr1 = "r(X) :- q(Y), not p(Y). q(Y). p(Y) :- not r(X). s(b) :- r(a), not t(d)."; + String aspStr2 = "r(X) :- not p(Y). q(Y). p(Y) :- not r(X)."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } } 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 c49a5ca39..e076348ec 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 @@ -39,6 +39,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import at.ac.tuwien.kr.alpha.core.programs.transformation.SimplePreprocessing; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -142,7 +143,9 @@ public NormalProgram normalizeProgram(ASPCore2Program program) { @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { LOGGER.debug("Preprocessing InternalProgram!"); - InternalProgram retVal = InternalProgram.fromNormalProgram(program); + SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); + NormalProgram simplePreprocessed = simplePreprocessing.apply(program); + InternalProgram retVal = InternalProgram.fromNormalProgram(simplePreprocessed); if (config.isEvaluateStratifiedPart()) { AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); retVal = new StratifiedEvaluation().apply(analyzed); From 424cfcac3606edb575d44f2d44c25ba77952e3ae Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 18 Jan 2022 16:12:20 +0100 Subject: [PATCH 09/56] refactored and fixed bugs in SimplePreprocessing, added tests --- .../programs/transformation/SimplePreprocessing.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 5c216fb9f..8fb9bbc0a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -13,8 +13,6 @@ import java.util.*; -import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; - /** * Simplifies an internal input program by simplifying and deleting redundant rules. */ @@ -28,14 +26,10 @@ public NormalProgram apply(NormalProgram inputProgram) { boolean modified = true; while (modified) { modified = false; - //implements s0 by using a Set (deleting duplicate rules) + //implements s0 by using a Set (delete duplicate rules) Set newRules = new LinkedHashSet<>(); for (NormalRule rule : srcRules) { - //s9 - if (checkForNonDerivableLiterals(rule, srcRules, facts)) { - continue; - } - //s10 + //s9 + s10 NormalRule simplifiedRule = simplifyRule(rule, srcRules, facts); if (simplifiedRule == null) { continue; From 99580063dc34e00f823190847627ddf425eee871 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 25 Jan 2022 15:00:41 +0100 Subject: [PATCH 10/56] fixed bugs in SimplePreprocessing, added tests --- .../transformation/SimplePreprocessing.java | 183 ++++++++++-------- .../SimplePreprocessingTest.java | 159 +++++++++++---- 2 files changed, 225 insertions(+), 117 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 8fb9bbc0a..7e3ee4a71 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -22,33 +22,10 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = inputProgram.getRules(); - Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - boolean modified = true; - while (modified) { - modified = false; - //implements s0 by using a Set (delete duplicate rules) - Set newRules = new LinkedHashSet<>(); - for (NormalRule rule : srcRules) { - //s9 + s10 - NormalRule simplifiedRule = simplifyRule(rule, srcRules, facts); - if (simplifiedRule == null) { - continue; - } - else if (simplifiedRule.getBody().isEmpty()) { - facts.add(simplifiedRule.getHeadAtom()); - modified = true; - continue; - } else { - if(!simplifiedRule.equals(rule)) { - modified = true; - rule = simplifiedRule; - } - } - newRules.add(rule); - } - srcRules = new LinkedList<>(newRules); - } + //Implements s0 by using a Set (delete duplicate rules). Set newRules = new LinkedHashSet<>(); + Set facts = new LinkedHashSet<>(inputProgram.getFacts()); + boolean canBeModified = true; for (NormalRule rule: srcRules) { //s2 if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { @@ -60,7 +37,55 @@ else if (simplifiedRule.getBody().isEmpty()) { } newRules.add(rule); } - return new NormalProgramImpl(new LinkedList<>(newRules),new LinkedList<>(facts),inputProgram.getInlineDirectives()); + srcRules = new LinkedList<>(newRules); + //s9 + s10 + while (canBeModified) { + newRules = new LinkedHashSet<>(); + canBeModified = false; + for (NormalRule rule : srcRules) { + SimpleReturn simpleReturn = simplifyRule(rule, srcRules, facts); + if (simpleReturn != null) { + if (simpleReturn == SimpleReturn.NO_FIRE) { + canBeModified = true; + } else if (simpleReturn.isFact()) { + facts.add(simpleReturn.getRule().getHeadAtom()); + canBeModified = true; + } else if (simpleReturn.isModified()) { + newRules.add(simpleReturn.getRule()); + canBeModified = true; + } else { + newRules.add(rule); + } + } + } + srcRules = new LinkedList<>(newRules); + } + return new NormalProgramImpl(new LinkedList<>(newRules), new LinkedList<>(facts), inputProgram.getInlineDirectives()); + } + + private static class SimpleReturn { + public final static SimpleReturn NO_FIRE = new SimpleReturn(null, false, false); + private final NormalRule rule; + private final boolean isModified; + private final boolean isFact; + + public SimpleReturn(NormalRule rule, boolean isModified, boolean isFact) { + this.rule = rule; + this.isModified = isModified; + this.isFact = isFact; + } + + public NormalRule getRule() { + return rule; + } + + public boolean isModified() { + return isModified; + } + + public boolean isFact() { + return isFact; + } } /** @@ -91,70 +116,54 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { return false; } - /** - * This method checks rules for bodies containing non-derivable literals or negated literals, that are facts. - * implements s9 - * @param rule the rule to check - * @param rules the rules from which the literals should be derivable from - * @param facts the facts from which the literals should be derivable from - * @return true if the rule is non-derivable, false if it is derivable - */ - private boolean checkForNonDerivableLiterals(NormalRule rule, List rules, Set facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return true; - } - } else { - if (isNonDerivable(literal, rules)) { - return true; - } - } - } - return false; - } - /** * This method checks for literals from rule bodies, that are already facts or non-derivable. - * implements s10 + * implements s9 + s10 * @param rule the rule to check * @param rules the rules from which the literals should be derivable from * @param facts the facts from which the literals should be derivable from - * @return the possibly shortened rule or null, if the rule is not derivable + * @return SimpleReturn containing the (possibly modified) rule, a boolean isModified and a boolean isFact. On + * non-derivable rules it returns the value NO_FIRE. */ - private NormalRule simplifyRule(NormalRule rule, List rules, Set facts) { + private SimpleReturn simplifyRule(NormalRule rule, List rules, Set facts) { + Set redundantLiterals = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { if (literal.isNegated()) { if (facts.contains(literal.getAtom())) { - return null; + return SimpleReturn.NO_FIRE; } - else if (isNonDerivable(literal, rules)) { - return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); - } - } - else { - if (isNonDerivable(literal, rules)) { - return null; + if (isNonDerivable(literal.getAtom(), rules, facts)) { + redundantLiterals.add(literal); } - else if (facts.contains(literal.getAtom())) { - return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); + } else { + if (facts.contains(literal.getAtom())) { + if (literal.isGround()) { //TODO: Safety Check + redundantLiterals.add(literal); + } + } else if (isNonDerivable(literal.getAtom(), rules, facts)) { + return SimpleReturn.NO_FIRE; } } } - return rule; + if (redundantLiterals.isEmpty()) { + return new SimpleReturn(rule, false, false); + } else { + return removeLiteralsFromRule(rule, redundantLiterals); + } } /** - * This method checks whether a literal is non-derivable, i.e. it is not unifiable with the head atom of a rule. + * This method checks whether an atom is non-derivable, i.e. it is not unifiable with the head atom of a rule. * implements s5 conditions - * @param literal the literal to check + * @param atom the atom to check * @param rules the rules from which the literal should be derivable from * @return true if the literal is not derivable, false otherwise */ - private boolean isNonDerivable(Literal literal, List rules) { + private boolean isNonDerivable(Atom atom, List rules, Set facts) { + boolean unclear = false; for (NormalRule rule : rules) { boolean hasSharedVariable = false; - Set leftOccurringVariables = literal.getAtom().getOccurringVariables(); + Set leftOccurringVariables = atom.getOccurringVariables(); Set rightOccurringVariables = rule.getHeadAtom().getOccurringVariables(); boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; @@ -162,30 +171,52 @@ private boolean isNonDerivable(Literal literal, List rules) { for (VariableTerm variableTerm : smallerSet) { if (largerSet.contains(variableTerm)) { hasSharedVariable = true; + unclear = true; + break; + } + } + if (!hasSharedVariable) { + if (Unification.instantiate(rule.getHeadAtom(), atom) != null) { + return false; + } + } + } + for (Atom fact : facts) { + boolean hasSharedVariable = false; + Set leftOccurringVariables = atom.getOccurringVariables(); + Set rightOccurringVariables = fact.getOccurringVariables(); + boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); + Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; + Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; + for (VariableTerm variableTerm : smallerSet) { + if (largerSet.contains(variableTerm)) { + hasSharedVariable = true; + unclear = true; break; } } if (!hasSharedVariable) { - if(Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { + if (Unification.instantiate(fact, atom) != null) { return false; } } } - return true; + return !unclear; } /** - * Returns a copy of the rule with the specified literal removed - ** @return the rule without the specified literal + * Returns a copy of the rule with the specified literals removed + ** @return the rule without the specified literals */ - private NormalRule removeLiteralFromRule(NormalRule rule, Literal literal) { + private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set literals) { BasicAtom headAtom = rule.getHeadAtom(); - List newBody = new LinkedList<>(); + Set newBody = new LinkedHashSet<>(); for (Literal bodyLiteral : rule.getBody()) { - if (!literal.equals(bodyLiteral)) { + if (!literals.contains(bodyLiteral)) { newBody.add(bodyLiteral); } } - return new NormalRuleImpl(Heads.newNormalHead(headAtom), newBody); + return new SimpleReturn(new NormalRuleImpl(Heads.newNormalHead(headAtom), new LinkedList<>(newBody)), + !literals.isEmpty(), newBody.isEmpty()); } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 48b5e723c..9d3b5c790 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -6,14 +6,15 @@ import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; 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.solver.SolverFactory; +import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; import org.junit.jupiter.api.Test; import java.util.Set; @@ -26,10 +27,12 @@ public class SimplePreprocessingTest { private final ProgramParser parser = new ProgramParserImpl(); private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private final Function parseAndEvaluate = (str) -> { + private final Function parseAndNormalize = (str) -> { + return normalizer.apply(parser.parse(str)); + }; + private final Function parseAndPreprocess = (str) -> { return evaluator.apply(normalizer.apply(parser.parse(str))); }; - private final Function> solveCompiledProg = (prog) -> { AtomStore atomStore = new AtomStoreImpl(); Grounder grounder = GrounderFactory.getInstance("naive", prog, atomStore, false); @@ -38,56 +41,130 @@ public class SimplePreprocessingTest { }; @Test - public void testDuplicateRules() { - String aspStr1 = "a :- b. a :- b. b."; - String aspStr2 = "a :- b. b."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testDuplicateRuleRemoval() { + String aspStr1 = "a :- not b. a :- not b. b :- not a."; + String aspStr2 = "a :- not b. b :- not a."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } @Test - public void testConflictingBodyLiterals() { - String aspStr1 = "a :- b, not b. b :- c."; - String aspStr2 = " b :- c."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testConflictingRuleRemoval() { + String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; + String aspStr2 = " b :- not c. c :- not b."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } @Test - public void testHeadInBody() { - String aspStr1 = "a :- a, not b. b :- c."; - String aspStr2 = " b :- c."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testHeadInBodyRuleRemoval() { + String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; + String aspStr2 = " b :- not c. c :- not b."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } - //@Test - public void testNonDerivableLiterals() { - String aspStr1 = "a :- not b. b :- c. d. e :- not d."; - String aspStr2 = "a :- not b. d."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + @Test + public void testNoFireRuleRemoval() { + String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; + String aspStr2 = "a :- not b. b :- not a. d."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } - //@Test - public void testSimplifiedRules() { - String aspStr1 = "a :- b, not c. b. c :- not a. e :- a, not d."; + @Test + public void testAlwaysTrueLiteralRemoval() { + String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } @Test - public void testNonGroundProgram() { - String aspStr1 = "r(X) :- q(Y), not p(Y). q(Y). p(Y) :- not r(X). s(b) :- r(a), not t(d)."; - String aspStr2 = "r(X) :- not p(Y). q(Y). p(Y) :- not r(X)."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testNonDerivableLiteralRemovalNonGround() { + String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; + String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); + } + + @Test void testNonDerivableLiteralRemovalNonGround2() { + String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; + String aspStr2 = "p(X) :- q(X), not r(X). q(Y) :- p(Y). s(a)."; + //TODO: should be "p(X) :- q(X). q(Y) :- p(Y). s(a)." Need to rename Variables before Unification. + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); + } + + @Test void testRuleToFact() { + String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; + String aspStr2 = "r(c). q(a)."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); + } + + @Test void testAlwaysTrueLiteralRemovalNonGround() { + String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; + String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } -} +} \ No newline at end of file From fe38c94e1307db950170a4261446feb97a8ad673 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Sat, 29 Jan 2022 02:36:54 +0100 Subject: [PATCH 11/56] fixed bug with constraints in SimplePreprocessing --- .../transformation/SimplePreprocessing.java | 85 +++++------- .../SimplePreprocessingTest.java | 127 +++++------------- 2 files changed, 66 insertions(+), 146 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 7e3ee4a71..a64eef826 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -5,12 +5,12 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; import at.ac.tuwien.kr.alpha.core.grounder.Unification; import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; +import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; import java.util.*; /** @@ -25,7 +25,7 @@ public NormalProgram apply(NormalProgram inputProgram) { //Implements s0 by using a Set (delete duplicate rules). Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - boolean canBeModified = true; + boolean canBePreprocessed = true; for (NormalRule rule: srcRules) { //s2 if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { @@ -39,20 +39,20 @@ public NormalProgram apply(NormalProgram inputProgram) { } srcRules = new LinkedList<>(newRules); //s9 + s10 - while (canBeModified) { + while (canBePreprocessed) { newRules = new LinkedHashSet<>(); - canBeModified = false; + canBePreprocessed = false; for (NormalRule rule : srcRules) { - SimpleReturn simpleReturn = simplifyRule(rule, srcRules, facts); - if (simpleReturn != null) { - if (simpleReturn == SimpleReturn.NO_FIRE) { - canBeModified = true; - } else if (simpleReturn.isFact()) { - facts.add(simpleReturn.getRule().getHeadAtom()); - canBeModified = true; - } else if (simpleReturn.isModified()) { - newRules.add(simpleReturn.getRule()); - canBeModified = true; + SimpleReturn simplifiedRule = simplifyRule(rule, srcRules, facts); + if (simplifiedRule != null) { + if (simplifiedRule == SimpleReturn.NO_FIRE) { + canBePreprocessed = true; + } else if (simplifiedRule.isFact()) { + facts.add(simplifiedRule.getRule().getHeadAtom()); + canBePreprocessed = true; + } else if (simplifiedRule.isModified()) { + newRules.add(simplifiedRule.getRule()); + canBePreprocessed = true; } else { newRules.add(rule); } @@ -128,6 +128,9 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { private SimpleReturn simplifyRule(NormalRule rule, List rules, Set facts) { Set redundantLiterals = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { + if (literal.toString().startsWith("&") || literal.toString().startsWith("not &")) { + continue; + } if (literal.isNegated()) { if (facts.contains(literal.getAtom())) { return SimpleReturn.NO_FIRE; @@ -137,9 +140,7 @@ private SimpleReturn simplifyRule(NormalRule rule, List rules, Set rules, Set rules, Set facts) { - boolean unclear = false; + Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { - boolean hasSharedVariable = false; - Set leftOccurringVariables = atom.getOccurringVariables(); - Set rightOccurringVariables = rule.getHeadAtom().getOccurringVariables(); - boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); - Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; - Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; - for (VariableTerm variableTerm : smallerSet) { - if (largerSet.contains(variableTerm)) { - hasSharedVariable = true; - unclear = true; - break; - } - } - if (!hasSharedVariable) { - if (Unification.instantiate(rule.getHeadAtom(), atom) != null) { + if (!rule.isConstraint()) { + if (Unification.unifyAtoms(rule.getHeadAtom(), tempAtom) != null) { return false; } } } - for (Atom fact : facts) { - boolean hasSharedVariable = false; - Set leftOccurringVariables = atom.getOccurringVariables(); - Set rightOccurringVariables = fact.getOccurringVariables(); - boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); - Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; - Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; - for (VariableTerm variableTerm : smallerSet) { - if (largerSet.contains(variableTerm)) { - hasSharedVariable = true; - unclear = true; - break; - } - } - if (!hasSharedVariable) { - if (Unification.instantiate(fact, atom) != null) { - return false; - } + Unifier uni; + for (Atom fact:facts) { + if ((uni = Unification.instantiate(tempAtom, fact)) != null) { + return false; } } - return !unclear; + return true; } /** @@ -216,7 +190,10 @@ private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set litera newBody.add(bodyLiteral); } } - return new SimpleReturn(new NormalRuleImpl(Heads.newNormalHead(headAtom), new LinkedList<>(newBody)), - !literals.isEmpty(), newBody.isEmpty()); + NormalRuleImpl newRule = new NormalRuleImpl(headAtom != null ? Heads.newNormalHead(headAtom) : null, new LinkedList<>(newBody)); + if (newRule.isConstraint() && newBody.isEmpty()) { + return SimpleReturn.NO_FIRE; + } + return new SimpleReturn(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 9d3b5c790..3494481e2 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -1,24 +1,12 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -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.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.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.solver.SolverFactory; -import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; import org.junit.jupiter.api.Test; -import java.util.Set; -import java.util.function.Function; +import java.util.HashSet; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -27,144 +15,99 @@ public class SimplePreprocessingTest { private final ProgramParser parser = new ProgramParserImpl(); private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private final Function parseAndNormalize = (str) -> { + + private NormalProgram parseAndNormalize(String str) { return normalizer.apply(parser.parse(str)); - }; - private final Function parseAndPreprocess = (str) -> { + } + + private NormalProgram parseAndPreprocess(String str) { return evaluator.apply(normalizer.apply(parser.parse(str))); - }; - 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(); - }; + } @Test public void testDuplicateRuleRemoval() { String aspStr1 = "a :- not b. a :- not b. b :- not a."; String aspStr2 = "a :- not b. b :- not a."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testConflictingRuleRemoval() { String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testHeadInBodyRuleRemoval() { String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testNoFireRuleRemoval() { String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; String aspStr2 = "a :- not b. b :- not a. d."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testAlwaysTrueLiteralRemoval() { String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test void testNonDerivableLiteralRemovalNonGround2() { String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; - String aspStr2 = "p(X) :- q(X), not r(X). q(Y) :- p(Y). s(a)."; - //TODO: should be "p(X) :- q(X). q(Y) :- p(Y). s(a)." Need to rename Variables before Unification. - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + String aspStr2 = "p(X) :- q(X). q(Y) :- p(Y). s(a)."; + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test void testRuleToFact() { String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; String aspStr2 = "r(c). q(a)."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test void testAlwaysTrueLiteralRemovalNonGround() { String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } } \ No newline at end of file From 65b74c0b429c07fccdcfa4c212e706c4b9e96df4 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Sat, 29 Jan 2022 02:37:12 +0100 Subject: [PATCH 12/56] fixed bug with constraints in SimplePreprocessing --- .../core/programs/transformation/SimplePreprocessing.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index a64eef826..e1ff09c3b 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -169,9 +169,8 @@ private boolean isNonDerivable(Atom atom, List rules, Set fact } } } - Unifier uni; for (Atom fact:facts) { - if ((uni = Unification.instantiate(tempAtom, fact)) != null) { + if ((Unification.instantiate(tempAtom, fact)) != null) { return false; } } From e3b3d15a5ae89db5da63dad6d86ca497b2a48add Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 1 Feb 2022 16:00:25 +0100 Subject: [PATCH 13/56] limited SimplePreprocessing to basic literals --- .../transformation/SimplePreprocessing.java | 117 ++++++++---------- 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index e1ff09c3b..3f5c81456 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -3,6 +3,7 @@ import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; @@ -10,11 +11,14 @@ import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; -import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; import java.util.*; /** - * Simplifies an internal input program by simplifying and deleting redundant rules. + * Simplifies the input program by deleting redundant literals and rules, as well as adding rule heads that will + * always be true as facts. The approach is adopted from preprocessing techniques employed by traditional ground ASP + * solvers, as seen in: + * Gebser, M., Kaufmann, B., Neumann, A., & Schaub, T. (2008, June). Advanced Preprocessing for Answer Set Solving. + * In ECAI (Vol. 178, pp. 15-19). */ public class SimplePreprocessing extends ProgramTransformation { @@ -22,40 +26,34 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = inputProgram.getRules(); - //Implements s0 by using a Set (delete duplicate rules). Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); boolean canBePreprocessed = true; for (NormalRule rule: srcRules) { - //s2 if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { continue; } - //s3 if (checkForHeadInBody(rule.getBody(), rule.getHeadAtom())) { continue; } newRules.add(rule); } srcRules = new LinkedList<>(newRules); - //s9 + s10 while (canBePreprocessed) { newRules = new LinkedHashSet<>(); canBePreprocessed = false; for (NormalRule rule : srcRules) { - SimpleReturn simplifiedRule = simplifyRule(rule, srcRules, facts); - if (simplifiedRule != null) { - if (simplifiedRule == SimpleReturn.NO_FIRE) { - canBePreprocessed = true; - } else if (simplifiedRule.isFact()) { - facts.add(simplifiedRule.getRule().getHeadAtom()); - canBePreprocessed = true; - } else if (simplifiedRule.isModified()) { - newRules.add(simplifiedRule.getRule()); - canBePreprocessed = true; - } else { - newRules.add(rule); - } + RuleEvaluation eval = evaluateRule(rule, srcRules, facts); + if (eval == RuleEvaluation.NO_FIRE) { + canBePreprocessed = true; + } else if (eval.isFact()) { + facts.add(eval.getRule().getHeadAtom()); + canBePreprocessed = true; + } else if (eval.isModified()) { + newRules.add(eval.getRule()); + canBePreprocessed = true; + } else { + newRules.add(rule); } } srcRules = new LinkedList<>(newRules); @@ -63,13 +61,13 @@ public NormalProgram apply(NormalProgram inputProgram) { return new NormalProgramImpl(new LinkedList<>(newRules), new LinkedList<>(facts), inputProgram.getInlineDirectives()); } - private static class SimpleReturn { - public final static SimpleReturn NO_FIRE = new SimpleReturn(null, false, false); + private static class RuleEvaluation { + public final static RuleEvaluation NO_FIRE = new RuleEvaluation(null, false, false); private final NormalRule rule; private final boolean isModified; private final boolean isFact; - public SimpleReturn(NormalRule rule, boolean isModified, boolean isFact) { + public RuleEvaluation(NormalRule rule, boolean isModified, boolean isFact) { this.rule = rule; this.isModified = isModified; this.isFact = isFact; @@ -88,11 +86,6 @@ public boolean isFact() { } } - /** - * This method checks if a rule contains a literal in both the positive and the negative body. - * implements s2 - * @return true if the rule contains conflicting literals, false otherwise - */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { for (Literal positiveLiteral : positiveBody) { if (negativeBody.contains(positiveLiteral.negate())) { @@ -102,11 +95,6 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { for (Literal literal : body) { if (literal.getAtom().equals(headAtom)) { @@ -117,49 +105,40 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { } /** - * This method checks for literals from rule bodies, that are already facts or non-derivable. - * implements s9 + s10 - * @param rule the rule to check - * @param rules the rules from which the literals should be derivable from - * @param facts the facts from which the literals should be derivable from - * @return SimpleReturn containing the (possibly modified) rule, a boolean isModified and a boolean isFact. On - * non-derivable rules it returns the value NO_FIRE. + * Evaluates and attempts to simplify a rule by looking for always-true and always-false literals. + * @param rule the rule to be evaluated. + * @param rules the rules from which literals could be derived from. + * @param facts the facts from which literals could be derived from. + * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was modified, + * is a fact or will never fire. */ - private SimpleReturn simplifyRule(NormalRule rule, List rules, Set facts) { + private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { Set redundantLiterals = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { - if (literal.toString().startsWith("&") || literal.toString().startsWith("not &")) { - continue; - } - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return SimpleReturn.NO_FIRE; - } - if (isNonDerivable(literal.getAtom(), rules, facts)) { - redundantLiterals.add(literal); - } - } else { - if (facts.contains(literal.getAtom())) { - redundantLiterals.add(literal); - } else if (isNonDerivable(literal.getAtom(), rules, facts)) { - return SimpleReturn.NO_FIRE; + if (literal instanceof BasicLiteral) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return RuleEvaluation.NO_FIRE; + } + if (isNonDerivable(literal.getAtom(), rules, facts)) { + redundantLiterals.add(literal); + } + } else { + if (facts.contains(literal.getAtom())) { + redundantLiterals.add(literal); + } else if (isNonDerivable(literal.getAtom(), rules, facts)) { + return RuleEvaluation.NO_FIRE; + } } } } if (redundantLiterals.isEmpty()) { - return new SimpleReturn(rule, false, false); + return new RuleEvaluation(rule, false, false); } else { return removeLiteralsFromRule(rule, redundantLiterals); } } - /** - * This method checks whether an atom is non-derivable, i.e. it is not unifiable with the head atom of a rule. - * implements s5 conditions - * @param atom the atom to check - * @param rules the rules from which the literal should be derivable from - * @return true if the literal is not derivable, false otherwise - */ private boolean isNonDerivable(Atom atom, List rules, Set facts) { Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { @@ -178,10 +157,12 @@ private boolean isNonDerivable(Atom atom, List rules, Set fact } /** - * Returns a copy of the rule with the specified literals removed - ** @return the rule without the specified literals + * removes a set of given literals from the rule body. + * @param rule the rule from which literals should be removed. + * @param literals The literals to remove. + * @return the resulting rule or fact. */ - private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set literals) { + private RuleEvaluation removeLiteralsFromRule(NormalRule rule, Set literals) { BasicAtom headAtom = rule.getHeadAtom(); Set newBody = new LinkedHashSet<>(); for (Literal bodyLiteral : rule.getBody()) { @@ -191,8 +172,8 @@ private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set litera } NormalRuleImpl newRule = new NormalRuleImpl(headAtom != null ? Heads.newNormalHead(headAtom) : null, new LinkedList<>(newBody)); if (newRule.isConstraint() && newBody.isEmpty()) { - return SimpleReturn.NO_FIRE; + return RuleEvaluation.NO_FIRE; } - return new SimpleReturn(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); + return new RuleEvaluation(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); } } From 7d98e201763965b65fc4ab6a0cf6571811de09dd Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 1 Feb 2022 17:54:35 +0100 Subject: [PATCH 14/56] added command line option for preprocessing --- .../ac/tuwien/kr/alpha/api/config/SystemConfig.java | 10 ++++++++++ .../kr/alpha/app/config/CommandLineParser.java | 13 +++++++++++-- .../at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java | 9 ++++++--- .../ac/tuwien/kr/alpha/api/impl/AlphaImplTest.java | 3 ++- 4 files changed, 29 insertions(+), 6 deletions(-) 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..f32750183 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 @@ -58,6 +58,7 @@ public class SystemConfig { 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_PREPROCESSING_ENABLED = 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; @@ -79,6 +80,7 @@ public class SystemConfig { private boolean sortAnswerSets = DEFAULT_SORT_ANSWER_SETS; private List replayChoices = DEFAULT_REPLAY_CHOICES; private boolean evaluateStratifiedPart = DEFAULT_STRATIFIED_EVALUATION; + private boolean enablePreprocessing = DEFAULT_PREPROCESSING_ENABLED; private boolean disableNoGoodDeletion = DEFAULT_DISABLE_NOGOOD_DELETION; private String grounderToleranceConstraints = DEFAULT_GROUNDER_TOLERANCE_CONSTRAINTS; private String grounderToleranceRules = DEFAULT_GROUNDER_TOLERANCE_RULES; @@ -232,6 +234,14 @@ public void setEvaluateStratifiedPart(boolean evaluateStratifiedPart) { this.evaluateStratifiedPart = evaluateStratifiedPart; } + public boolean isPreprocessingEnabled() { + return this.enablePreprocessing; + } + + public void setPreprocessingEnabled(boolean enablePreprocessing) { + this.enablePreprocessing = enablePreprocessing; + } + public boolean isDisableNoGoodDeletion() { return this.disableNoGoodDeletion; } 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 4b3ccf1f5..ea461dd57 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 @@ -149,6 +149,9 @@ public class CommandLineParser { .desc("a character (sequence) to use as separator for atoms in printed answer sets (default: " + SystemConfig.DEFAULT_ATOM_SEPARATOR + ")") .build(); + private static final Option OPT_DISABLE_PROGRAM_PREPROCESSING = Option.builder("dpp").longOpt("disableProgramPreprocessing") + .desc("disable preprocessing of input program") + .build(); //@formatter:on private static final Options CLI_OPTS = new Options(); @@ -189,6 +192,7 @@ public class CommandLineParser { CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_TOLERANCE_RULES); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_ACCUMULATOR_ENABLED); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_OUTPUT_ATOM_SEPARATOR); + CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_DISABLE_PROGRAM_PREPROCESSING); } /* @@ -240,12 +244,13 @@ 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_EVAL_STRATIFIED.getOpt(), this::handleDisableStratifiedEval); 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); this.globalOptionHandlers.put(CommandLineParser.OPT_GROUNDER_ACCUMULATOR_ENABLED.getOpt(), this::handleGrounderNoInstanceRemoval); this.globalOptionHandlers.put(CommandLineParser.OPT_OUTPUT_ATOM_SEPARATOR.getOpt(), this::handleAtomSeparator); + this.globalOptionHandlers.put(CommandLineParser.OPT_DISABLE_PROGRAM_PREPROCESSING.getOpt(), this::handleDisablePreprocessing); } private void initializeInputOptionHandlers() { @@ -441,7 +446,7 @@ private void handleDisableNegativeSumElements(Option opt, SystemConfig cfg) { cfg.getAggregateRewritingConfig().setSupportNegativeValuesInSums(false); } - private void handleDisableStratifedEval(Option opt, SystemConfig cfg) { + private void handleDisableStratifiedEval(Option opt, SystemConfig cfg) { cfg.setEvaluateStratifiedPart(false); } @@ -470,5 +475,9 @@ private void handleGrounderNoInstanceRemoval(Option opt, SystemConfig cfg) { private void handleAtomSeparator(Option opt, SystemConfig cfg) { cfg.setAtomSeparator(StringEscapeUtils.unescapeJava(opt.getValue(SystemConfig.DEFAULT_ATOM_SEPARATOR))); } + + private void handleDisablePreprocessing(Option opt, SystemConfig cfg) { + cfg.setPreprocessingEnabled(false); + } } 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 e076348ec..056b6221a 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 @@ -142,10 +142,13 @@ public NormalProgram normalizeProgram(ASPCore2Program program) { @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { + InternalProgram retVal = InternalProgram.fromNormalProgram(program); + if (config.isPreprocessingEnabled()) { + SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); + NormalProgram simplePreprocessed = simplePreprocessing.apply(program); + retVal = InternalProgram.fromNormalProgram(simplePreprocessed); + } LOGGER.debug("Preprocessing InternalProgram!"); - SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); - NormalProgram simplePreprocessed = simplePreprocessing.apply(program); - InternalProgram retVal = InternalProgram.fromNormalProgram(simplePreprocessed); if (config.isEvaluateStratifiedPart()) { AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); retVal = new StratifiedEvaluation().apply(analyzed); 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 176862d40..0c51da218 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 @@ -618,6 +618,7 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE config.setDebugInternalChecks(true); config.setDisableJustificationSearch(false); config.setEvaluateStratifiedPart(false); + config.setPreprocessingEnabled(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 @@ -627,4 +628,4 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE assertTrue(answerSet.isPresent()); } -} +} \ No newline at end of file From 26f07bdce78b49861922ddc3e6e88600a21d1fcd Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 8 Feb 2022 16:11:06 +0100 Subject: [PATCH 15/56] added tests for command line option for preprocessing --- .../tuwien/kr/alpha/app/config/CommandLineParserTest.java | 7 +++++++ 1 file changed, 7 insertions(+) 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..52ac06c16 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 @@ -181,4 +181,11 @@ public void atomSeparator() throws ParseException { assertEquals("some-string", cfg.getSystemConfig().getAtomSeparator()); } + @Test + public void disableProgramPreprocessing() throws ParseException { + CommandLineParser parser = new CommandLineParser(DEFAULT_COMMAND_LINE, DEFAULT_ABORT_ACTION); + AlphaConfig ctx = parser.parseCommandLine(new String[]{"-str", "aString.", "-dpp"}); + assertFalse(ctx.getSystemConfig().isPreprocessingEnabled()); + } + } From 2e35223d644794c6e554eaa9bb3e8dddb19a9253 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Mon, 14 Feb 2022 17:33:54 +0100 Subject: [PATCH 16/56] rebuilt tests to not depend on NormalizeProgramTransformation --- .../SimplePreprocessingTest.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 3494481e2..0d5693a45 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -1,9 +1,9 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; import org.junit.jupiter.api.Test; import java.util.HashSet; @@ -13,15 +13,14 @@ public class SimplePreprocessingTest { private final ProgramParser parser = new ProgramParserImpl(); - private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private NormalProgram parseAndNormalize(String str) { - return normalizer.apply(parser.parse(str)); + private NormalProgram parse(String str) { + return NormalProgramImpl.fromInputProgram(parser.parse(str)); } private NormalProgram parseAndPreprocess(String str) { - return evaluator.apply(normalizer.apply(parser.parse(str))); + return evaluator.apply(NormalProgramImpl.fromInputProgram(parser.parse(str))); } @Test @@ -29,7 +28,7 @@ public void testDuplicateRuleRemoval() { String aspStr1 = "a :- not b. a :- not b. b :- not a."; String aspStr2 = "a :- not b. b :- not a."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -39,7 +38,7 @@ public void testConflictingRuleRemoval() { String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -49,7 +48,7 @@ public void testHeadInBodyRuleRemoval() { String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -59,7 +58,7 @@ public void testNoFireRuleRemoval() { String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; String aspStr2 = "a :- not b. b :- not a. d."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -69,7 +68,7 @@ public void testAlwaysTrueLiteralRemoval() { String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -79,7 +78,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -88,7 +87,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; String aspStr2 = "p(X) :- q(X). q(Y) :- p(Y). s(a)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -97,7 +96,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; String aspStr2 = "r(c). q(a)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -106,7 +105,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } From 1fad17f7b87eb07f9197dfc3319a4d6f6a8a20f4 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Mon, 14 Feb 2022 18:24:35 +0100 Subject: [PATCH 17/56] implemented removal of rules, that have heads that are already facts --- .../transformation/SimplePreprocessing.java | 7 +- .../SimplePreprocessingTest.java | 81 ++++++++++--------- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 3f5c81456..eeffab0f6 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -109,11 +109,14 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { * @param rule the rule to be evaluated. * @param rules the rules from which literals could be derived from. * @param facts the facts from which literals could be derived from. - * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was modified, - * is a fact or will never fire. + * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was + * modified, is a fact or will never fire. */ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { Set redundantLiterals = new LinkedHashSet<>(); + if (facts.contains(rule.getHeadAtom())) { + return RuleEvaluation.NO_FIRE; + } for (Literal literal : rule.getBody()) { if (literal instanceof BasicLiteral) { if (literal.isNegated()) { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 0d5693a45..ccdbc4ec9 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -27,86 +27,95 @@ private NormalProgram parseAndPreprocess(String str) { public void testDuplicateRuleRemoval() { String aspStr1 = "a :- not b. a :- not b. b :- not a."; String aspStr2 = "a :- not b. b :- not a."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testConflictingRuleRemoval() { String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testHeadInBodyRuleRemoval() { String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testNoFireRuleRemoval() { String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; String aspStr2 = "a :- not b. b :- not a. d."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testAlwaysTrueLiteralRemoval() { String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test void testNonDerivableLiteralRemovalNonGround2() { String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; String aspStr2 = "p(X) :- q(X). q(Y) :- p(Y). s(a)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test void testRuleToFact() { String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; String aspStr2 = "r(c). q(a)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test void testAlwaysTrueLiteralRemovalNonGround() { String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); + } + + @Test void testHeadIsFactRuleRemoval() { + String aspStr1 = "r(a) :- not p(b). r(a). p(b) :- not q(c). q(c) :- not p(b)."; + String aspStr2 = " r(a). p(b) :- not q(c). q(c) :- not p(b)."; + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } } \ No newline at end of file From cd65902156fb4a196938b02a357862c0ad1d2785 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 15 Feb 2022 15:38:08 +0100 Subject: [PATCH 18/56] removed unnecessary changes --- .../kr/alpha/core/grounder/NaiveGrounder.java | 108 +++++++++--------- .../grounder/ProgramAnalyzingGrounder.java | 4 +- .../structure/AnalyzeUnjustified.java | 24 ++-- .../transformation/SimplePreprocessing.java | 4 +- .../kr/alpha/core/rules/CompiledRule.java | 2 - .../kr/alpha/core/rules/InternalRule.java | 19 +-- .../kr/alpha/api/impl/AlphaImplTest.java | 1 - 7 files changed, 69 insertions(+), 93 deletions(-) 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 299a80bfb..7c40e85c3 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 @@ -25,57 +25,57 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package at.ac.tuwien.kr.alpha.core.grounder; - - import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; - import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; - - import java.util.ArrayList; - import java.util.Collection; - 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.Set; - import java.util.SortedSet; - import java.util.TreeSet; - - import org.apache.commons.lang3.tuple.ImmutablePair; - import org.apache.commons.lang3.tuple.Pair; - import org.slf4j.Logger; - import org.slf4j.LoggerFactory; - - import at.ac.tuwien.kr.alpha.api.AnswerSet; - import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; - import at.ac.tuwien.kr.alpha.api.grounder.Substitution; - import at.ac.tuwien.kr.alpha.api.programs.Predicate; - import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; - import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; - import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; - import at.ac.tuwien.kr.alpha.commons.AnswerSets; - import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; - import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; - import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; - import at.ac.tuwien.kr.alpha.commons.util.Util; - import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; - import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; - import at.ac.tuwien.kr.alpha.core.common.Assignment; - import at.ac.tuwien.kr.alpha.core.common.AtomStore; - import at.ac.tuwien.kr.alpha.core.common.IntIterator; - import at.ac.tuwien.kr.alpha.core.common.NoGood; - import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; - import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; - import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; - import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; - import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +package at.ac.tuwien.kr.alpha.core.grounder; + +import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; +import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; + +import java.util.ArrayList; +import java.util.Collection; +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.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.AnswerSets; +import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; +import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; +import at.ac.tuwien.kr.alpha.commons.util.Util; +import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; +import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.common.Assignment; +import at.ac.tuwien.kr.alpha.core.common.AtomStore; +import at.ac.tuwien.kr.alpha.core.common.IntIterator; +import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; +import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; +import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; +import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; /** * A semi-naive grounder. @@ -112,13 +112,11 @@ public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debug this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, - Bridge... bridges) { + private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java index 12960995a..d64388123 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java @@ -15,10 +15,10 @@ public interface ProgramAnalyzingGrounder extends Grounder { /** * Justifies the absence of an atom, i.e., returns reasons why the atom is not TRUE given the assignment. * @param atomToJustify the atom to justify. - * @param assignment the current assignment. + * @param currentAssignment the current assignment. * @return a set of literals who jointly imply the atomToJustify not being TRUE. */ - Set justifyAtom(int atomToJustify, Assignment assignment); + Set justifyAtom(int atomToJustify, Assignment currentAssignment); /** * Returns true iff the given atom is known to the grounder as a fact (hence not occurring in any assignment). diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java index c04c9578c..cb12167db 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java @@ -54,7 +54,7 @@ public AnalyzeUnjustified(CompiledProgram programAnalysis, AtomStore atomStore, private Map> assignedAtoms; - public Set analyze(int atomToJustify, Assignment assignment) { + public Set analyze(int atomToJustify, Assignment currentAssignment) { padDepth = 0; Atom atom = atomStore.get(atomToJustify); if (!(atom instanceof BasicAtom)) { @@ -69,7 +69,7 @@ public Set analyze(int atomToJustify, Assignment assignment) { //@formatter:on assignedAtoms = new LinkedHashMap<>(); for (int i = 1; i <= atomStore.getMaxAtomId(); i++) { - ThriceTruth truth = assignment.getTruth(i); + ThriceTruth truth = currentAssignment.getTruth(i); if (truth == null) { continue; } @@ -77,11 +77,11 @@ public Set analyze(int atomToJustify, Assignment assignment) { assignedAtoms.putIfAbsent(assignedAtom.getPredicate(), new ArrayList<>()); assignedAtoms.get(assignedAtom.getPredicate()).add(assignedAtom); } - return analyze((BasicAtom) atom, assignment); + return analyze((BasicAtom) atom, currentAssignment); } - private Set analyze(BasicAtom atom, Assignment assignment) { - log(pad("Starting analyze, current assignment is: {}"), assignment); + private Set analyze(BasicAtom atom, Assignment currentAssignment) { + log(pad("Starting analyze, current assignment is: {}"), currentAssignment); LinkedHashSet vL = new LinkedHashSet<>(); LinkedHashSet vToDo = new LinkedHashSet<>(Collections.singleton(new LitSet(atom, new LinkedHashSet<>()))); LinkedHashSet vDone = new LinkedHashSet<>(); @@ -92,7 +92,7 @@ private Set analyze(BasicAtom atom, Assignment assignment) { log(""); log("Treating now: {}", x); vDone.add(x); - ReturnExplainUnjust unjustRet = explainUnjust(x, assignment); + ReturnExplainUnjust unjustRet = explainUnjust(x, currentAssignment); log("Additional ToDo: {}", unjustRet.vToDo); // Check each new LitSet if it does not already occur as done. for (LitSet todoLitSet : unjustRet.vToDo) { @@ -105,7 +105,7 @@ private Set analyze(BasicAtom atom, Assignment assignment) { return vL; } - private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { + private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment) { padDepth += 2; log("Begin explainUnjust(): {}", x); Atom p = x.getAtom(); @@ -151,7 +151,7 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { log("Considering: {}", lg); if (atomStore.contains(lg)) { int atomId = atomStore.get(lg); - if (!assignment.getTruth(atomId).toBoolean()) { + if (!currentAssignment.getTruth(atomId).toBoolean()) { log("{} is not assigned TRUE or MBT. Skipping.", lg); continue; } @@ -188,14 +188,14 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { } } log("Calling UnjustCover() for positive body."); - ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, assignment)); + ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, currentAssignment)); } log("End explainUnjust()."); padDepth -= 2; return ret; } - private Set unjustCover(List vB, Set vY, Set vN, Assignment assignment) { + private Set unjustCover(List vB, Set vY, Set vN, Assignment currentAssignment) { padDepth += 2; log("Begin UnjustCoverFixed()"); log("Finding unjustified body literals in: {} / {} excluded {}", vB, vY, vN); @@ -228,7 +228,7 @@ private Set unjustCover(List vB, Set vY, Set log("Checking atom: {}", atom); if (atomStore.contains(atom)) { int atomId = atomStore.get(atom); - if (assignment.getTruth(atomId) != ThriceTruth.TRUE) { + if (currentAssignment.getTruth(atomId) != ThriceTruth.TRUE) { log("Atom is not TRUE. Skipping."); continue; } @@ -274,7 +274,7 @@ private Set unjustCover(List vB, Set vY, Set } ArrayList newB = new ArrayList<>(vB); newB.remove(chosenLiteralPos); - ret.addAll(unjustCover(newB, vYp, vN, assignment)); + ret.addAll(unjustCover(newB, vYp, vN, currentAssignment)); log("Literal set(s) to treat: {}", ret); } log("End unjustCover()."); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index eeffab0f6..7626f2580 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -17,10 +17,8 @@ * Simplifies the input program by deleting redundant literals and rules, as well as adding rule heads that will * always be true as facts. The approach is adopted from preprocessing techniques employed by traditional ground ASP * solvers, as seen in: - * Gebser, M., Kaufmann, B., Neumann, A., & Schaub, T. (2008, June). Advanced Preprocessing for Answer Set Solving. - * In ECAI (Vol. 178, pp. 15-19). + * @see doi:10.3233/978-1-58603-891-5-15 */ - public class SimplePreprocessing extends ProgramTransformation { @Override diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java index 754e0fe3d..bb489ea7e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java @@ -3,7 +3,6 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfo; @@ -19,5 +18,4 @@ public interface CompiledRule extends NormalRule { boolean isGround(); - CompiledRule returnCopyWithoutLiteral(Literal literal); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index 38ca6b6f1..9a72fca12 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -31,6 +31,7 @@ import java.util.List; import com.google.common.annotations.VisibleForTesting; + import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; @@ -142,22 +143,4 @@ public int getRuleId() { return this.ruleId; } - /** - * Returns a copy of the rule with the specified literal removed, or null if the new rule would have an empty body. - * @return the rule without the specified literal, null if no body remains. - */ - public InternalRule returnCopyWithoutLiteral(Literal literal) { - BasicAtom headAtom = this.getHeadAtom(); - List newBody = new ArrayList<>(this.getBody().size()); - for (Literal bodyLiteral : this.getBody()) { - if (!literal.equals(bodyLiteral)) { - newBody.add(bodyLiteral); - } - } - if (newBody.isEmpty()) { - return null; - } - return new InternalRule(Heads.newNormalHead(headAtom), newBody); - } - } 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 0c51da218..df3be414d 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 @@ -627,5 +627,4 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE Optional answerSet = alpha.solve(parsedProgram).findFirst(); assertTrue(answerSet.isPresent()); } - } \ No newline at end of file From 6326ca221efc130be4fd7a56d991faddfe04cbcc Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 15 Feb 2022 15:49:14 +0100 Subject: [PATCH 19/56] removed unnecessary changes --- .../kr/alpha/core/grounder/NaiveGrounder.java | 18 ++++++++++-------- ...aultLazyGroundingInstantiationStrategy.java | 1 + .../kr/alpha/core/rules/CompiledRule.java | 1 - ...neralizedDependencyDrivenPyroHeuristic.java | 2 +- .../ac/tuwien/kr/alpha/api/impl/AlphaImpl.java | 2 +- .../kr/alpha/api/impl/AlphaImplTest.java | 3 ++- 6 files changed, 15 insertions(+), 12 deletions(-) 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 7c40e85c3..1b8483a0d 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 @@ -112,11 +112,13 @@ public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debug this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, + Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, + GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; @@ -412,7 +414,7 @@ public int register(NoGood noGood) { // Ideally, this method should be private. It's only visible because NaiveGrounderTest needs to access it. BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, - Assignment currentAssignment) { + Assignment currentAssignment) { int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint()); if (tolerance < 0) { tolerance = Integer.MAX_VALUE; @@ -452,7 +454,7 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou * tolerance is less than zero. */ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - ImmutablePair lastLiteralBindingResult) { + ImmutablePair lastLiteralBindingResult) { Substitution substitution = lastLiteralBindingResult.left; AssignmentStatus lastBoundLiteralAssignmentStatus = lastLiteralBindingResult.right; switch (lastBoundLiteralAssignmentStatus) { @@ -476,13 +478,13 @@ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int ord } private BindingResult advanceAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { groundingOrder.considerUntilCurrentEnd(); return bindNextAtomInRule(groundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution); } private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { RuleGroundingOrder modifiedGroundingOrder = groundingOrder.pushBack(orderPosition); if (modifiedGroundingOrder == null) { return BindingResult.empty(); @@ -507,7 +509,7 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding */ //@formatter:on private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition); if (currentLiteral == null) { LOGGER.trace("No more literals found in grounding order, therefore stopping binding!"); @@ -645,4 +647,4 @@ private static class FirstBindingAtom { } } -} \ No newline at end of file +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java index e54f9d627..621e4616b 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java @@ -37,6 +37,7 @@ import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.grounder.IndexedInstanceStorage; +import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; import at.ac.tuwien.kr.alpha.core.grounder.WorkingMemory; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java index bb489ea7e..b15dfbc41 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java @@ -17,5 +17,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/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java index 2fe6a59f8..f4c8e71f7 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java @@ -45,7 +45,7 @@ public class GeneralizedDependencyDrivenPyroHeuristic extends GeneralizedDependencyDrivenHeuristic { public GeneralizedDependencyDrivenPyroHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random, - BodyActivityType bodyActivityType) { + BodyActivityType bodyActivityType) { super(assignment, choiceManager, decayPeriod, decayFactor, random, bodyActivityType); } 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 056b6221a..70e9d69b0 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 @@ -39,7 +39,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import at.ac.tuwien.kr.alpha.core.programs.transformation.SimplePreprocessing; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,6 +71,7 @@ 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.programs.transformation.SimplePreprocessing; import at.ac.tuwien.kr.alpha.core.solver.SolverFactory; public class AlphaImpl implements Alpha { 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 df3be414d..1d73948c1 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 @@ -627,4 +627,5 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE Optional answerSet = alpha.solve(parsedProgram).findFirst(); assertTrue(answerSet.isPresent()); } -} \ No newline at end of file + +} From 08aa3766990fc83d0aa6c637082220c9e9ab9daf Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 22 Mar 2022 15:47:51 +0100 Subject: [PATCH 20/56] added comments --- .../src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 70e9d69b0..aaf619131 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 @@ -142,13 +142,13 @@ public NormalProgram normalizeProgram(ASPCore2Program program) { @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { + LOGGER.debug("Performing program preprocessing!"); InternalProgram retVal = InternalProgram.fromNormalProgram(program); if (config.isPreprocessingEnabled()) { SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); NormalProgram simplePreprocessed = simplePreprocessing.apply(program); retVal = InternalProgram.fromNormalProgram(simplePreprocessed); } - LOGGER.debug("Preprocessing InternalProgram!"); if (config.isEvaluateStratifiedPart()) { AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); retVal = new StratifiedEvaluation().apply(analyzed); From 0a73d07389984fc95dd018b84ad09942e2c0b921 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 22 Mar 2022 15:48:26 +0100 Subject: [PATCH 21/56] added comments --- .../transformation/SimplePreprocessing.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 7626f2580..648f27194 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -14,19 +14,26 @@ import java.util.*; /** - * Simplifies the input program by deleting redundant literals and rules, as well as adding rule heads that will - * always be true as facts. The approach is adopted from preprocessing techniques employed by traditional ground ASP - * solvers, as seen in: + * Simplifies the input program by deleting redundant literals and rules, as well as identifying rule heads that can + * always be derived from facts and adding them to the known facts. The approach is adopted from preprocessing + * techniques employed by traditional ground ASP solvers, as seen in: * @see doi:10.3233/978-1-58603-891-5-15 */ public class SimplePreprocessing extends ProgramTransformation { + + /** + * Evaluates all rules of the input program and tries to simplify them by applying a number of rule transformations. + * @param inputProgram a normalized ASP program to be preprocessed. + * @return the preprocessed program. + */ @Override public NormalProgram apply(NormalProgram inputProgram) { List srcRules = inputProgram.getRules(); Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - boolean canBePreprocessed = true; + + // Eliminate rules that will never fire, without regarding other rules. for (NormalRule rule: srcRules) { if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { continue; @@ -37,6 +44,10 @@ public NormalProgram apply(NormalProgram inputProgram) { newRules.add(rule); } srcRules = new LinkedList<>(newRules); + + // Analyze every rule in regard to the other rules and facts and if applicable, simplify or remove it. Repeat + // until a fixpoint is reached. + boolean canBePreprocessed = true; while (canBePreprocessed) { newRules = new LinkedHashSet<>(); canBePreprocessed = false; @@ -111,10 +122,17 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { * modified, is a fact or will never fire. */ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { - Set redundantLiterals = new LinkedHashSet<>(); + // Check if the rule head is already a fact, making the rule redundant. if (facts.contains(rule.getHeadAtom())) { return RuleEvaluation.NO_FIRE; } + + // Collect all literals that can be removed from the rule. + Set redundantLiterals = new LinkedHashSet<>(); + + // Check if body literals can be derived from facts or other rules. If a body literal is not derivable, the + // rule can never fire. If a literal is already proven within the program context, the rule will be simplified + // by removing it. for (Literal literal : rule.getBody()) { if (literal instanceof BasicLiteral) { if (literal.isNegated()) { @@ -140,6 +158,7 @@ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set } } + // Checks if an atom cannot be derived from a rule or a fact. private boolean isNonDerivable(Atom atom, List rules, Set facts) { Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { @@ -158,7 +177,7 @@ private boolean isNonDerivable(Atom atom, List rules, Set fact } /** - * removes a set of given literals from the rule body. + * Removes a set of given literals from the rule body. * @param rule the rule from which literals should be removed. * @param literals The literals to remove. * @return the resulting rule or fact. From 6a2975e791b263877edb3f68257b17e3732bef9e Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Mon, 11 Apr 2022 23:53:47 +0200 Subject: [PATCH 22/56] doc: Add ConfWS21 paper to README (#339) * doc: Add ConfWS21 paper to README Co-authored-by: Richard Taupe --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6992cc5c6..5ffcedb95 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,10 @@ run into trouble feel free to file an issue. Peer-reviewed publications part of journals, conferences and workshops: +#### 2021 + + * [Solving Configuration Problems with ASP and Declarative Domain-Specific Heuristics](http://ceur-ws.org/Vol-2945/21-RT-ConfWS21_paper_4.pdf) + #### 2020 * [Conflict Generalisation in ASP: Learning Correct and Effective Non-Ground Constraints](https://doi.org/10.1017/S1471068420000368) From 22f2af3fafa7edacc8aa95afb73c3f7f9f45b528 Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Thu, 7 Jul 2022 17:15:10 +0200 Subject: [PATCH 23/56] introduce nonterminal numeral to account for negative numbers as part of interval term --- .../ac/tuwien/kr/alpha/core/antlr/ASPCore2.g4 | 10 +++-- .../alpha/core/parser/ParseTreeVisitor.java | 42 ++++++++++++------- 2 files changed, 33 insertions(+), 19 deletions(-) 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 aeca5cc2d..4f80be1a2 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 @@ -56,7 +56,7 @@ terms : term (COMMA terms)?; term : ID # term_const | ID (PAREN_OPEN terms? PAREN_CLOSE) # term_func - | NUMBER # term_number + | numeral # term_number | QUOTED_STRING # term_string | VARIABLE # term_variable | ANONYMOUS_VARIABLE # term_anonymousVariable @@ -69,7 +69,11 @@ term : ID # term_const | term BITXOR term # term_bitxorArithTerm ; -interval : lower = (NUMBER | VARIABLE) DOT DOT upper = (NUMBER | VARIABLE); // NOT Core2 syntax, but widespread +numeral : MINUS? NUMBER; + +interval : lower = interval_bound DOT DOT upper = interval_bound; // NOT Core2 syntax, but widespread + +interval_bound : numeral | VARIABLE; external_atom : MINUS? AMPERSAND ID (SQUARE_OPEN input = terms SQUARE_CLOSE)? (PAREN_OPEN output = terms PAREN_CLOSE)?; // NOT Core2 syntax. @@ -81,7 +85,7 @@ basic_terms : basic_term (COMMA basic_terms)? ; basic_term : ground_term | variable_term; -ground_term : /*SYMBOLIC_CONSTANT*/ ID | QUOTED_STRING | MINUS? NUMBER; +ground_term : /*SYMBOLIC_CONSTANT*/ ID | QUOTED_STRING | numeral; variable_term : VARIABLE | ANONYMOUS_VARIABLE; 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 1498a4f0c..ad9e48f10 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 @@ -72,7 +72,6 @@ import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2BaseVisitor; -import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Lexer; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; import at.ac.tuwien.kr.alpha.core.programs.InputProgram; import at.ac.tuwien.kr.alpha.core.rules.BasicRule; @@ -320,7 +319,6 @@ 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)?; boolean isPositive = ctx.NAF() == null; Term lt = null; @@ -383,18 +381,17 @@ public Term visitBasic_term(ASPCore2Parser.Basic_termContext ctx) { @Override public Term visitGround_term(ASPCore2Parser.Ground_termContext ctx) { - // ground_term : ID | QUOTED_STRING | MINUS? NUMBER; + // ground_term : ID | QUOTED_STRING | numeral; if (ctx.ID() != null) { + // ID return Terms.newSymbolicConstant(ctx.ID().getText()); } else if (ctx.QUOTED_STRING() != null) { + // QUOTED_STRING String quotedString = ctx.QUOTED_STRING().getText(); return Terms.newConstant(quotedString.substring(1, quotedString.length() - 1)); } else { - int multiplier = 1; - if (ctx.MINUS() != null) { - multiplier = -1; - } - return Terms.newConstant(multiplier * Integer.parseInt(ctx.NUMBER().getText())); + // numeral + return Terms.newConstant(visitNumeral(ctx.numeral())); } } @@ -496,7 +493,14 @@ public List visitTerms(ASPCore2Parser.TermsContext ctx) { @Override public ConstantTerm visitTerm_number(ASPCore2Parser.Term_numberContext ctx) { - return Terms.newConstant(Integer.parseInt(ctx.NUMBER().getText())); + // term : numeral + return Terms.newConstant(visitNumeral(ctx.numeral())); + } + + public Integer visitNumeral(ASPCore2Parser.NumeralContext ctx) { + // numeral : MINUS? NUMBER; + int absValue = Integer.valueOf(ctx.NUMBER().getText()); + return ctx.MINUS() != null ? -1 * absValue : absValue; } @Override @@ -520,7 +524,6 @@ public VariableTerm visitTerm_anonymousVariable(ASPCore2Parser.Term_anonymousVar if (!acceptVariables) { throw notSupported(ctx); } - return Terms.newAnonymousVariable(); } @@ -529,7 +532,6 @@ public VariableTerm visitTerm_variable(ASPCore2Parser.Term_variableContext ctx) if (!acceptVariables) { throw notSupported(ctx); } - return Terms.newVariable(ctx.VARIABLE().getText()); } @@ -564,15 +566,23 @@ public ExternalAtom visitExternal_atom(ASPCore2Parser.External_atomContext ctx) @Override public IntervalTerm visitTerm_interval(ASPCore2Parser.Term_intervalContext ctx) { - // interval : lower = (NUMBER | VARIABLE) DOT DOT upper = (NUMBER | VARIABLE); + // interval : lower = interval_bound DOT DOT upper = interval_bound; ASPCore2Parser.IntervalContext ictx = ctx.interval(); - String lowerText = ictx.lower.getText(); - String upperText = ictx.upper.getText(); - Term lower = ictx.lower.getType() == ASPCore2Lexer.NUMBER ? Terms.newConstant(Integer.parseInt(lowerText)) : Terms.newVariable(lowerText); - Term upper = ictx.upper.getType() == ASPCore2Lexer.NUMBER ? Terms.newConstant(Integer.parseInt(upperText)) : Terms.newVariable(upperText); + Term lower = visitInterval_bound(ictx.lower); + Term upper = visitInterval_bound(ictx.upper); return IntervalTerm.getInstance(lower, upper); } + @Override + public Term visitInterval_bound(ASPCore2Parser.Interval_boundContext ctx) { + // interval_bound : numeral | VARIABLE; + if (ctx.numeral() != null) { + return Terms.newConstant(visitNumeral(ctx.numeral())); + } else { + return Terms.newVariable(ctx.VARIABLE().getText()); + } + } + @Override public Object visitTerm_minusArithTerm(ASPCore2Parser.Term_minusArithTermContext ctx) { // | MINUS term From ca3dba1af265eff3a8527c6ac551d25632139d70 Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Tue, 19 Jul 2022 13:07:33 +0200 Subject: [PATCH 24/56] Fix parsing of interval terms and move implementation to commons module --- .gitignore | 1 + .../kr/alpha/api/terms/IntervalTerm.java | 14 ++++ ...ntervalTerm.java => IntervalTermImpl.java} | 79 +++---------------- .../tuwien/kr/alpha/commons/terms/Terms.java | 33 ++++++++ .../kr/alpha/core/atoms/IntervalAtom.java | 2 +- .../kr/alpha/core/atoms/IntervalLiteral.java | 12 +-- .../core/grounder/FactIntervalEvaluator.java | 20 ++++- .../alpha/core/parser/ParseTreeVisitor.java | 4 +- .../ArithmeticTermsRewriting.java | 4 +- .../transformation/ChoiceHeadToNormal.java | 3 +- .../IntervalTermToIntervalAtom.java | 2 +- .../kr/alpha/core/parser/ParserTest.java | 39 ++++----- 12 files changed, 111 insertions(+), 102 deletions(-) create mode 100644 alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java rename alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/{IntervalTerm.java => IntervalTermImpl.java} (51%) diff --git a/.gitignore b/.gitignore index 7f953ccdb..42635d337 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,4 @@ gradle-app.setting /.dbeaver /Scripts /.vscode/ +workspace.code-workspace diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java new file mode 100644 index 000000000..4411715db --- /dev/null +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java @@ -0,0 +1,14 @@ +package at.ac.tuwien.kr.alpha.api.terms; + +/** + * A term representing an interval within the integers. + * Intervals are syntactic sugar, e.g. the rule "p(X) :- X = 1..2." is a shorthand for + * "p(X) :- X = 1. p(X) :- X = 2.". + */ +public interface IntervalTerm extends Term{ + + Term getLowerBound(); + + Term getUpperBound(); + +} diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTerm.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java similarity index 51% rename from alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTerm.java rename to alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java index 069a47382..27ba696c0 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTerm.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java @@ -4,28 +4,24 @@ import java.util.Set; import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.util.Interner; -import at.ac.tuwien.kr.alpha.commons.util.Util; /** * An IntervalTerm represents the shorthand notation for a set of rules where all elements in this interval occur once, e.g., fact(2..5). * An IntervalTerm is a meta-term and the grounder must replace it with its corresponding set of facts or rules. * Copyright (c) 2017, the Alpha Team. */ -public class IntervalTerm extends AbstractTerm { - private static final Interner INTERNER = new Interner<>(); +class IntervalTermImpl extends AbstractTerm implements IntervalTerm { + private static final Interner INTERNER = new Interner<>(); private final Term lowerBoundTerm; private final Term upperBoundTerm; - private final int lowerBound; - private final int upperBound; - private final boolean ground; - private IntervalTerm(Term lowerBound, Term upperBound) { + private IntervalTermImpl(Term lowerBound, Term upperBound) { if (lowerBound == null || upperBound == null) { throw new IllegalArgumentException(); } @@ -34,18 +30,10 @@ private IntervalTerm(Term lowerBound, Term upperBound) { this.lowerBoundTerm = lowerBound; this.upperBoundTerm = upperBound; - - if (this.ground) { - this.upperBound = Integer.parseInt(upperBoundTerm.toString()); - this.lowerBound = Integer.parseInt(lowerBoundTerm.toString()); - } else { - this.upperBound = -1; - this.lowerBound = -1; - } } - public static IntervalTerm getInstance(Term lowerBound, Term upperBound) { - return INTERNER.intern(new IntervalTerm(lowerBound, upperBound)); + static IntervalTermImpl getInstance(Term lowerBound, Term upperBound) { + return INTERNER.intern(new IntervalTermImpl(lowerBound, upperBound)); } @Override @@ -53,25 +41,11 @@ public boolean isGround() { return this.ground; } - public int getLowerBound() { - if (!isGround()) { - throw Util.oops("Cannot get the lower bound of non-ground interval"); - } - return this.lowerBound; - } - - public int getUpperBound() { - if (!isGround()) { - throw Util.oops("Cannot get the upper bound of non-ground interval"); - } - return this.upperBound; - } - - public Term getLowerBoundTerm() { + public Term getLowerBound() { return lowerBoundTerm; } - public Term getUpperBoundTerm() { + public Term getUpperBound() { return upperBoundTerm; } @@ -88,11 +62,11 @@ public Set getOccurringVariables() { } @Override - public IntervalTerm substitute(Substitution substitution) { + public IntervalTermImpl substitute(Substitution substitution) { if (isGround()) { return this; } - return new IntervalTerm(lowerBoundTerm.substitute(substitution), upperBoundTerm.substitute(substitution)); + return new IntervalTermImpl(lowerBoundTerm.substitute(substitution), upperBoundTerm.substitute(substitution)); } @Override @@ -109,7 +83,7 @@ public boolean equals(Object o) { return false; } - IntervalTerm that = (IntervalTerm) o; + IntervalTermImpl that = (IntervalTermImpl) o; if (!lowerBoundTerm.equals(that.lowerBoundTerm)) { return false; @@ -130,41 +104,14 @@ public int compareTo(Term o) { @Override public Term renameVariables(String renamePrefix) { - return new IntervalTerm(lowerBoundTerm.renameVariables(renamePrefix), upperBoundTerm.renameVariables(renamePrefix)); + return new IntervalTermImpl(lowerBoundTerm.renameVariables(renamePrefix), upperBoundTerm.renameVariables(renamePrefix)); } @Override public Term normalizeVariables(String renamePrefix, Term.RenameCounter counter) { - return IntervalTerm.getInstance( + return IntervalTermImpl.getInstance( lowerBoundTerm.normalizeVariables(renamePrefix, counter), upperBoundTerm.normalizeVariables(renamePrefix, counter)); } - /** - * Returns true if the term contains (or is) some IntervalTerm. - * @param term the term to test - * @return true iff an IntervalTerm occurs in term. - */ - public static boolean termContainsIntervalTerm(Term term) { - if (term instanceof IntervalTerm) { - return true; - } else if (term instanceof FunctionTermImpl) { - return functionTermContainsIntervals((FunctionTermImpl) term); - } else { - return false; - } - } - - public static boolean functionTermContainsIntervals(FunctionTerm functionTerm) { - // Test whether a function term contains an interval term (recursively). - for (Term term : functionTerm.getTerms()) { - if (term instanceof IntervalTerm) { - return true; - } - if (term instanceof FunctionTermImpl && functionTermContainsIntervals((FunctionTerm) term)) { - return true; - } - } - return false; - } } \ No newline at end of file diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java index b02e00c7b..e8052b973 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java @@ -9,6 +9,7 @@ import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; @@ -65,6 +66,10 @@ public static Term newMinusTerm(Term negatedTerm) { return MinusTerm.getInstance(negatedTerm); } + public static IntervalTerm newIntervalTerm(Term lowerBound, Term upperBound) { + return IntervalTermImpl.getInstance(lowerBound, upperBound); + } + @SafeVarargs public static > List> asTermList(T... values) { List> retVal = new ArrayList<>(); @@ -117,4 +122,32 @@ static Integer evaluateGroundTermHelper(Term term) { } } + /** + * Returns true if the term contains (or is) some IntervalTerm. + * @param term the term to test + * @return true iff an IntervalTerm occurs in term. + */ + public static boolean termContainsIntervalTerm(Term term) { + if (term instanceof IntervalTermImpl) { + return true; + } else if (term instanceof FunctionTermImpl) { + return functionTermContainsIntervals((FunctionTermImpl) term); + } else { + return false; + } + } + + public static boolean functionTermContainsIntervals(FunctionTerm functionTerm) { + // Test whether a function term contains an interval term (recursively). + for (Term term : functionTerm.getTerms()) { + if (term instanceof IntervalTermImpl) { + return true; + } + if (term instanceof FunctionTermImpl && functionTermContainsIntervals((FunctionTerm) term)) { + return true; + } + } + return false; + } + } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalAtom.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalAtom.java index 4c0236f95..f9d39be68 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalAtom.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalAtom.java @@ -34,10 +34,10 @@ import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.VariableNormalizableAtom; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.atoms.AbstractAtom; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java index b0f142c94..68589a176 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java @@ -37,11 +37,11 @@ import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.programs.literals.FixedInterpretationLiteral; import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.literals.AbstractLiteral; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; /** @@ -63,15 +63,19 @@ public IntervalLiteral negate() { throw new UnsupportedOperationException("IntervalLiteral cannot be negated"); } + @SuppressWarnings("unchecked") private List getIntervalSubstitutions(Substitution partialSubstitution) { List substitutions = new ArrayList<>(); List terms = getTerms(); Term intervalRepresentingVariable = terms.get(1); IntervalTerm intervalTerm = (IntervalTerm) terms.get(0); + // Note: Unchecked cast is OK, assuming IntervalRewriting worked, the interval term will be ground + int intervalLowerBound = ((ConstantTerm) intervalTerm.getLowerBound()).getObject(); + int intervalUpperBound = ((ConstantTerm) intervalTerm.getUpperBound()).getObject(); // Check whether intervalRepresentingVariable is bound already. if (intervalRepresentingVariable instanceof VariableTerm) { // Still a variable, generate all elements in the interval. - for (int i = intervalTerm.getLowerBound(); i <= intervalTerm.getUpperBound(); i++) { + for (int i = intervalLowerBound; i <= intervalUpperBound; i++) { Substitution ith = new BasicSubstitution(partialSubstitution); ith.put((VariableTerm) intervalRepresentingVariable, Terms.newConstant(i)); substitutions.add(ith); @@ -84,10 +88,8 @@ private List getIntervalSubstitutions(Substitution partialSubstitu // Term is not bound to an integer constant, not in the interval. return Collections.emptyList(); } - // TODO to avoid that type of unchecked cast, we may want interval terms to not extend AbstractTerm - @SuppressWarnings("unchecked") Integer integer = ((ConstantTerm) intervalRepresentingVariable).getObject(); - if (intervalTerm.getLowerBound() <= integer && integer <= intervalTerm.getUpperBound()) { + if (intervalLowerBound <= integer && integer <= intervalUpperBound) { return Collections.singletonList(partialSubstitution); } return Collections.emptyList(); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java index 197df1254..508f25cbe 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/FactIntervalEvaluator.java @@ -5,10 +5,11 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; /** @@ -34,7 +35,7 @@ public static List constructFactInstances(Atom fact) { currentTerms[i] = term; if (term instanceof IntervalTerm) { containsIntervals = true; - } else if (term instanceof FunctionTerm && IntervalTerm.functionTermContainsIntervals((FunctionTerm) term)) { + } else if (term instanceof FunctionTerm && Terms.functionTermContainsIntervals((FunctionTerm) term)) { containsIntervals = true; throw new UnsupportedOperationException("Intervals inside function terms in facts are not supported yet. Try turning the fact into a rule."); } @@ -47,6 +48,7 @@ public static List constructFactInstances(Atom fact) { return unrollInstances(currentTerms, 0); } + @SuppressWarnings("unchecked") private static List unrollInstances(Term[] currentTerms, int currentPosition) { if (currentPosition == currentTerms.length) { return Collections.singletonList(new Instance(currentTerms)); @@ -58,8 +60,18 @@ private static List unrollInstances(Term[] currentTerms, int currentPo List instances = new ArrayList<>(); - int lower = ((IntervalTerm) currentTerm).getLowerBound(); - int upper = ((IntervalTerm) currentTerm).getUpperBound(); + Term lowerBoundTerm = ((IntervalTerm) currentTerm).getLowerBound(); + Term upperBoundTerm = ((IntervalTerm) currentTerm).getUpperBound(); + if (!(lowerBoundTerm instanceof ConstantTerm)) { + throw new IllegalArgumentException("Cannot unroll interval term with non-integer bound: " + lowerBoundTerm); + } + if (!(upperBoundTerm instanceof ConstantTerm)) { + throw new IllegalArgumentException("Cannot unroll interval term with non-integer bound: " + upperBoundTerm); + } + + int lower = ((ConstantTerm) lowerBoundTerm).getObject(); + int upper = ((ConstantTerm) upperBoundTerm).getObject(); + for (int i = lower; i <= upper; i++) { Term[] clonedTerms = currentTerms.clone(); 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 ad9e48f10..868222d85 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 @@ -61,6 +61,7 @@ import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.AnswerSets; @@ -69,7 +70,6 @@ import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; import at.ac.tuwien.kr.alpha.commons.literals.Literals; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2BaseVisitor; import at.ac.tuwien.kr.alpha.core.antlr.ASPCore2Parser; @@ -570,7 +570,7 @@ public IntervalTerm visitTerm_interval(ASPCore2Parser.Term_intervalContext ctx) ASPCore2Parser.IntervalContext ictx = ctx.interval(); Term lower = visitInterval_bound(ictx.lower); Term upper = visitInterval_bound(ictx.upper); - return IntervalTerm.getInstance(lower, upper); + return Terms.newIntervalTerm(lower, upper); } @Override 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 026cde8c5..259d410a9 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 @@ -13,12 +13,12 @@ import at.ac.tuwien.kr.alpha.api.terms.ArithmeticTerm; import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.commons.util.Util; import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; @@ -171,7 +171,7 @@ private boolean containsArithmeticTerm(Term term) { } return false; } else if (term instanceof IntervalTerm) { - return containsArithmeticTerm(((IntervalTerm) term).getLowerBoundTerm()) || containsArithmeticTerm(((IntervalTerm) term).getUpperBoundTerm()); + return containsArithmeticTerm(((IntervalTerm) term).getLowerBound()) || containsArithmeticTerm(((IntervalTerm) term).getUpperBound()); } else { throw Util.oops("Unexpected term type: " + term.getClass()); } 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 f54778b8c..70da8e765 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 @@ -44,7 +44,6 @@ import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.core.programs.InputProgram; import at.ac.tuwien.kr.alpha.core.rules.BasicRule; @@ -121,7 +120,7 @@ public ASPCore2Program apply(ASPCore2Program inputProgram) { private static boolean containsIntervalTerms(Atom atom) { for (Term term : atom.getTerms()) { - if (IntervalTerm.termContainsIntervalTerm(term)) { + if (Terms.termContainsIntervalTerm(term)) { return true; } } 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 36920ec71..013aaab5d 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 @@ -41,10 +41,10 @@ import at.ac.tuwien.kr.alpha.api.rules.NormalRule; import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.terms.Terms; import at.ac.tuwien.kr.alpha.core.atoms.IntervalAtom; import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; 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 d63009bbb..08f95a453 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,6 +27,23 @@ */ 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 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.atoms.AggregateAtom; @@ -35,30 +52,14 @@ import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.heads.ChoiceHead; import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.Predicates; import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; import at.ac.tuwien.kr.alpha.commons.comparisons.ComparisonOperators; -import at.ac.tuwien.kr.alpha.commons.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.commons.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.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.stream.Stream; - -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; /** * Copyright (c) 2016, the Alpha Team. @@ -124,9 +125,9 @@ public void parseProgramWithDisjunctionInHead() { public void parseInterval() { ASPCore2Program 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(IntervalTerm.getInstance(Terms.newConstant(2), Terms.newConstant(5)))); + assertTrue(factInterval.equals(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(IntervalTerm.getInstance(Terms.newConstant(3), Terms.newVariable("X")))); + assertTrue(bodyInterval.equals(Terms.newIntervalTerm(Terms.newConstant(3), Terms.newVariable("X")))); } @Test From faf1e88320a4f58bf3dc05157c5519afc64afbe6 Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Wed, 20 Jul 2022 14:10:32 +0200 Subject: [PATCH 25/56] improve tesst coverage for IntervalTermImpl --- .../kr/alpha/api/terms/IntervalTerm.java | 2 +- .../alpha/commons/terms/IntervalTermImpl.java | 1 + .../kr/alpha/commons/terms/TermTest.java | 20 +++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java index 4411715db..43a1e8730 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java @@ -5,7 +5,7 @@ * Intervals are syntactic sugar, e.g. the rule "p(X) :- X = 1..2." is a shorthand for * "p(X) :- X = 1. p(X) :- X = 2.". */ -public interface IntervalTerm extends Term{ +public interface IntervalTerm extends Term { Term getLowerBound(); diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java index 27ba696c0..eb14b44f7 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/IntervalTermImpl.java @@ -15,6 +15,7 @@ * Copyright (c) 2017, the Alpha Team. */ class IntervalTermImpl extends AbstractTerm implements IntervalTerm { + private static final Interner INTERNER = new Interner<>(); private final Term lowerBoundTerm; private final Term upperBoundTerm; diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java index ea0ebcfc1..e9d9934df 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java @@ -12,7 +12,9 @@ import org.junit.jupiter.api.Test; +import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; @@ -27,10 +29,13 @@ public void testTermReferenceEquality() { // Terms must have a unique representation so that reference comparison is // sufficient to check // whether two terms are equal. + + // Test for constant terms. ConstantTerm ta1 = Terms.newConstant("a"); ConstantTerm ta2 = Terms.newConstant("a"); assertTrue(ta1 == ta2, "Two instances of ConstantTerms for the same term symbol must be the same object"); + // Test for function terms. List termList = new LinkedList<>(); termList.add(ta1); termList.add(ta2); @@ -40,6 +45,21 @@ public void testTermReferenceEquality() { termList2.add(ta2); FunctionTermImpl ft2 = FunctionTermImpl.getInstance("f", termList2); assertTrue(ft1 == ft2, "Two instances of FunctionTerms for the same term symbol and equal term lists must be the same object"); + + // Test for arithmetic terms. + Term tArith1 = ArithmeticTermImpl.getInstance(Terms.newConstant(2), ArithmeticOperator.PLUS, Terms.newConstant(2)); + Term tArith2 = ArithmeticTermImpl.getInstance(Terms.newConstant(2), ArithmeticOperator.PLUS, Terms.newConstant(2)); + assertTrue(tArith1 == tArith2, "Two instances of ArithmeticTerms for the same operator symbol and equal term lists must be the same object"); + + // Test for interval terms. + IntervalTerm tInt1 = IntervalTermImpl.getInstance(Terms.newConstant(-3), Terms.newVariable("X")); + IntervalTerm tInt2 = IntervalTermImpl.getInstance(Terms.newConstant(-3), Terms.newVariable("X")); + assertTrue(tInt1 == tInt2, "Two instances of IntervalTerms for the same bounds must be the same object"); + + // Test for variables. + VariableTerm tVar1 = VariableTermImpl.getInstance("X"); + VariableTerm tVar2 = VariableTermImpl.getInstance("X"); + assertTrue(tVar1 == tVar2, "Two instances of VariableTerms for the same name must be the same object"); } @Test From d4bd8f91cfbb097ed9343150cc4101c70b018132 Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Mon, 25 Jul 2022 16:29:10 +0200 Subject: [PATCH 26/56] improve test coverage for term implementations --- .../kr/alpha/commons/terms/TermTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java index e9d9934df..ebb36c0b8 100644 --- a/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java +++ b/alpha-commons/src/test/java/at/ac/tuwien/kr/alpha/commons/terms/TermTest.java @@ -12,11 +12,14 @@ import org.junit.jupiter.api.Test; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; import at.ac.tuwien.kr.alpha.api.terms.ArithmeticOperator; import at.ac.tuwien.kr.alpha.api.terms.ConstantTerm; +import at.ac.tuwien.kr.alpha.api.terms.FunctionTerm; import at.ac.tuwien.kr.alpha.api.terms.IntervalTerm; import at.ac.tuwien.kr.alpha.api.terms.Term; import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; /** * Copyright (c) 2016-2021, the Alpha Team. @@ -110,4 +113,30 @@ public void testStringVsConstantSymbolEquality() { // hashCode, i.e. return a non-zero result for non-equal objects assertNotEquals(0, stringConstant.compareTo(constantSymbol)); } + + @Test + public void testVariableSubstitution() { + Substitution substitution = new BasicSubstitution(); + substitution.put(Terms.newVariable("X"), Terms.newConstant(1)); + + // Test variable term (trivial case, substituting results in constant). + VariableTerm var = VariableTermImpl.getInstance("X"); + Term substitutedVar = var.substitute(substitution); + assertEquals(Terms.newConstant(1), substitutedVar); + + // Test function term. + FunctionTerm func = FunctionTermImpl.getInstance("f", VariableTermImpl.getInstance("X")); + Term substitutedFunc = func.substitute(substitution); + assertTrue(substitutedFunc.isGround()); + + // Test arithmetic term (note that arithmetic term with ground operands gets evaluated, result is therefore "2" rather than "1 + 1" ). + Term arith = ArithmeticTermImpl.getInstance(VariableTermImpl.getInstance("X"), ArithmeticOperator.PLUS, ConstantTermImpl.getInstance(1)); + Term substitutedArith = arith.substitute(substitution); + assertEquals(Terms.newConstant(2), substitutedArith); + + // Test interval term. + IntervalTerm interval = IntervalTermImpl.getInstance(VariableTermImpl.getInstance("X"), Terms.newConstant(3)); + Term substitutedInterval = interval.substitute(substitution); + assertEquals(Terms.newIntervalTerm(Terms.newConstant(1), Terms.newConstant(3)), substitutedInterval); + } } From 891d1fbc5275f48e2d16628f519fdcb6e7b4315c Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Tue, 26 Jul 2022 14:18:25 +0200 Subject: [PATCH 27/56] Update alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java Co-authored-by: Antonius Weinzierl --- .../main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java index 43a1e8730..3e3a7f394 100644 --- a/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java +++ b/alpha-api/src/main/java/at/ac/tuwien/kr/alpha/api/terms/IntervalTerm.java @@ -1,7 +1,7 @@ package at.ac.tuwien.kr.alpha.api.terms; /** - * A term representing an interval within the integers. + * A term representing an interval of integers. * Intervals are syntactic sugar, e.g. the rule "p(X) :- X = 1..2." is a shorthand for * "p(X) :- X = 1. p(X) :- X = 2.". */ From 68cc827d716f89716b39262a007cbbcd2123cb3c Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Tue, 26 Jul 2022 14:35:09 +0200 Subject: [PATCH 28/56] improve javadoc --- .../java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java index e8052b973..c651a70aa 100644 --- a/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java +++ b/alpha-commons/src/main/java/at/ac/tuwien/kr/alpha/commons/terms/Terms.java @@ -137,8 +137,12 @@ public static boolean termContainsIntervalTerm(Term term) { } } + /** + * Returns true if the given {@link FunctionTerm} contains some IntervalTerm. + * @param functionTerm the term to test + * @return true iff an IntervalTerm occurs in functionTerm. + */ public static boolean functionTermContainsIntervals(FunctionTerm functionTerm) { - // Test whether a function term contains an interval term (recursively). for (Term term : functionTerm.getTerms()) { if (term instanceof IntervalTermImpl) { return true; From 0b488fcbe3ab6f3939f0dd8a9ca70d4a5004eadf Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Tue, 26 Jul 2022 15:01:30 +0200 Subject: [PATCH 29/56] check for interval bounds not being constants --- .../tuwien/kr/alpha/core/atoms/IntervalLiteral.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java index 68589a176..a0d762bf2 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/atoms/IntervalLiteral.java @@ -43,6 +43,7 @@ import at.ac.tuwien.kr.alpha.commons.literals.AbstractLiteral; import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; import at.ac.tuwien.kr.alpha.commons.terms.Terms; +import at.ac.tuwien.kr.alpha.commons.util.Util; /** * @see IntervalAtom @@ -63,14 +64,20 @@ public IntervalLiteral negate() { throw new UnsupportedOperationException("IntervalLiteral cannot be negated"); } - @SuppressWarnings("unchecked") private List getIntervalSubstitutions(Substitution partialSubstitution) { List substitutions = new ArrayList<>(); List terms = getTerms(); Term intervalRepresentingVariable = terms.get(1); IntervalTerm intervalTerm = (IntervalTerm) terms.get(0); - // Note: Unchecked cast is OK, assuming IntervalRewriting worked, the interval term will be ground + if (!(intervalTerm.getLowerBound() instanceof ConstantTerm)) { + throw Util.oops("Lower bound of interval term " + intervalTerm + " is not a constant!"); + } + @SuppressWarnings("unchecked") int intervalLowerBound = ((ConstantTerm) intervalTerm.getLowerBound()).getObject(); + if (!(intervalTerm.getUpperBound() instanceof ConstantTerm)) { + throw Util.oops("Upper bound of interval term " + intervalTerm + " is not a constant!"); + } + @SuppressWarnings("unchecked") int intervalUpperBound = ((ConstantTerm) intervalTerm.getUpperBound()).getObject(); // Check whether intervalRepresentingVariable is bound already. if (intervalRepresentingVariable instanceof VariableTerm) { @@ -88,6 +95,7 @@ private List getIntervalSubstitutions(Substitution partialSubstitu // Term is not bound to an integer constant, not in the interval. return Collections.emptyList(); } + @SuppressWarnings("unchecked") Integer integer = ((ConstantTerm) intervalRepresentingVariable).getObject(); if (intervalLowerBound <= integer && integer <= intervalUpperBound) { return Collections.singletonList(partialSubstitution); From fea4765f6dd71c9d846316c2ee11664b79c794d1 Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Tue, 30 Aug 2022 15:38:38 +0200 Subject: [PATCH 30/56] add reference to asp-guide --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5ffcedb95..c76ff482a 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ $ java -jar alpha.jar -i benchmarks/omiga/omiga-testcases/3col/3col-10-18.txt -f Note that in this example the path to the input file is relative to the root of this repository. If you have not checked out the repository, you can just [download the example file from GitHub](/benchmarks/omiga/omiga-testcases/3col/3col-10-18.txt). +[A coder's guide to answer set programming](https://madmike200590.github.io/asp-guide/) provides a short and high-level tutorial on Answer Set Programming. + ## Building Alpha uses the [Gradle build automation system](https://gradle.org). Executing From 482ca921579579720b4ca178276f69a9ea00f5ae Mon Sep 17 00:00:00 2001 From: Michael Langowski Date: Tue, 30 Aug 2022 15:44:10 +0200 Subject: [PATCH 31/56] add asp-guide to suggested reading --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c76ff482a..6e5147a2c 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,10 @@ run into trouble feel free to file an issue. ## Suggested Reading +### Beginners' Tutorials + * [A coder's guide to answer set programming](https://madmike200590.github.io/asp-guide/) + +### Theoretical Background and Language Specification * [Answer Set Programming: A Primer](http://www.kr.tuwien.ac.at/staff/tkren/pub/2009/rw2009-asp.pdf) * [ASP-Core-2 Input Language Format](https://www.mat.unical.it/aspcomp2013/files/ASP-CORE-2.01c.pdf) * [Conflict-Driven Answer Set Solving: From Theory to Practice](http://www.cs.uni-potsdam.de/wv/pdfformat/gekasc12c.pdf) From 33cbbaa453a8e1e6591e24579c5dde2c558d0dfc Mon Sep 17 00:00:00 2001 From: Paul Behofsics Date: Sun, 11 Sep 2022 13:54:03 +0200 Subject: [PATCH 32/56] Fix SimpleLogger time format --- alpha-cli-app/src/main/resources/simplelogger.properties | 3 +-- alpha-cli-app/src/test/resources/simplelogger.properties | 3 +-- alpha-commons/src/test/resources/simplelogger.properties | 3 +-- alpha-core/src/test/resources/simplelogger.properties | 3 +-- alpha-solver/src/test/resources/simplelogger.properties | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/alpha-cli-app/src/main/resources/simplelogger.properties b/alpha-cli-app/src/main/resources/simplelogger.properties index e9d221fed..2585a0852 100644 --- a/alpha-cli-app/src/main/resources/simplelogger.properties +++ b/alpha-cli-app/src/main/resources/simplelogger.properties @@ -22,8 +22,7 @@ org.slf4j.simpleLogger.log.at.ac.tuwien.kr.alpha.core.solver.heuristics.HeapOfAc org.slf4j.simpleLogger.showDateTime=true # Format for logged timestamps. -# For Alpha, we use milliseconds since startup -org.slf4j.simpleLogger.dateTimeFormat=S +# For Alpha, we use milliseconds since startup, which is the default time format # Disable including thread name in logged line since Alpha is currently single-threaded. org.slf4j.simpleLogger.showThreadName=false \ No newline at end of file diff --git a/alpha-cli-app/src/test/resources/simplelogger.properties b/alpha-cli-app/src/test/resources/simplelogger.properties index a4e464d4a..f2ae884d2 100644 --- a/alpha-cli-app/src/test/resources/simplelogger.properties +++ b/alpha-cli-app/src/test/resources/simplelogger.properties @@ -22,8 +22,7 @@ org.slf4j.simpleLogger.log.at.ac.tuwien.kr.alpha.core.solver.heuristics.HeapOfAc org.slf4j.simpleLogger.showDateTime=true # Format for logged timestamps. -# For Alpha, we use milliseconds since startup -org.slf4j.simpleLogger.dateTimeFormat=S +# For Alpha, we use milliseconds since startup, which is the default time format # Disable including thread name in logged line since Alpha is currently single-threaded. org.slf4j.simpleLogger.showThreadName=false \ No newline at end of file diff --git a/alpha-commons/src/test/resources/simplelogger.properties b/alpha-commons/src/test/resources/simplelogger.properties index a4e464d4a..f2ae884d2 100644 --- a/alpha-commons/src/test/resources/simplelogger.properties +++ b/alpha-commons/src/test/resources/simplelogger.properties @@ -22,8 +22,7 @@ org.slf4j.simpleLogger.log.at.ac.tuwien.kr.alpha.core.solver.heuristics.HeapOfAc org.slf4j.simpleLogger.showDateTime=true # Format for logged timestamps. -# For Alpha, we use milliseconds since startup -org.slf4j.simpleLogger.dateTimeFormat=S +# For Alpha, we use milliseconds since startup, which is the default time format # Disable including thread name in logged line since Alpha is currently single-threaded. org.slf4j.simpleLogger.showThreadName=false \ No newline at end of file diff --git a/alpha-core/src/test/resources/simplelogger.properties b/alpha-core/src/test/resources/simplelogger.properties index a4e464d4a..f2ae884d2 100644 --- a/alpha-core/src/test/resources/simplelogger.properties +++ b/alpha-core/src/test/resources/simplelogger.properties @@ -22,8 +22,7 @@ org.slf4j.simpleLogger.log.at.ac.tuwien.kr.alpha.core.solver.heuristics.HeapOfAc org.slf4j.simpleLogger.showDateTime=true # Format for logged timestamps. -# For Alpha, we use milliseconds since startup -org.slf4j.simpleLogger.dateTimeFormat=S +# For Alpha, we use milliseconds since startup, which is the default time format # Disable including thread name in logged line since Alpha is currently single-threaded. org.slf4j.simpleLogger.showThreadName=false \ No newline at end of file diff --git a/alpha-solver/src/test/resources/simplelogger.properties b/alpha-solver/src/test/resources/simplelogger.properties index a4e464d4a..f2ae884d2 100644 --- a/alpha-solver/src/test/resources/simplelogger.properties +++ b/alpha-solver/src/test/resources/simplelogger.properties @@ -22,8 +22,7 @@ org.slf4j.simpleLogger.log.at.ac.tuwien.kr.alpha.core.solver.heuristics.HeapOfAc org.slf4j.simpleLogger.showDateTime=true # Format for logged timestamps. -# For Alpha, we use milliseconds since startup -org.slf4j.simpleLogger.dateTimeFormat=S +# For Alpha, we use milliseconds since startup, which is the default time format # Disable including thread name in logged line since Alpha is currently single-threaded. org.slf4j.simpleLogger.showThreadName=false \ No newline at end of file From fee81a86398741e842988c8a206f99edc37012f2 Mon Sep 17 00:00:00 2001 From: Antonius Weinzierl Date: Fri, 2 Dec 2022 05:22:18 +0100 Subject: [PATCH 33/56] Improve logging output for debugging. --- .../tuwien/kr/alpha/core/common/NoGood.java | 21 ++++++++----- .../core/solver/NoGoodStoreAlphaRoaming.java | 2 +- .../kr/alpha/core/solver/TrailAssignment.java | 31 ++++++++++--------- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java index 3575669ba..3705b0c18 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/common/NoGood.java @@ -27,6 +27,14 @@ */ package at.ac.tuwien.kr.alpha.core.common; +import at.ac.tuwien.kr.alpha.commons.util.Util; +import at.ac.tuwien.kr.alpha.core.solver.Antecedent; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.IntStream; + import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isNegated; import static at.ac.tuwien.kr.alpha.core.atoms.Literals.isPositive; @@ -37,14 +45,6 @@ import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.STATIC; import static at.ac.tuwien.kr.alpha.core.common.NoGoodInterface.Type.SUPPORT; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.stream.IntStream; - -import at.ac.tuwien.kr.alpha.commons.util.Util; -import at.ac.tuwien.kr.alpha.core.solver.Antecedent; - public class NoGood implements NoGoodInterface, Comparable { public static final int HEAD = 0; public static final NoGood UNSAT = new NoGood(); @@ -163,6 +163,11 @@ public void bumpActivity() { @Override public void decreaseActivity() { } + + @Override + public String toString() { + return NoGood.this + "(unwatched)"; + } }; } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java index 8b4d1977e..4e80e769f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/NoGoodStoreAlphaRoaming.java @@ -774,7 +774,7 @@ public int size() { @Override public String toString() { - return "BinaryWatchList(" + forLiteral + ")"; + return "BinaryWatchList(" + literalToString(forLiteral) + ")"; } @Override diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java index 9194925d8..10716621d 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/TrailAssignment.java @@ -27,6 +27,19 @@ */ package at.ac.tuwien.kr.alpha.core.solver; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.core.common.Assignment; +import at.ac.tuwien.kr.alpha.core.common.AtomStore; +import at.ac.tuwien.kr.alpha.core.common.IntIterator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import static at.ac.tuwien.kr.alpha.commons.util.Util.arrayGrowthSize; import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; @@ -37,20 +50,6 @@ import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.MBT; import static at.ac.tuwien.kr.alpha.core.solver.ThriceTruth.TRUE; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.core.common.Assignment; -import at.ac.tuwien.kr.alpha.core.common.AtomStore; -import at.ac.tuwien.kr.alpha.core.common.IntIterator; - /** * An implementation of Assignment using a trail (of literals) and arrays as underlying structures for storing * assignments. @@ -73,7 +72,11 @@ public void bumpActivity() { @Override public void decreaseActivity() { + } + @Override + public String toString() { + return "ClosingIndicatorAntecedent"; } }; From 451fdf3dcd8ecbb55a2a62337f0a34837e876ee3 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 1 Aug 2023 21:34:28 +0200 Subject: [PATCH 34/56] refactored SimplePreprocessing --- .../transformation/SimplePreprocessing.java | 131 ++++++++++-------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 648f27194..565286378 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -6,6 +6,7 @@ import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.rules.Rule; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; import at.ac.tuwien.kr.alpha.core.grounder.Unification; import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; @@ -13,6 +14,8 @@ import java.util.*; +import static java.util.stream.Collectors.toList; + /** * Simplifies the input program by deleting redundant literals and rules, as well as identifying rule heads that can * always be derived from facts and adding them to the known facts. The approach is adopted from preprocessing @@ -33,13 +36,13 @@ public NormalProgram apply(NormalProgram inputProgram) { Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - // Eliminate rules that will never fire, without regarding other rules. + // Check if the rules are redundant or will never fire, without taking other rules into consideration. for (NormalRule rule: srcRules) { - if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { + if (facts.contains(rule.getHeadAtom()) || containsConflictingBodyLiterals(rule) || containsHeadInPositiveBody(rule)) { continue; } - if (checkForHeadInBody(rule.getBody(), rule.getHeadAtom())) { - continue; + if (containsHeadInNegativeBody(rule)) { + newRules.add(new NormalRuleImpl(null, new ArrayList<>(rule.getBody()))); } newRules.add(rule); } @@ -70,42 +73,28 @@ public NormalProgram apply(NormalProgram inputProgram) { return new NormalProgramImpl(new LinkedList<>(newRules), new LinkedList<>(facts), inputProgram.getInlineDirectives()); } - private static class RuleEvaluation { - public final static RuleEvaluation NO_FIRE = new RuleEvaluation(null, false, false); - private final NormalRule rule; - private final boolean isModified; - private final boolean isFact; - - public RuleEvaluation(NormalRule rule, boolean isModified, boolean isFact) { - this.rule = rule; - this.isModified = isModified; - this.isFact = isFact; - } - - public NormalRule getRule() { - return rule; - } - - public boolean isModified() { - return isModified; - } - - public boolean isFact() { - return isFact; + private boolean containsConflictingBodyLiterals(NormalRule rule) { + for (Literal positiveLiteral : rule.getPositiveBody()) { + if (rule.getNegativeBody().contains(positiveLiteral.negate())) { + return true; + } } + return false; } - private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - for (Literal positiveLiteral : positiveBody) { - if (negativeBody.contains(positiveLiteral.negate())) { + private boolean containsHeadInPositiveBody(NormalRule rule) { + Atom headAtom = rule.getHeadAtom(); + for (Literal literal : rule.getPositiveBody()) { + if (literal.getAtom().equals(headAtom)) { return true; } } return false; } - private boolean checkForHeadInBody(Set body, Atom headAtom) { - for (Literal literal : body) { + private boolean containsHeadInNegativeBody(NormalRule rule) { + Atom headAtom = rule.getHeadAtom(); + for (Literal literal : rule.getNegativeBody()) { if (literal.getAtom().equals(headAtom)) { return true; } @@ -118,39 +107,36 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { * @param rule the rule to be evaluated. * @param rules the rules from which literals could be derived from. * @param facts the facts from which literals could be derived from. - * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was + * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was * modified, is a fact or will never fire. */ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { - // Check if the rule head is already a fact, making the rule redundant. - if (facts.contains(rule.getHeadAtom())) { - return RuleEvaluation.NO_FIRE; - } - - // Collect all literals that can be removed from the rule. + // Collect all literals that can be removed from the rule here. Set redundantLiterals = new LinkedHashSet<>(); // Check if body literals can be derived from facts or other rules. If a body literal is not derivable, the // rule can never fire. If a literal is already proven within the program context, the rule will be simplified - // by removing it. - for (Literal literal : rule.getBody()) { - if (literal instanceof BasicLiteral) { - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return RuleEvaluation.NO_FIRE; - } - if (isNonDerivable(literal.getAtom(), rules, facts)) { - redundantLiterals.add(literal); - } - } else { - if (facts.contains(literal.getAtom())) { - redundantLiterals.add(literal); - } else if (isNonDerivable(literal.getAtom(), rules, facts)) { - return RuleEvaluation.NO_FIRE; - } - } + // by removing the literal. + List basicBodyLiterals = rule.getBody().stream().filter(BasicLiteral.class::isInstance).collect(toList()); + for (Literal literal : basicBodyLiterals) { + if (literal.isNegated() && facts.contains(literal.getAtom()) + || !literal.isNegated() && isNonDerivable(literal.getAtom(), rules, facts)) { + return RuleEvaluation.NO_FIRE; + } + if (literal.isNegated() && isNonDerivable(literal.getAtom(), rules, facts) + || !literal.isNegated() && facts.contains(literal.getAtom())) { + redundantLiterals.add(literal); } } + + // Checks if a constraint has the same body, meaning the had of the rule cannot be derived by the rule. + List constraints = rules.stream().filter(Rule::isConstraint).collect(toList()); + for (NormalRule constraint : constraints) { + if (!rule.isConstraint() && rule.getBody().equals(constraint.getBody())) { + return RuleEvaluation.NO_FIRE; + } + } + if (redundantLiterals.isEmpty()) { return new RuleEvaluation(rule, false, false); } else { @@ -162,10 +148,8 @@ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set private boolean isNonDerivable(Atom atom, List rules, Set facts) { Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { - if (!rule.isConstraint()) { - if (Unification.unifyAtoms(rule.getHeadAtom(), tempAtom) != null) { - return false; - } + if (!rule.isConstraint() && Unification.unifyAtoms(rule.getHeadAtom(), tempAtom) != null) { + return false; } } for (Atom fact:facts) { @@ -196,4 +180,33 @@ private RuleEvaluation removeLiteralsFromRule(NormalRule rule, Set lite } return new RuleEvaluation(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); } + + /** + * Internal helper class containing the possibly simplified rule and indicates whether it could + * or could not be simplified, is a fact or will never fire. + */ + private static class RuleEvaluation { + public static final RuleEvaluation NO_FIRE = new RuleEvaluation(null, false, false); + private final NormalRule rule; + private final boolean isModified; + private final boolean isFact; + + public RuleEvaluation(NormalRule rule, boolean isModified, boolean isFact) { + this.rule = rule; + this.isModified = isModified; + this.isFact = isFact; + } + + public NormalRule getRule() { + return rule; + } + + public boolean isModified() { + return isModified; + } + + public boolean isFact() { + return isFact; + } + } } From e9dd86040868de7be78b92a5e78ce7aac73b11a3 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Thu, 28 Oct 2021 12:03:11 +0200 Subject: [PATCH 35/56] added SimplePreprocessing ProgramTransformation --- .../transformation/SimplePreprocessing.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java new file mode 100644 index 000000000..6f84520c9 --- /dev/null +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -0,0 +1,63 @@ +package at.ac.tuwien.kr.alpha.grounder.transformation; + +import at.ac.tuwien.kr.alpha.common.atoms.Atom; +import at.ac.tuwien.kr.alpha.common.atoms.Literal; +import at.ac.tuwien.kr.alpha.common.program.NormalProgram; +import at.ac.tuwien.kr.alpha.common.rule.NormalRule; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Simplifies a normal input program by deleting redundant rules. + */ + +public class SimplePreprocessing extends ProgramTransformation{ + + @Override + public NormalProgram apply(NormalProgram inputProgram) { + + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + + Iterator ruleIterator = srcRules.iterator(); + + while(ruleIterator.hasNext()) { + NormalRule rule = ruleIterator.next(); + boolean redundantRule = false; + + Atom headAtom = rule.getHead().getAtom(); + Set body = rule.getBody(); + Set positiveBody = rule.getPositiveBody(); + Set negativeBody = rule.getNegativeBody(); + + //implements s3: deletes rule if body contains head atom + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.getAtom().equals(headAtom)) { + redundantRule = true; + break; + } + } + + //implements s2: deletes rule if body contains both positive and negative literal of an atom + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + if (negativeBody.contains(positiveLiteral.negate())) { + redundantRule = true; + break; + } + } + + //implements s0: delete duplicate rules + if (!redundantRule && !transformedRules.contains(rule)) { + transformedRules.add(rule); + } + } + return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + } +} From 9cfa9cb6bca57764561614055e24b8c3ce51b329 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 14:47:12 +0100 Subject: [PATCH 36/56] added preprocesssing steps in SimplePreprocessing, removal of a literal in InternalRule --- .../kr/alpha/core/grounder/NaiveGrounder.java | 163 +++++++++--------- .../grounder/ProgramAnalyzingGrounder.java | 4 +- .../structure/AnalyzeUnjustified.java | 24 +-- .../transformation/SimplePreprocessing.java | 154 ++++++++++++++--- .../kr/alpha/core/rules/InternalRule.java | 11 ++ ...eralizedDependencyDrivenPyroHeuristic.java | 2 +- 6 files changed, 233 insertions(+), 125 deletions(-) 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 1e498d50d..6dd46430c 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 @@ -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. - *

+ * 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 @@ -25,10 +25,15 @@ * 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.grounder; -import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; -import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; +import static at.ac.tuwien.kr.alpha.Util.oops; +import static at.ac.tuwien.kr.alpha.common.Literals.atomOf; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; @@ -43,39 +48,31 @@ import java.util.SortedSet; import java.util.TreeSet; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import at.ac.tuwien.kr.alpha.api.AnswerSet; -import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; -import at.ac.tuwien.kr.alpha.api.grounder.Substitution; -import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.commons.AnswerSets; -import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; -import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; -import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; -import at.ac.tuwien.kr.alpha.commons.util.Util; -import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; -import at.ac.tuwien.kr.alpha.core.common.Assignment; -import at.ac.tuwien.kr.alpha.core.common.AtomStore; -import at.ac.tuwien.kr.alpha.core.common.IntIterator; -import at.ac.tuwien.kr.alpha.core.common.NoGood; -import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; -import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; -import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; -import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; -import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.Util; +import at.ac.tuwien.kr.alpha.common.AnswerSet; +import at.ac.tuwien.kr.alpha.common.Assignment; +import at.ac.tuwien.kr.alpha.common.AtomStore; +import at.ac.tuwien.kr.alpha.common.BasicAnswerSet; +import at.ac.tuwien.kr.alpha.common.IntIterator; +import at.ac.tuwien.kr.alpha.common.NoGood; +import at.ac.tuwien.kr.alpha.common.NoGoodInterface; +import at.ac.tuwien.kr.alpha.common.Predicate; +import at.ac.tuwien.kr.alpha.common.atoms.Atom; +import at.ac.tuwien.kr.alpha.common.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.common.atoms.Literal; +import at.ac.tuwien.kr.alpha.common.program.InternalProgram; +import at.ac.tuwien.kr.alpha.common.rule.InternalRule; +import at.ac.tuwien.kr.alpha.common.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.grounder.atoms.ChoiceAtom; +import at.ac.tuwien.kr.alpha.grounder.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.grounder.bridges.Bridge; +import at.ac.tuwien.kr.alpha.grounder.heuristics.GrounderHeuristicsConfiguration; +import at.ac.tuwien.kr.alpha.grounder.instantiation.AssignmentStatus; +import at.ac.tuwien.kr.alpha.grounder.instantiation.BindingResult; +import at.ac.tuwien.kr.alpha.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; +import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiationResult; +import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiator; +import at.ac.tuwien.kr.alpha.grounder.structure.AnalyzeUnjustified; /** * A semi-naive grounder. @@ -90,14 +87,14 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final NogoodRegistry registry = new NogoodRegistry(); final NoGoodGenerator noGoodGenerator; private final ChoiceRecorder choiceRecorder; - private final CompiledProgram program; + private final InternalProgram program; private final AnalyzeUnjustified analyzeUnjustified; private final Map> factsFromProgram; private final Map> rulesUsingPredicateWorkingMemory = new HashMap<>(); - private final Map knownNonGroundRules; + private final Map knownNonGroundRules; - private ArrayList fixedRules = new ArrayList<>(); + private ArrayList fixedRules = new ArrayList<>(); private LinkedHashSet removeAfterObtainingNewNoGoods = new LinkedHashSet<>(); private final boolean debugInternalChecks; @@ -108,16 +105,16 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final LiteralInstantiator ruleInstantiator; private final DefaultLazyGroundingInstantiationStrategy instantiationStrategy; - public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { + public NaiveGrounder(InternalProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, + private NaiveGrounder(InternalProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, + NaiveGrounder(InternalProgram program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; @@ -133,7 +130,7 @@ private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeur this.initializeFactsAndRules(); - final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); + final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); choiceRecorder = new ChoiceRecorder(atomStore); noGoodGenerator = new NoGoodGenerator(atomStore, choiceRecorder, factsFromProgram, this.program, uniqueGroundRulePerGroundHead); @@ -162,7 +159,7 @@ private void initializeFactsAndRules() { workingMemory.initialize(ChoiceAtom.ON); // Initialize rules and constraints in working memory. - for (CompiledRule nonGroundRule : program.getRulesById().values()) { + for (InternalRule nonGroundRule : program.getRulesById().values()) { // Create working memories for all predicates occurring in the rule. for (Predicate predicate : nonGroundRule.getOccurringPredicates()) { // FIXME: this also contains interval/builtin predicates that are not needed. @@ -170,30 +167,30 @@ private void initializeFactsAndRules() { } // If the rule has fixed ground instantiations, it is not registered but grounded once like facts. - if (nonGroundRule.getGroundingInfo().hasFixedInstantiation()) { + if (nonGroundRule.getGroundingOrders().fixedInstantiation()) { fixedRules.add(nonGroundRule); continue; } // Register each starting literal at the corresponding working memory. - for (Literal literal : nonGroundRule.getGroundingInfo().getStartingLiterals()) { + for (Literal literal : nonGroundRule.getGroundingOrders().getStartingLiterals()) { registerLiteralAtWorkingMemory(literal, nonGroundRule); } } } - private Set getRulesWithUniqueHead() { + private Set getRulesWithUniqueHead() { // FIXME: below optimisation (adding support nogoods if there is only one rule instantiation per unique atom over the interpretation) could // be done as a transformation (adding a non-ground constraint corresponding to the nogood that is generated by the grounder). // Record all unique rule heads. - final Set uniqueGroundRulePerGroundHead = new HashSet<>(); + final Set uniqueGroundRulePerGroundHead = new HashSet<>(); - for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { + for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { if (headDefiningRules.getValue().size() != 1) { continue; } - CompiledRule nonGroundRule = headDefiningRules.getValue().iterator().next(); + InternalRule nonGroundRule = headDefiningRules.getValue().iterator().next(); // Check that all variables of the body also occur in the head (otherwise grounding is not unique). Atom headAtom = nonGroundRule.getHeadAtom(); @@ -224,7 +221,7 @@ private Set getRulesWithUniqueHead() { * * @param nonGroundRule the rule in which the literal occurs. */ - private void registerLiteralAtWorkingMemory(Literal literal, CompiledRule nonGroundRule) { + private void registerLiteralAtWorkingMemory(Literal literal, InternalRule nonGroundRule) { if (literal.isNegated()) { throw new RuntimeException("Literal to register is negated. Should not happen."); } @@ -278,15 +275,15 @@ public AnswerSet assignmentToAnswerSet(Iterable trueAtoms) { predicateInstances.putIfAbsent(factPredicate, new TreeSet<>()); for (Instance factInstance : facts.getValue()) { SortedSet instances = predicateInstances.get(factPredicate); - instances.add(Atoms.newBasicAtom(factPredicate, factInstance.terms)); + instances.add(new BasicAtom(factPredicate, factInstance.terms)); } } if (knownPredicates.isEmpty()) { - return AnswerSets.EMPTY_SET; + return BasicAnswerSet.EMPTY; } - return AnswerSets.newAnswerSet(knownPredicates, predicateInstances); + return new BasicAnswerSet(knownPredicates, predicateInstances); } /** @@ -302,10 +299,10 @@ protected HashMap bootstrap() { workingMemory.addInstances(predicate, true, factsFromProgram.get(predicate)); } - for (CompiledRule nonGroundRule : fixedRules) { + for (InternalRule nonGroundRule : fixedRules) { // Generate NoGoods for all rules that have a fixed grounding. - RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingInfo().getFixedGroundingOrder(); - BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new BasicSubstitution(), null); + RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingOrders().getFixedGroundingOrder(); + BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new Substitution(), null); groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), groundNogoods); } @@ -337,14 +334,14 @@ public Map getNoGoods(Assignment currentAssignment) { for (FirstBindingAtom firstBindingAtom : firstBindingAtoms) { // Use the recently added instances from the modified working memory to construct an initial substitution - CompiledRule nonGroundRule = firstBindingAtom.rule; + InternalRule nonGroundRule = firstBindingAtom.rule; // Generate substitutions from each recent instance. for (Instance instance : modifiedWorkingMemory.getRecentlyAddedInstances()) { // Check instance if it matches with the atom. - final Substitution unifier = BasicSubstitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, - BasicSubstitution.EMPTY_SUBSTITUTION); + final Substitution unifier = Substitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, + Substitution.EMPTY_SUBSTITUTION); if (unifier == null) { continue; @@ -352,7 +349,7 @@ public Map getNoGoods(Assignment currentAssignment) { final BindingResult bindingResult = getGroundInstantiations( nonGroundRule, - nonGroundRule.getGroundingInfo().orderStartingFrom(firstBindingAtom.startingLiteral), + nonGroundRule.getGroundingOrders().orderStartingFrom(firstBindingAtom.startingLiteral), unifier, currentAssignment); @@ -400,7 +397,7 @@ public Map getNoGoods(Assignment currentAssignment) { * @param substitutions the substitutions to be applied. * @param newNoGoods a set of nogoods to which newly generated nogoods will be added. */ - private void groundAndRegister(final CompiledRule nonGroundRule, final List substitutions, final Map newNoGoods) { + private void groundAndRegister(final InternalRule nonGroundRule, final List substitutions, final Map newNoGoods) { for (Substitution substitution : substitutions) { List generatedNoGoods = noGoodGenerator.generateNoGoodsFromGroundSubstitution(nonGroundRule, substitution); registry.register(generatedNoGoods, newNoGoods); @@ -438,13 +435,13 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou } /** - * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrderImpl, int, int, int, BasicSubstitution)}. - * - * Takes an ImmutablePair of a {@link BasicSubstitution} and an accompanying {@link AssignmentStatus} and calls + * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrder, int, int, int, Substitution)}. + * + * Takes an ImmutablePair of a {@link Substitution} and an accompanying {@link AssignmentStatus} and calls * bindNextAtomInRule for the next literal in the grounding order. * If the assignment status for the last bound literal was {@link AssignmentStatus#UNASSIGNED}, the remainingTolerance * parameter is decreased by 1. If the remaining tolerance drops below zero, this method returns an empty {@link BindingResult}. - * + * * @param groundingOrder * @param orderPosition * @param originalTolerance @@ -494,12 +491,12 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding //@formatter:off /** - * Computes ground substitutions for a literal based on a {@link RuleGroundingOrderImpl} and a {@link BasicSubstitution}. - * + * Computes ground substitutions for a literal based on a {@link RuleGroundingOrder} and a {@link Substitution}. + * * Computes ground substitutions for the literal at position orderPosition of groundingOrder * Actual substitutions are computed by this grounder's {@link LiteralInstantiator}. - * - * @param groundingOrder a {@link RuleGroundingOrderImpl} representing the body literals of a rule in the + * + * @param groundingOrder a {@link RuleGroundingOrder} representing the body literals of a rule in the * sequence in which the should be bound during grounding. * @param orderPosition the current position within groundingOrder, indicates which literal should be bound * @param originalTolerance the original tolerance of the used grounding heuristic @@ -588,7 +585,7 @@ public void forgetAssignment(int[] atomIds) { } @Override - public CompiledRule getNonGroundRule(Integer ruleId) { + public InternalRule getNonGroundRule(Integer ruleId) { return knownNonGroundRules.get(ruleId); } @@ -620,8 +617,8 @@ public Set justifyAtom(int atomToJustify, Assignment currentAssignment) /** * Checks that every nogood not marked as {@link NoGoodInterface.Type#INTERNAL} contains only - * atoms which are not {@link PredicateImpl#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). - * + * atoms which are not {@link Predicate#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). + * * @param newNoGoods */ private void checkTypesOfNoGoods(Collection newNoGoods) { @@ -638,10 +635,10 @@ private void checkTypesOfNoGoods(Collection newNoGoods) { } private static class FirstBindingAtom { - final CompiledRule rule; + final InternalRule rule; final Literal startingLiteral; - FirstBindingAtom(CompiledRule rule, Literal startingLiteral) { + FirstBindingAtom(InternalRule rule, Literal startingLiteral) { this.rule = rule; this.startingLiteral = startingLiteral; } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java index d64388123..12960995a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java @@ -15,10 +15,10 @@ public interface ProgramAnalyzingGrounder extends Grounder { /** * Justifies the absence of an atom, i.e., returns reasons why the atom is not TRUE given the assignment. * @param atomToJustify the atom to justify. - * @param currentAssignment the current assignment. + * @param assignment the current assignment. * @return a set of literals who jointly imply the atomToJustify not being TRUE. */ - Set justifyAtom(int atomToJustify, Assignment currentAssignment); + Set justifyAtom(int atomToJustify, Assignment assignment); /** * Returns true iff the given atom is known to the grounder as a fact (hence not occurring in any assignment). diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java index cb12167db..c04c9578c 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java @@ -54,7 +54,7 @@ public AnalyzeUnjustified(CompiledProgram programAnalysis, AtomStore atomStore, private Map> assignedAtoms; - public Set analyze(int atomToJustify, Assignment currentAssignment) { + public Set analyze(int atomToJustify, Assignment assignment) { padDepth = 0; Atom atom = atomStore.get(atomToJustify); if (!(atom instanceof BasicAtom)) { @@ -69,7 +69,7 @@ public Set analyze(int atomToJustify, Assignment currentAssignment) { //@formatter:on assignedAtoms = new LinkedHashMap<>(); for (int i = 1; i <= atomStore.getMaxAtomId(); i++) { - ThriceTruth truth = currentAssignment.getTruth(i); + ThriceTruth truth = assignment.getTruth(i); if (truth == null) { continue; } @@ -77,11 +77,11 @@ public Set analyze(int atomToJustify, Assignment currentAssignment) { assignedAtoms.putIfAbsent(assignedAtom.getPredicate(), new ArrayList<>()); assignedAtoms.get(assignedAtom.getPredicate()).add(assignedAtom); } - return analyze((BasicAtom) atom, currentAssignment); + return analyze((BasicAtom) atom, assignment); } - private Set analyze(BasicAtom atom, Assignment currentAssignment) { - log(pad("Starting analyze, current assignment is: {}"), currentAssignment); + private Set analyze(BasicAtom atom, Assignment assignment) { + log(pad("Starting analyze, current assignment is: {}"), assignment); LinkedHashSet vL = new LinkedHashSet<>(); LinkedHashSet vToDo = new LinkedHashSet<>(Collections.singleton(new LitSet(atom, new LinkedHashSet<>()))); LinkedHashSet vDone = new LinkedHashSet<>(); @@ -92,7 +92,7 @@ private Set analyze(BasicAtom atom, Assignment currentAssignment) { log(""); log("Treating now: {}", x); vDone.add(x); - ReturnExplainUnjust unjustRet = explainUnjust(x, currentAssignment); + ReturnExplainUnjust unjustRet = explainUnjust(x, assignment); log("Additional ToDo: {}", unjustRet.vToDo); // Check each new LitSet if it does not already occur as done. for (LitSet todoLitSet : unjustRet.vToDo) { @@ -105,7 +105,7 @@ private Set analyze(BasicAtom atom, Assignment currentAssignment) { return vL; } - private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment) { + private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { padDepth += 2; log("Begin explainUnjust(): {}", x); Atom p = x.getAtom(); @@ -151,7 +151,7 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment log("Considering: {}", lg); if (atomStore.contains(lg)) { int atomId = atomStore.get(lg); - if (!currentAssignment.getTruth(atomId).toBoolean()) { + if (!assignment.getTruth(atomId).toBoolean()) { log("{} is not assigned TRUE or MBT. Skipping.", lg); continue; } @@ -188,14 +188,14 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment } } log("Calling UnjustCover() for positive body."); - ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, currentAssignment)); + ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, assignment)); } log("End explainUnjust()."); padDepth -= 2; return ret; } - private Set unjustCover(List vB, Set vY, Set vN, Assignment currentAssignment) { + private Set unjustCover(List vB, Set vY, Set vN, Assignment assignment) { padDepth += 2; log("Begin UnjustCoverFixed()"); log("Finding unjustified body literals in: {} / {} excluded {}", vB, vY, vN); @@ -228,7 +228,7 @@ private Set unjustCover(List vB, Set vY, Set log("Checking atom: {}", atom); if (atomStore.contains(atom)) { int atomId = atomStore.get(atom); - if (currentAssignment.getTruth(atomId) != ThriceTruth.TRUE) { + if (assignment.getTruth(atomId) != ThriceTruth.TRUE) { log("Atom is not TRUE. Skipping."); continue; } @@ -274,7 +274,7 @@ private Set unjustCover(List vB, Set vY, Set } ArrayList newB = new ArrayList<>(vB); newB.remove(chosenLiteralPos); - ret.addAll(unjustCover(newB, vYp, vN, currentAssignment)); + ret.addAll(unjustCover(newB, vYp, vN, assignment)); log("Literal set(s) to treat: {}", ret); } log("End unjustCover()."); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 6f84520c9..9e7ffb750 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -2,8 +2,9 @@ import at.ac.tuwien.kr.alpha.common.atoms.Atom; import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.NormalProgram; -import at.ac.tuwien.kr.alpha.common.rule.NormalRule; +import at.ac.tuwien.kr.alpha.common.program.InternalProgram; +import at.ac.tuwien.kr.alpha.common.rule.InternalRule; +import at.ac.tuwien.kr.alpha.grounder.Unification; import java.util.ArrayList; import java.util.Iterator; @@ -11,21 +12,19 @@ import java.util.Set; /** - * Simplifies a normal input program by deleting redundant rules. + * Simplifies an internal input program by deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation{ +public class SimplePreprocessing extends ProgramTransformation{ @Override - public NormalProgram apply(NormalProgram inputProgram) { - - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - Iterator ruleIterator = srcRules.iterator(); + public InternalProgram apply(InternalProgram inputProgram) { + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + Iterator ruleIterator = srcRules.iterator(); while(ruleIterator.hasNext()) { - NormalRule rule = ruleIterator.next(); + InternalRule rule = ruleIterator.next(); boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); @@ -33,31 +32,132 @@ public NormalProgram apply(NormalProgram inputProgram) { Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); - //implements s3: deletes rule if body contains head atom - Iterator literalIterator = body.iterator(); + if (checkForHeadInBody(body,headAtom)) { + redundantRule = true; + } + if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + redundantRule = true; + } + //implements s0: delete duplicate rules + if (!(redundantRule || transformedRules.contains(rule))) { + transformedRules.add(rule); + } + } + deleteConflictingRules(transformedRules, inputProgram.getFacts()); + + simplifyRules(transformedRules, inputProgram.getFacts()); + + return new InternalProgram(transformedRules, inputProgram.getFacts()); + } + + /** + * This method checks if a rule contains a literal in both the positive and the negative body. + * implements s2 + */ + private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + //TODO: implement literal.equals() + if (negativeBody.contains(positiveLiteral.negate())) { + return true; + } + } + return false; + } + + /** + * This method checks if the head atom occurs in the rule's body. + * implements s3 + */ + private boolean checkForHeadInBody(Set body, Atom headAtom) { + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + //TODO: implement atom.equals() + if (literal.getAtom().equals(headAtom)) { + return true; + } + } + return false; + } + + /** + * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * implements s9 + */ + private List deleteConflictingRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); + while(literalIterator.hasNext()) { Literal literal = literalIterator.next(); - if (literal.getAtom().equals(headAtom)) { - redundantRule = true; - break; + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + } + else { + if (isDerivable(literal, rules)) { + transformedRules.add(rule); + } } } + } + return transformedRules; + } + + + /** + * This method removes literals from rule bodies, that are already facts (when positive) + * or not derivable (when negated). + * implements s10 + */ + private List simplifyRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); - //implements s2: deletes rule if body contains both positive and negative literal of an atom - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - if (negativeBody.contains(positiveLiteral.negate())) { - redundantRule = true; - break; + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + else transformedRules.add(rule.removeLiteral(literal)); + } + else { + if (!isDerivable(literal, rules)) { + transformedRules.add(rule.removeLiteral(literal)); + } + else transformedRules.add(rule); } } + } + return transformedRules; + } - //implements s0: delete duplicate rules - if (!redundantRule && !transformedRules.contains(rule)) { - transformedRules.add(rule); + + /** + * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * implements s5 conditions + */ + private boolean isDerivable(Literal literal, List rules){ + Iterator ruleIterator = rules.iterator(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + return true; } } - return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return false; } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index 9a72fca12..aaa15c5fa 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -143,4 +143,15 @@ public int getRuleId() { return this.ruleId; } + public InternalRule removeLiteral(Literal literal) { + Atom headAtom = this.getHeadAtom(); + List newBody = new ArrayList<>(this.getBody().size()); + for (Literal bodyLiteral : this.getBody()) { + if(!literal.equals(bodyLiteral)) { + newBody.add(bodyLiteral); + } + } + return new InternalRule(new NormalHead(headAtom), newBody); + } + } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java index f4c8e71f7..586dc3598 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java @@ -45,7 +45,7 @@ public class GeneralizedDependencyDrivenPyroHeuristic extends GeneralizedDependencyDrivenHeuristic { public GeneralizedDependencyDrivenPyroHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random, - BodyActivityType bodyActivityType) { + BodyActivityType bodyActivityType) { super(assignment, choiceManager, decayPeriod, decayFactor, random, bodyActivityType); } From e00e247015a02c42e2fec1490fa7b5ce245f3af3 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 15:29:36 +0100 Subject: [PATCH 37/56] refactored SimplePreprocessing loops --- .../transformation/SimplePreprocessing.java | 121 ++++++++---------- 1 file changed, 53 insertions(+), 68 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 9e7ffb750..3a705c9da 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -5,6 +5,7 @@ import at.ac.tuwien.kr.alpha.common.program.InternalProgram; import at.ac.tuwien.kr.alpha.common.rule.InternalRule; import at.ac.tuwien.kr.alpha.grounder.Unification; +import org.apache.poi.util.Internal; import java.util.ArrayList; import java.util.Iterator; @@ -12,7 +13,7 @@ import java.util.Set; /** - * Simplifies an internal input program by deleting redundant rules. + * Simplifies an internal input program by simplifying and deleting redundant rules. */ public class SimplePreprocessing extends ProgramTransformation{ @@ -21,31 +22,42 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = new ArrayList<>(inputProgram.getRules()); List transformedRules = new ArrayList<>(); - Iterator ruleIterator = srcRules.iterator(); - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); + for (InternalRule rule : srcRules) { boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); Set body = rule.getBody(); Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); + InternalRule simplifiedRule = null; - if (checkForHeadInBody(body,headAtom)) { + //implements s0: delete duplicate rules + if (transformedRules.contains(rule)) { //TODO: Add InternalRule.equals() redundantRule = true; } - if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + //implemnts s2 + if (checkForConflictingBodyLiterals(positiveBody, negativeBody)) { redundantRule = true; } - //implements s0: delete duplicate rules - if (!(redundantRule || transformedRules.contains(rule))) { + //implements s3 + if (checkForHeadInBody(body, headAtom)) { + redundantRule = true; + } + //implements s9 + if(checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { + redundantRule = true; + } + //implements s10 + simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); + if(simplifiedRule != null) { + rule = simplifiedRule; + } + + if(!redundantRule) { transformedRules.add(rule); } } - deleteConflictingRules(transformedRules, inputProgram.getFacts()); - - simplifyRules(transformedRules, inputProgram.getFacts()); return new InternalProgram(transformedRules, inputProgram.getFacts()); } @@ -55,10 +67,7 @@ public InternalProgram apply(InternalProgram inputProgram) { * implements s2 */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - //TODO: implement literal.equals() + for (Literal positiveLiteral : positiveBody) { if (negativeBody.contains(positiveLiteral.negate())) { return true; } @@ -71,10 +80,8 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { - Iterator literalIterator = body.iterator(); - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - //TODO: implement atom.equals() + for (Literal literal : body) { + //TODO: implement Atom.equals() if (literal.getAtom().equals(headAtom)) { return true; } @@ -82,79 +89,57 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { return false; } + /** - * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. * implements s9 */ - private List deleteConflictingRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } + private boolean checkForUnreachableLiterals (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + return false; } - else { - if (isDerivable(literal, rules)) { - transformedRules.add(rule); - } + } else { + if (isDerivable(literal, rules)) { + return false; } } } - return transformedRules; + return true; } /** - * This method removes literals from rule bodies, that are already facts (when positive) + * This method checks for literals from rule bodies, that are already facts (when positive) * or not derivable (when negated). * implements s10 */ - private List simplifyRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } - else transformedRules.add(rule.removeLiteral(literal)); - } - else { - if (!isDerivable(literal, rules)) { - transformedRules.add(rule.removeLiteral(literal)); - } - else transformedRules.add(rule); - } + private InternalRule checkForSimplifiableRule (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return null; + } else return rule.removeLiteral(literal); + } else { + if (!isDerivable(literal, rules)) { + return rule.removeLiteral(literal); + } else return null; } } - return transformedRules; + return null; } + + /** * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. * implements s5 conditions */ private boolean isDerivable(Literal literal, List rules){ - Iterator ruleIterator = rules.iterator(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + for (InternalRule rule : rules) { + if (Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { return true; } } From 3bcd281290fb42bf34f4e1bd5497f77d439dd19c Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Thu, 28 Oct 2021 12:03:11 +0200 Subject: [PATCH 38/56] added SimplePreprocessing ProgramTransformation --- .../transformation/SimplePreprocessing.java | 147 ++++-------------- 1 file changed, 31 insertions(+), 116 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 3a705c9da..6f84520c9 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -2,10 +2,8 @@ import at.ac.tuwien.kr.alpha.common.atoms.Atom; import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.InternalProgram; -import at.ac.tuwien.kr.alpha.common.rule.InternalRule; -import at.ac.tuwien.kr.alpha.grounder.Unification; -import org.apache.poi.util.Internal; +import at.ac.tuwien.kr.alpha.common.program.NormalProgram; +import at.ac.tuwien.kr.alpha.common.rule.NormalRule; import java.util.ArrayList; import java.util.Iterator; @@ -13,136 +11,53 @@ import java.util.Set; /** - * Simplifies an internal input program by simplifying and deleting redundant rules. + * Simplifies a normal input program by deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation{ +public class SimplePreprocessing extends ProgramTransformation{ @Override - public InternalProgram apply(InternalProgram inputProgram) { - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); + public NormalProgram apply(NormalProgram inputProgram) { - for (InternalRule rule : srcRules) { + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + + Iterator ruleIterator = srcRules.iterator(); + + while(ruleIterator.hasNext()) { + NormalRule rule = ruleIterator.next(); boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); Set body = rule.getBody(); Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); - InternalRule simplifiedRule = null; - - //implements s0: delete duplicate rules - if (transformedRules.contains(rule)) { //TODO: Add InternalRule.equals() - redundantRule = true; - } - //implemnts s2 - if (checkForConflictingBodyLiterals(positiveBody, negativeBody)) { - redundantRule = true; - } - //implements s3 - if (checkForHeadInBody(body, headAtom)) { - redundantRule = true; - } - //implements s9 - if(checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { - redundantRule = true; - } - //implements s10 - simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); - if(simplifiedRule != null) { - rule = simplifiedRule; - } - - if(!redundantRule) { - transformedRules.add(rule); - } - } - - return new InternalProgram(transformedRules, inputProgram.getFacts()); - } - - /** - * This method checks if a rule contains a literal in both the positive and the negative body. - * implements s2 - */ - private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - for (Literal positiveLiteral : positiveBody) { - if (negativeBody.contains(positiveLiteral.negate())) { - return true; - } - } - return false; - } - - /** - * This method checks if the head atom occurs in the rule's body. - * implements s3 - */ - private boolean checkForHeadInBody(Set body, Atom headAtom) { - for (Literal literal : body) { - //TODO: implement Atom.equals() - if (literal.getAtom().equals(headAtom)) { - return true; - } - } - return false; - } - - /** - * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. - * implements s9 - */ - private boolean checkForUnreachableLiterals (List rules, InternalRule rule, List facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - return false; - } - } else { - if (isDerivable(literal, rules)) { - return false; + //implements s3: deletes rule if body contains head atom + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.getAtom().equals(headAtom)) { + redundantRule = true; + break; } } - } - return true; - } - - /** - * This method checks for literals from rule bodies, that are already facts (when positive) - * or not derivable (when negated). - * implements s10 - */ - private InternalRule checkForSimplifiableRule (List rules, InternalRule rule, List facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return null; - } else return rule.removeLiteral(literal); - } else { - if (!isDerivable(literal, rules)) { - return rule.removeLiteral(literal); - } else return null; + //implements s2: deletes rule if body contains both positive and negative literal of an atom + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + if (negativeBody.contains(positiveLiteral.negate())) { + redundantRule = true; + break; + } } - } - return null; - } - - - - /** - * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. - * implements s5 conditions - */ - private boolean isDerivable(Literal literal, List rules){ - for (InternalRule rule : rules) { - if (Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { - return true; + //implements s0: delete duplicate rules + if (!redundantRule && !transformedRules.contains(rule)) { + transformedRules.add(rule); } } - return false; + return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); } } From 43f2661c3f4234983621047d4e35f9971342e4a9 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 14:47:12 +0100 Subject: [PATCH 39/56] added preprocesssing steps in SimplePreprocessing, removal of a literal in InternalRule --- .../transformation/SimplePreprocessing.java | 154 +++++++++++++++--- 1 file changed, 127 insertions(+), 27 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 6f84520c9..9e7ffb750 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -2,8 +2,9 @@ import at.ac.tuwien.kr.alpha.common.atoms.Atom; import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.NormalProgram; -import at.ac.tuwien.kr.alpha.common.rule.NormalRule; +import at.ac.tuwien.kr.alpha.common.program.InternalProgram; +import at.ac.tuwien.kr.alpha.common.rule.InternalRule; +import at.ac.tuwien.kr.alpha.grounder.Unification; import java.util.ArrayList; import java.util.Iterator; @@ -11,21 +12,19 @@ import java.util.Set; /** - * Simplifies a normal input program by deleting redundant rules. + * Simplifies an internal input program by deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation{ +public class SimplePreprocessing extends ProgramTransformation{ @Override - public NormalProgram apply(NormalProgram inputProgram) { - - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - Iterator ruleIterator = srcRules.iterator(); + public InternalProgram apply(InternalProgram inputProgram) { + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + Iterator ruleIterator = srcRules.iterator(); while(ruleIterator.hasNext()) { - NormalRule rule = ruleIterator.next(); + InternalRule rule = ruleIterator.next(); boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); @@ -33,31 +32,132 @@ public NormalProgram apply(NormalProgram inputProgram) { Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); - //implements s3: deletes rule if body contains head atom - Iterator literalIterator = body.iterator(); + if (checkForHeadInBody(body,headAtom)) { + redundantRule = true; + } + if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + redundantRule = true; + } + //implements s0: delete duplicate rules + if (!(redundantRule || transformedRules.contains(rule))) { + transformedRules.add(rule); + } + } + deleteConflictingRules(transformedRules, inputProgram.getFacts()); + + simplifyRules(transformedRules, inputProgram.getFacts()); + + return new InternalProgram(transformedRules, inputProgram.getFacts()); + } + + /** + * This method checks if a rule contains a literal in both the positive and the negative body. + * implements s2 + */ + private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { + Iterator positiveLiteralIterator = positiveBody.iterator(); + while(positiveLiteralIterator.hasNext()) { + Literal positiveLiteral = positiveLiteralIterator.next(); + //TODO: implement literal.equals() + if (negativeBody.contains(positiveLiteral.negate())) { + return true; + } + } + return false; + } + + /** + * This method checks if the head atom occurs in the rule's body. + * implements s3 + */ + private boolean checkForHeadInBody(Set body, Atom headAtom) { + Iterator literalIterator = body.iterator(); + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + //TODO: implement atom.equals() + if (literal.getAtom().equals(headAtom)) { + return true; + } + } + return false; + } + + /** + * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * implements s9 + */ + private List deleteConflictingRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); + while(literalIterator.hasNext()) { Literal literal = literalIterator.next(); - if (literal.getAtom().equals(headAtom)) { - redundantRule = true; - break; + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + } + else { + if (isDerivable(literal, rules)) { + transformedRules.add(rule); + } } } + } + return transformedRules; + } + + + /** + * This method removes literals from rule bodies, that are already facts (when positive) + * or not derivable (when negated). + * implements s10 + */ + private List simplifyRules (List rules, List facts) { + Iterator ruleIterator = rules.iterator(); + List transformedRules = new ArrayList<>(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + Iterator literalIterator = rule.getBody().iterator(); - //implements s2: deletes rule if body contains both positive and negative literal of an atom - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - if (negativeBody.contains(positiveLiteral.negate())) { - redundantRule = true; - break; + while(literalIterator.hasNext()) { + Literal literal = literalIterator.next(); + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + transformedRules.add(rule); + } + else transformedRules.add(rule.removeLiteral(literal)); + } + else { + if (!isDerivable(literal, rules)) { + transformedRules.add(rule.removeLiteral(literal)); + } + else transformedRules.add(rule); } } + } + return transformedRules; + } - //implements s0: delete duplicate rules - if (!redundantRule && !transformedRules.contains(rule)) { - transformedRules.add(rule); + + /** + * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * implements s5 conditions + */ + private boolean isDerivable(Literal literal, List rules){ + Iterator ruleIterator = rules.iterator(); + + while(ruleIterator.hasNext()) { + InternalRule rule = ruleIterator.next(); + if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + return true; } } - return new NormalProgram(transformedRules, inputProgram.getFacts(), inputProgram.getInlineDirectives()); + return false; } } From 1a60f8c41fe8981380b39da1412cd17824901b36 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 14 Dec 2021 15:29:36 +0100 Subject: [PATCH 40/56] refactored SimplePreprocessing loops --- .../transformation/SimplePreprocessing.java | 121 ++++++++---------- 1 file changed, 53 insertions(+), 68 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 9e7ffb750..3a705c9da 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -5,6 +5,7 @@ import at.ac.tuwien.kr.alpha.common.program.InternalProgram; import at.ac.tuwien.kr.alpha.common.rule.InternalRule; import at.ac.tuwien.kr.alpha.grounder.Unification; +import org.apache.poi.util.Internal; import java.util.ArrayList; import java.util.Iterator; @@ -12,7 +13,7 @@ import java.util.Set; /** - * Simplifies an internal input program by deleting redundant rules. + * Simplifies an internal input program by simplifying and deleting redundant rules. */ public class SimplePreprocessing extends ProgramTransformation{ @@ -21,31 +22,42 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = new ArrayList<>(inputProgram.getRules()); List transformedRules = new ArrayList<>(); - Iterator ruleIterator = srcRules.iterator(); - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); + for (InternalRule rule : srcRules) { boolean redundantRule = false; Atom headAtom = rule.getHead().getAtom(); Set body = rule.getBody(); Set positiveBody = rule.getPositiveBody(); Set negativeBody = rule.getNegativeBody(); + InternalRule simplifiedRule = null; - if (checkForHeadInBody(body,headAtom)) { + //implements s0: delete duplicate rules + if (transformedRules.contains(rule)) { //TODO: Add InternalRule.equals() redundantRule = true; } - if (checkForConflictingBodyLiterals(positiveBody,negativeBody)) { + //implemnts s2 + if (checkForConflictingBodyLiterals(positiveBody, negativeBody)) { redundantRule = true; } - //implements s0: delete duplicate rules - if (!(redundantRule || transformedRules.contains(rule))) { + //implements s3 + if (checkForHeadInBody(body, headAtom)) { + redundantRule = true; + } + //implements s9 + if(checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { + redundantRule = true; + } + //implements s10 + simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); + if(simplifiedRule != null) { + rule = simplifiedRule; + } + + if(!redundantRule) { transformedRules.add(rule); } } - deleteConflictingRules(transformedRules, inputProgram.getFacts()); - - simplifyRules(transformedRules, inputProgram.getFacts()); return new InternalProgram(transformedRules, inputProgram.getFacts()); } @@ -55,10 +67,7 @@ public InternalProgram apply(InternalProgram inputProgram) { * implements s2 */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - Iterator positiveLiteralIterator = positiveBody.iterator(); - while(positiveLiteralIterator.hasNext()) { - Literal positiveLiteral = positiveLiteralIterator.next(); - //TODO: implement literal.equals() + for (Literal positiveLiteral : positiveBody) { if (negativeBody.contains(positiveLiteral.negate())) { return true; } @@ -71,10 +80,8 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { - Iterator literalIterator = body.iterator(); - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - //TODO: implement atom.equals() + for (Literal literal : body) { + //TODO: implement Atom.equals() if (literal.getAtom().equals(headAtom)) { return true; } @@ -82,79 +89,57 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { return false; } + /** - * This method deletes Rules with bodies containing not derivable literals or negated literals, that are facts. + * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. * implements s9 */ - private List deleteConflictingRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } + private boolean checkForUnreachableLiterals (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + return false; } - else { - if (isDerivable(literal, rules)) { - transformedRules.add(rule); - } + } else { + if (isDerivable(literal, rules)) { + return false; } } } - return transformedRules; + return true; } /** - * This method removes literals from rule bodies, that are already facts (when positive) + * This method checks for literals from rule bodies, that are already facts (when positive) * or not derivable (when negated). * implements s10 */ - private List simplifyRules (List rules, List facts) { - Iterator ruleIterator = rules.iterator(); - List transformedRules = new ArrayList<>(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - Iterator literalIterator = rule.getBody().iterator(); - - while(literalIterator.hasNext()) { - Literal literal = literalIterator.next(); - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - transformedRules.add(rule); - } - else transformedRules.add(rule.removeLiteral(literal)); - } - else { - if (!isDerivable(literal, rules)) { - transformedRules.add(rule.removeLiteral(literal)); - } - else transformedRules.add(rule); - } + private InternalRule checkForSimplifiableRule (List rules, InternalRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return null; + } else return rule.removeLiteral(literal); + } else { + if (!isDerivable(literal, rules)) { + return rule.removeLiteral(literal); + } else return null; } } - return transformedRules; + return null; } + + /** * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. * implements s5 conditions */ private boolean isDerivable(Literal literal, List rules){ - Iterator ruleIterator = rules.iterator(); - - while(ruleIterator.hasNext()) { - InternalRule rule = ruleIterator.next(); - if (Unification.unifyAtoms(literal.getAtom(),rule.getHeadAtom()) != null) { + for (InternalRule rule : rules) { + if (Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { return true; } } From 1f8c43b56c1bc7fcc721f1d31a8d71f2ae52872e Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 21 Dec 2021 16:22:13 +0100 Subject: [PATCH 41/56] merged with master branch and fixed merging problems --- .../kr/alpha/core/grounder/NaiveGrounder.java | 213 ++++++------- ...ultLazyGroundingInstantiationStrategy.java | 1 - .../transformation/SimplePreprocessing.java | 279 +++++++++--------- .../kr/alpha/core/rules/CompiledRule.java | 3 + .../kr/alpha/core/rules/InternalRule.java | 21 +- .../SimplePreprocessingTest.java | 19 ++ 6 files changed, 289 insertions(+), 247 deletions(-) create mode 100644 alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java 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 6dd46430c..2d9320abd 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 @@ -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. - * + * 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 @@ -25,54 +25,57 @@ * 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.grounder; - -import static at.ac.tuwien.kr.alpha.Util.oops; -import static at.ac.tuwien.kr.alpha.common.Literals.atomOf; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collection; -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.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import at.ac.tuwien.kr.alpha.Util; -import at.ac.tuwien.kr.alpha.common.AnswerSet; -import at.ac.tuwien.kr.alpha.common.Assignment; -import at.ac.tuwien.kr.alpha.common.AtomStore; -import at.ac.tuwien.kr.alpha.common.BasicAnswerSet; -import at.ac.tuwien.kr.alpha.common.IntIterator; -import at.ac.tuwien.kr.alpha.common.NoGood; -import at.ac.tuwien.kr.alpha.common.NoGoodInterface; -import at.ac.tuwien.kr.alpha.common.Predicate; -import at.ac.tuwien.kr.alpha.common.atoms.Atom; -import at.ac.tuwien.kr.alpha.common.atoms.BasicAtom; -import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.InternalProgram; -import at.ac.tuwien.kr.alpha.common.rule.InternalRule; -import at.ac.tuwien.kr.alpha.common.terms.VariableTerm; -import at.ac.tuwien.kr.alpha.grounder.atoms.ChoiceAtom; -import at.ac.tuwien.kr.alpha.grounder.atoms.RuleAtom; -import at.ac.tuwien.kr.alpha.grounder.bridges.Bridge; -import at.ac.tuwien.kr.alpha.grounder.heuristics.GrounderHeuristicsConfiguration; -import at.ac.tuwien.kr.alpha.grounder.instantiation.AssignmentStatus; -import at.ac.tuwien.kr.alpha.grounder.instantiation.BindingResult; -import at.ac.tuwien.kr.alpha.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; -import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiationResult; -import at.ac.tuwien.kr.alpha.grounder.instantiation.LiteralInstantiator; -import at.ac.tuwien.kr.alpha.grounder.structure.AnalyzeUnjustified; + package at.ac.tuwien.kr.alpha.core.grounder; + + import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; + import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; + + import java.util.ArrayList; + import java.util.Collection; + 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.Set; + import java.util.SortedSet; + import java.util.TreeSet; + + import org.apache.commons.lang3.tuple.ImmutablePair; + import org.apache.commons.lang3.tuple.Pair; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + + import at.ac.tuwien.kr.alpha.api.AnswerSet; + import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; + import at.ac.tuwien.kr.alpha.api.grounder.Substitution; + import at.ac.tuwien.kr.alpha.api.programs.Predicate; + import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; + import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; + import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; + import at.ac.tuwien.kr.alpha.commons.AnswerSets; + import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; + import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; + import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; + import at.ac.tuwien.kr.alpha.commons.util.Util; + import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; + import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; + import at.ac.tuwien.kr.alpha.core.common.Assignment; + import at.ac.tuwien.kr.alpha.core.common.AtomStore; + import at.ac.tuwien.kr.alpha.core.common.IntIterator; + import at.ac.tuwien.kr.alpha.core.common.NoGood; + import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; + import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; + import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; + import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; + import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; + import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; /** * A semi-naive grounder. @@ -87,14 +90,14 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final NogoodRegistry registry = new NogoodRegistry(); final NoGoodGenerator noGoodGenerator; private final ChoiceRecorder choiceRecorder; - private final InternalProgram program; + private final CompiledProgram program; private final AnalyzeUnjustified analyzeUnjustified; private final Map> factsFromProgram; private final Map> rulesUsingPredicateWorkingMemory = new HashMap<>(); - private final Map knownNonGroundRules; + private final Map knownNonGroundRules; - private ArrayList fixedRules = new ArrayList<>(); + private ArrayList fixedRules = new ArrayList<>(); private LinkedHashSet removeAfterObtainingNewNoGoods = new LinkedHashSet<>(); private final boolean debugInternalChecks; @@ -105,17 +108,17 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr private final LiteralInstantiator ruleInstantiator; private final DefaultLazyGroundingInstantiationStrategy instantiationStrategy; - public NaiveGrounder(InternalProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { + public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(InternalProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, - Bridge... bridges) { + private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, + Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(InternalProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, + GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; @@ -130,7 +133,7 @@ private NaiveGrounder(InternalProgram program, AtomStore atomStore, GrounderHeur this.initializeFactsAndRules(); - final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); + final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead(); choiceRecorder = new ChoiceRecorder(atomStore); noGoodGenerator = new NoGoodGenerator(atomStore, choiceRecorder, factsFromProgram, this.program, uniqueGroundRulePerGroundHead); @@ -159,7 +162,7 @@ private void initializeFactsAndRules() { workingMemory.initialize(ChoiceAtom.ON); // Initialize rules and constraints in working memory. - for (InternalRule nonGroundRule : program.getRulesById().values()) { + for (CompiledRule nonGroundRule : program.getRulesById().values()) { // Create working memories for all predicates occurring in the rule. for (Predicate predicate : nonGroundRule.getOccurringPredicates()) { // FIXME: this also contains interval/builtin predicates that are not needed. @@ -167,30 +170,30 @@ private void initializeFactsAndRules() { } // If the rule has fixed ground instantiations, it is not registered but grounded once like facts. - if (nonGroundRule.getGroundingOrders().fixedInstantiation()) { + if (nonGroundRule.getGroundingInfo().hasFixedInstantiation()) { fixedRules.add(nonGroundRule); continue; } // Register each starting literal at the corresponding working memory. - for (Literal literal : nonGroundRule.getGroundingOrders().getStartingLiterals()) { + for (Literal literal : nonGroundRule.getGroundingInfo().getStartingLiterals()) { registerLiteralAtWorkingMemory(literal, nonGroundRule); } } } - private Set getRulesWithUniqueHead() { + private Set getRulesWithUniqueHead() { // FIXME: below optimisation (adding support nogoods if there is only one rule instantiation per unique atom over the interpretation) could // be done as a transformation (adding a non-ground constraint corresponding to the nogood that is generated by the grounder). // Record all unique rule heads. - final Set uniqueGroundRulePerGroundHead = new HashSet<>(); + final Set uniqueGroundRulePerGroundHead = new HashSet<>(); - for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { + for (Map.Entry> headDefiningRules : program.getPredicateDefiningRules().entrySet()) { if (headDefiningRules.getValue().size() != 1) { continue; } - InternalRule nonGroundRule = headDefiningRules.getValue().iterator().next(); + CompiledRule nonGroundRule = headDefiningRules.getValue().iterator().next(); // Check that all variables of the body also occur in the head (otherwise grounding is not unique). Atom headAtom = nonGroundRule.getHeadAtom(); @@ -218,10 +221,10 @@ private Set getRulesWithUniqueHead() { /** * Registers a starting literal of a NonGroundRule at its corresponding working memory. - * + * * @param nonGroundRule the rule in which the literal occurs. */ - private void registerLiteralAtWorkingMemory(Literal literal, InternalRule nonGroundRule) { + private void registerLiteralAtWorkingMemory(Literal literal, CompiledRule nonGroundRule) { if (literal.isNegated()) { throw new RuntimeException("Literal to register is negated. Should not happen."); } @@ -275,20 +278,20 @@ public AnswerSet assignmentToAnswerSet(Iterable trueAtoms) { predicateInstances.putIfAbsent(factPredicate, new TreeSet<>()); for (Instance factInstance : facts.getValue()) { SortedSet instances = predicateInstances.get(factPredicate); - instances.add(new BasicAtom(factPredicate, factInstance.terms)); + instances.add(Atoms.newBasicAtom(factPredicate, factInstance.terms)); } } if (knownPredicates.isEmpty()) { - return BasicAnswerSet.EMPTY; + return AnswerSets.EMPTY_SET; } - return new BasicAnswerSet(knownPredicates, predicateInstances); + return AnswerSets.newAnswerSet(knownPredicates, predicateInstances); } /** * Prepares facts of the input program for joining and derives all NoGoods representing ground rules. May only be called once. - * + * * @return */ protected HashMap bootstrap() { @@ -299,10 +302,10 @@ protected HashMap bootstrap() { workingMemory.addInstances(predicate, true, factsFromProgram.get(predicate)); } - for (InternalRule nonGroundRule : fixedRules) { + for (CompiledRule nonGroundRule : fixedRules) { // Generate NoGoods for all rules that have a fixed grounding. - RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingOrders().getFixedGroundingOrder(); - BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new Substitution(), null); + RuleGroundingOrder groundingOrder = nonGroundRule.getGroundingInfo().getFixedGroundingOrder(); + BindingResult bindingResult = getGroundInstantiations(nonGroundRule, groundingOrder, new BasicSubstitution(), null); groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), groundNogoods); } @@ -334,14 +337,14 @@ public Map getNoGoods(Assignment currentAssignment) { for (FirstBindingAtom firstBindingAtom : firstBindingAtoms) { // Use the recently added instances from the modified working memory to construct an initial substitution - InternalRule nonGroundRule = firstBindingAtom.rule; + CompiledRule nonGroundRule = firstBindingAtom.rule; // Generate substitutions from each recent instance. for (Instance instance : modifiedWorkingMemory.getRecentlyAddedInstances()) { // Check instance if it matches with the atom. - final Substitution unifier = Substitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, - Substitution.EMPTY_SUBSTITUTION); + final Substitution unifier = BasicSubstitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, + BasicSubstitution.EMPTY_SUBSTITUTION); if (unifier == null) { continue; @@ -349,7 +352,7 @@ public Map getNoGoods(Assignment currentAssignment) { final BindingResult bindingResult = getGroundInstantiations( nonGroundRule, - nonGroundRule.getGroundingOrders().orderStartingFrom(firstBindingAtom.startingLiteral), + nonGroundRule.getGroundingInfo().orderStartingFrom(firstBindingAtom.startingLiteral), unifier, currentAssignment); @@ -397,7 +400,7 @@ public Map getNoGoods(Assignment currentAssignment) { * @param substitutions the substitutions to be applied. * @param newNoGoods a set of nogoods to which newly generated nogoods will be added. */ - private void groundAndRegister(final InternalRule nonGroundRule, final List substitutions, final Map newNoGoods) { + private void groundAndRegister(final CompiledRule nonGroundRule, final List substitutions, final Map newNoGoods) { for (Substitution substitution : substitutions) { List generatedNoGoods = noGoodGenerator.generateNoGoodsFromGroundSubstitution(nonGroundRule, substitution); registry.register(generatedNoGoods, newNoGoods); @@ -411,7 +414,7 @@ public int register(NoGood noGood) { // Ideally, this method should be private. It's only visible because NaiveGrounderTest needs to access it. BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, - Assignment currentAssignment) { + Assignment currentAssignment) { int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint()); if (tolerance < 0) { tolerance = Integer.MAX_VALUE; @@ -435,13 +438,13 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou } /** - * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrder, int, int, int, Substitution)}. - * - * Takes an ImmutablePair of a {@link Substitution} and an accompanying {@link AssignmentStatus} and calls + * Helper method used by {@link NaiveGrounder#bindNextAtomInRule(RuleGroundingOrderImpl, int, int, int, BasicSubstitution)}. + * + * Takes an ImmutablePair of a {@link BasicSubstitution} and an accompanying {@link AssignmentStatus} and calls * bindNextAtomInRule for the next literal in the grounding order. * If the assignment status for the last bound literal was {@link AssignmentStatus#UNASSIGNED}, the remainingTolerance * parameter is decreased by 1. If the remaining tolerance drops below zero, this method returns an empty {@link BindingResult}. - * + * * @param groundingOrder * @param orderPosition * @param originalTolerance @@ -451,7 +454,7 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou * tolerance is less than zero. */ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - ImmutablePair lastLiteralBindingResult) { + ImmutablePair lastLiteralBindingResult) { Substitution substitution = lastLiteralBindingResult.left; AssignmentStatus lastBoundLiteralAssignmentStatus = lastLiteralBindingResult.right; switch (lastBoundLiteralAssignmentStatus) { @@ -475,13 +478,13 @@ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int ord } private BindingResult advanceAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { groundingOrder.considerUntilCurrentEnd(); return bindNextAtomInRule(groundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution); } private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { RuleGroundingOrder modifiedGroundingOrder = groundingOrder.pushBack(orderPosition); if (modifiedGroundingOrder == null) { return BindingResult.empty(); @@ -491,12 +494,12 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding //@formatter:off /** - * Computes ground substitutions for a literal based on a {@link RuleGroundingOrder} and a {@link Substitution}. - * + * Computes ground substitutions for a literal based on a {@link RuleGroundingOrderImpl} and a {@link BasicSubstitution}. + * * Computes ground substitutions for the literal at position orderPosition of groundingOrder * Actual substitutions are computed by this grounder's {@link LiteralInstantiator}. - * - * @param groundingOrder a {@link RuleGroundingOrder} representing the body literals of a rule in the + * + * @param groundingOrder a {@link RuleGroundingOrderImpl} representing the body literals of a rule in the * sequence in which the should be bound during grounding. * @param orderPosition the current position within groundingOrder, indicates which literal should be bound * @param originalTolerance the original tolerance of the used grounding heuristic @@ -506,7 +509,7 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding */ //@formatter:on private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition); if (currentLiteral == null) { LOGGER.trace("No more literals found in grounding order, therefore stopping binding!"); @@ -585,7 +588,7 @@ public void forgetAssignment(int[] atomIds) { } @Override - public InternalRule getNonGroundRule(Integer ruleId) { + public CompiledRule getNonGroundRule(Integer ruleId) { return knownNonGroundRules.get(ruleId); } @@ -617,8 +620,8 @@ public Set justifyAtom(int atomToJustify, Assignment currentAssignment) /** * Checks that every nogood not marked as {@link NoGoodInterface.Type#INTERNAL} contains only - * atoms which are not {@link Predicate#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). - * + * atoms which are not {@link PredicateImpl#isSolverInternal()} (except {@link RuleAtom}s, which are allowed). + * * @param newNoGoods */ private void checkTypesOfNoGoods(Collection newNoGoods) { @@ -635,13 +638,13 @@ private void checkTypesOfNoGoods(Collection newNoGoods) { } private static class FirstBindingAtom { - final InternalRule rule; + final CompiledRule rule; final Literal startingLiteral; - FirstBindingAtom(InternalRule rule, Literal startingLiteral) { + FirstBindingAtom(CompiledRule rule, Literal startingLiteral) { this.rule = rule; this.startingLiteral = startingLiteral; } } -} +} \ No newline at end of file diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java index 621e4616b..e54f9d627 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java @@ -37,7 +37,6 @@ import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.grounder.IndexedInstanceStorage; -import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; import at.ac.tuwien.kr.alpha.core.grounder.WorkingMemory; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 3a705c9da..b8ce81cf9 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -1,14 +1,18 @@ -package at.ac.tuwien.kr.alpha.grounder.transformation; - -import at.ac.tuwien.kr.alpha.common.atoms.Atom; -import at.ac.tuwien.kr.alpha.common.atoms.Literal; -import at.ac.tuwien.kr.alpha.common.program.InternalProgram; -import at.ac.tuwien.kr.alpha.common.rule.InternalRule; -import at.ac.tuwien.kr.alpha.grounder.Unification; -import org.apache.poi.util.Internal; +package at.ac.tuwien.kr.alpha.core.programs.transformation; + +import at.ac.tuwien.kr.alpha.api.programs.Program; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.rules.Rule; +import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.core.grounder.Unification; +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.InputProgram; +import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -16,133 +20,132 @@ * Simplifies an internal input program by simplifying and deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation{ - - @Override - public InternalProgram apply(InternalProgram inputProgram) { - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - for (InternalRule rule : srcRules) { - boolean redundantRule = false; - - Atom headAtom = rule.getHead().getAtom(); - Set body = rule.getBody(); - Set positiveBody = rule.getPositiveBody(); - Set negativeBody = rule.getNegativeBody(); - InternalRule simplifiedRule = null; - - //implements s0: delete duplicate rules - if (transformedRules.contains(rule)) { //TODO: Add InternalRule.equals() - redundantRule = true; - } - //implemnts s2 - if (checkForConflictingBodyLiterals(positiveBody, negativeBody)) { - redundantRule = true; - } - //implements s3 - if (checkForHeadInBody(body, headAtom)) { - redundantRule = true; - } - //implements s9 - if(checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { - redundantRule = true; - } - //implements s10 - simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); - if(simplifiedRule != null) { - rule = simplifiedRule; - } - - if(!redundantRule) { - transformedRules.add(rule); - } - } - - return new InternalProgram(transformedRules, inputProgram.getFacts()); - } - - /** - * This method checks if a rule contains a literal in both the positive and the negative body. - * implements s2 - */ - private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - for (Literal positiveLiteral : positiveBody) { - if (negativeBody.contains(positiveLiteral.negate())) { - return true; - } - } - return false; - } - - /** - * This method checks if the head atom occurs in the rule's body. - * implements s3 - */ - private boolean checkForHeadInBody(Set body, Atom headAtom) { - for (Literal literal : body) { - //TODO: implement Atom.equals() - if (literal.getAtom().equals(headAtom)) { - return true; - } - } - return false; - } - - - /** - * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. - * implements s9 - */ - private boolean checkForUnreachableLiterals (List rules, InternalRule rule, List facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - return false; - } - } else { - if (isDerivable(literal, rules)) { - return false; - } - } - } - return true; - } - - - /** - * This method checks for literals from rule bodies, that are already facts (when positive) - * or not derivable (when negated). - * implements s10 - */ - private InternalRule checkForSimplifiableRule (List rules, InternalRule rule, List facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return null; - } else return rule.removeLiteral(literal); - } else { - if (!isDerivable(literal, rules)) { - return rule.removeLiteral(literal); - } else return null; - } - } - return null; - } - - - - - /** - * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. - * implements s5 conditions - */ - private boolean isDerivable(Literal literal, List rules){ - for (InternalRule rule : rules) { - if (Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { - return true; - } - } - return false; - } +public class SimplePreprocessing extends ProgramTransformation { + + @Override + public CompiledProgram apply(CompiledProgram inputProgram) { + List srcRules = new ArrayList<>(inputProgram.getRules()); + List transformedRules = new ArrayList<>(); + + for (CompiledRule rule : srcRules) { + boolean redundantRule = false; + + Atom headAtom = rule.getHead().getAtom(); + Set body = rule.getBody(); + Set positiveBody = rule.getPositiveBody(); + Set negativeBody = rule.getNegativeBody(); + CompiledRule simplifiedRule = null; + + //implements s0: delete duplicate rules + if (transformedRules.contains(rule)) { + redundantRule = true; + } + //implements s2 + if (!redundantRule && checkForConflictingBodyLiterals(positiveBody, negativeBody)) { + redundantRule = true; + } + //implements s3 + if (!redundantRule && checkForHeadInBody(body, headAtom)) { + redundantRule = true; + } + //implements s9 + if (!redundantRule && checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { + redundantRule = true; + } + //implements s10 + simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); + if (simplifiedRule != null) { + rule = simplifiedRule; + } + + if(!redundantRule) { + transformedRules.add(rule); + } + } + + if(inputProgram.getClass() == InternalProgram.class) { + return new InternalProgram(transformedRules, inputProgram.getFacts()); + } + else { + return new AnalyzedProgram(transformedRules, inputProgram.getFacts()); + } + } + + /** + * This method checks if a rule contains a literal in both the positive and the negative body. + * implements s2 + */ + private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { + for (Literal positiveLiteral : positiveBody) { + if (negativeBody.contains(positiveLiteral.negate())) { + return true; + } + } + return false; + } + + /** + * This method checks if the head atom occurs in the rule's body. + * implements s3 + */ + private boolean checkForHeadInBody(Set body, Atom headAtom) { + for (Literal literal : body) { + if (literal.getAtom().equals(headAtom)) { + return true; + } + } + return false; + } + + /** + * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. + * implements s9 + */ + private boolean checkForUnreachableLiterals (List rules, CompiledRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (!facts.contains(literal.getAtom())) { + return false; + } + } else { + if (isDerivable(literal, rules)) { + return false; + } + } + } + return true; + } + + /** + * This method checks for literals from rule bodies, that are already facts (when positive) + * or not derivable (when negated). + * implements s10 + */ + private CompiledRule checkForSimplifiableRule (List rules, CompiledRule rule, List facts) { + for (Literal literal : rule.getBody()) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return null; + } else return rule.returnCopyWithoutLiteral(literal); + } else { + if (!isDerivable(literal, rules)) { + return rule.returnCopyWithoutLiteral(literal); + } else return null; + } + } + return null; + } + + /** + * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * implements s5 conditions + */ + private boolean isDerivable(Literal literal, List rules){ + for (Rule rule : rules) { + if (Unification.unifyAtoms(literal.getAtom(), rule.getHead().getAtom()) != null) { + return true; + } + } + return false; + } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java index b15dfbc41..754e0fe3d 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java @@ -3,6 +3,7 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfo; @@ -17,4 +18,6 @@ public interface CompiledRule extends NormalRule { CompiledRule renameVariables(String str); boolean isGround(); + + CompiledRule returnCopyWithoutLiteral(Literal literal); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index aaa15c5fa..70c05b5e1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -29,7 +29,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import com.google.common.annotations.VisibleForTesting; import at.ac.tuwien.kr.alpha.api.programs.Predicate; @@ -143,15 +145,28 @@ public int getRuleId() { return this.ruleId; } - public InternalRule removeLiteral(Literal literal) { - Atom headAtom = this.getHeadAtom(); + public InternalRule returnCopyWithoutLiteral(Literal literal) { + BasicAtom headAtom = this.getHeadAtom(); List newBody = new ArrayList<>(this.getBody().size()); for (Literal bodyLiteral : this.getBody()) { if(!literal.equals(bodyLiteral)) { newBody.add(bodyLiteral); } } - return new InternalRule(new NormalHead(headAtom), newBody); + return new InternalRule(Heads.newNormalHead(headAtom), newBody); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InternalRule that = (InternalRule) o; + + return Objects.equals(occurringPredicates, that.occurringPredicates); } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java new file mode 100644 index 000000000..c04f2e6b5 --- /dev/null +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -0,0 +1,19 @@ +package at.ac.tuwien.kr.alpha.core.programs.transformation; + +import at.ac.tuwien.kr.alpha.api.config.SystemConfig; +import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +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 java.util.function.Function; + +public class SimplePreprocessingTest { + + private final ProgramParser parser = new ProgramParserImpl(); + private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + private final SimplePreprocessing evaluator = new SimplePreprocessing(); + private final Function parseAndEvaluate = (str) -> { + return evaluator.apply(AnalyzedProgram.analyzeNormalProgram(normalizer.apply(parser.parse(str)))); + }; +} From b8ee9db4ea234d7f87e6a3f38f33548df87fc461 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 18 Jan 2022 15:42:42 +0100 Subject: [PATCH 42/56] refactored and fixed bugs in SimplePreprocessing, added tests --- .../kr/alpha/core/grounder/NaiveGrounder.java | 12 +- .../kr/alpha/core/grounder/Unification.java | 8 +- .../transformation/SimplePreprocessing.java | 198 +++++++++++------- .../kr/alpha/core/rules/InternalRule.java | 25 +-- ...eralizedDependencyDrivenPyroHeuristic.java | 2 +- .../SimplePreprocessingTest.java | 88 +++++++- .../tuwien/kr/alpha/api/impl/AlphaImpl.java | 5 +- 7 files changed, 226 insertions(+), 112 deletions(-) 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 2d9320abd..299a80bfb 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 @@ -113,12 +113,12 @@ public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debug } private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, - Bridge... bridges) { + Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; @@ -414,7 +414,7 @@ public int register(NoGood noGood) { // Ideally, this method should be private. It's only visible because NaiveGrounderTest needs to access it. BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, - Assignment currentAssignment) { + Assignment currentAssignment) { int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint()); if (tolerance < 0) { tolerance = Integer.MAX_VALUE; @@ -454,7 +454,7 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou * tolerance is less than zero. */ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - ImmutablePair lastLiteralBindingResult) { + ImmutablePair lastLiteralBindingResult) { Substitution substitution = lastLiteralBindingResult.left; AssignmentStatus lastBoundLiteralAssignmentStatus = lastLiteralBindingResult.right; switch (lastBoundLiteralAssignmentStatus) { @@ -478,7 +478,7 @@ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int ord } private BindingResult advanceAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { groundingOrder.considerUntilCurrentEnd(); return bindNextAtomInRule(groundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution); } @@ -509,7 +509,7 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding */ //@formatter:on private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition); if (currentLiteral == null) { LOGGER.trace("No more literals found in grounding order, therefore stopping binding!"); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java index ab2647942..819890808 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/Unification.java @@ -65,10 +65,10 @@ public static Unifier instantiate(Atom general, Atom specific) { private static Unifier unifyAtoms(Atom left, Atom right, boolean keepLeftAsIs) { Set leftOccurringVariables = left.getOccurringVariables(); - Set rightOccurringVaribles = right.getOccurringVariables(); - boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVaribles.size(); - Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVaribles; - Set largerSet = leftSmaller ? rightOccurringVaribles : leftOccurringVariables; + Set rightOccurringVariables = right.getOccurringVariables(); + boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); + Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; + Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; for (VariableTerm variableTerm : smallerSet) { if (largerSet.contains(variableTerm)) { throw oops("Left and right atom share variables."); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index b8ce81cf9..5c216fb9f 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -1,79 +1,78 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import at.ac.tuwien.kr.alpha.api.programs.Program; +import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; -import at.ac.tuwien.kr.alpha.api.rules.Rule; -import at.ac.tuwien.kr.alpha.api.rules.heads.NormalHead; +import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; import at.ac.tuwien.kr.alpha.core.grounder.Unification; -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.InputProgram; -import at.ac.tuwien.kr.alpha.core.programs.InternalProgram; -import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; +import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; + +import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; /** * Simplifies an internal input program by simplifying and deleting redundant rules. */ -public class SimplePreprocessing extends ProgramTransformation { +public class SimplePreprocessing extends ProgramTransformation { @Override - public CompiledProgram apply(CompiledProgram inputProgram) { - List srcRules = new ArrayList<>(inputProgram.getRules()); - List transformedRules = new ArrayList<>(); - - for (CompiledRule rule : srcRules) { - boolean redundantRule = false; - - Atom headAtom = rule.getHead().getAtom(); - Set body = rule.getBody(); - Set positiveBody = rule.getPositiveBody(); - Set negativeBody = rule.getNegativeBody(); - CompiledRule simplifiedRule = null; - - //implements s0: delete duplicate rules - if (transformedRules.contains(rule)) { - redundantRule = true; - } - //implements s2 - if (!redundantRule && checkForConflictingBodyLiterals(positiveBody, negativeBody)) { - redundantRule = true; - } - //implements s3 - if (!redundantRule && checkForHeadInBody(body, headAtom)) { - redundantRule = true; - } - //implements s9 - if (!redundantRule && checkForUnreachableLiterals(srcRules, rule, inputProgram.getFacts())) { - redundantRule = true; + public NormalProgram apply(NormalProgram inputProgram) { + List srcRules = inputProgram.getRules(); + Set facts = new LinkedHashSet<>(inputProgram.getFacts()); + boolean modified = true; + while (modified) { + modified = false; + //implements s0 by using a Set (deleting duplicate rules) + Set newRules = new LinkedHashSet<>(); + for (NormalRule rule : srcRules) { + //s9 + if (checkForNonDerivableLiterals(rule, srcRules, facts)) { + continue; + } + //s10 + NormalRule simplifiedRule = simplifyRule(rule, srcRules, facts); + if (simplifiedRule == null) { + continue; + } + else if (simplifiedRule.getBody().isEmpty()) { + facts.add(simplifiedRule.getHeadAtom()); + modified = true; + continue; + } else { + if(!simplifiedRule.equals(rule)) { + modified = true; + rule = simplifiedRule; + } + } + newRules.add(rule); } - //implements s10 - simplifiedRule = checkForSimplifiableRule(srcRules, rule, inputProgram.getFacts()); - if (simplifiedRule != null) { - rule = simplifiedRule; + srcRules = new LinkedList<>(newRules); + } + Set newRules = new LinkedHashSet<>(); + for (NormalRule rule: srcRules) { + //s2 + if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { + continue; } - - if(!redundantRule) { - transformedRules.add(rule); + //s3 + if (checkForHeadInBody(rule.getBody(), rule.getHeadAtom())) { + continue; } + newRules.add(rule); } - - if(inputProgram.getClass() == InternalProgram.class) { - return new InternalProgram(transformedRules, inputProgram.getFacts()); - } - else { - return new AnalyzedProgram(transformedRules, inputProgram.getFacts()); - } + return new NormalProgramImpl(new LinkedList<>(newRules),new LinkedList<>(facts),inputProgram.getInlineDirectives()); } /** * This method checks if a rule contains a literal in both the positive and the negative body. * implements s2 + * @return true if the rule contains conflicting literals, false otherwise */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { for (Literal positiveLiteral : positiveBody) { @@ -87,6 +86,7 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { for (Literal literal : body) { @@ -98,54 +98,100 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { } /** - * This method checks for rules with bodies containing not derivable literals or negated literals, that are facts. + * This method checks rules for bodies containing non-derivable literals or negated literals, that are facts. * implements s9 + * @param rule the rule to check + * @param rules the rules from which the literals should be derivable from + * @param facts the facts from which the literals should be derivable from + * @return true if the rule is non-derivable, false if it is derivable */ - private boolean checkForUnreachableLiterals (List rules, CompiledRule rule, List facts) { + private boolean checkForNonDerivableLiterals(NormalRule rule, List rules, Set facts) { for (Literal literal : rule.getBody()) { if (literal.isNegated()) { - if (!facts.contains(literal.getAtom())) { - return false; + if (facts.contains(literal.getAtom())) { + return true; } } else { - if (isDerivable(literal, rules)) { - return false; + if (isNonDerivable(literal, rules)) { + return true; } } } - return true; + return false; } /** - * This method checks for literals from rule bodies, that are already facts (when positive) - * or not derivable (when negated). + * This method checks for literals from rule bodies, that are already facts or non-derivable. * implements s10 + * @param rule the rule to check + * @param rules the rules from which the literals should be derivable from + * @param facts the facts from which the literals should be derivable from + * @return the possibly shortened rule or null, if the rule is not derivable */ - private CompiledRule checkForSimplifiableRule (List rules, CompiledRule rule, List facts) { + private NormalRule simplifyRule(NormalRule rule, List rules, Set facts) { for (Literal literal : rule.getBody()) { if (literal.isNegated()) { if (facts.contains(literal.getAtom())) { return null; - } else return rule.returnCopyWithoutLiteral(literal); - } else { - if (!isDerivable(literal, rules)) { - return rule.returnCopyWithoutLiteral(literal); - } else return null; + } + else if (isNonDerivable(literal, rules)) { + return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); + } + } + else { + if (isNonDerivable(literal, rules)) { + return null; + } + else if (facts.contains(literal.getAtom())) { + return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); + } } } - return null; + return rule; } /** - * This method checks whether a literal is derivable, ie. it is unifiable with the head atom of a rule. + * This method checks whether a literal is non-derivable, i.e. it is not unifiable with the head atom of a rule. * implements s5 conditions + * @param literal the literal to check + * @param rules the rules from which the literal should be derivable from + * @return true if the literal is not derivable, false otherwise */ - private boolean isDerivable(Literal literal, List rules){ - for (Rule rule : rules) { - if (Unification.unifyAtoms(literal.getAtom(), rule.getHead().getAtom()) != null) { - return true; + private boolean isNonDerivable(Literal literal, List rules) { + for (NormalRule rule : rules) { + boolean hasSharedVariable = false; + Set leftOccurringVariables = literal.getAtom().getOccurringVariables(); + Set rightOccurringVariables = rule.getHeadAtom().getOccurringVariables(); + boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); + Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; + Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; + for (VariableTerm variableTerm : smallerSet) { + if (largerSet.contains(variableTerm)) { + hasSharedVariable = true; + break; + } + } + if (!hasSharedVariable) { + if(Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { + return false; + } } } - return false; + return true; + } + + /** + * Returns a copy of the rule with the specified literal removed + ** @return the rule without the specified literal + */ + private NormalRule removeLiteralFromRule(NormalRule rule, Literal literal) { + BasicAtom headAtom = rule.getHeadAtom(); + List newBody = new LinkedList<>(); + for (Literal bodyLiteral : rule.getBody()) { + if (!literal.equals(bodyLiteral)) { + newBody.add(bodyLiteral); + } + } + return new NormalRuleImpl(Heads.newNormalHead(headAtom), newBody); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index 70c05b5e1..38ca6b6f1 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -29,11 +29,8 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import com.google.common.annotations.VisibleForTesting; - import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; @@ -145,28 +142,22 @@ public int getRuleId() { return this.ruleId; } + /** + * Returns a copy of the rule with the specified literal removed, or null if the new rule would have an empty body. + * @return the rule without the specified literal, null if no body remains. + */ public InternalRule returnCopyWithoutLiteral(Literal literal) { BasicAtom headAtom = this.getHeadAtom(); List newBody = new ArrayList<>(this.getBody().size()); for (Literal bodyLiteral : this.getBody()) { - if(!literal.equals(bodyLiteral)) { + if (!literal.equals(bodyLiteral)) { newBody.add(bodyLiteral); } } - return new InternalRule(Heads.newNormalHead(headAtom), newBody); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; + if (newBody.isEmpty()) { + return null; } - InternalRule that = (InternalRule) o; - - return Objects.equals(occurringPredicates, that.occurringPredicates); + return new InternalRule(Heads.newNormalHead(headAtom), newBody); } } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java index 586dc3598..2fe6a59f8 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java @@ -45,7 +45,7 @@ public class GeneralizedDependencyDrivenPyroHeuristic extends GeneralizedDependencyDrivenHeuristic { public GeneralizedDependencyDrivenPyroHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random, - BodyActivityType bodyActivityType) { + BodyActivityType bodyActivityType) { super(assignment, choiceManager, decayPeriod, decayFactor, random, bodyActivityType); } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index c04f2e6b5..48b5e723c 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -1,19 +1,93 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; +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.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +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 org.junit.jupiter.api.Test; +import java.util.Set; import java.util.function.Function; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class SimplePreprocessingTest { - private final ProgramParser parser = new ProgramParserImpl(); - private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); - private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private final Function parseAndEvaluate = (str) -> { - return evaluator.apply(AnalyzedProgram.analyzeNormalProgram(normalizer.apply(parser.parse(str)))); - }; + private final ProgramParser parser = new ProgramParserImpl(); + private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); + private final SimplePreprocessing evaluator = new SimplePreprocessing(); + private final Function parseAndEvaluate = (str) -> { + return evaluator.apply(normalizer.apply(parser.parse(str))); + }; + + 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(); + }; + + @Test + public void testDuplicateRules() { + String aspStr1 = "a :- b. a :- b. b."; + String aspStr2 = "a :- b. b."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + @Test + public void testConflictingBodyLiterals() { + String aspStr1 = "a :- b, not b. b :- c."; + String aspStr2 = " b :- c."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + @Test + public void testHeadInBody() { + String aspStr1 = "a :- a, not b. b :- c."; + String aspStr2 = " b :- c."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + //@Test + public void testNonDerivableLiterals() { + String aspStr1 = "a :- not b. b :- c. d. e :- not d."; + String aspStr2 = "a :- not b. d."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + //@Test + public void testSimplifiedRules() { + String aspStr1 = "a :- b, not c. b. c :- not a. e :- a, not d."; + String aspStr2 = "a :- not c. b. c :- not a."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } + + @Test + public void testNonGroundProgram() { + String aspStr1 = "r(X) :- q(Y), not p(Y). q(Y). p(Y) :- not r(X). s(b) :- r(a), not t(d)."; + String aspStr2 = "r(X) :- not p(Y). q(Y). p(Y) :- not r(X)."; + NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); + NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); + assertEquals(evaluated1.getRules(), evaluated2.getRules()); + } } 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 c49a5ca39..e076348ec 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 @@ -39,6 +39,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import at.ac.tuwien.kr.alpha.core.programs.transformation.SimplePreprocessing; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -142,7 +143,9 @@ public NormalProgram normalizeProgram(ASPCore2Program program) { @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { LOGGER.debug("Preprocessing InternalProgram!"); - InternalProgram retVal = InternalProgram.fromNormalProgram(program); + SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); + NormalProgram simplePreprocessed = simplePreprocessing.apply(program); + InternalProgram retVal = InternalProgram.fromNormalProgram(simplePreprocessed); if (config.isEvaluateStratifiedPart()) { AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); retVal = new StratifiedEvaluation().apply(analyzed); From d6e4f49d6956876e76d55ea7209b6b9af8249fce Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 18 Jan 2022 16:12:20 +0100 Subject: [PATCH 43/56] refactored and fixed bugs in SimplePreprocessing, added tests --- .../programs/transformation/SimplePreprocessing.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 5c216fb9f..8fb9bbc0a 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -13,8 +13,6 @@ import java.util.*; -import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; - /** * Simplifies an internal input program by simplifying and deleting redundant rules. */ @@ -28,14 +26,10 @@ public NormalProgram apply(NormalProgram inputProgram) { boolean modified = true; while (modified) { modified = false; - //implements s0 by using a Set (deleting duplicate rules) + //implements s0 by using a Set (delete duplicate rules) Set newRules = new LinkedHashSet<>(); for (NormalRule rule : srcRules) { - //s9 - if (checkForNonDerivableLiterals(rule, srcRules, facts)) { - continue; - } - //s10 + //s9 + s10 NormalRule simplifiedRule = simplifyRule(rule, srcRules, facts); if (simplifiedRule == null) { continue; From aff3346dfb66a0d2ba1facfa4f28455be357a2aa Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 25 Jan 2022 15:00:41 +0100 Subject: [PATCH 44/56] fixed bugs in SimplePreprocessing, added tests --- .../transformation/SimplePreprocessing.java | 183 ++++++++++-------- .../SimplePreprocessingTest.java | 159 +++++++++++---- 2 files changed, 225 insertions(+), 117 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 8fb9bbc0a..7e3ee4a71 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -22,33 +22,10 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = inputProgram.getRules(); - Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - boolean modified = true; - while (modified) { - modified = false; - //implements s0 by using a Set (delete duplicate rules) - Set newRules = new LinkedHashSet<>(); - for (NormalRule rule : srcRules) { - //s9 + s10 - NormalRule simplifiedRule = simplifyRule(rule, srcRules, facts); - if (simplifiedRule == null) { - continue; - } - else if (simplifiedRule.getBody().isEmpty()) { - facts.add(simplifiedRule.getHeadAtom()); - modified = true; - continue; - } else { - if(!simplifiedRule.equals(rule)) { - modified = true; - rule = simplifiedRule; - } - } - newRules.add(rule); - } - srcRules = new LinkedList<>(newRules); - } + //Implements s0 by using a Set (delete duplicate rules). Set newRules = new LinkedHashSet<>(); + Set facts = new LinkedHashSet<>(inputProgram.getFacts()); + boolean canBeModified = true; for (NormalRule rule: srcRules) { //s2 if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { @@ -60,7 +37,55 @@ else if (simplifiedRule.getBody().isEmpty()) { } newRules.add(rule); } - return new NormalProgramImpl(new LinkedList<>(newRules),new LinkedList<>(facts),inputProgram.getInlineDirectives()); + srcRules = new LinkedList<>(newRules); + //s9 + s10 + while (canBeModified) { + newRules = new LinkedHashSet<>(); + canBeModified = false; + for (NormalRule rule : srcRules) { + SimpleReturn simpleReturn = simplifyRule(rule, srcRules, facts); + if (simpleReturn != null) { + if (simpleReturn == SimpleReturn.NO_FIRE) { + canBeModified = true; + } else if (simpleReturn.isFact()) { + facts.add(simpleReturn.getRule().getHeadAtom()); + canBeModified = true; + } else if (simpleReturn.isModified()) { + newRules.add(simpleReturn.getRule()); + canBeModified = true; + } else { + newRules.add(rule); + } + } + } + srcRules = new LinkedList<>(newRules); + } + return new NormalProgramImpl(new LinkedList<>(newRules), new LinkedList<>(facts), inputProgram.getInlineDirectives()); + } + + private static class SimpleReturn { + public final static SimpleReturn NO_FIRE = new SimpleReturn(null, false, false); + private final NormalRule rule; + private final boolean isModified; + private final boolean isFact; + + public SimpleReturn(NormalRule rule, boolean isModified, boolean isFact) { + this.rule = rule; + this.isModified = isModified; + this.isFact = isFact; + } + + public NormalRule getRule() { + return rule; + } + + public boolean isModified() { + return isModified; + } + + public boolean isFact() { + return isFact; + } } /** @@ -91,70 +116,54 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { return false; } - /** - * This method checks rules for bodies containing non-derivable literals or negated literals, that are facts. - * implements s9 - * @param rule the rule to check - * @param rules the rules from which the literals should be derivable from - * @param facts the facts from which the literals should be derivable from - * @return true if the rule is non-derivable, false if it is derivable - */ - private boolean checkForNonDerivableLiterals(NormalRule rule, List rules, Set facts) { - for (Literal literal : rule.getBody()) { - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return true; - } - } else { - if (isNonDerivable(literal, rules)) { - return true; - } - } - } - return false; - } - /** * This method checks for literals from rule bodies, that are already facts or non-derivable. - * implements s10 + * implements s9 + s10 * @param rule the rule to check * @param rules the rules from which the literals should be derivable from * @param facts the facts from which the literals should be derivable from - * @return the possibly shortened rule or null, if the rule is not derivable + * @return SimpleReturn containing the (possibly modified) rule, a boolean isModified and a boolean isFact. On + * non-derivable rules it returns the value NO_FIRE. */ - private NormalRule simplifyRule(NormalRule rule, List rules, Set facts) { + private SimpleReturn simplifyRule(NormalRule rule, List rules, Set facts) { + Set redundantLiterals = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { if (literal.isNegated()) { if (facts.contains(literal.getAtom())) { - return null; + return SimpleReturn.NO_FIRE; } - else if (isNonDerivable(literal, rules)) { - return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); - } - } - else { - if (isNonDerivable(literal, rules)) { - return null; + if (isNonDerivable(literal.getAtom(), rules, facts)) { + redundantLiterals.add(literal); } - else if (facts.contains(literal.getAtom())) { - return simplifyRule(removeLiteralFromRule(rule, literal), rules, facts); + } else { + if (facts.contains(literal.getAtom())) { + if (literal.isGround()) { //TODO: Safety Check + redundantLiterals.add(literal); + } + } else if (isNonDerivable(literal.getAtom(), rules, facts)) { + return SimpleReturn.NO_FIRE; } } } - return rule; + if (redundantLiterals.isEmpty()) { + return new SimpleReturn(rule, false, false); + } else { + return removeLiteralsFromRule(rule, redundantLiterals); + } } /** - * This method checks whether a literal is non-derivable, i.e. it is not unifiable with the head atom of a rule. + * This method checks whether an atom is non-derivable, i.e. it is not unifiable with the head atom of a rule. * implements s5 conditions - * @param literal the literal to check + * @param atom the atom to check * @param rules the rules from which the literal should be derivable from * @return true if the literal is not derivable, false otherwise */ - private boolean isNonDerivable(Literal literal, List rules) { + private boolean isNonDerivable(Atom atom, List rules, Set facts) { + boolean unclear = false; for (NormalRule rule : rules) { boolean hasSharedVariable = false; - Set leftOccurringVariables = literal.getAtom().getOccurringVariables(); + Set leftOccurringVariables = atom.getOccurringVariables(); Set rightOccurringVariables = rule.getHeadAtom().getOccurringVariables(); boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; @@ -162,30 +171,52 @@ private boolean isNonDerivable(Literal literal, List rules) { for (VariableTerm variableTerm : smallerSet) { if (largerSet.contains(variableTerm)) { hasSharedVariable = true; + unclear = true; + break; + } + } + if (!hasSharedVariable) { + if (Unification.instantiate(rule.getHeadAtom(), atom) != null) { + return false; + } + } + } + for (Atom fact : facts) { + boolean hasSharedVariable = false; + Set leftOccurringVariables = atom.getOccurringVariables(); + Set rightOccurringVariables = fact.getOccurringVariables(); + boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); + Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; + Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; + for (VariableTerm variableTerm : smallerSet) { + if (largerSet.contains(variableTerm)) { + hasSharedVariable = true; + unclear = true; break; } } if (!hasSharedVariable) { - if(Unification.unifyAtoms(literal.getAtom(), rule.getHeadAtom()) != null) { + if (Unification.instantiate(fact, atom) != null) { return false; } } } - return true; + return !unclear; } /** - * Returns a copy of the rule with the specified literal removed - ** @return the rule without the specified literal + * Returns a copy of the rule with the specified literals removed + ** @return the rule without the specified literals */ - private NormalRule removeLiteralFromRule(NormalRule rule, Literal literal) { + private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set literals) { BasicAtom headAtom = rule.getHeadAtom(); - List newBody = new LinkedList<>(); + Set newBody = new LinkedHashSet<>(); for (Literal bodyLiteral : rule.getBody()) { - if (!literal.equals(bodyLiteral)) { + if (!literals.contains(bodyLiteral)) { newBody.add(bodyLiteral); } } - return new NormalRuleImpl(Heads.newNormalHead(headAtom), newBody); + return new SimpleReturn(new NormalRuleImpl(Heads.newNormalHead(headAtom), new LinkedList<>(newBody)), + !literals.isEmpty(), newBody.isEmpty()); } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 48b5e723c..9d3b5c790 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -6,14 +6,15 @@ import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.api.rules.NormalRule; 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.solver.SolverFactory; +import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; import org.junit.jupiter.api.Test; import java.util.Set; @@ -26,10 +27,12 @@ public class SimplePreprocessingTest { private final ProgramParser parser = new ProgramParserImpl(); private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private final Function parseAndEvaluate = (str) -> { + private final Function parseAndNormalize = (str) -> { + return normalizer.apply(parser.parse(str)); + }; + private final Function parseAndPreprocess = (str) -> { return evaluator.apply(normalizer.apply(parser.parse(str))); }; - private final Function> solveCompiledProg = (prog) -> { AtomStore atomStore = new AtomStoreImpl(); Grounder grounder = GrounderFactory.getInstance("naive", prog, atomStore, false); @@ -38,56 +41,130 @@ public class SimplePreprocessingTest { }; @Test - public void testDuplicateRules() { - String aspStr1 = "a :- b. a :- b. b."; - String aspStr2 = "a :- b. b."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testDuplicateRuleRemoval() { + String aspStr1 = "a :- not b. a :- not b. b :- not a."; + String aspStr2 = "a :- not b. b :- not a."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } @Test - public void testConflictingBodyLiterals() { - String aspStr1 = "a :- b, not b. b :- c."; - String aspStr2 = " b :- c."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testConflictingRuleRemoval() { + String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; + String aspStr2 = " b :- not c. c :- not b."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } @Test - public void testHeadInBody() { - String aspStr1 = "a :- a, not b. b :- c."; - String aspStr2 = " b :- c."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testHeadInBodyRuleRemoval() { + String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; + String aspStr2 = " b :- not c. c :- not b."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } - //@Test - public void testNonDerivableLiterals() { - String aspStr1 = "a :- not b. b :- c. d. e :- not d."; - String aspStr2 = "a :- not b. d."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + @Test + public void testNoFireRuleRemoval() { + String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; + String aspStr2 = "a :- not b. b :- not a. d."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } - //@Test - public void testSimplifiedRules() { - String aspStr1 = "a :- b, not c. b. c :- not a. e :- a, not d."; + @Test + public void testAlwaysTrueLiteralRemoval() { + String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } @Test - public void testNonGroundProgram() { - String aspStr1 = "r(X) :- q(Y), not p(Y). q(Y). p(Y) :- not r(X). s(b) :- r(a), not t(d)."; - String aspStr2 = "r(X) :- not p(Y). q(Y). p(Y) :- not r(X)."; - NormalProgram evaluated1 = parseAndEvaluate.apply(aspStr1); - NormalProgram evaluated2 = parseAndEvaluate.apply(aspStr2); - assertEquals(evaluated1.getRules(), evaluated2.getRules()); + public void testNonDerivableLiteralRemovalNonGround() { + String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; + String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); + } + + @Test void testNonDerivableLiteralRemovalNonGround2() { + String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; + String aspStr2 = "p(X) :- q(X), not r(X). q(Y) :- p(Y). s(a)."; + //TODO: should be "p(X) :- q(X). q(Y) :- p(Y). s(a)." Need to rename Variables before Unification. + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); + } + + @Test void testRuleToFact() { + String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; + String aspStr2 = "r(c). q(a)."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); + } + + @Test void testAlwaysTrueLiteralRemovalNonGround() { + String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; + String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; + NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); + NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + assertEquals(evaluated2.getRules(), evaluated1.getRules()); + TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); + + NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); + Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); + Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); + TestUtils.assertAnswerSetsEqual(as1,as2); } -} +} \ No newline at end of file From c61ee71846c73121df4deb7a44b4ebef3d4ab72a Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Sat, 29 Jan 2022 02:36:54 +0100 Subject: [PATCH 45/56] fixed bug with constraints in SimplePreprocessing --- .../transformation/SimplePreprocessing.java | 85 +++++------- .../SimplePreprocessingTest.java | 127 +++++------------- 2 files changed, 66 insertions(+), 146 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 7e3ee4a71..a64eef826 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -5,12 +5,12 @@ import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; -import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; import at.ac.tuwien.kr.alpha.core.grounder.Unification; import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; +import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; import java.util.*; /** @@ -25,7 +25,7 @@ public NormalProgram apply(NormalProgram inputProgram) { //Implements s0 by using a Set (delete duplicate rules). Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - boolean canBeModified = true; + boolean canBePreprocessed = true; for (NormalRule rule: srcRules) { //s2 if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { @@ -39,20 +39,20 @@ public NormalProgram apply(NormalProgram inputProgram) { } srcRules = new LinkedList<>(newRules); //s9 + s10 - while (canBeModified) { + while (canBePreprocessed) { newRules = new LinkedHashSet<>(); - canBeModified = false; + canBePreprocessed = false; for (NormalRule rule : srcRules) { - SimpleReturn simpleReturn = simplifyRule(rule, srcRules, facts); - if (simpleReturn != null) { - if (simpleReturn == SimpleReturn.NO_FIRE) { - canBeModified = true; - } else if (simpleReturn.isFact()) { - facts.add(simpleReturn.getRule().getHeadAtom()); - canBeModified = true; - } else if (simpleReturn.isModified()) { - newRules.add(simpleReturn.getRule()); - canBeModified = true; + SimpleReturn simplifiedRule = simplifyRule(rule, srcRules, facts); + if (simplifiedRule != null) { + if (simplifiedRule == SimpleReturn.NO_FIRE) { + canBePreprocessed = true; + } else if (simplifiedRule.isFact()) { + facts.add(simplifiedRule.getRule().getHeadAtom()); + canBePreprocessed = true; + } else if (simplifiedRule.isModified()) { + newRules.add(simplifiedRule.getRule()); + canBePreprocessed = true; } else { newRules.add(rule); } @@ -128,6 +128,9 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { private SimpleReturn simplifyRule(NormalRule rule, List rules, Set facts) { Set redundantLiterals = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { + if (literal.toString().startsWith("&") || literal.toString().startsWith("not &")) { + continue; + } if (literal.isNegated()) { if (facts.contains(literal.getAtom())) { return SimpleReturn.NO_FIRE; @@ -137,9 +140,7 @@ private SimpleReturn simplifyRule(NormalRule rule, List rules, Set rules, Set rules, Set facts) { - boolean unclear = false; + Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { - boolean hasSharedVariable = false; - Set leftOccurringVariables = atom.getOccurringVariables(); - Set rightOccurringVariables = rule.getHeadAtom().getOccurringVariables(); - boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); - Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; - Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; - for (VariableTerm variableTerm : smallerSet) { - if (largerSet.contains(variableTerm)) { - hasSharedVariable = true; - unclear = true; - break; - } - } - if (!hasSharedVariable) { - if (Unification.instantiate(rule.getHeadAtom(), atom) != null) { + if (!rule.isConstraint()) { + if (Unification.unifyAtoms(rule.getHeadAtom(), tempAtom) != null) { return false; } } } - for (Atom fact : facts) { - boolean hasSharedVariable = false; - Set leftOccurringVariables = atom.getOccurringVariables(); - Set rightOccurringVariables = fact.getOccurringVariables(); - boolean leftSmaller = leftOccurringVariables.size() < rightOccurringVariables.size(); - Set smallerSet = leftSmaller ? leftOccurringVariables : rightOccurringVariables; - Set largerSet = leftSmaller ? rightOccurringVariables : leftOccurringVariables; - for (VariableTerm variableTerm : smallerSet) { - if (largerSet.contains(variableTerm)) { - hasSharedVariable = true; - unclear = true; - break; - } - } - if (!hasSharedVariable) { - if (Unification.instantiate(fact, atom) != null) { - return false; - } + Unifier uni; + for (Atom fact:facts) { + if ((uni = Unification.instantiate(tempAtom, fact)) != null) { + return false; } } - return !unclear; + return true; } /** @@ -216,7 +190,10 @@ private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set litera newBody.add(bodyLiteral); } } - return new SimpleReturn(new NormalRuleImpl(Heads.newNormalHead(headAtom), new LinkedList<>(newBody)), - !literals.isEmpty(), newBody.isEmpty()); + NormalRuleImpl newRule = new NormalRuleImpl(headAtom != null ? Heads.newNormalHead(headAtom) : null, new LinkedList<>(newBody)); + if (newRule.isConstraint() && newBody.isEmpty()) { + return SimpleReturn.NO_FIRE; + } + return new SimpleReturn(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); } } diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 9d3b5c790..3494481e2 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -1,24 +1,12 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -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.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; -import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; -import at.ac.tuwien.kr.alpha.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.solver.SolverFactory; -import at.ac.tuwien.kr.alpha.core.test.util.TestUtils; import org.junit.jupiter.api.Test; -import java.util.Set; -import java.util.function.Function; +import java.util.HashSet; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -27,144 +15,99 @@ public class SimplePreprocessingTest { private final ProgramParser parser = new ProgramParserImpl(); private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private final Function parseAndNormalize = (str) -> { + + private NormalProgram parseAndNormalize(String str) { return normalizer.apply(parser.parse(str)); - }; - private final Function parseAndPreprocess = (str) -> { + } + + private NormalProgram parseAndPreprocess(String str) { return evaluator.apply(normalizer.apply(parser.parse(str))); - }; - 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(); - }; + } @Test public void testDuplicateRuleRemoval() { String aspStr1 = "a :- not b. a :- not b. b :- not a."; String aspStr2 = "a :- not b. b :- not a."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testConflictingRuleRemoval() { String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testHeadInBodyRuleRemoval() { String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testNoFireRuleRemoval() { String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; String aspStr2 = "a :- not b. b :- not a. d."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testAlwaysTrueLiteralRemoval() { String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test void testNonDerivableLiteralRemovalNonGround2() { String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; - String aspStr2 = "p(X) :- q(X), not r(X). q(Y) :- p(Y). s(a)."; - //TODO: should be "p(X) :- q(X). q(Y) :- p(Y). s(a)." Need to rename Variables before Unification. - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + String aspStr2 = "p(X) :- q(X). q(Y) :- p(Y). s(a)."; + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test void testRuleToFact() { String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; String aspStr2 = "r(c). q(a)."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @Test void testAlwaysTrueLiteralRemovalNonGround() { String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; - NormalProgram evaluated1 = parseAndPreprocess.apply(aspStr1); - NormalProgram evaluated2 = parseAndNormalize.apply(aspStr2); + NormalProgram evaluated1 = parseAndPreprocess(aspStr1); + NormalProgram evaluated2 = parseAndNormalize(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); - TestUtils.assertFactsContainedInProgram(evaluated1, evaluated2.getFacts().toArray(new Atom[0])); - - NormalProgram evaluated3 = parseAndNormalize.apply(aspStr1); - Set as1 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated1)); - Set as2 = solveCompiledProg.apply(InternalProgram.fromNormalProgram(evaluated3)); - TestUtils.assertAnswerSetsEqual(as1,as2); + assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } } \ No newline at end of file From 97f23fc152e82b04817d37e2b11a9441fc6b80d9 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Sat, 29 Jan 2022 02:37:12 +0100 Subject: [PATCH 46/56] fixed bug with constraints in SimplePreprocessing --- .../core/programs/transformation/SimplePreprocessing.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index a64eef826..e1ff09c3b 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -169,9 +169,8 @@ private boolean isNonDerivable(Atom atom, List rules, Set fact } } } - Unifier uni; for (Atom fact:facts) { - if ((uni = Unification.instantiate(tempAtom, fact)) != null) { + if ((Unification.instantiate(tempAtom, fact)) != null) { return false; } } From 2e8f6c9e830006ff3f5e959dd1673ec9569dc803 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 1 Feb 2022 16:00:25 +0100 Subject: [PATCH 47/56] limited SimplePreprocessing to basic literals --- .../transformation/SimplePreprocessing.java | 117 ++++++++---------- 1 file changed, 49 insertions(+), 68 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index e1ff09c3b..3f5c81456 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -3,6 +3,7 @@ import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; +import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; @@ -10,11 +11,14 @@ import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; import at.ac.tuwien.kr.alpha.core.rules.NormalRuleImpl; -import at.ac.tuwien.kr.alpha.commons.substitutions.Unifier; import java.util.*; /** - * Simplifies an internal input program by simplifying and deleting redundant rules. + * Simplifies the input program by deleting redundant literals and rules, as well as adding rule heads that will + * always be true as facts. The approach is adopted from preprocessing techniques employed by traditional ground ASP + * solvers, as seen in: + * Gebser, M., Kaufmann, B., Neumann, A., & Schaub, T. (2008, June). Advanced Preprocessing for Answer Set Solving. + * In ECAI (Vol. 178, pp. 15-19). */ public class SimplePreprocessing extends ProgramTransformation { @@ -22,40 +26,34 @@ public class SimplePreprocessing extends ProgramTransformation srcRules = inputProgram.getRules(); - //Implements s0 by using a Set (delete duplicate rules). Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); boolean canBePreprocessed = true; for (NormalRule rule: srcRules) { - //s2 if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { continue; } - //s3 if (checkForHeadInBody(rule.getBody(), rule.getHeadAtom())) { continue; } newRules.add(rule); } srcRules = new LinkedList<>(newRules); - //s9 + s10 while (canBePreprocessed) { newRules = new LinkedHashSet<>(); canBePreprocessed = false; for (NormalRule rule : srcRules) { - SimpleReturn simplifiedRule = simplifyRule(rule, srcRules, facts); - if (simplifiedRule != null) { - if (simplifiedRule == SimpleReturn.NO_FIRE) { - canBePreprocessed = true; - } else if (simplifiedRule.isFact()) { - facts.add(simplifiedRule.getRule().getHeadAtom()); - canBePreprocessed = true; - } else if (simplifiedRule.isModified()) { - newRules.add(simplifiedRule.getRule()); - canBePreprocessed = true; - } else { - newRules.add(rule); - } + RuleEvaluation eval = evaluateRule(rule, srcRules, facts); + if (eval == RuleEvaluation.NO_FIRE) { + canBePreprocessed = true; + } else if (eval.isFact()) { + facts.add(eval.getRule().getHeadAtom()); + canBePreprocessed = true; + } else if (eval.isModified()) { + newRules.add(eval.getRule()); + canBePreprocessed = true; + } else { + newRules.add(rule); } } srcRules = new LinkedList<>(newRules); @@ -63,13 +61,13 @@ public NormalProgram apply(NormalProgram inputProgram) { return new NormalProgramImpl(new LinkedList<>(newRules), new LinkedList<>(facts), inputProgram.getInlineDirectives()); } - private static class SimpleReturn { - public final static SimpleReturn NO_FIRE = new SimpleReturn(null, false, false); + private static class RuleEvaluation { + public final static RuleEvaluation NO_FIRE = new RuleEvaluation(null, false, false); private final NormalRule rule; private final boolean isModified; private final boolean isFact; - public SimpleReturn(NormalRule rule, boolean isModified, boolean isFact) { + public RuleEvaluation(NormalRule rule, boolean isModified, boolean isFact) { this.rule = rule; this.isModified = isModified; this.isFact = isFact; @@ -88,11 +86,6 @@ public boolean isFact() { } } - /** - * This method checks if a rule contains a literal in both the positive and the negative body. - * implements s2 - * @return true if the rule contains conflicting literals, false otherwise - */ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { for (Literal positiveLiteral : positiveBody) { if (negativeBody.contains(positiveLiteral.negate())) { @@ -102,11 +95,6 @@ private boolean checkForConflictingBodyLiterals(Set positiveBody, Set body, Atom headAtom) { for (Literal literal : body) { if (literal.getAtom().equals(headAtom)) { @@ -117,49 +105,40 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { } /** - * This method checks for literals from rule bodies, that are already facts or non-derivable. - * implements s9 + s10 - * @param rule the rule to check - * @param rules the rules from which the literals should be derivable from - * @param facts the facts from which the literals should be derivable from - * @return SimpleReturn containing the (possibly modified) rule, a boolean isModified and a boolean isFact. On - * non-derivable rules it returns the value NO_FIRE. + * Evaluates and attempts to simplify a rule by looking for always-true and always-false literals. + * @param rule the rule to be evaluated. + * @param rules the rules from which literals could be derived from. + * @param facts the facts from which literals could be derived from. + * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was modified, + * is a fact or will never fire. */ - private SimpleReturn simplifyRule(NormalRule rule, List rules, Set facts) { + private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { Set redundantLiterals = new LinkedHashSet<>(); for (Literal literal : rule.getBody()) { - if (literal.toString().startsWith("&") || literal.toString().startsWith("not &")) { - continue; - } - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return SimpleReturn.NO_FIRE; - } - if (isNonDerivable(literal.getAtom(), rules, facts)) { - redundantLiterals.add(literal); - } - } else { - if (facts.contains(literal.getAtom())) { - redundantLiterals.add(literal); - } else if (isNonDerivable(literal.getAtom(), rules, facts)) { - return SimpleReturn.NO_FIRE; + if (literal instanceof BasicLiteral) { + if (literal.isNegated()) { + if (facts.contains(literal.getAtom())) { + return RuleEvaluation.NO_FIRE; + } + if (isNonDerivable(literal.getAtom(), rules, facts)) { + redundantLiterals.add(literal); + } + } else { + if (facts.contains(literal.getAtom())) { + redundantLiterals.add(literal); + } else if (isNonDerivable(literal.getAtom(), rules, facts)) { + return RuleEvaluation.NO_FIRE; + } } } } if (redundantLiterals.isEmpty()) { - return new SimpleReturn(rule, false, false); + return new RuleEvaluation(rule, false, false); } else { return removeLiteralsFromRule(rule, redundantLiterals); } } - /** - * This method checks whether an atom is non-derivable, i.e. it is not unifiable with the head atom of a rule. - * implements s5 conditions - * @param atom the atom to check - * @param rules the rules from which the literal should be derivable from - * @return true if the literal is not derivable, false otherwise - */ private boolean isNonDerivable(Atom atom, List rules, Set facts) { Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { @@ -178,10 +157,12 @@ private boolean isNonDerivable(Atom atom, List rules, Set fact } /** - * Returns a copy of the rule with the specified literals removed - ** @return the rule without the specified literals + * removes a set of given literals from the rule body. + * @param rule the rule from which literals should be removed. + * @param literals The literals to remove. + * @return the resulting rule or fact. */ - private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set literals) { + private RuleEvaluation removeLiteralsFromRule(NormalRule rule, Set literals) { BasicAtom headAtom = rule.getHeadAtom(); Set newBody = new LinkedHashSet<>(); for (Literal bodyLiteral : rule.getBody()) { @@ -191,8 +172,8 @@ private SimpleReturn removeLiteralsFromRule(NormalRule rule, Set litera } NormalRuleImpl newRule = new NormalRuleImpl(headAtom != null ? Heads.newNormalHead(headAtom) : null, new LinkedList<>(newBody)); if (newRule.isConstraint() && newBody.isEmpty()) { - return SimpleReturn.NO_FIRE; + return RuleEvaluation.NO_FIRE; } - return new SimpleReturn(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); + return new RuleEvaluation(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); } } From 0900fc05693f6688d0b7f6440f08730e6ccbf8b6 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 1 Feb 2022 17:54:35 +0100 Subject: [PATCH 48/56] added command line option for preprocessing --- .../ac/tuwien/kr/alpha/api/config/SystemConfig.java | 10 ++++++++++ .../kr/alpha/app/config/CommandLineParser.java | 13 +++++++++++-- .../at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java | 9 ++++++--- .../ac/tuwien/kr/alpha/api/impl/AlphaImplTest.java | 3 ++- 4 files changed, 29 insertions(+), 6 deletions(-) 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..f32750183 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 @@ -58,6 +58,7 @@ public class SystemConfig { 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_PREPROCESSING_ENABLED = 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; @@ -79,6 +80,7 @@ public class SystemConfig { private boolean sortAnswerSets = DEFAULT_SORT_ANSWER_SETS; private List replayChoices = DEFAULT_REPLAY_CHOICES; private boolean evaluateStratifiedPart = DEFAULT_STRATIFIED_EVALUATION; + private boolean enablePreprocessing = DEFAULT_PREPROCESSING_ENABLED; private boolean disableNoGoodDeletion = DEFAULT_DISABLE_NOGOOD_DELETION; private String grounderToleranceConstraints = DEFAULT_GROUNDER_TOLERANCE_CONSTRAINTS; private String grounderToleranceRules = DEFAULT_GROUNDER_TOLERANCE_RULES; @@ -232,6 +234,14 @@ public void setEvaluateStratifiedPart(boolean evaluateStratifiedPart) { this.evaluateStratifiedPart = evaluateStratifiedPart; } + public boolean isPreprocessingEnabled() { + return this.enablePreprocessing; + } + + public void setPreprocessingEnabled(boolean enablePreprocessing) { + this.enablePreprocessing = enablePreprocessing; + } + public boolean isDisableNoGoodDeletion() { return this.disableNoGoodDeletion; } 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 4b3ccf1f5..ea461dd57 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 @@ -149,6 +149,9 @@ public class CommandLineParser { .desc("a character (sequence) to use as separator for atoms in printed answer sets (default: " + SystemConfig.DEFAULT_ATOM_SEPARATOR + ")") .build(); + private static final Option OPT_DISABLE_PROGRAM_PREPROCESSING = Option.builder("dpp").longOpt("disableProgramPreprocessing") + .desc("disable preprocessing of input program") + .build(); //@formatter:on private static final Options CLI_OPTS = new Options(); @@ -189,6 +192,7 @@ public class CommandLineParser { CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_TOLERANCE_RULES); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_ACCUMULATOR_ENABLED); CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_OUTPUT_ATOM_SEPARATOR); + CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_DISABLE_PROGRAM_PREPROCESSING); } /* @@ -240,12 +244,13 @@ 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_EVAL_STRATIFIED.getOpt(), this::handleDisableStratifiedEval); 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); this.globalOptionHandlers.put(CommandLineParser.OPT_GROUNDER_ACCUMULATOR_ENABLED.getOpt(), this::handleGrounderNoInstanceRemoval); this.globalOptionHandlers.put(CommandLineParser.OPT_OUTPUT_ATOM_SEPARATOR.getOpt(), this::handleAtomSeparator); + this.globalOptionHandlers.put(CommandLineParser.OPT_DISABLE_PROGRAM_PREPROCESSING.getOpt(), this::handleDisablePreprocessing); } private void initializeInputOptionHandlers() { @@ -441,7 +446,7 @@ private void handleDisableNegativeSumElements(Option opt, SystemConfig cfg) { cfg.getAggregateRewritingConfig().setSupportNegativeValuesInSums(false); } - private void handleDisableStratifedEval(Option opt, SystemConfig cfg) { + private void handleDisableStratifiedEval(Option opt, SystemConfig cfg) { cfg.setEvaluateStratifiedPart(false); } @@ -470,5 +475,9 @@ private void handleGrounderNoInstanceRemoval(Option opt, SystemConfig cfg) { private void handleAtomSeparator(Option opt, SystemConfig cfg) { cfg.setAtomSeparator(StringEscapeUtils.unescapeJava(opt.getValue(SystemConfig.DEFAULT_ATOM_SEPARATOR))); } + + private void handleDisablePreprocessing(Option opt, SystemConfig cfg) { + cfg.setPreprocessingEnabled(false); + } } 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 e076348ec..056b6221a 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 @@ -142,10 +142,13 @@ public NormalProgram normalizeProgram(ASPCore2Program program) { @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { + InternalProgram retVal = InternalProgram.fromNormalProgram(program); + if (config.isPreprocessingEnabled()) { + SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); + NormalProgram simplePreprocessed = simplePreprocessing.apply(program); + retVal = InternalProgram.fromNormalProgram(simplePreprocessed); + } LOGGER.debug("Preprocessing InternalProgram!"); - SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); - NormalProgram simplePreprocessed = simplePreprocessing.apply(program); - InternalProgram retVal = InternalProgram.fromNormalProgram(simplePreprocessed); if (config.isEvaluateStratifiedPart()) { AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); retVal = new StratifiedEvaluation().apply(analyzed); 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 176862d40..0c51da218 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 @@ -618,6 +618,7 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE config.setDebugInternalChecks(true); config.setDisableJustificationSearch(false); config.setEvaluateStratifiedPart(false); + config.setPreprocessingEnabled(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 @@ -627,4 +628,4 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE assertTrue(answerSet.isPresent()); } -} +} \ No newline at end of file From 7310b0b5cb11939df7ddaaff26aa483802e2bc05 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 8 Feb 2022 16:11:06 +0100 Subject: [PATCH 49/56] added tests for command line option for preprocessing --- .../tuwien/kr/alpha/app/config/CommandLineParserTest.java | 7 +++++++ 1 file changed, 7 insertions(+) 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..52ac06c16 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 @@ -181,4 +181,11 @@ public void atomSeparator() throws ParseException { assertEquals("some-string", cfg.getSystemConfig().getAtomSeparator()); } + @Test + public void disableProgramPreprocessing() throws ParseException { + CommandLineParser parser = new CommandLineParser(DEFAULT_COMMAND_LINE, DEFAULT_ABORT_ACTION); + AlphaConfig ctx = parser.parseCommandLine(new String[]{"-str", "aString.", "-dpp"}); + assertFalse(ctx.getSystemConfig().isPreprocessingEnabled()); + } + } From e43d71762a4e35156bd620437aa311070c245079 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Mon, 14 Feb 2022 17:33:54 +0100 Subject: [PATCH 50/56] rebuilt tests to not depend on NormalizeProgramTransformation --- .../SimplePreprocessingTest.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 3494481e2..0d5693a45 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -1,9 +1,9 @@ package at.ac.tuwien.kr.alpha.core.programs.transformation; -import at.ac.tuwien.kr.alpha.api.config.SystemConfig; import at.ac.tuwien.kr.alpha.api.programs.NormalProgram; import at.ac.tuwien.kr.alpha.api.programs.ProgramParser; import at.ac.tuwien.kr.alpha.core.parser.ProgramParserImpl; +import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; import org.junit.jupiter.api.Test; import java.util.HashSet; @@ -13,15 +13,14 @@ public class SimplePreprocessingTest { private final ProgramParser parser = new ProgramParserImpl(); - private final NormalizeProgramTransformation normalizer = new NormalizeProgramTransformation(SystemConfig.DEFAULT_AGGREGATE_REWRITING_CONFIG); private final SimplePreprocessing evaluator = new SimplePreprocessing(); - private NormalProgram parseAndNormalize(String str) { - return normalizer.apply(parser.parse(str)); + private NormalProgram parse(String str) { + return NormalProgramImpl.fromInputProgram(parser.parse(str)); } private NormalProgram parseAndPreprocess(String str) { - return evaluator.apply(normalizer.apply(parser.parse(str))); + return evaluator.apply(NormalProgramImpl.fromInputProgram(parser.parse(str))); } @Test @@ -29,7 +28,7 @@ public void testDuplicateRuleRemoval() { String aspStr1 = "a :- not b. a :- not b. b :- not a."; String aspStr2 = "a :- not b. b :- not a."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -39,7 +38,7 @@ public void testConflictingRuleRemoval() { String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -49,7 +48,7 @@ public void testHeadInBodyRuleRemoval() { String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -59,7 +58,7 @@ public void testNoFireRuleRemoval() { String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; String aspStr2 = "a :- not b. b :- not a. d."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -69,7 +68,7 @@ public void testAlwaysTrueLiteralRemoval() { String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -79,7 +78,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -88,7 +87,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; String aspStr2 = "p(X) :- q(X). q(Y) :- p(Y). s(a)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -97,7 +96,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; String aspStr2 = "r(c). q(a)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } @@ -106,7 +105,7 @@ public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parseAndNormalize(aspStr2); + NormalProgram evaluated2 = parse(aspStr2); assertEquals(evaluated2.getRules(), evaluated1.getRules()); assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); } From 7e8ce92fe4ed4e72f9305e0beb026612fabc9904 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Mon, 14 Feb 2022 18:24:35 +0100 Subject: [PATCH 51/56] implemented removal of rules, that have heads that are already facts --- .../transformation/SimplePreprocessing.java | 7 +- .../SimplePreprocessingTest.java | 81 ++++++++++--------- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 3f5c81456..eeffab0f6 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -109,11 +109,14 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { * @param rule the rule to be evaluated. * @param rules the rules from which literals could be derived from. * @param facts the facts from which literals could be derived from. - * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was modified, - * is a fact or will never fire. + * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was + * modified, is a fact or will never fire. */ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { Set redundantLiterals = new LinkedHashSet<>(); + if (facts.contains(rule.getHeadAtom())) { + return RuleEvaluation.NO_FIRE; + } for (Literal literal : rule.getBody()) { if (literal instanceof BasicLiteral) { if (literal.isNegated()) { diff --git a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java index 0d5693a45..ccdbc4ec9 100644 --- a/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java +++ b/alpha-core/src/test/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessingTest.java @@ -27,86 +27,95 @@ private NormalProgram parseAndPreprocess(String str) { public void testDuplicateRuleRemoval() { String aspStr1 = "a :- not b. a :- not b. b :- not a."; String aspStr2 = "a :- not b. b :- not a."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testConflictingRuleRemoval() { String aspStr1 = "a :- b, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testHeadInBodyRuleRemoval() { String aspStr1 = "a :- a, not b. b :- not c. c :- not b."; String aspStr2 = " b :- not c. c :- not b."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testNoFireRuleRemoval() { String aspStr1 = "a :- not b. b :- not a. b :- c. d. e :- not d."; String aspStr2 = "a :- not b. b :- not a. d."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testAlwaysTrueLiteralRemoval() { String aspStr1 = "a :- b, not c. b. c :- not a."; String aspStr2 = "a :- not c. b. c :- not a."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test public void testNonDerivableLiteralRemovalNonGround() { String aspStr1 = "r(X) :- p(X), not q(c). p(a). u(Y) :- s(Y), not v(Y). s(b) :- p(a), not v(a). v(a) :- not u(b)."; String aspStr2 = "r(X) :- p(X). p(a). u(Y) :- s(Y), not v(Y). s(b) :- not v(a). v(a) :- not u(b)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test void testNonDerivableLiteralRemovalNonGround2() { String aspStr1 = "p(X) :- q(X), not r(X). q(Y) :- p(Y), s(a). s(a)."; String aspStr2 = "p(X) :- q(X). q(Y) :- p(Y). s(a)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test void testRuleToFact() { String aspStr1 = "r(c) :- q(a), not p(b). q(a)."; String aspStr2 = "r(c). q(a)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } @Test void testAlwaysTrueLiteralRemovalNonGround() { String aspStr1 = "r(X) :- t(X), s(b), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; String aspStr2 = "r(X) :- t(X), not q(a). s(b). t(X) :- r(X). q(a) :- not r(a)."; - NormalProgram evaluated1 = parseAndPreprocess(aspStr1); - NormalProgram evaluated2 = parse(aspStr2); - assertEquals(evaluated2.getRules(), evaluated1.getRules()); - assertEquals(new HashSet<>(evaluated2.getFacts()), new HashSet<>(evaluated1.getFacts())); + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); + } + + @Test void testHeadIsFactRuleRemoval() { + String aspStr1 = "r(a) :- not p(b). r(a). p(b) :- not q(c). q(c) :- not p(b)."; + String aspStr2 = " r(a). p(b) :- not q(c). q(c) :- not p(b)."; + NormalProgram preprocessedProgram = parseAndPreprocess(aspStr1); + NormalProgram parsedProgram = parse(aspStr2); + assertEquals(parsedProgram.getRules(), preprocessedProgram.getRules()); + assertEquals(new HashSet<>(parsedProgram.getFacts()), new HashSet<>(preprocessedProgram.getFacts())); } } \ No newline at end of file From 593748b3a086aa07741c6d1008c28080b5015755 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 15 Feb 2022 15:38:08 +0100 Subject: [PATCH 52/56] removed unnecessary changes --- .../kr/alpha/core/grounder/NaiveGrounder.java | 108 +++++++++--------- .../grounder/ProgramAnalyzingGrounder.java | 4 +- .../structure/AnalyzeUnjustified.java | 24 ++-- .../transformation/SimplePreprocessing.java | 4 +- .../kr/alpha/core/rules/CompiledRule.java | 2 - .../kr/alpha/core/rules/InternalRule.java | 19 +-- .../kr/alpha/api/impl/AlphaImplTest.java | 1 - 7 files changed, 69 insertions(+), 93 deletions(-) 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 299a80bfb..7c40e85c3 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 @@ -25,57 +25,57 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package at.ac.tuwien.kr.alpha.core.grounder; - - import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; - import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; - - import java.util.ArrayList; - import java.util.Collection; - 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.Set; - import java.util.SortedSet; - import java.util.TreeSet; - - import org.apache.commons.lang3.tuple.ImmutablePair; - import org.apache.commons.lang3.tuple.Pair; - import org.slf4j.Logger; - import org.slf4j.LoggerFactory; - - import at.ac.tuwien.kr.alpha.api.AnswerSet; - import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; - import at.ac.tuwien.kr.alpha.api.grounder.Substitution; - import at.ac.tuwien.kr.alpha.api.programs.Predicate; - import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; - import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; - import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; - import at.ac.tuwien.kr.alpha.commons.AnswerSets; - import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; - import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; - import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; - import at.ac.tuwien.kr.alpha.commons.util.Util; - import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; - import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; - import at.ac.tuwien.kr.alpha.core.common.Assignment; - import at.ac.tuwien.kr.alpha.core.common.AtomStore; - import at.ac.tuwien.kr.alpha.core.common.IntIterator; - import at.ac.tuwien.kr.alpha.core.common.NoGood; - import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; - import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; - import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; - import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; - import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; - import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; +package at.ac.tuwien.kr.alpha.core.grounder; + +import static at.ac.tuwien.kr.alpha.commons.util.Util.oops; +import static at.ac.tuwien.kr.alpha.core.atoms.Literals.atomOf; + +import java.util.ArrayList; +import java.util.Collection; +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.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.ac.tuwien.kr.alpha.api.AnswerSet; +import at.ac.tuwien.kr.alpha.api.config.GrounderHeuristicsConfiguration; +import at.ac.tuwien.kr.alpha.api.grounder.Substitution; +import at.ac.tuwien.kr.alpha.api.programs.Predicate; +import at.ac.tuwien.kr.alpha.api.programs.atoms.Atom; +import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; +import at.ac.tuwien.kr.alpha.api.terms.VariableTerm; +import at.ac.tuwien.kr.alpha.commons.AnswerSets; +import at.ac.tuwien.kr.alpha.commons.atoms.Atoms; +import at.ac.tuwien.kr.alpha.commons.substitutions.BasicSubstitution; +import at.ac.tuwien.kr.alpha.commons.substitutions.Instance; +import at.ac.tuwien.kr.alpha.commons.util.Util; +import at.ac.tuwien.kr.alpha.core.atoms.ChoiceAtom; +import at.ac.tuwien.kr.alpha.core.atoms.RuleAtom; +import at.ac.tuwien.kr.alpha.core.common.Assignment; +import at.ac.tuwien.kr.alpha.core.common.AtomStore; +import at.ac.tuwien.kr.alpha.core.common.IntIterator; +import at.ac.tuwien.kr.alpha.core.common.NoGood; +import at.ac.tuwien.kr.alpha.core.common.NoGoodInterface; +import at.ac.tuwien.kr.alpha.core.grounder.bridges.Bridge; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.AssignmentStatus; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.DefaultLazyGroundingInstantiationStrategy; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiationResult; +import at.ac.tuwien.kr.alpha.core.grounder.instantiation.LiteralInstantiator; +import at.ac.tuwien.kr.alpha.core.grounder.structure.AnalyzeUnjustified; +import at.ac.tuwien.kr.alpha.core.programs.CompiledProgram; +import at.ac.tuwien.kr.alpha.core.rules.CompiledRule; /** * A semi-naive grounder. @@ -112,13 +112,11 @@ public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debug this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, - Bridge... bridges) { + private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, - GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java index 12960995a..d64388123 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/ProgramAnalyzingGrounder.java @@ -15,10 +15,10 @@ public interface ProgramAnalyzingGrounder extends Grounder { /** * Justifies the absence of an atom, i.e., returns reasons why the atom is not TRUE given the assignment. * @param atomToJustify the atom to justify. - * @param assignment the current assignment. + * @param currentAssignment the current assignment. * @return a set of literals who jointly imply the atomToJustify not being TRUE. */ - Set justifyAtom(int atomToJustify, Assignment assignment); + Set justifyAtom(int atomToJustify, Assignment currentAssignment); /** * Returns true iff the given atom is known to the grounder as a fact (hence not occurring in any assignment). diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java index c04c9578c..cb12167db 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/structure/AnalyzeUnjustified.java @@ -54,7 +54,7 @@ public AnalyzeUnjustified(CompiledProgram programAnalysis, AtomStore atomStore, private Map> assignedAtoms; - public Set analyze(int atomToJustify, Assignment assignment) { + public Set analyze(int atomToJustify, Assignment currentAssignment) { padDepth = 0; Atom atom = atomStore.get(atomToJustify); if (!(atom instanceof BasicAtom)) { @@ -69,7 +69,7 @@ public Set analyze(int atomToJustify, Assignment assignment) { //@formatter:on assignedAtoms = new LinkedHashMap<>(); for (int i = 1; i <= atomStore.getMaxAtomId(); i++) { - ThriceTruth truth = assignment.getTruth(i); + ThriceTruth truth = currentAssignment.getTruth(i); if (truth == null) { continue; } @@ -77,11 +77,11 @@ public Set analyze(int atomToJustify, Assignment assignment) { assignedAtoms.putIfAbsent(assignedAtom.getPredicate(), new ArrayList<>()); assignedAtoms.get(assignedAtom.getPredicate()).add(assignedAtom); } - return analyze((BasicAtom) atom, assignment); + return analyze((BasicAtom) atom, currentAssignment); } - private Set analyze(BasicAtom atom, Assignment assignment) { - log(pad("Starting analyze, current assignment is: {}"), assignment); + private Set analyze(BasicAtom atom, Assignment currentAssignment) { + log(pad("Starting analyze, current assignment is: {}"), currentAssignment); LinkedHashSet vL = new LinkedHashSet<>(); LinkedHashSet vToDo = new LinkedHashSet<>(Collections.singleton(new LitSet(atom, new LinkedHashSet<>()))); LinkedHashSet vDone = new LinkedHashSet<>(); @@ -92,7 +92,7 @@ private Set analyze(BasicAtom atom, Assignment assignment) { log(""); log("Treating now: {}", x); vDone.add(x); - ReturnExplainUnjust unjustRet = explainUnjust(x, assignment); + ReturnExplainUnjust unjustRet = explainUnjust(x, currentAssignment); log("Additional ToDo: {}", unjustRet.vToDo); // Check each new LitSet if it does not already occur as done. for (LitSet todoLitSet : unjustRet.vToDo) { @@ -105,7 +105,7 @@ private Set analyze(BasicAtom atom, Assignment assignment) { return vL; } - private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { + private ReturnExplainUnjust explainUnjust(LitSet x, Assignment currentAssignment) { padDepth += 2; log("Begin explainUnjust(): {}", x); Atom p = x.getAtom(); @@ -151,7 +151,7 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { log("Considering: {}", lg); if (atomStore.contains(lg)) { int atomId = atomStore.get(lg); - if (!assignment.getTruth(atomId).toBoolean()) { + if (!currentAssignment.getTruth(atomId).toBoolean()) { log("{} is not assigned TRUE or MBT. Skipping.", lg); continue; } @@ -188,14 +188,14 @@ private ReturnExplainUnjust explainUnjust(LitSet x, Assignment assignment) { } } log("Calling UnjustCover() for positive body."); - ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, assignment)); + ret.vToDo.addAll(unjustCover(bodyPos, Collections.singleton(sigma), vNp, currentAssignment)); } log("End explainUnjust()."); padDepth -= 2; return ret; } - private Set unjustCover(List vB, Set vY, Set vN, Assignment assignment) { + private Set unjustCover(List vB, Set vY, Set vN, Assignment currentAssignment) { padDepth += 2; log("Begin UnjustCoverFixed()"); log("Finding unjustified body literals in: {} / {} excluded {}", vB, vY, vN); @@ -228,7 +228,7 @@ private Set unjustCover(List vB, Set vY, Set log("Checking atom: {}", atom); if (atomStore.contains(atom)) { int atomId = atomStore.get(atom); - if (assignment.getTruth(atomId) != ThriceTruth.TRUE) { + if (currentAssignment.getTruth(atomId) != ThriceTruth.TRUE) { log("Atom is not TRUE. Skipping."); continue; } @@ -274,7 +274,7 @@ private Set unjustCover(List vB, Set vY, Set } ArrayList newB = new ArrayList<>(vB); newB.remove(chosenLiteralPos); - ret.addAll(unjustCover(newB, vYp, vN, assignment)); + ret.addAll(unjustCover(newB, vYp, vN, currentAssignment)); log("Literal set(s) to treat: {}", ret); } log("End unjustCover()."); diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index eeffab0f6..7626f2580 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -17,10 +17,8 @@ * Simplifies the input program by deleting redundant literals and rules, as well as adding rule heads that will * always be true as facts. The approach is adopted from preprocessing techniques employed by traditional ground ASP * solvers, as seen in: - * Gebser, M., Kaufmann, B., Neumann, A., & Schaub, T. (2008, June). Advanced Preprocessing for Answer Set Solving. - * In ECAI (Vol. 178, pp. 15-19). + * @see doi:10.3233/978-1-58603-891-5-15 */ - public class SimplePreprocessing extends ProgramTransformation { @Override diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java index 754e0fe3d..bb489ea7e 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java @@ -3,7 +3,6 @@ import java.util.List; import at.ac.tuwien.kr.alpha.api.programs.Predicate; -import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; import at.ac.tuwien.kr.alpha.core.grounder.RuleGroundingInfo; @@ -19,5 +18,4 @@ public interface CompiledRule extends NormalRule { boolean isGround(); - CompiledRule returnCopyWithoutLiteral(Literal literal); } diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java index 38ca6b6f1..9a72fca12 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/InternalRule.java @@ -31,6 +31,7 @@ import java.util.List; import com.google.common.annotations.VisibleForTesting; + import at.ac.tuwien.kr.alpha.api.programs.Predicate; import at.ac.tuwien.kr.alpha.api.programs.atoms.BasicAtom; import at.ac.tuwien.kr.alpha.api.programs.literals.AggregateLiteral; @@ -142,22 +143,4 @@ public int getRuleId() { return this.ruleId; } - /** - * Returns a copy of the rule with the specified literal removed, or null if the new rule would have an empty body. - * @return the rule without the specified literal, null if no body remains. - */ - public InternalRule returnCopyWithoutLiteral(Literal literal) { - BasicAtom headAtom = this.getHeadAtom(); - List newBody = new ArrayList<>(this.getBody().size()); - for (Literal bodyLiteral : this.getBody()) { - if (!literal.equals(bodyLiteral)) { - newBody.add(bodyLiteral); - } - } - if (newBody.isEmpty()) { - return null; - } - return new InternalRule(Heads.newNormalHead(headAtom), newBody); - } - } 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 0c51da218..df3be414d 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 @@ -627,5 +627,4 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE Optional answerSet = alpha.solve(parsedProgram).findFirst(); assertTrue(answerSet.isPresent()); } - } \ No newline at end of file From c0abf4ce611bb9a9df8f37b02791ec5eab5a4863 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 15 Feb 2022 15:49:14 +0100 Subject: [PATCH 53/56] removed unnecessary changes --- .../kr/alpha/core/grounder/NaiveGrounder.java | 18 ++++++++++-------- ...aultLazyGroundingInstantiationStrategy.java | 1 + .../kr/alpha/core/rules/CompiledRule.java | 1 - ...neralizedDependencyDrivenPyroHeuristic.java | 2 +- .../ac/tuwien/kr/alpha/api/impl/AlphaImpl.java | 2 +- .../kr/alpha/api/impl/AlphaImplTest.java | 3 ++- 6 files changed, 15 insertions(+), 12 deletions(-) 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 7c40e85c3..1b8483a0d 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 @@ -112,11 +112,13 @@ public NaiveGrounder(CompiledProgram program, AtomStore atomStore, boolean debug this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges); } - private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + private NaiveGrounder(CompiledProgram program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, + Bridge... bridges) { this(program, atomStore, p -> true, heuristicsConfiguration, debugInternalChecks, bridges); } - NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { + NaiveGrounder(CompiledProgram program, AtomStore atomStore, java.util.function.Predicate filter, + GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) { super(filter, bridges); this.atomStore = atomStore; this.heuristicsConfiguration = heuristicsConfiguration; @@ -412,7 +414,7 @@ public int register(NoGood noGood) { // Ideally, this method should be private. It's only visible because NaiveGrounderTest needs to access it. BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, - Assignment currentAssignment) { + Assignment currentAssignment) { int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint()); if (tolerance < 0) { tolerance = Integer.MAX_VALUE; @@ -452,7 +454,7 @@ BindingResult getGroundInstantiations(CompiledRule rule, RuleGroundingOrder grou * tolerance is less than zero. */ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - ImmutablePair lastLiteralBindingResult) { + ImmutablePair lastLiteralBindingResult) { Substitution substitution = lastLiteralBindingResult.left; AssignmentStatus lastBoundLiteralAssignmentStatus = lastLiteralBindingResult.right; switch (lastBoundLiteralAssignmentStatus) { @@ -476,13 +478,13 @@ private BindingResult continueBinding(RuleGroundingOrder groundingOrder, int ord } private BindingResult advanceAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { groundingOrder.considerUntilCurrentEnd(); return bindNextAtomInRule(groundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution); } private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { RuleGroundingOrder modifiedGroundingOrder = groundingOrder.pushBack(orderPosition); if (modifiedGroundingOrder == null) { return BindingResult.empty(); @@ -507,7 +509,7 @@ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder grounding */ //@formatter:on private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, - Substitution partialSubstitution) { + Substitution partialSubstitution) { Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition); if (currentLiteral == null) { LOGGER.trace("No more literals found in grounding order, therefore stopping binding!"); @@ -645,4 +647,4 @@ private static class FirstBindingAtom { } } -} \ No newline at end of file +} diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java index e54f9d627..621e4616b 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/grounder/instantiation/DefaultLazyGroundingInstantiationStrategy.java @@ -37,6 +37,7 @@ import at.ac.tuwien.kr.alpha.core.common.Assignment; import at.ac.tuwien.kr.alpha.core.common.AtomStore; import at.ac.tuwien.kr.alpha.core.grounder.IndexedInstanceStorage; +import at.ac.tuwien.kr.alpha.core.grounder.NaiveGrounder; import at.ac.tuwien.kr.alpha.core.grounder.WorkingMemory; import at.ac.tuwien.kr.alpha.core.solver.ThriceTruth; diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java index bb489ea7e..b15dfbc41 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/rules/CompiledRule.java @@ -17,5 +17,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/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java index 2fe6a59f8..f4c8e71f7 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/solver/heuristics/GeneralizedDependencyDrivenPyroHeuristic.java @@ -45,7 +45,7 @@ public class GeneralizedDependencyDrivenPyroHeuristic extends GeneralizedDependencyDrivenHeuristic { public GeneralizedDependencyDrivenPyroHeuristic(Assignment assignment, ChoiceManager choiceManager, int decayPeriod, double decayFactor, Random random, - BodyActivityType bodyActivityType) { + BodyActivityType bodyActivityType) { super(assignment, choiceManager, decayPeriod, decayFactor, random, bodyActivityType); } 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 056b6221a..70e9d69b0 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 @@ -39,7 +39,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import at.ac.tuwien.kr.alpha.core.programs.transformation.SimplePreprocessing; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,6 +71,7 @@ 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.programs.transformation.SimplePreprocessing; import at.ac.tuwien.kr.alpha.core.solver.SolverFactory; public class AlphaImpl implements Alpha { 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 df3be414d..1d73948c1 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 @@ -627,4 +627,5 @@ public void testLearnedUnaryNoGoodCausingOutOfOrderLiteralsConflict() throws IOE Optional answerSet = alpha.solve(parsedProgram).findFirst(); assertTrue(answerSet.isPresent()); } -} \ No newline at end of file + +} From d5e959f745cc49c2fcbd39c055763e7ac67d484e Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 22 Mar 2022 15:47:51 +0100 Subject: [PATCH 54/56] added comments --- .../src/main/java/at/ac/tuwien/kr/alpha/api/impl/AlphaImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 70e9d69b0..aaf619131 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 @@ -142,13 +142,13 @@ public NormalProgram normalizeProgram(ASPCore2Program program) { @VisibleForTesting InternalProgram performProgramPreprocessing(NormalProgram program) { + LOGGER.debug("Performing program preprocessing!"); InternalProgram retVal = InternalProgram.fromNormalProgram(program); if (config.isPreprocessingEnabled()) { SimplePreprocessing simplePreprocessing = new SimplePreprocessing(); NormalProgram simplePreprocessed = simplePreprocessing.apply(program); retVal = InternalProgram.fromNormalProgram(simplePreprocessed); } - LOGGER.debug("Preprocessing InternalProgram!"); if (config.isEvaluateStratifiedPart()) { AnalyzedProgram analyzed = new AnalyzedProgram(retVal.getRules(), retVal.getFacts()); retVal = new StratifiedEvaluation().apply(analyzed); From 1e9160a130572b3195c836c71d34f9f7d124adfe Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 22 Mar 2022 15:48:26 +0100 Subject: [PATCH 55/56] added comments --- .../transformation/SimplePreprocessing.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 7626f2580..648f27194 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -14,19 +14,26 @@ import java.util.*; /** - * Simplifies the input program by deleting redundant literals and rules, as well as adding rule heads that will - * always be true as facts. The approach is adopted from preprocessing techniques employed by traditional ground ASP - * solvers, as seen in: + * Simplifies the input program by deleting redundant literals and rules, as well as identifying rule heads that can + * always be derived from facts and adding them to the known facts. The approach is adopted from preprocessing + * techniques employed by traditional ground ASP solvers, as seen in: * @see doi:10.3233/978-1-58603-891-5-15 */ public class SimplePreprocessing extends ProgramTransformation { + + /** + * Evaluates all rules of the input program and tries to simplify them by applying a number of rule transformations. + * @param inputProgram a normalized ASP program to be preprocessed. + * @return the preprocessed program. + */ @Override public NormalProgram apply(NormalProgram inputProgram) { List srcRules = inputProgram.getRules(); Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - boolean canBePreprocessed = true; + + // Eliminate rules that will never fire, without regarding other rules. for (NormalRule rule: srcRules) { if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { continue; @@ -37,6 +44,10 @@ public NormalProgram apply(NormalProgram inputProgram) { newRules.add(rule); } srcRules = new LinkedList<>(newRules); + + // Analyze every rule in regard to the other rules and facts and if applicable, simplify or remove it. Repeat + // until a fixpoint is reached. + boolean canBePreprocessed = true; while (canBePreprocessed) { newRules = new LinkedHashSet<>(); canBePreprocessed = false; @@ -111,10 +122,17 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { * modified, is a fact or will never fire. */ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { - Set redundantLiterals = new LinkedHashSet<>(); + // Check if the rule head is already a fact, making the rule redundant. if (facts.contains(rule.getHeadAtom())) { return RuleEvaluation.NO_FIRE; } + + // Collect all literals that can be removed from the rule. + Set redundantLiterals = new LinkedHashSet<>(); + + // Check if body literals can be derived from facts or other rules. If a body literal is not derivable, the + // rule can never fire. If a literal is already proven within the program context, the rule will be simplified + // by removing it. for (Literal literal : rule.getBody()) { if (literal instanceof BasicLiteral) { if (literal.isNegated()) { @@ -140,6 +158,7 @@ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set } } + // Checks if an atom cannot be derived from a rule or a fact. private boolean isNonDerivable(Atom atom, List rules, Set facts) { Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { @@ -158,7 +177,7 @@ private boolean isNonDerivable(Atom atom, List rules, Set fact } /** - * removes a set of given literals from the rule body. + * Removes a set of given literals from the rule body. * @param rule the rule from which literals should be removed. * @param literals The literals to remove. * @return the resulting rule or fact. From f0c239f8c720357b80416828553fa88f4d091a39 Mon Sep 17 00:00:00 2001 From: mschmutzhart Date: Tue, 1 Aug 2023 21:34:28 +0200 Subject: [PATCH 56/56] refactored SimplePreprocessing --- .../transformation/SimplePreprocessing.java | 131 ++++++++++-------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java index 648f27194..565286378 100644 --- a/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java +++ b/alpha-core/src/main/java/at/ac/tuwien/kr/alpha/core/programs/transformation/SimplePreprocessing.java @@ -6,6 +6,7 @@ import at.ac.tuwien.kr.alpha.api.programs.literals.BasicLiteral; import at.ac.tuwien.kr.alpha.api.programs.literals.Literal; import at.ac.tuwien.kr.alpha.api.rules.NormalRule; +import at.ac.tuwien.kr.alpha.api.rules.Rule; import at.ac.tuwien.kr.alpha.commons.rules.heads.Heads; import at.ac.tuwien.kr.alpha.core.grounder.Unification; import at.ac.tuwien.kr.alpha.core.programs.NormalProgramImpl; @@ -13,6 +14,8 @@ import java.util.*; +import static java.util.stream.Collectors.toList; + /** * Simplifies the input program by deleting redundant literals and rules, as well as identifying rule heads that can * always be derived from facts and adding them to the known facts. The approach is adopted from preprocessing @@ -33,13 +36,13 @@ public NormalProgram apply(NormalProgram inputProgram) { Set newRules = new LinkedHashSet<>(); Set facts = new LinkedHashSet<>(inputProgram.getFacts()); - // Eliminate rules that will never fire, without regarding other rules. + // Check if the rules are redundant or will never fire, without taking other rules into consideration. for (NormalRule rule: srcRules) { - if (checkForConflictingBodyLiterals(rule.getPositiveBody(), rule.getNegativeBody())) { + if (facts.contains(rule.getHeadAtom()) || containsConflictingBodyLiterals(rule) || containsHeadInPositiveBody(rule)) { continue; } - if (checkForHeadInBody(rule.getBody(), rule.getHeadAtom())) { - continue; + if (containsHeadInNegativeBody(rule)) { + newRules.add(new NormalRuleImpl(null, new ArrayList<>(rule.getBody()))); } newRules.add(rule); } @@ -70,42 +73,28 @@ public NormalProgram apply(NormalProgram inputProgram) { return new NormalProgramImpl(new LinkedList<>(newRules), new LinkedList<>(facts), inputProgram.getInlineDirectives()); } - private static class RuleEvaluation { - public final static RuleEvaluation NO_FIRE = new RuleEvaluation(null, false, false); - private final NormalRule rule; - private final boolean isModified; - private final boolean isFact; - - public RuleEvaluation(NormalRule rule, boolean isModified, boolean isFact) { - this.rule = rule; - this.isModified = isModified; - this.isFact = isFact; - } - - public NormalRule getRule() { - return rule; - } - - public boolean isModified() { - return isModified; - } - - public boolean isFact() { - return isFact; + private boolean containsConflictingBodyLiterals(NormalRule rule) { + for (Literal positiveLiteral : rule.getPositiveBody()) { + if (rule.getNegativeBody().contains(positiveLiteral.negate())) { + return true; + } } + return false; } - private boolean checkForConflictingBodyLiterals(Set positiveBody, Set negativeBody) { - for (Literal positiveLiteral : positiveBody) { - if (negativeBody.contains(positiveLiteral.negate())) { + private boolean containsHeadInPositiveBody(NormalRule rule) { + Atom headAtom = rule.getHeadAtom(); + for (Literal literal : rule.getPositiveBody()) { + if (literal.getAtom().equals(headAtom)) { return true; } } return false; } - private boolean checkForHeadInBody(Set body, Atom headAtom) { - for (Literal literal : body) { + private boolean containsHeadInNegativeBody(NormalRule rule) { + Atom headAtom = rule.getHeadAtom(); + for (Literal literal : rule.getNegativeBody()) { if (literal.getAtom().equals(headAtom)) { return true; } @@ -118,39 +107,36 @@ private boolean checkForHeadInBody(Set body, Atom headAtom) { * @param rule the rule to be evaluated. * @param rules the rules from which literals could be derived from. * @param facts the facts from which literals could be derived from. - * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was + * @return The ({@link RuleEvaluation}) contains the possibly simplified rule and indicates whether it was * modified, is a fact or will never fire. */ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set facts) { - // Check if the rule head is already a fact, making the rule redundant. - if (facts.contains(rule.getHeadAtom())) { - return RuleEvaluation.NO_FIRE; - } - - // Collect all literals that can be removed from the rule. + // Collect all literals that can be removed from the rule here. Set redundantLiterals = new LinkedHashSet<>(); // Check if body literals can be derived from facts or other rules. If a body literal is not derivable, the // rule can never fire. If a literal is already proven within the program context, the rule will be simplified - // by removing it. - for (Literal literal : rule.getBody()) { - if (literal instanceof BasicLiteral) { - if (literal.isNegated()) { - if (facts.contains(literal.getAtom())) { - return RuleEvaluation.NO_FIRE; - } - if (isNonDerivable(literal.getAtom(), rules, facts)) { - redundantLiterals.add(literal); - } - } else { - if (facts.contains(literal.getAtom())) { - redundantLiterals.add(literal); - } else if (isNonDerivable(literal.getAtom(), rules, facts)) { - return RuleEvaluation.NO_FIRE; - } - } + // by removing the literal. + List basicBodyLiterals = rule.getBody().stream().filter(BasicLiteral.class::isInstance).collect(toList()); + for (Literal literal : basicBodyLiterals) { + if (literal.isNegated() && facts.contains(literal.getAtom()) + || !literal.isNegated() && isNonDerivable(literal.getAtom(), rules, facts)) { + return RuleEvaluation.NO_FIRE; + } + if (literal.isNegated() && isNonDerivable(literal.getAtom(), rules, facts) + || !literal.isNegated() && facts.contains(literal.getAtom())) { + redundantLiterals.add(literal); } } + + // Checks if a constraint has the same body, meaning the had of the rule cannot be derived by the rule. + List constraints = rules.stream().filter(Rule::isConstraint).collect(toList()); + for (NormalRule constraint : constraints) { + if (!rule.isConstraint() && rule.getBody().equals(constraint.getBody())) { + return RuleEvaluation.NO_FIRE; + } + } + if (redundantLiterals.isEmpty()) { return new RuleEvaluation(rule, false, false); } else { @@ -162,10 +148,8 @@ private RuleEvaluation evaluateRule(NormalRule rule, List rules, Set private boolean isNonDerivable(Atom atom, List rules, Set facts) { Atom tempAtom = atom.renameVariables("Prep"); for (NormalRule rule : rules) { - if (!rule.isConstraint()) { - if (Unification.unifyAtoms(rule.getHeadAtom(), tempAtom) != null) { - return false; - } + if (!rule.isConstraint() && Unification.unifyAtoms(rule.getHeadAtom(), tempAtom) != null) { + return false; } } for (Atom fact:facts) { @@ -196,4 +180,33 @@ private RuleEvaluation removeLiteralsFromRule(NormalRule rule, Set lite } return new RuleEvaluation(newRule, !literals.isEmpty(), newBody.isEmpty() && !newRule.isConstraint()); } + + /** + * Internal helper class containing the possibly simplified rule and indicates whether it could + * or could not be simplified, is a fact or will never fire. + */ + private static class RuleEvaluation { + public static final RuleEvaluation NO_FIRE = new RuleEvaluation(null, false, false); + private final NormalRule rule; + private final boolean isModified; + private final boolean isFact; + + public RuleEvaluation(NormalRule rule, boolean isModified, boolean isFact) { + this.rule = rule; + this.isModified = isModified; + this.isFact = isFact; + } + + public NormalRule getRule() { + return rule; + } + + public boolean isModified() { + return isModified; + } + + public boolean isFact() { + return isFact; + } + } }