org.ggp.base.util.reasoner.gdl.GdlChainingReasoner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alloy-ggp-base Show documentation
Show all versions of alloy-ggp-base Show documentation
A modified version of the GGP-Base library for Alloy.
The newest version!
package org.ggp.base.util.reasoner.gdl;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.ggp.base.util.concurrency.ConcurrencyUtils;
import org.ggp.base.util.gdl.GdlUtils;
import org.ggp.base.util.gdl.grammar.GdlConstant;
import org.ggp.base.util.gdl.grammar.GdlDistinct;
import org.ggp.base.util.gdl.grammar.GdlLiteral;
import org.ggp.base.util.gdl.grammar.GdlNot;
import org.ggp.base.util.gdl.grammar.GdlOr;
import org.ggp.base.util.gdl.grammar.GdlRule;
import org.ggp.base.util.gdl.grammar.GdlSentence;
import org.ggp.base.util.gdl.grammar.GdlVariable;
import org.ggp.base.util.gdl.model.SentenceDomainModel;
import org.ggp.base.util.gdl.model.SentenceDomainModels;
import org.ggp.base.util.gdl.model.SentenceDomainModels.VarDomainOpts;
import org.ggp.base.util.gdl.model.SentenceForm;
import org.ggp.base.util.gdl.model.SentenceFormModel;
import org.ggp.base.util.gdl.model.assignments.AddibleFunctionInfo;
import org.ggp.base.util.gdl.model.assignments.AssignmentIterator;
import org.ggp.base.util.gdl.model.assignments.Assignments;
import org.ggp.base.util.gdl.model.assignments.AssignmentsImpl;
import org.ggp.base.util.gdl.model.assignments.FunctionInfo;
import org.ggp.base.util.gdl.transforms.CommonTransforms;
import org.ggp.base.util.gdl.transforms.ImmutableConstantChecker;
import org.ggp.base.util.reasoner.DifferentialForwardChainingReasoner;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.SetMultimap;
/**
* An implementation of a ForwardChainingReasoner that uses Gdl objects
* directly and allows for differential processing of rules.
*/
//This is at least effectively immutable.
public class GdlChainingReasoner implements
DifferentialForwardChainingReasoner {
private final SentenceFormModel model;
private final ImmutableMultimap constants;
private GdlChainingReasoner(SentenceFormModel model, ImmutableMultimap constants) {
this.model = model;
this.constants = constants;
}
public static GdlChainingReasoner create(SentenceFormModel model) {
ImmutableMultimap.Builder constantsBuilder = ImmutableMultimap.builder();
for (SentenceForm form : model.getSentenceForms()) {
constantsBuilder.putAll(form, model.getSentencesListedAsTrue(form));
}
return new GdlChainingReasoner(model, constantsBuilder.build());
}
public static GdlChainingReasoner create(ImmutableConstantChecker checker) {
SentenceFormModel model = checker.getSentenceFormModel();
ImmutableMultimap.Builder constantsBuilder = ImmutableMultimap.builder();
for (SentenceForm form : model.getSentenceForms()) {
constantsBuilder.putAll(form, model.getSentencesListedAsTrue(form));
}
for (SentenceForm form : checker.getConstantSentenceForms()) {
constantsBuilder.putAll(form, checker.getTrueSentences(form));
}
return new GdlChainingReasoner(model, constantsBuilder.build());
}
@Override
public GdlSentenceSet getConstantSentences() {
return GdlSentenceSet.create(constants);
}
@Override
public GdlSentenceSet getRuleResults(GdlRule rule,
SentenceDomainModel domainModel,
GdlSentenceSet sentencesSoFar) throws InterruptedException {
ConcurrencyUtils.checkForInterruption();
SentenceForm headForm = model.getSentenceForm(rule.getHead());
Map> varDomains = SentenceDomainModels.getVarDomains(rule, domainModel, VarDomainOpts.INCLUDE_HEAD);
Map functionInfoMap = sentencesSoFar.getFunctionInfo();
Map> completedSentenceFormValues = sentencesSoFar.getSentences().asMap();
AssignmentsImpl assignments = new AssignmentsImpl(rule, varDomains, functionInfoMap, completedSentenceFormValues);
AssignmentIterator asnItr = assignments.getIterator();
GdlSentenceSet sentencesToAdd = GdlSentenceSet.create();
while (asnItr.hasNext()) {
Map assignment = asnItr.next();
boolean allSatisfied = true;
for (GdlLiteral literal : rule.getBody()) {
ConcurrencyUtils.checkForInterruption();
if (!satisfies(assignment, literal, sentencesSoFar.getSentences())) {
asnItr.changeOneInNext(GdlUtils.getVariables(literal), assignment);
allSatisfied = false;
break;
}
}
if (allSatisfied) {
GdlSentence head = rule.getHead();
sentencesToAdd.put(headForm, CommonTransforms.replaceVariables(head, assignment));
asnItr.changeOneInNext(GdlUtils.getVariables(head), assignment);
}
}
return sentencesToAdd;
}
private boolean satisfies(Map assignment,
GdlLiteral literal, SetMultimap sentencesSoFar) {
if (literal instanceof GdlSentence) {
return satisfiesSentence(assignment, (GdlSentence) literal, sentencesSoFar);
} else if (literal instanceof GdlNot) {
GdlLiteral body = ((GdlNot) literal).getBody();
if (!(body instanceof GdlSentence)) {
throw new IllegalStateException("Negated literal should be a sentence but isn't: " + body);
}
return !satisfiesSentence(assignment, (GdlSentence) body, sentencesSoFar);
} else if (literal instanceof GdlDistinct) {
return satisfiesDistinct(assignment, (GdlDistinct) literal);
} else if (literal instanceof GdlOr) {
GdlOr or = (GdlOr) literal;
for (int i = 0; i < or.arity(); i++) {
GdlLiteral innerLiteral = or.get(i);
if (satisfies(assignment, innerLiteral, sentencesSoFar)) {
return true;
}
}
return false;
} else {
throw new IllegalArgumentException("Unrecognized type of literal " + literal.getClass() + " for literal " + literal);
}
}
private boolean satisfiesSentence(Map assignment,
GdlSentence sentence,
SetMultimap sentencesSoFar) {
sentence = CommonTransforms.replaceVariables(sentence, assignment);
SentenceForm form = model.getSentenceForm(sentence);
return sentencesSoFar.get(form).contains(sentence);
}
private boolean satisfiesDistinct(Map assignment,
GdlDistinct distinct) {
distinct = CommonTransforms.replaceVariables(distinct, assignment);
return distinct.getArg1() != distinct.getArg2();
}
@Override
public GdlSentenceSet getUnion(
GdlSentenceSet oldSentences,
GdlSentenceSet newSentences) {
oldSentences.putAll(newSentences.getSentences());
return oldSentences;
}
@Override
public boolean isSubsetOf(
GdlSentenceSet oldSentences,
GdlSentenceSet newSentences) {
for (Entry entry : newSentences.getSentences().entries()) {
if (!oldSentences.containsSentence(entry.getKey(), entry.getValue())) {
return false;
}
}
return true;
}
@Override
public GdlSentenceSet getRuleResultsForNewSentences(
GdlRule rule, SentenceDomainModel domainModel,
GdlSentenceSet allSentences,
GdlSentenceSet newSentences) throws InterruptedException {
GdlSentenceSet results = GdlSentenceSet.create();
for (GdlLiteral literal : rule.getBody()) {
ConcurrencyUtils.checkForInterruption();
if (literal instanceof GdlSentence) {
SentenceForm literalForm = domainModel.getSentenceForm((GdlSentence) literal);
addRuleResultsForChosenLiteral(
rule,
(GdlSentence) literal,
newSentences.getSentences().get(literalForm),
domainModel,
allSentences,
results);
} else if (literal instanceof GdlOr) {
throw new IllegalArgumentException("Need more implementation work for this to work with ORs here");
}
}
return results;
}
private void addRuleResultsForChosenLiteral(GdlRule rule,
GdlSentence chosenLiteral, Set chosenNewSentences,
SentenceDomainModel domainModel,
GdlSentenceSet allSentences,
GdlSentenceSet sentencesToAdd) {
SentenceForm headForm = model.getSentenceForm(rule.getHead());
Map> varDomains = SentenceDomainModels.getVarDomains(rule, domainModel, VarDomainOpts.INCLUDE_HEAD);
Map functionInfoMap = allSentences.getFunctionInfo();
Map> completedSentenceFormValues = allSentences.getSentences().asMap();
for (GdlSentence chosenNewSentence : chosenNewSentences) {
Map preassignments = GdlUtils.getAssignmentMakingLeftIntoGroundRight(chosenLiteral, chosenNewSentence);
if (preassignments != null) {
//TODO: Use an AIP instead? These next two lines take most of our time
Assignments assignments = new AssignmentsImpl(preassignments, rule, varDomains, functionInfoMap, completedSentenceFormValues);
AssignmentIterator asnItr = assignments.getIterator();
while (asnItr.hasNext()) {
Map assignment = asnItr.next();
boolean allSatisfied = true;
for (GdlLiteral literal : rule.getBody()) {
if (literal == chosenLiteral) {
//Already satisfied
continue;
}
if (!satisfies(assignment, literal, allSentences.getSentences())) {
asnItr.changeOneInNext(GdlUtils.getVariables(literal), assignment);
allSatisfied = false;
break;
}
}
if (allSatisfied) {
GdlSentence head = rule.getHead();
GdlSentence newHead = CommonTransforms.replaceVariables(head, assignment);
if (!allSentences.containsSentence(headForm, newHead)) {
sentencesToAdd.put(headForm, newHead);
}
asnItr.changeOneInNext(GdlUtils.getVariables(head), assignment);
}
}
}
}
}
}