package org.ggp.base.util.gdl.model.assignments;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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.GdlSentence;
import org.ggp.base.util.gdl.grammar.GdlTerm;
import org.ggp.base.util.gdl.grammar.GdlVariable;
import org.ggp.base.util.gdl.model.SentenceForm;
import org.ggp.base.util.gdl.transforms.ConstantChecker;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
//Represents information about a sentence form that is constant.
public class FunctionInfoImpl implements FunctionInfo {
private SentenceForm form;
//True iff the slot has at most one value given the other slots' values
private List<Boolean> dependentSlots = new ArrayList<Boolean>();
private List<Map<ImmutableList<GdlConstant>, GdlConstant>> valueMaps = Lists.newArrayList();
public FunctionInfoImpl(SentenceForm form, Set<GdlSentence> trueSentences) throws InterruptedException {
this.form = form;
int numSlots = form.getTupleSize();
for(int i = 0; i < numSlots; i++) {
//We want to establish whether or not this is a constant...
Map<ImmutableList<GdlConstant>, GdlConstant> functionMap = Maps.newHashMap();
boolean functional = true;
for (GdlSentence sentence : trueSentences) {
ConcurrencyUtils.checkForInterruption();
List<GdlConstant> tuple = GdlUtils.getTupleFromGroundSentence(sentence);
List<GdlConstant> tuplePart = Lists.newArrayListWithCapacity(tuple.size() - 1);
tuplePart.addAll(tuple.subList(0, i));
tuplePart.addAll(tuple.subList(i + 1, tuple.size()));
if(functionMap.containsKey(tuplePart)) {
//We have two tuples with different values in just this slot
functional = false;
break;
}
//Otherwise, we record it
functionMap.put(ImmutableList.copyOf(tuplePart), tuple.get(i));
}
if(functional) {
//Record the function
dependentSlots.add(true);
valueMaps.add(functionMap);
} else {
//Forget it
dependentSlots.add(false);
valueMaps.add(null);
}
}
}
@Override
public Map<ImmutableList<GdlConstant>, GdlConstant> getValueMap(int index) {
return valueMaps.get(index);
}
@Override
public List<Boolean> getDependentSlots() {
return dependentSlots;
}
/**
* Given a sentence of the constant form's sentence form, finds all
* the variables in the sentence that can be produced functionally.
*
* Note the corner case: If a variable appears twice in a sentence,
* it CANNOT be produced in this way.
*/
@Override
public Set<GdlVariable> getProducibleVars(GdlSentence sentence) {
if(!form.matches(sentence))
throw new RuntimeException("Sentence "+sentence+" does not match constant form");
List<GdlTerm> tuple = GdlUtils.getTupleFromSentence(sentence);
Set<GdlVariable> candidateVars = new HashSet<GdlVariable>();
//Variables that appear multiple times go into multipleVars
Set<GdlVariable> multipleVars = new HashSet<GdlVariable>();
//...which, of course, means we have to spot non-candidate vars
Set<GdlVariable> nonCandidateVars = new HashSet<GdlVariable>();
for(int i = 0; i < tuple.size(); i++) {
GdlTerm term = tuple.get(i);
if(term instanceof GdlVariable
&& !multipleVars.contains(term)) {
GdlVariable var = (GdlVariable) term;
if(candidateVars.contains(var)
|| nonCandidateVars.contains(var)) {
multipleVars.add(var);
candidateVars.remove(var);
} else if(dependentSlots.get(i)) {
candidateVars.add(var);
} else {
nonCandidateVars.add(var);
}
}
}
return candidateVars;
}
public static FunctionInfo create(SentenceForm form,
ConstantChecker constantChecker) throws InterruptedException {
return new FunctionInfoImpl(form, ImmutableSet.copyOf(constantChecker.getTrueSentences(form)));
}
public static FunctionInfo create(SentenceForm form,
Set<GdlSentence> set) throws InterruptedException {
return new FunctionInfoImpl(form, set);
}
@Override
public SentenceForm getSentenceForm() {
return form;
}
@Override
public String toString() {
return "FunctionInfoImpl [form=" + form + ", dependentSlots="
+ dependentSlots + ", valueMaps=" + valueMaps + "]";
}
}