Package org.ggp.base.util.gdl.model

Source Code of org.ggp.base.util.gdl.model.SentenceFormsFinder$NameAndArity

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<Gdl> description;
  private final Map<NameAndArity, List<TermModel>> sentencesModel = Maps.newHashMap();
  private boolean haveCreatedModel = false;

  public SentenceFormsFinder(ImmutableList<Gdl> description) {
    this.description = description;
  }

  public ImmutableSet<SentenceForm> findSentenceForms() throws InterruptedException {
    createModel();

    return ImmutableSet.copyOf(getSentenceFormsFromModel());
  }

  public Map<SentenceForm, SentenceFormDomain> findCartesianDomains() throws InterruptedException {
    createModel();

    return getCartesianDomainsFromModel();
  }

  private void createModel() throws InterruptedException {
    synchronized (this) {
      if (!haveCreatedModel) {
        addTrueSentencesToModel();
        applyRulesToModel();
        haveCreatedModel = true;
      }
    }
  }

  private Map<SentenceForm, SentenceFormDomain> getCartesianDomainsFromModel() throws InterruptedException {
    Map<SentenceForm, SentenceFormDomain> results = Maps.newHashMap();
    for (Entry<NameAndArity, List<TermModel>> sentenceEntry : sentencesModel.entrySet()) {
      ConcurrencyUtils.checkForInterruption();
      NameAndArity nameAndArity = sentenceEntry.getKey();
      GdlConstant name = nameAndArity.getName();
      List<TermModel> 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.<Set<GdlConstant>>of()));
      } else {
        List<Set<GdlTerm>> sampleTerms = toSampleTerms(bodyModels);
        for (List<GdlTerm> 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<Set<GdlConstant>> domainContents = Lists.newArrayList();
    getDomainInternal(sentence.getBody(), sentencesModel.get(new NameAndArity(sentence)), domainContents);
    return CartesianSentenceFormDomain.create(form, domainContents);
  }

  //Appends to domainContents
  private void getDomainInternal(List<GdlTerm> body, List<TermModel> bodyModel,
      List<Set<GdlConstant>> 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<TermModel> functionBodyModel = termModel.getFunctionBodyModel(function);
        getDomainInternal(function.getBody(), functionBodyModel, domainContents);
      } else {
        throw new IllegalStateException();
      }
    }
  }

  private Set<SentenceForm> getSentenceFormsFromModel() {
    Set<SentenceForm> results = Sets.newHashSet();
    for (Entry<NameAndArity, List<TermModel>> sentenceEntry : sentencesModel.entrySet()) {
      NameAndArity nameAndArity = sentenceEntry.getKey();
      GdlConstant name = nameAndArity.getName();
      List<TermModel> 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<Set<GdlTerm>> sampleTerms = toSampleTerms(bodyModels);
        for (List<GdlTerm> terms : Sets.cartesianProduct(sampleTerms)) {
          GdlSentence sentence = GdlPool.getRelation(name, terms);
          results.add(SimpleSentenceForm.create(sentence));
        }
      }
    }
    return results;
  }

  private List<Set<GdlTerm>> toSampleTerms(List<TermModel> bodyModels) {
    List<Set<GdlTerm>> results = Lists.newArrayList();
    for (TermModel termModel : bodyModels) {
      results.add(toSampleTerms(termModel));
    }
    return results;
  }

  private Set<GdlTerm> toSampleTerms(TermModel termModel) {
    Set<GdlTerm> results = Sets.newHashSet();
    if (!termModel.getPossibleConstants().isEmpty()) {
      results.add(termModel.getPossibleConstants().iterator().next());
    }
    for (NameAndArity nameAndArity : termModel.getPossibleFunctions().keySet()) {
      List<TermModel> bodyModel = termModel.getPossibleFunctions().get(nameAndArity);
      List<Set<GdlTerm>> functionSampleTerms = toSampleTerms(bodyModel);
      Set<List<GdlTerm>> functionBodies = Sets.cartesianProduct(functionSampleTerms);
      for (List<GdlTerm> 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<TermModel> oldModel = sentencesModel.get(oldName);
      if (!sentencesModel.containsKey(newName)) {
        changesMade = true;
        sentencesModel.put(newName, getNTermModels(newName.arity));
      }
      List<TermModel> 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<GdlVariable, TermModel> varsToModelsMap = getVarsToModelsMap(rule);

    return addSentenceToModel(headSentence, varsToModelsMap);
  }

  private Map<GdlVariable, TermModel> getVarsToModelsMap(GdlRule rule) {
    Set<GdlVariable> varsToUse = Sets.newHashSet(GdlUtils.getVariables(rule.getHead()));
    Map<GdlVariable, TermModel> varsToModelsMap = Maps.newHashMap();
    for (GdlVariable var : varsToUse) {
      varsToModelsMap.put(var, new TermModel());
    }

    for (GdlLiteral literal : rule.getBody()) {
      if (literal instanceof GdlRelation) {
        List<GdlTerm> literalBody = ((GdlRelation) literal).getBody();
        NameAndArity nameAndArity = new NameAndArity((GdlSentence) literal);
        if (!sentencesModel.containsKey(nameAndArity)) {
          sentencesModel.put(nameAndArity, getNTermModels(nameAndArity.getArity()));
        }
        List<TermModel> literalModel = sentencesModel.get(nameAndArity);
        addVariablesToMap(literalBody, literalModel, varsToModelsMap);
      }
    }
    return varsToModelsMap;
  }

  private void addVariablesToMap(List<GdlTerm> body,
      List<TermModel> model,
      Map<GdlVariable, TermModel> 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<TermModel> 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.<GdlVariable, TermModel>of());
      }
    }
  }

  private boolean addSentenceToModel(GdlSentence sentence, Map<GdlVariable, TermModel> 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<TermModel> getNTermModels(int arity) {
    List<TermModel> result = Lists.newArrayListWithCapacity(arity);
    for (int i = 0; i < arity; i++) {
      result.add(new TermModel());
    }
    return result;
  }

  private static boolean addBodyToModel(List<TermModel> model, List<GdlTerm> body, Map<GdlVariable, TermModel> 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<GdlConstant> possibleConstants = Sets.newHashSet();
    private final Map<NameAndArity, List<TermModel>> possibleFunctions = Maps.newHashMap();

    public List<TermModel> getFunctionBodyModel(GdlFunction function) {
      return possibleFunctions.get(new NameAndArity(function));
    }

    public Set<GdlConstant> getPossibleConstants() {
      return possibleConstants;
    }

    public Map<NameAndArity, List<TermModel>> getPossibleFunctions() {
      return possibleFunctions;
    }

    public boolean mergeIn(TermModel other) {
      boolean changesMade = false;
      changesMade |= possibleConstants.addAll(other.possibleConstants);
      for (NameAndArity key : other.possibleFunctions.keySet()) {
        List<TermModel> theirFunctionBodies = other.possibleFunctions.get(key);
        if (!possibleFunctions.containsKey(key)) {
          possibleFunctions.put(key, deepCopyOf(theirFunctionBodies));
          changesMade = true;
        } else {
          List<TermModel> 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<GdlVariable, TermModel> 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<TermModel> deepCopyOf(List<TermModel> original) {
    List<TermModel> copy = Lists.newArrayListWithCapacity(original.size());
    for (TermModel originalTermModel : original) {
      copy.add(TermModel.copyOf(originalTermModel));
    }
    return copy;
  }
}
TOP

Related Classes of org.ggp.base.util.gdl.model.SentenceFormsFinder$NameAndArity

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.