use of at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult in project Alpha by alpha-asp.
the class NaiveGrounderTest method testPermissiveGrounderHeuristicTolerance.
/**
* Tests if {@link NaiveGrounder#getGroundInstantiations(InternalRule, RuleGroundingOrder, Substitution, Assignment)}
* produces ground instantiations for the rule with ID {@code ruleID} in {@code program} when {@code startingLiteral}
* unified with the numeric instance {@code startingInstance} is used as starting literal and the following
* additional conditions are established:
* <ul>
* <li>The atoms {@code b([startingInstance], 1), ..., b([startingInstance], n)} are added to the grounder's
* working memory without changing the assignment, where {@code arityOfB-1} occurences of {@code startingInstance}
* are used instead of {@code [startingInstance]} and {@code n} is the length of the {@code truthsOfB} array.
* For example, if the length of {@code truthsOfB} is 2 and {@code arityOfB} is also 2, these atoms are
* {@code b(1,1), b(1,2)}.
* </li>
* <li>The same atoms are assigned the truth values in the {@code truthsOfB} array.</li>
* </ul>
* It is asserted that ground instantiations are produced if and only if {@code expectNoGoods} is true.
* If ground instantiations are produced, it is also asserted that the numbers of unassigned positive body atoms
* determined by {@code getGroundInstantiations} match those given in {@code expectedNumbersOfUnassignedPositiveBodyAtoms}.
*/
private void testPermissiveGrounderHeuristicTolerance(ASPCore2Program program, int ruleID, Literal startingLiteral, int startingInstance, int tolerance, ThriceTruth[] truthsOfB, int arityOfB, boolean expectNoGoods, List<Integer> expectedNumbersOfUnassignedPositiveBodyAtoms) {
CompiledProgram internalPrg = InternalProgram.fromNormalProgram(NORMALIZE_TRANSFORM.apply(program));
AtomStore atomStore = new AtomStoreImpl();
TrailAssignment currentAssignment = new TrailAssignment(atomStore);
GrounderHeuristicsConfiguration heuristicConfiguration = GrounderHeuristicsConfiguration.getInstance(tolerance, tolerance);
NaiveGrounder grounder = (NaiveGrounder) GrounderFactory.getInstance("naive", internalPrg, atomStore, p -> true, heuristicConfiguration, true);
int[] bAtomIDs = new int[truthsOfB.length];
for (int i = 0; i < truthsOfB.length; i++) {
int[] bTerms = new int[arityOfB];
for (int n = 0; n < arityOfB; n++) {
bTerms[n] = (n == arityOfB - 1) ? i + 1 : startingInstance;
}
bAtomIDs[i] = atomStore.putIfAbsent(atom("b", bTerms));
}
addAtomsToWorkingMemoryWithoutChangingTheAssignment(atomStore, grounder, bAtomIDs);
assign(currentAssignment, bAtomIDs, truthsOfB);
grounder.bootstrap();
final CompiledRule nonGroundRule = grounder.getNonGroundRule(ruleID);
final Substitution substStartingLiteral = BasicSubstitution.specializeSubstitution(startingLiteral, new Instance(Terms.newConstant(startingInstance)), BasicSubstitution.EMPTY_SUBSTITUTION);
final BindingResult bindingResult = grounder.getGroundInstantiations(nonGroundRule, nonGroundRule.getGroundingInfo().orderStartingFrom(startingLiteral), substStartingLiteral, currentAssignment);
assertEquals(expectNoGoods, bindingResult.size() > 0);
if (bindingResult.size() > 0) {
assertEquals(expectedNumbersOfUnassignedPositiveBodyAtoms, bindingResult.getNumbersOfUnassignedPositiveBodyAtoms());
} else {
assertTrue(bindingResult.getNumbersOfUnassignedPositiveBodyAtoms().isEmpty());
}
}
use of at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult in project Alpha by alpha-asp.
the class NaiveGrounder method bootstrap.
/**
* Prepares facts of the input program for joining and derives all NoGoods representing ground rules. May only be called once.
*
* @return
*/
protected HashMap<Integer, NoGood> bootstrap() {
final HashMap<Integer, NoGood> groundNogoods = new LinkedHashMap<>();
for (Predicate predicate : factsFromProgram.keySet()) {
// Instead of generating NoGoods, add instance to working memories directly.
workingMemory.addInstances(predicate, true, factsFromProgram.get(predicate));
}
for (CompiledRule 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);
groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), groundNogoods);
}
fixedRules = null;
return groundNogoods;
}
use of at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult in project Alpha by alpha-asp.
the class NaiveGrounder method bindNextAtomInRule.
// @formatter:off
/**
* Computes ground substitutions for a literal based on a {@link RuleGroundingOrderImpl} and a {@link BasicSubstitution}.
*
* Computes ground substitutions for the literal at position <code>orderPosition</code> of <code>groundingOrder</code>
* Actual substitutions are computed by this grounder's {@link LiteralInstantiator}.
*
* @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 <code>groundingOrder</code>, indicates which literal should be bound
* @param originalTolerance the original tolerance of the used grounding heuristic
* @param remainingTolerance the remaining tolerance, determining if binding continues in the presence of substitutions based on unassigned atoms
* @param partialSubstitution a substitution
* @return a {@link BindingResult} representing applicable ground substitutions for all literals after orderPosition in groundingOrder
*/
// @formatter:on
private BindingResult bindNextAtomInRule(RuleGroundingOrder groundingOrder, int orderPosition, int originalTolerance, int remainingTolerance, Substitution partialSubstitution) {
Literal currentLiteral = groundingOrder.getLiteralAtOrderPosition(orderPosition);
if (currentLiteral == null) {
LOGGER.trace("No more literals found in grounding order, therefore stopping binding!");
return BindingResult.singleton(partialSubstitution, originalTolerance - remainingTolerance);
}
LOGGER.trace("Binding current literal {} with remaining tolerance {} and partial substitution {}.", currentLiteral, remainingTolerance, partialSubstitution);
LiteralInstantiationResult instantiationResult = ruleInstantiator.instantiateLiteral(currentLiteral, partialSubstitution);
switch(instantiationResult.getType()) {
case CONTINUE:
/*
* Recursively call bindNextAtomInRule for each generated substitution
* and the next literal in the grounding order (i.e. advance), thereby reducing remaining
* tolerance by 1 iff a substitution uses an unassigned ground atom.
* If remainingTolerance falls below zero, an empty {@link BindingResult} is returned.
*/
List<ImmutablePair<Substitution, AssignmentStatus>> substitutionInfos = instantiationResult.getSubstitutions();
LOGGER.trace("Literal instantiator yielded {} substitutions for literal {}.", substitutionInfos.size(), currentLiteral);
BindingResult retVal = new BindingResult();
for (ImmutablePair<Substitution, AssignmentStatus> substitutionInfo : substitutionInfos) {
retVal.add(this.continueBinding(groundingOrder, orderPosition, originalTolerance, remainingTolerance, substitutionInfo));
}
return retVal;
case PUSH_BACK:
/*
* Delegate to pushBackAndBindNextAtomInRule(RuleGroundingOrder, int, int, int, Substitution, Assignment).
* Pushes the current literal to the end of the grounding order and calls bindNextAtomInRule with the modified grounding oder.
*/
LOGGER.trace("Pushing back literal {} in grounding order.", currentLiteral);
return pushBackAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution);
case MAYBE_PUSH_BACK:
/*
* Indicates that the rule instantiator could not find any substitutions for the current literal. If a permissive grounder heuristic is in
* use, push the current literal to the end of the grounding order and proceed with the next one, otherwise return an empty BindingResult.
*/
if (originalTolerance > 0) {
LOGGER.trace("No substitutions yielded by literal instantiator for literal {}, but using permissive heuristic, therefore pushing the literal back.", currentLiteral);
// i.e. it is deemed acceptable to have ground rules where a number of body atoms are not yet assigned a truth value by the solver.
return pushBackAndBindNextAtomInRule(groundingOrder, orderPosition, originalTolerance, remainingTolerance, partialSubstitution);
} else {
LOGGER.trace("No substitutions found for literal {}", currentLiteral);
return BindingResult.empty();
}
case STOP_BINDING:
LOGGER.trace("No substitutions found for literal {}", currentLiteral);
return BindingResult.empty();
default:
throw Util.oops("Unhandled literal instantiation result type: " + instantiationResult.getType());
}
}
use of at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult in project Alpha by alpha-asp.
the class NaiveGrounder method getGroundInstantiations.
// 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) {
int tolerance = heuristicsConfiguration.getTolerance(rule.isConstraint());
if (tolerance < 0) {
tolerance = Integer.MAX_VALUE;
}
// 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);
BindingResult bindingResult = bindNextAtomInRule(groundingOrder, 0, tolerance, tolerance, partialSubstitution);
if (LOGGER.isDebugEnabled()) {
for (int i = 0; i < bindingResult.size(); i++) {
Integer numberOfUnassignedPositiveBodyAtoms = bindingResult.getNumbersOfUnassignedPositiveBodyAtoms().get(i);
if (numberOfUnassignedPositiveBodyAtoms > 0) {
LOGGER.debug("Grounded rule in which {} positive atoms are still unassigned: {} (substitution: {})", numberOfUnassignedPositiveBodyAtoms, rule, bindingResult.getGeneratedSubstitutions().get(i));
}
}
}
return bindingResult;
}
use of at.ac.tuwien.kr.alpha.core.grounder.instantiation.BindingResult in project Alpha by alpha-asp.
the class NaiveGrounder method getNoGoods.
@Override
public Map<Integer, NoGood> getNoGoods(Assignment currentAssignment) {
// In first call, prepare facts and ground rules.
final Map<Integer, NoGood> newNoGoods = fixedRules != null ? bootstrap() : new LinkedHashMap<>();
// 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.
Predicate workingMemoryPredicate = modifiedWorkingMemory.getPredicate();
if (workingMemoryPredicate.isSolverInternal()) {
continue;
}
// Iterate over all rules whose body contains the interpretation corresponding to the current workingMemory.
final ArrayList<FirstBindingAtom> firstBindingAtoms = rulesUsingPredicateWorkingMemory.get(modifiedWorkingMemory);
// Skip working memories that are not used by any rule.
if (firstBindingAtoms == null) {
continue;
}
for (FirstBindingAtom firstBindingAtom : firstBindingAtoms) {
// Use the recently added instances from the modified working memory to construct an initial substitution
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 = BasicSubstitution.specializeSubstitution(firstBindingAtom.startingLiteral, instance, BasicSubstitution.EMPTY_SUBSTITUTION);
if (unifier == null) {
continue;
}
final BindingResult bindingResult = getGroundInstantiations(nonGroundRule, nonGroundRule.getGroundingInfo().orderStartingFrom(firstBindingAtom.startingLiteral), unifier, currentAssignment);
groundAndRegister(nonGroundRule, bindingResult.getGeneratedSubstitutions(), newNoGoods);
}
}
// Mark instances added by updateAssignment as done
modifiedWorkingMemory.markRecentlyAddedInstancesDone();
}
workingMemory.reset();
for (Atom removeAtom : removeAfterObtainingNewNoGoods) {
final IndexedInstanceStorage storage = workingMemory.get(removeAtom, true);
Instance instance = new Instance(removeAtom.getTerms());
if (storage.containsInstance(instance)) {
// permissive grounder heuristics may attempt to remove instances that are not yet in the working memory
storage.removeInstance(instance);
}
}
// Re-Initialize the stale working memory entries set and pass to instantiation strategy.
removeAfterObtainingNewNoGoods = new LinkedHashSet<>();
instantiationStrategy.setStaleWorkingMemoryEntries(removeAfterObtainingNewNoGoods);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Grounded NoGoods are:");
for (Map.Entry<Integer, NoGood> noGoodEntry : newNoGoods.entrySet()) {
LOGGER.debug("{} == {}", noGoodEntry.getValue(), atomStore.noGoodToString(noGoodEntry.getValue()));
}
LOGGER.debug("{}", choiceRecorder);
}
if (debugInternalChecks) {
checkTypesOfNoGoods(newNoGoods.values());
}
return newNoGoods;
}
Aggregations