![JAR search and dependency download from the Maven repository](/logo.png)
org.ggp.base.util.gdl.model.SentenceFormsFinder 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.gdl.model;
import java.util.List;
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.Gdl;
import org.ggp.base.util.gdl.grammar.GdlConstant;
import org.ggp.base.util.gdl.grammar.GdlFunction;
import org.ggp.base.util.gdl.grammar.GdlLiteral;
import org.ggp.base.util.gdl.grammar.GdlPool;
import org.ggp.base.util.gdl.grammar.GdlRelation;
import org.ggp.base.util.gdl.grammar.GdlRule;
import org.ggp.base.util.gdl.grammar.GdlSentence;
import org.ggp.base.util.gdl.grammar.GdlTerm;
import org.ggp.base.util.gdl.grammar.GdlVariable;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class SentenceFormsFinder {
private final ImmutableList description;
private final Map> sentencesModel = Maps.newHashMap();
private boolean haveCreatedModel = false;
public SentenceFormsFinder(ImmutableList description) {
this.description = description;
}
public ImmutableSet findSentenceForms() throws InterruptedException {
createModel();
return ImmutableSet.copyOf(getSentenceFormsFromModel());
}
public Map findCartesianDomains() throws InterruptedException {
createModel();
return getCartesianDomainsFromModel();
}
private void createModel() throws InterruptedException {
synchronized (this) {
if (!haveCreatedModel) {
addTrueSentencesToModel();
applyRulesToModel();
haveCreatedModel = true;
}
}
}
private Map getCartesianDomainsFromModel() throws InterruptedException {
Map results = Maps.newHashMap();
for (Entry> sentenceEntry : sentencesModel.entrySet()) {
ConcurrencyUtils.checkForInterruption();
NameAndArity nameAndArity = sentenceEntry.getKey();
GdlConstant name = nameAndArity.getName();
List bodyModels = sentenceEntry.getValue();
// We'll end up taking the Cartesian product of the different
// types of terms we have available
if (nameAndArity.getArity() == 0) {
GdlSentence sentence = GdlPool.getProposition(name);
SimpleSentenceForm form = SimpleSentenceForm.create(sentence);
results.put(form, CartesianSentenceFormDomain.create(form, ImmutableList.>of()));
} else {
List> sampleTerms = toSampleTerms(bodyModels);
for (List terms : Sets.cartesianProduct(sampleTerms)) {
ConcurrencyUtils.checkForInterruption();
GdlRelation sentence = GdlPool.getRelation(name, terms);
SimpleSentenceForm form = SimpleSentenceForm.create(sentence);
SentenceFormDomain domain = getDomain(form, sentence);
results.put(form, domain);
}
}
}
return results;
}
private SentenceFormDomain getDomain(SentenceForm form, GdlRelation sentence) {
List> domainContents = Lists.newArrayList();
getDomainInternal(sentence.getBody(), sentencesModel.get(new NameAndArity(sentence)), domainContents);
return CartesianSentenceFormDomain.create(form, domainContents);
}
//Appends to domainContents
private void getDomainInternal(List body, List bodyModel,
List> domainContents) {
if (body.size() != bodyModel.size()) {
throw new IllegalStateException("Should have same arity in example as in model");
}
for (int i = 0; i < body.size(); i++) {
GdlTerm term = body.get(i);
TermModel termModel = bodyModel.get(i);
if (term instanceof GdlConstant) {
domainContents.add(termModel.getPossibleConstants());
} else if (term instanceof GdlFunction) {
GdlFunction function = (GdlFunction) term;
List functionBodyModel = termModel.getFunctionBodyModel(function);
getDomainInternal(function.getBody(), functionBodyModel, domainContents);
} else {
throw new IllegalStateException();
}
}
}
private Set getSentenceFormsFromModel() {
Set results = Sets.newHashSet();
for (Entry> sentenceEntry : sentencesModel.entrySet()) {
NameAndArity nameAndArity = sentenceEntry.getKey();
GdlConstant name = nameAndArity.getName();
List bodyModels = sentenceEntry.getValue();
// We'll end up taking the Cartesian product of the different
// types of terms we have available
if (nameAndArity.getArity() == 0) {
GdlSentence sentence = GdlPool.getProposition(name);
results.add(SimpleSentenceForm.create(sentence));
} else {
List> sampleTerms = toSampleTerms(bodyModels);
for (List terms : Sets.cartesianProduct(sampleTerms)) {
GdlSentence sentence = GdlPool.getRelation(name, terms);
results.add(SimpleSentenceForm.create(sentence));
}
}
}
return results;
}
private List> toSampleTerms(List bodyModels) {
List> results = Lists.newArrayList();
for (TermModel termModel : bodyModels) {
results.add(toSampleTerms(termModel));
}
return results;
}
private Set toSampleTerms(TermModel termModel) {
Set results = Sets.newHashSet();
if (!termModel.getPossibleConstants().isEmpty()) {
results.add(termModel.getPossibleConstants().iterator().next());
}
for (NameAndArity nameAndArity : termModel.getPossibleFunctions().keySet()) {
List bodyModel = termModel.getPossibleFunctions().get(nameAndArity);
List> functionSampleTerms = toSampleTerms(bodyModel);
Set> functionBodies = Sets.cartesianProduct(functionSampleTerms);
for (List functionBody : functionBodies) {
GdlFunction function = GdlPool.getFunction(nameAndArity.getName(), functionBody);
results.add(function);
}
}
return results;
}
private void applyRulesToModel() throws InterruptedException {
//Apply injections
boolean changeMade = true;
while (changeMade) {
changeMade = false;
for (Gdl gdl : description) {
if (gdl instanceof GdlRule) {
changeMade |= addRule((GdlRule) gdl);
}
}
changeMade |= applyLanguageRules();
}
}
private boolean applyLanguageRules() throws InterruptedException {
boolean changesMade = false;
changesMade |= applyInjection(new NameAndArity(GdlPool.INIT, 1), new NameAndArity(GdlPool.TRUE, 1));
changesMade |= applyInjection(new NameAndArity(GdlPool.NEXT, 1), new NameAndArity(GdlPool.TRUE, 1));
changesMade |= applyInjection(new NameAndArity(GdlPool.LEGAL, 2), new NameAndArity(GdlPool.DOES, 2));
return changesMade;
}
private boolean applyInjection(NameAndArity oldName,
NameAndArity newName) throws InterruptedException {
ConcurrencyUtils.checkForInterruption();
Preconditions.checkArgument(oldName.getArity() == newName.getArity());
boolean changesMade = false;
if (sentencesModel.containsKey(oldName)) {
List oldModel = sentencesModel.get(oldName);
if (!sentencesModel.containsKey(newName)) {
changesMade = true;
sentencesModel.put(newName, getNTermModels(newName.arity));
}
List newModel = sentencesModel.get(newName);
if (oldModel.size() != newModel.size()) {
throw new IllegalStateException();
}
for (int i = 0; i < oldModel.size(); i++) {
ConcurrencyUtils.checkForInterruption();
changesMade |= newModel.get(i).mergeIn(oldModel.get(i));
}
}
return changesMade;
}
private boolean addRule(GdlRule rule) throws InterruptedException {
// Stuff can make it into the head sentence form either as part of
// the head of the rule as presented or due to a variable connected
// to the positive literals in the rule. (In the latter case, it
// should be in the intersection of the models of all such positive
// literals.) For each slot in the body, we want to set up everything
// that will be injected into it.
GdlSentence headSentence = rule.getHead();
// We need to get the possible contents of variables beforehand, to
// deal with the case of variables being inside functions.
Map varsToModelsMap = getVarsToModelsMap(rule);
return addSentenceToModel(headSentence, varsToModelsMap);
}
private Map getVarsToModelsMap(GdlRule rule) {
Set varsToUse = Sets.newHashSet(GdlUtils.getVariables(rule.getHead()));
Map varsToModelsMap = Maps.newHashMap();
for (GdlVariable var : varsToUse) {
varsToModelsMap.put(var, new TermModel());
}
for (GdlLiteral literal : rule.getBody()) {
if (literal instanceof GdlRelation) {
List literalBody = ((GdlRelation) literal).getBody();
NameAndArity nameAndArity = new NameAndArity((GdlSentence) literal);
if (!sentencesModel.containsKey(nameAndArity)) {
sentencesModel.put(nameAndArity, getNTermModels(nameAndArity.getArity()));
}
List literalModel = sentencesModel.get(nameAndArity);
addVariablesToMap(literalBody, literalModel, varsToModelsMap);
}
}
return varsToModelsMap;
}
private void addVariablesToMap(List body,
List model,
Map varsToModelsMap) {
if (body.size() != model.size()) {
throw new IllegalArgumentException("The term model and body sizes don't match: model is " + model + ", body is: " + body);
}
for (int i = 0; i < body.size(); i++) {
GdlTerm term = body.get(i);
TermModel termModel = model.get(i);
if (term instanceof GdlVariable) {
GdlVariable var = (GdlVariable) term;
if (varsToModelsMap.containsKey(var)) {
varsToModelsMap.get(var).mergeIn(termModel);
}
} else if (term instanceof GdlFunction) {
GdlFunction function = (GdlFunction) term;
List functionBodyModel = termModel.getFunctionBodyModel(function);
if (functionBodyModel != null) {
addVariablesToMap(function.getBody(), functionBodyModel, varsToModelsMap);
}
}
}
}
private void addTrueSentencesToModel() throws InterruptedException {
for (Gdl gdl : description) {
ConcurrencyUtils.checkForInterruption();
if (gdl instanceof GdlSentence) {
addSentenceToModel((GdlSentence) gdl, ImmutableMap.of());
}
}
}
private boolean addSentenceToModel(GdlSentence sentence, Map varsToModelsMap) throws InterruptedException {
ConcurrencyUtils.checkForInterruption();
boolean changesMade = false;
NameAndArity sentenceName = new NameAndArity(sentence);
if (!sentencesModel.containsKey(sentenceName)) {
changesMade = true;
sentencesModel.put(sentenceName, getNTermModels(sentence.arity()));
}
changesMade |= addBodyToModel(sentencesModel.get(sentenceName), sentence.getBody(), varsToModelsMap);
return changesMade;
}
private static List getNTermModels(int arity) {
List result = Lists.newArrayListWithCapacity(arity);
for (int i = 0; i < arity; i++) {
result.add(new TermModel());
}
return result;
}
private static boolean addBodyToModel(List model, List body, Map varsToModelsMap) {
boolean changesMade = false;
if (model.size() != body.size()) {
throw new IllegalArgumentException("The term model and body sizes don't match: model is " + model + ", body is: " + body);
}
for (int i = 0; i < model.size(); i++) {
TermModel termModel = model.get(i);
GdlTerm term = body.get(i);
changesMade |= termModel.addTerm(term, varsToModelsMap);
}
return changesMade;
}
private static class TermModel {
private final Set possibleConstants = Sets.newHashSet();
private final Map> possibleFunctions = Maps.newHashMap();
public List getFunctionBodyModel(GdlFunction function) {
return possibleFunctions.get(new NameAndArity(function));
}
public Set getPossibleConstants() {
return possibleConstants;
}
public Map> getPossibleFunctions() {
return possibleFunctions;
}
public boolean mergeIn(TermModel other) {
boolean changesMade = false;
changesMade |= possibleConstants.addAll(other.possibleConstants);
for (NameAndArity key : other.possibleFunctions.keySet()) {
List theirFunctionBodies = other.possibleFunctions.get(key);
if (!possibleFunctions.containsKey(key)) {
possibleFunctions.put(key, deepCopyOf(theirFunctionBodies));
changesMade = true;
} else {
List ourFunctionBodies = possibleFunctions.get(key);
if (ourFunctionBodies.size() != theirFunctionBodies.size()) {
throw new IllegalStateException();
}
for (int i = 0; i < ourFunctionBodies.size(); i++) {
changesMade |= ourFunctionBodies.get(i).mergeIn(theirFunctionBodies.get(i));
}
}
}
return changesMade;
}
public TermModel() {
}
public boolean addTerm(GdlTerm term, Map varsToModelsMap) {
boolean changesMade = false;
if (term instanceof GdlConstant) {
changesMade = possibleConstants.add((GdlConstant) term);
} else if (term instanceof GdlFunction) {
GdlFunction function = (GdlFunction) term;
NameAndArity sentenceName = new NameAndArity(function);
if (!possibleFunctions.containsKey(sentenceName)) {
changesMade = true;
possibleFunctions.put(sentenceName, getNTermModels(function.arity()));
}
changesMade |= addBodyToModel(possibleFunctions.get(sentenceName), function.getBody(), varsToModelsMap);
} else if (term instanceof GdlVariable) {
changesMade = mergeIn(varsToModelsMap.get(term));
} else {
throw new RuntimeException("Unrecognized term type " + term.getClass() + " for term " + term);
}
return changesMade;
}
@Override
public String toString() {
return "NewTermModel [possibleConstants=" + possibleConstants
+ ", possibleFunctions=" + possibleFunctions + "]";
}
public static TermModel copyOf(TermModel originalTermModel) {
TermModel termModel = new TermModel();
termModel.mergeIn(originalTermModel);
return termModel;
}
}
private static class NameAndArity {
private final GdlConstant name;
private final int arity;
public NameAndArity(GdlSentence sentence) {
this.name = sentence.getName();
this.arity = sentence.arity();
}
public NameAndArity(GdlFunction function) {
this.name = function.getName();
this.arity = function.arity();
}
public NameAndArity(GdlConstant name, int arity) {
this.name = name;
this.arity = arity;
}
public GdlConstant getName() {
return name;
}
public int getArity() {
return arity;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + arity;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NameAndArity other = (NameAndArity) obj;
if (arity != other.arity)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "NameAndArity [name=" + name + ", arity=" + arity + "]";
}
}
public static List deepCopyOf(List original) {
List copy = Lists.newArrayListWithCapacity(original.size());
for (TermModel originalTermModel : original) {
copy.add(TermModel.copyOf(originalTermModel));
}
return copy;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy