diff --git a/.travis.yml b/.travis.yml
index f9d534d9d..f319d099c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -45,7 +45,7 @@ install:
- true
script:
- - ./gradlew build --scan --stacktrace
+ - travis_wait ./gradlew build --scan --stacktrace
after_success:
- ./gradlew jacocoTestReport coveralls
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/Alpha.java b/src/main/java/at/ac/tuwien/kr/alpha/Alpha.java
index 4dcb2e2a1..a355ca45a 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/Alpha.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/Alpha.java
@@ -33,6 +33,7 @@
import at.ac.tuwien.kr.alpha.config.SystemConfig;
import at.ac.tuwien.kr.alpha.grounder.Grounder;
import at.ac.tuwien.kr.alpha.grounder.GrounderFactory;
+import at.ac.tuwien.kr.alpha.grounder.heuristics.GrounderHeuristicsConfiguration;
import at.ac.tuwien.kr.alpha.grounder.parser.ProgramParser;
import at.ac.tuwien.kr.alpha.solver.Solver;
import at.ac.tuwien.kr.alpha.solver.SolverFactory;
@@ -103,8 +104,12 @@ public Solver prepareSolverFor(Program program, java.util.function.Predicate
solve(Program program, java.util.function.Predicate retVal = this.prepareSolverFor(program, filter).stream();
return this.config.isSortAnswerSets() ? retVal.sorted() : retVal;
}
-
+
public Stream solve(Program program) {
return this.solve(program, InputConfig.DEFAULT_FILTER);
}
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/common/Assignment.java b/src/main/java/at/ac/tuwien/kr/alpha/common/Assignment.java
index 638696fce..9e3b6ca00 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/common/Assignment.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/common/Assignment.java
@@ -33,7 +33,8 @@
import java.util.Iterator;
import java.util.Set;
-import static at.ac.tuwien.kr.alpha.common.Literals.*;
+import static at.ac.tuwien.kr.alpha.common.Literals.atomOf;
+import static at.ac.tuwien.kr.alpha.common.Literals.isNegated;
public interface Assignment {
Entry get(int atom);
@@ -71,6 +72,13 @@ default ThriceTruth getTruth(int atom) {
*/
Antecedent getImpliedBy(int atom);
+ /**
+ * Returns the last truth value (i.e., phase) assigned to the atom.
+ * @param atom the atom
+ * @return the last truth value.
+ */
+ boolean getLastValue(int atom);
+
/**
* Determines if the given {@code noGood} is undefined in the current assignment.
*
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/common/atoms/ComparisonLiteral.java b/src/main/java/at/ac/tuwien/kr/alpha/common/atoms/ComparisonLiteral.java
index 6a57c4061..91ac679d3 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/common/atoms/ComparisonLiteral.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/common/atoms/ComparisonLiteral.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017-2018, the Alpha Team.
+ * Copyright (c) 2017-2019, the Alpha Team.
* All rights reserved.
*
* Additional changes made by Siemens.
@@ -171,6 +171,12 @@ public List getSubstitutions(Substitution partialSubstitution) {
extendedSubstitution.put(variable, resultTerm);
return Collections.singletonList(extendedSubstitution);
}
+
+ public boolean isLeftOrRightAssigning() {
+ final Term left = getTerms().get(0);
+ final Term right = getTerms().get(1);
+ return isNormalizedEquality && (assignable(left) && right.isGround() || assignable(right) && left.isGround());
+ }
private Term evaluateTerm(Term term) {
// Evaluate arithmetics.
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/config/CommandLineParser.java b/src/main/java/at/ac/tuwien/kr/alpha/config/CommandLineParser.java
index 6efa8e4b4..063f7c1c6 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/config/CommandLineParser.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/config/CommandLineParser.java
@@ -107,6 +107,24 @@ public class CommandLineParser {
.desc("disable the deletion of (learned, little active) nogoods (default: "
+ SystemConfig.DEFAULT_DISABLE_NOGOOD_DELETION + ")")
.build();
+ private static final Option OPT_GROUNDER_TOLERANCE_CONSTRAINTS = Option.builder("gtc").longOpt("grounderToleranceConstraints")
+ .desc("grounder tolerance for constraints (default: " + SystemConfig.DEFAULT_GROUNDER_TOLERANCE_CONSTRAINTS + ")")
+ .hasArg().argName("tolerance")
+ .build();
+ private static final Option OPT_GROUNDER_TOLERANCE_RULES = Option.builder("gtr").longOpt("grounderToleranceRules")
+ .desc("grounder tolerance for rules (default: " + SystemConfig.DEFAULT_GROUNDER_TOLERANCE_RULES + ")")
+ .hasArg().argName("tolerance")
+ .build();
+ private static final Option OPT_NO_INSTANCE_REMOVAL = Option.builder("dir").longOpt("disableInstanceRemoval")
+ .desc("activates the accumulator grounding strategy by disabling removal of instances from grounder memory in certain cases (default: " + SystemConfig.DEFAULT_DISABLE_INSTANCE_REMOVAL + ")")
+ .build();
+ private static final Option OPT_ENABLE_RESTARTS = Option.builder("rs").longOpt("enableRestarts")
+ .desc("enable the usage of (dynamic and static) restarts (default: "
+ + SystemConfig.DEFAULT_ENABLE_RESTARTS + ")")
+ .build();
+ private static final Option OPT_INITIAL_PHASE = Option.builder("ph").longOpt("initialPhase").hasArg(true).argName("initializer")
+ .desc("set the initial phase [ alltrue | allfalse | random ] (default: " + SystemConfig.DEFAULT_PHASE_INITIALIZER + ")")
+ .build();
private static final Options CLI_OPTS = new Options();
@@ -137,6 +155,11 @@ public class CommandLineParser {
CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NO_JUSTIFICATION);
CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NORMALIZATION_GRID);
CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NO_NOGOOD_DELETION);
+ CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_TOLERANCE_CONSTRAINTS);
+ CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_GROUNDER_TOLERANCE_RULES);
+ CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_NO_INSTANCE_REMOVAL);
+ CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_ENABLE_RESTARTS);
+ CommandLineParser.CLI_OPTS.addOption(CommandLineParser.OPT_INITIAL_PHASE);
}
/*
@@ -180,6 +203,11 @@ public CommandLineParser(String cmdLineSyntax, Consumer abortAction) {
this.globalOptionHandlers.put(CommandLineParser.OPT_NO_JUSTIFICATION.getOpt(), this::handleNoJustification);
this.globalOptionHandlers.put(CommandLineParser.OPT_NORMALIZATION_GRID.getOpt(), this::handleNormalizationGrid);
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_NO_INSTANCE_REMOVAL.getOpt(), this::handleNoInstanceRemoval);
+ this.globalOptionHandlers.put(CommandLineParser.OPT_ENABLE_RESTARTS.getOpt(), this::handleEnableRestarts);
+ this.globalOptionHandlers.put(CommandLineParser.OPT_INITIAL_PHASE.getOpt(), this::handleInitialPhase);
this.inputOptionHandlers.put(CommandLineParser.OPT_NUM_ANSWER_SETS.getOpt(), this::handleNumAnswerSets);
this.inputOptionHandlers.put(CommandLineParser.OPT_INPUT.getOpt(), this::handleInput);
@@ -325,7 +353,7 @@ private void handleMomsStrategy(Option opt, SystemConfig cfg) throws ParseExcept
throw new ParseException("Unknown mom's strategy: " + momsStrategyName + ". Please try one of the following: " + BinaryNoGoodPropagationEstimation.Strategy.listAllowedValues());
}
}
-
+
private void handleReplayChoices(Option opt, SystemConfig cfg) throws ParseException {
String replayChoices = opt.getValue(SystemConfig.DEFAULT_REPLAY_CHOICES.toString());
try {
@@ -359,4 +387,25 @@ private void handleNoNoGoodDeletion(Option opt, SystemConfig cfg) {
cfg.setDisableNoGoodDeletion(true);
}
+ private void handleGrounderToleranceConstraints(Option opt, SystemConfig cfg) {
+ String grounderToleranceConstraints = opt.getValue(SystemConfig.DEFAULT_GROUNDER_TOLERANCE_CONSTRAINTS);
+ cfg.setGrounderToleranceConstraints(grounderToleranceConstraints);
+ }
+
+ private void handleGrounderToleranceRules(Option opt, SystemConfig cfg) {
+ String grounderToleranceRules = opt.getValue(SystemConfig.DEFAULT_GROUNDER_TOLERANCE_RULES);
+ cfg.setGrounderToleranceRules(grounderToleranceRules);
+ }
+
+ private void handleNoInstanceRemoval(Option opt, SystemConfig cfg) {
+ cfg.setDisableInstanceRemoval(true);
+ }
+
+ private void handleEnableRestarts(Option opt, SystemConfig cfg) {
+ cfg.setRestartsEnabled(true);
+ }
+
+ private void handleInitialPhase(Option opt, SystemConfig cfg) {
+ cfg.setPhaseInitializer(opt.getValue(SystemConfig.DEFAULT_PHASE_INITIALIZER));
+ }
}
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/config/SystemConfig.java b/src/main/java/at/ac/tuwien/kr/alpha/config/SystemConfig.java
index 6ffeeb8cf..8c6e74306 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/config/SystemConfig.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/config/SystemConfig.java
@@ -27,6 +27,7 @@
*/
package at.ac.tuwien.kr.alpha.config;
+import at.ac.tuwien.kr.alpha.grounder.heuristics.GrounderHeuristicsConfiguration;
import at.ac.tuwien.kr.alpha.solver.BinaryNoGoodPropagationEstimation;
import at.ac.tuwien.kr.alpha.solver.heuristics.BranchingHeuristicFactory.Heuristic;
@@ -56,6 +57,11 @@ 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_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;
+ public static final boolean DEFAULT_DISABLE_INSTANCE_REMOVAL = false;
+ public static final boolean DEFAULT_ENABLE_RESTARTS = false;
+ public static final String DEFAULT_PHASE_INITIALIZER = "random";
private String grounderName = SystemConfig.DEFAULT_GROUNDER_NAME;
private String solverName = SystemConfig.DEFAULT_SOLVER_NAME;
@@ -72,6 +78,11 @@ public class SystemConfig {
private boolean sortAnswerSets = SystemConfig.DEFAULT_SORT_ANSWER_SETS;
private List replayChoices = SystemConfig.DEFAULT_REPLAY_CHOICES;
private boolean disableNoGoodDeletion = SystemConfig.DEFAULT_DISABLE_NOGOOD_DELETION;
+ private String grounderToleranceConstraints = DEFAULT_GROUNDER_TOLERANCE_CONSTRAINTS;
+ private String grounderToleranceRules = DEFAULT_GROUNDER_TOLERANCE_RULES;
+ private boolean disableInstanceRemoval = DEFAULT_DISABLE_INSTANCE_REMOVAL;
+ private boolean areRestartsEnabled = SystemConfig.DEFAULT_ENABLE_RESTARTS;
+ private String phaseInitializer = SystemConfig.DEFAULT_PHASE_INITIALIZER;
public String getGrounderName() {
return this.grounderName;
@@ -205,4 +216,43 @@ public void setDisableNoGoodDeletion(boolean disableNoGoodDeletion) {
this.disableNoGoodDeletion = disableNoGoodDeletion;
}
+ public String getGrounderToleranceConstraints() {
+ return grounderToleranceConstraints;
+ }
+
+ public void setGrounderToleranceConstraints(String grounderToleranceConstraints) {
+ this.grounderToleranceConstraints = grounderToleranceConstraints;
+ }
+
+ public String getGrounderToleranceRules() {
+ return grounderToleranceRules;
+ }
+
+ public void setGrounderToleranceRules(String grounderToleranceRules) {
+ this.grounderToleranceRules = grounderToleranceRules;
+ }
+
+ public boolean isDisableInstanceRemoval() {
+ return disableInstanceRemoval;
+ }
+
+ public void setDisableInstanceRemoval(boolean disableInstanceRemoval) {
+ this.disableInstanceRemoval = disableInstanceRemoval;
+ }
+ public boolean areRestartsEnabled() {
+ return areRestartsEnabled;
+ }
+
+ public void setRestartsEnabled(boolean areRestartsEnabled) {
+ this.areRestartsEnabled = areRestartsEnabled;
+ }
+
+ public String getPhaseInitializerName() {
+ return phaseInitializer;
+ }
+
+ public void setPhaseInitializer(String phaseInitializer) {
+ this.phaseInitializer = phaseInitializer;
+ }
+
}
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/ChoiceRecorder.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/ChoiceRecorder.java
index c807e0bae..d4b223a60 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/ChoiceRecorder.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/ChoiceRecorder.java
@@ -121,7 +121,7 @@ public String toString() {
}
sb.append(" disablers: ");
for (Map.Entry disablers : newChoiceAtoms.getRight().entrySet()) {
- sb.append(disablers.getKey()).append("/").append(disablers.getValue());
+ sb.append(disablers.getKey()).append("/").append(disablers.getValue()).append(", ");
}
return sb.append("]").toString();
}
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/Grounder.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/Grounder.java
index cee82381e..89503f40f 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/Grounder.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/Grounder.java
@@ -31,6 +31,7 @@
import at.ac.tuwien.kr.alpha.common.Assignment;
import at.ac.tuwien.kr.alpha.common.NoGood;
import at.ac.tuwien.kr.alpha.grounder.atoms.RuleAtom;
+import at.ac.tuwien.kr.alpha.grounder.structure.AtomChoiceRelation;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Iterator;
@@ -79,4 +80,11 @@ public interface Grounder {
* @return
*/
int register(NoGood noGood);
+
+
+ /**
+ * Returns the relation between atoms and choices in form of an {@link AtomChoiceRelation} object.
+ * @return the {@link AtomChoiceRelation} of the grounded program parts.
+ */
+ AtomChoiceRelation getAtomChoiceRelation();
}
diff --git a/src/main/java/at/ac/tuwien/kr/alpha/grounder/GrounderFactory.java b/src/main/java/at/ac/tuwien/kr/alpha/grounder/GrounderFactory.java
index 55742d30d..555a18986 100644
--- a/src/main/java/at/ac/tuwien/kr/alpha/grounder/GrounderFactory.java
+++ b/src/main/java/at/ac/tuwien/kr/alpha/grounder/GrounderFactory.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016-2018, the Alpha Team.
+ * Copyright (c) 2016-2019, the Alpha Team.
* All rights reserved.
*
* Additional changes made by Siemens.
@@ -32,21 +32,22 @@
import at.ac.tuwien.kr.alpha.common.Program;
import at.ac.tuwien.kr.alpha.config.InputConfig;
import at.ac.tuwien.kr.alpha.grounder.bridges.Bridge;
+import at.ac.tuwien.kr.alpha.grounder.heuristics.GrounderHeuristicsConfiguration;
public final class GrounderFactory {
- public static Grounder getInstance(String name, Program program, AtomStore atomStore, java.util.function.Predicate filter, boolean useCountingGridNormalization, boolean debugInternalChecks, Bridge... bridges) {
+ public static Grounder getInstance(String name, Program program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean useCountingGridNormalization, boolean debugInternalChecks, Bridge... bridges) {
switch (name.toLowerCase()) {
case "naive":
- return new NaiveGrounder(program, atomStore, filter, useCountingGridNormalization, debugInternalChecks, bridges);
+ return new NaiveGrounder(program, atomStore, filter, heuristicsConfiguration, useCountingGridNormalization, debugInternalChecks, bridges);
}
throw new IllegalArgumentException("Unknown grounder requested.");
}
- public static Grounder getInstance(String name, Program program, AtomStore atomStore, java.util.function.Predicate filter, boolean debugInternalChecks) {
- return getInstance(name, program, atomStore, filter, false, debugInternalChecks);
- }
-
+ public static Grounder getInstance(String name, Program program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks) {
+ return getInstance(name, program, atomStore, filter, heuristicsConfiguration, false, debugInternalChecks);
+ }
+
public static Grounder getInstance(String name, Program program, AtomStore atomStore, boolean debugInternalChecks) {
- return getInstance(name, program, atomStore, InputConfig.DEFAULT_FILTER, false, debugInternalChecks);
+ return getInstance(name, program, atomStore, InputConfig.DEFAULT_FILTER, new GrounderHeuristicsConfiguration(), false, debugInternalChecks);
}
}
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 387f86a4e..dbdb6866b 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
@@ -29,16 +29,16 @@
import at.ac.tuwien.kr.alpha.common.*;
import at.ac.tuwien.kr.alpha.common.NoGood.Type;
-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.FixedInterpretationLiteral;
-import at.ac.tuwien.kr.alpha.common.atoms.Literal;
+import at.ac.tuwien.kr.alpha.common.atoms.*;
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.EnumerationAtom;
+import at.ac.tuwien.kr.alpha.grounder.atoms.IntervalLiteral;
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.structure.AnalyzeUnjustified;
+import at.ac.tuwien.kr.alpha.grounder.structure.AtomChoiceRelation;
import at.ac.tuwien.kr.alpha.grounder.structure.ProgramAnalysis;
import at.ac.tuwien.kr.alpha.grounder.transformation.*;
import at.ac.tuwien.kr.alpha.solver.ThriceTruth;
@@ -50,12 +50,11 @@
import static at.ac.tuwien.kr.alpha.Util.oops;
import static at.ac.tuwien.kr.alpha.common.Literals.atomOf;
-import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
/**
* A semi-naive grounder.
- * Copyright (c) 2016-2018, the Alpha Team.
+ * Copyright (c) 2016-2019, the Alpha Team.
*/
public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGrounder {
private static final Logger LOGGER = LoggerFactory.getLogger(NaiveGrounder.class);
@@ -72,29 +71,28 @@ public class NaiveGrounder extends BridgedGrounder implements ProgramAnalyzingGr
private final Map> rulesUsingPredicateWorkingMemory = new HashMap<>();
private final Map> knownGroundingSubstitutions = new HashMap<>();
private final Map knownNonGroundRules = new HashMap<>();
+ private final AtomChoiceRelation atomChoiceRelation = new AtomChoiceRelation();
private ArrayList fixedRules = new ArrayList<>();
private LinkedHashSet removeAfterObtainingNewNoGoods = new LinkedHashSet<>();
- private int maxAtomIdBeforeGroundingNewNoGoods = -1;
- private boolean disableInstanceRemoval;
- private boolean useCountingGridNormalization;
- private boolean debugInternalChecks;
-
- /**
- * If this configuration parameter is {@code true} (which it is by default),
- * the grounder stops grounding a rule if it contains a positive body atom which is not
- * yet true, except if the whole rule is already ground. Is currently used only internally,
- * but might be used for grounder heuristics and also set from the outside in the future.
- */
- private boolean stopBindingAtNonTruePositiveBody = true;
+ private final boolean useCountingGridNormalization;
+ private final boolean debugInternalChecks;
+
+ private final GrounderHeuristicsConfiguration heuristicsConfiguration;
public NaiveGrounder(Program program, AtomStore atomStore, boolean debugInternalChecks, Bridge... bridges) {
- this(program, atomStore, p -> true, false, debugInternalChecks, bridges);
+ this(program, atomStore, new GrounderHeuristicsConfiguration(), debugInternalChecks, bridges);
+ }
+
+ private NaiveGrounder(Program program, AtomStore atomStore, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean debugInternalChecks, Bridge... bridges) {
+ this(program, atomStore, p -> true, heuristicsConfiguration, false, debugInternalChecks, bridges);
}
- NaiveGrounder(Program program, AtomStore atomStore, java.util.function.Predicate filter, boolean useCountingGrid, boolean debugInternalChecks, Bridge... bridges) {
+ NaiveGrounder(Program program, AtomStore atomStore, java.util.function.Predicate filter, GrounderHeuristicsConfiguration heuristicsConfiguration, boolean useCountingGrid, boolean debugInternalChecks, Bridge... bridges) {
super(filter, bridges);
this.atomStore = atomStore;
+ this.heuristicsConfiguration = heuristicsConfiguration;
+ LOGGER.debug("Grounder configuration: " + heuristicsConfiguration);
programAnalysis = new ProgramAnalysis(program);
analyzeUnjustified = new AnalyzeUnjustified(programAnalysis, atomStore, factsFromProgram);
@@ -108,11 +106,15 @@ public NaiveGrounder(Program program, AtomStore atomStore, boolean debugInternal
final Set uniqueGroundRulePerGroundHead = getRulesWithUniqueHead();
choiceRecorder = new ChoiceRecorder(atomStore);
- noGoodGenerator = new NoGoodGenerator(atomStore, choiceRecorder, factsFromProgram, programAnalysis, uniqueGroundRulePerGroundHead);
-
+ noGoodGenerator = new NoGoodGenerator(atomStore, choiceRecorder, factsFromProgram, programAnalysis, uniqueGroundRulePerGroundHead, atomChoiceRelation);
this.debugInternalChecks = debugInternalChecks;
}
+ @Override
+ public AtomChoiceRelation getAtomChoiceRelation() {
+ return atomChoiceRelation;
+ }
+
private void initializeFactsAndRules(Program program) {
// initialize all facts
for (Atom fact : program.getFacts()) {
@@ -140,6 +142,7 @@ private void initializeFactsAndRules(Program program) {
// Record the rule for later use
NonGroundRule nonGroundRule = NonGroundRule.constructNonGroundRule(rule);
knownNonGroundRules.put(nonGroundRule.getRuleId(), nonGroundRule);
+ LOGGER.debug("NonGroundRule #" + nonGroundRule.getRuleId() + ": " + nonGroundRule);
// Record defining rules for each predicate.
Atom headAtom = nonGroundRule.getHeadAtom();
@@ -292,7 +295,7 @@ public AnswerSet assignmentToAnswerSet(Iterable trueAtoms) {
* Prepares facts of the input program for joining and derives all NoGoods representing ground rules. May only be called once.
* @return
*/
- private HashMap bootstrap() {
+ HashMap bootstrap() {
final HashMap groundNogoods = new LinkedHashMap<>();
for (Predicate predicate : factsFromProgram.keySet()) {
@@ -302,9 +305,9 @@ private HashMap bootstrap() {
for (NonGroundRule nonGroundRule : fixedRules) {
// Generate NoGoods for all rules that have a fixed grounding.
- Literal[] groundingOrder = nonGroundRule.groundingOrder.getFixedGroundingOrder();
- List substitutions = bindNextAtomInRule(nonGroundRule, groundingOrder, 0, new Substitution(), null);
- groundAndRegister(nonGroundRule, substitutions, groundNogoods);
+ RuleGroundingOrder groundingOrder = nonGroundRule.groundingOrder.getFixedGroundingOrder();
+ BindingResult bindingResult = bindNextAtomInRule(nonGroundRule, groundingOrder, new Substitution(), null);
+ groundAndRegister(nonGroundRule, bindingResult.generatedSubstitutions, groundNogoods);
}
fixedRules = null;
@@ -317,7 +320,6 @@ public Map getNoGoods(Assignment currentAssignment) {
// In first call, prepare facts and ground rules.
final Map newNoGoods = fixedRules != null ? bootstrap() : new LinkedHashMap<>();
- maxAtomIdBeforeGroundingNewNoGoods = atomStore.getMaxAtomId();
// Compute new ground rule (evaluate joins with newly changed atoms)
for (IndexedInstanceStorage modifiedWorkingMemory : workingMemory.modified()) {
// Skip predicates solely used in the solver which do not occur in rules.
@@ -348,15 +350,14 @@ public Map getNoGoods(Assignment currentAssignment) {
continue;
}
- final List substitutions = bindNextAtomInRule(
+ final BindingResult bindingResult = bindNextAtomInRule(
nonGroundRule,
nonGroundRule.groundingOrder.orderStartingFrom(firstBindingAtom.startingLiteral),
- 0,
unifier,
currentAssignment
);
- groundAndRegister(nonGroundRule, substitutions, newNoGoods);
+ groundAndRegister(nonGroundRule, bindingResult.generatedSubstitutions, newNoGoods);
}
}
@@ -367,7 +368,11 @@ public Map getNoGoods(Assignment currentAssignment) {
workingMemory.reset();
for (Atom removeAtom : removeAfterObtainingNewNoGoods) {
final IndexedInstanceStorage storage = this.workingMemory.get(removeAtom, true);
- storage.removeInstance(new Instance(removeAtom.getTerms()));
+ Instance instance = new Instance(removeAtom.getTerms());
+ if (storage.containsInstance(instance)) {
+ // lax grounder heuristics may attempt to remove instances that are not yet in the working memory
+ storage.removeInstance(instance);
+ }
}
removeAfterObtainingNewNoGoods = new LinkedHashSet<>();
@@ -378,17 +383,17 @@ public Map getNoGoods(Assignment currentAssignment) {
}
LOGGER.debug("{}", choiceRecorder);
}
-
+
if (debugInternalChecks) {
checkTypesOfNoGoods(newNoGoods.values());
}
-
+
return newNoGoods;
}
/**
* Grounds the given {@code nonGroundRule} by applying the given {@code substitutions} and registers the nogoods generated during that process.
- *
+ *
* @param nonGroundRule
* the rule to be grounded
* @param substitutions
@@ -408,92 +413,135 @@ public int register(NoGood noGood) {
return registry.register(noGood);
}
- private List bindNextAtomInRule(NonGroundRule rule, Literal[] groundingOrder, int orderPosition, Substitution partialSubstitution, Assignment currentAssignment) {
- if (orderPosition == groundingOrder.length) {
- return singletonList(partialSubstitution);
+ BindingResult bindNextAtomInRule(NonGroundRule rule, RuleGroundingOrder groundingOrder, Substitution partialSubstitution, Assignment currentAssignment) {
+ int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint());
+ if (tolerance < 0) {
+ tolerance = Integer.MAX_VALUE;
+ }
+ BindingResult bindingResult = bindNextAtomInRule(groundingOrder, 0, tolerance, tolerance, partialSubstitution, currentAssignment);
+ if (LOGGER.isDebugEnabled()) {
+ for (int i = 0; i < bindingResult.size(); i++) {
+ Integer numberOfUnassignedPositiveBodyAtoms = bindingResult.numbersOfUnassignedPositiveBodyAtoms.get(i);
+ if (numberOfUnassignedPositiveBodyAtoms > 0) {
+ LOGGER.debug("Grounded rule in which " + numberOfUnassignedPositiveBodyAtoms + " positive atoms are still unassigned: " + rule + " (substitution: " + bindingResult.generatedSubstitutions.get(i) + ")");
+ }
+ }
+ }
+ return bindingResult;
+ }
+
+ private BindingResult advanceAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, Substitution partialSubstitution, Assignment currentAssignment) {
+ groundingOrder.considerUntilCurrentEnd();
+ return bindNextAtomInRule(groundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment);
+ }
+
+ private BindingResult pushBackAndBindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, Substitution partialSubstitution, Assignment currentAssignment) {
+ RuleGroundingOrder modifiedGroundingOrder = groundingOrder.pushBack(orderPosition);
+ if (modifiedGroundingOrder == null) {
+ return BindingResult.empty();
+ }
+ return bindNextAtomInRule(modifiedGroundingOrder, orderPosition + 1, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment);
+ }
+
+ private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, Substitution partialSubstitution, Assignment currentAssignment) {
+ boolean laxGrounderHeuristic = originalTolerance > 0;
+
+ Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition);
+ if (currentLiteral == null) {
+ return BindingResult.singleton(partialSubstitution, originalTolerance - remainingTolerance);
}
- Literal currentLiteral = groundingOrder[orderPosition];
Atom currentAtom = currentLiteral.getAtom();
if (currentLiteral instanceof FixedInterpretationLiteral) {
// Generate all substitutions for the builtin/external/interval atom.
- final List substitutions = ((FixedInterpretationLiteral)currentLiteral.substitute(partialSubstitution)).getSubstitutions(partialSubstitution);
+ FixedInterpretationLiteral substitutedLiteral = (FixedInterpretationLiteral)currentLiteral.substitute(partialSubstitution);
+ if (shallPushBackFixedInterpretationLiteral(substitutedLiteral)) {
+ return pushBackAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment);
+ }
+ final List substitutions = substitutedLiteral.getSubstitutions(partialSubstitution);
if (substitutions.isEmpty()) {
- return emptyList();
+ // if FixedInterpretationLiteral cannot be satisfied now, it will never be
+ return BindingResult.empty();
}
- final List generatedSubstitutions = new ArrayList<>();
+ final BindingResult bindingResult = new BindingResult();
for (Substitution substitution : substitutions) {
// Continue grounding with each of the generated values.
- generatedSubstitutions.addAll(bindNextAtomInRule(rule, groundingOrder, orderPosition + 1, substitution, currentAssignment));
+ bindingResult.add(advanceAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, substitution, currentAssignment));
}
- return generatedSubstitutions;
+ return bindingResult;
}
if (currentAtom instanceof EnumerationAtom) {
// Get the enumeration value and add it to the current partialSubstitution.
((EnumerationAtom) currentAtom).addEnumerationToSubstitution(partialSubstitution);
- return bindNextAtomInRule(rule, groundingOrder, orderPosition + 1, partialSubstitution, currentAssignment);
+ return advanceAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment);
}
+ Collection instances = null;
+
// check if partialVariableSubstitution already yields a ground atom
final Atom substitute = currentAtom.substitute(partialSubstitution);
-
if (substitute.isGround()) {
// Substituted atom is ground, in case it is positive, only ground if it also holds true
if (currentLiteral.isNegated()) {
// Atom occurs negated in the rule: continue grounding
- return bindNextAtomInRule(rule, groundingOrder, orderPosition + 1, partialSubstitution, currentAssignment);
- }
-
- if (stopBindingAtNonTruePositiveBody && !rule.getRule().isGround() && !workingMemory.get(currentAtom.getPredicate(), true).containsInstance(new Instance(substitute.getTerms()))) {
- // Generate no variable substitution.
- return emptyList();
+ return advanceAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment);
}
- // Check if atom is also assigned true.
- final LinkedHashSet instances = factsFromProgram.get(substitute.getPredicate());
- if (!(instances == null || !instances.contains(new Instance(substitute.getTerms())))) {
- // Ground literal holds, continue finding a variable substitution.
- return bindNextAtomInRule(rule, groundingOrder, orderPosition + 1, partialSubstitution, currentAssignment);
+ if (!groundingOrder.isGround() && remainingTolerance <= 0
+ && !workingMemory.get(currentAtom.getPredicate(), true).containsInstance(new Instance(substitute.getTerms()))) {
+ // Generate no variable substitution.
+ return BindingResult.empty();
}
- // Atom is not a fact already.
- final int atomId = atomStore.putIfAbsent(substitute);
-
- if (currentAssignment != null) {
- final ThriceTruth truth = currentAssignment.getTruth(atomId);
-
- if (atomId > maxAtomIdBeforeGroundingNewNoGoods || truth == null || !truth.toBoolean()) {
- // Atom currently does not hold, skip further grounding.
- // TODO: investigate grounding heuristics for use here, i.e., ground anyways to avoid re-grounding in the future.
- if (!disableInstanceRemoval) {
- removeAfterObtainingNewNoGoods.add(substitute);
- return emptyList();
- }
- }
- }
+ instances = singletonList(new Instance(substitute.getTerms()));
}
// substituted atom contains variables
if (currentLiteral.isNegated()) {
- throw oops("Current atom should be positive at this point but is not");
+ if (laxGrounderHeuristic) {
+ return pushBackAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment);
+ } else {
+ throw oops("Current atom should be positive at this point but is not");
+ }
+ }
+
+ if (instances == null) {
+ instances = getInstancesForSubstitute(substitute, partialSubstitution);
+ }
+
+ if (laxGrounderHeuristic && instances.isEmpty()) {
+ // we have reached a point where we have to terminate binding,
+ // but it might be possible that a different grounding order would allow us to continue binding
+ // under the presence of a lax grounder heuristic
+ return pushBackAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment);
}
- IndexedInstanceStorage storage = workingMemory.get(currentAtom.getPredicate(), true);
+ return createBindings(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution, currentAssignment, instances, substitute);
+ }
+
+ private boolean shallPushBackFixedInterpretationLiteral(FixedInterpretationLiteral substitutedLiteral) {
+ return !(substitutedLiteral.isGround() ||
+ (substitutedLiteral instanceof ComparisonLiteral && ((ComparisonLiteral)substitutedLiteral).isLeftOrRightAssigning()) ||
+ (substitutedLiteral instanceof IntervalLiteral && substitutedLiteral.getTerms().get(0).isGround()) ||
+ (substitutedLiteral instanceof ExternalLiteral));
+ }
+
+ private Collection getInstancesForSubstitute(Atom substitute, Substitution partialSubstitution) {
Collection instances;
+ IndexedInstanceStorage storage = workingMemory.get(substitute.getPredicate(), true);
if (partialSubstitution.isEmpty()) {
- if (currentLiteral.isGround()) {
- instances = singletonList(new Instance(currentLiteral.getTerms()));
- } else {
- // No variables are bound, but first atom in the body became recently true, consider all instances now.
- instances = storage.getAllInstances();
- }
+ // No variables are bound, but first atom in the body became recently true, consider all instances now.
+ instances = storage.getAllInstances();
} else {
instances = storage.getInstancesFromPartiallyGroundAtom(substitute);
}
+ return instances;
+ }
- ArrayList generatedSubstitutions = new ArrayList<>();
+ private BindingResult createBindings(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, Substitution partialSubstitution, Assignment currentAssignment, Collection instances, Atom substitute) {
+ BindingResult bindingResult = new BindingResult();
for (Instance instance : instances) {
// Check each instance if it matches with the atom.
Substitution unified = Substitution.unify(substitute, instance, new Substitution(partialSubstitution));
@@ -509,32 +557,70 @@ private List bindNextAtomInRule(NonGroundRule rule, Literal[] grou
}
if (factsFromProgram.get(substitutedAtom.getPredicate()) == null || !factsFromProgram.get(substitutedAtom.getPredicate()).contains(new Instance(substitutedAtom.getTerms()))) {
- int atomId = atomStore.putIfAbsent(substitutedAtom);
-
- if (currentAssignment != null) {
- ThriceTruth truth = currentAssignment.getTruth(atomId);
- if (atomId > maxAtomIdBeforeGroundingNewNoGoods || truth == null || !truth.toBoolean()) {
- // Atom currently does not hold, skip further grounding.
- // TODO: investigate grounding heuristics for use here, i.e., ground anyways to avoid re-grounding in the future.
- if (!disableInstanceRemoval) {
- removeAfterObtainingNewNoGoods.add(substitutedAtom);
- continue;
- }
- }
+ final TerminateOrTolerate terminateOrTolerate = storeAtomAndTerminateIfAtomDoesNotHold(substitutedAtom, currentAssignment, remainingTolerance);
+ if (terminateOrTolerate.decrementTolerance) {
+ remainingTolerance--;
+ }
+ if (terminateOrTolerate.terminate) {
+ continue;
+ }
+ }
+ bindingResult.add(advanceAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, unified, currentAssignment));
+ }
+
+ return bindingResult;
+ }
+
+ private TerminateOrTolerate storeAtomAndTerminateIfAtomDoesNotHold(final Atom substitute, final Assignment currentAssignment, final int remainingTolerance) {
+ int decrementedTolerance = remainingTolerance;
+ if (currentAssignment != null) { // if we are not in bootstrapping
+ final int atomId = atomStore.putIfAbsent(substitute);
+ ThriceTruth truth = currentAssignment.isAssigned(atomId) ? currentAssignment.getTruth(atomId) : null;
+
+ if (heuristicsConfiguration.isDisableInstanceRemoval()) {
+ final Instance instance = new Instance(substitute.getTerms());
+ boolean isInWorkingMemory = workingMemory.get(substitute, true).containsInstance(instance);
+ if (isInWorkingMemory) {
+ return new TerminateOrTolerate(false, false);
+ }
+ if (truth != null && !truth.toBoolean()) {
+ return new TerminateOrTolerate(true, false);
+ }
+ if (--decrementedTolerance < 0) {
+ // terminate if more positive atoms are unsatisfied as tolerated by the heuristic
+ return new TerminateOrTolerate(true, true);
+ }
+ } else {
+ if (truth == null || !truth.toBoolean()) {
+ // Atom currently does not hold
+ removeAfterObtainingNewNoGoods.add(substitute);
+ }
+ if (truth == null && --decrementedTolerance < 0) {
+ // terminate if more positive atoms are unsatisfied as tolerated by the heuristic
+ return new TerminateOrTolerate(true, true);
}
+ // terminate if positive body atom is assigned false
+ return new TerminateOrTolerate(truth != null && !truth.toBoolean(), decrementedTolerance < remainingTolerance);
}
- List boundSubstitutions = bindNextAtomInRule(rule, groundingOrder, orderPosition + 1, unified, currentAssignment);
- generatedSubstitutions.addAll(boundSubstitutions);
}
+ return new TerminateOrTolerate(false, decrementedTolerance < remainingTolerance);
+ }
+
+ private static class TerminateOrTolerate {
+ boolean terminate;
+ boolean decrementTolerance;
- return generatedSubstitutions;
+ TerminateOrTolerate(boolean terminate, boolean decrementTolerance) {
+ this.terminate = terminate;
+ this.decrementTolerance = decrementTolerance;
+ }
}
@Override
public Pair