package org.ggp.base.util.gdl.model;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.ggp.base.util.gdl.GdlUtils;
import org.ggp.base.util.gdl.grammar.GdlConstant;
import org.ggp.base.util.gdl.grammar.GdlLiteral;
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.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
public class SentenceDomainModels {
public static enum VarDomainOpts {
INCLUDE_HEAD,
BODY_ONLY
}
public static Map<GdlVariable, Set<GdlConstant>> getVarDomains(
GdlRule rule,
SentenceDomainModel domainModel,
VarDomainOpts includeHead) {
// For each positive definition of sentences in the rule, intersect their
// domains everywhere the variables show up
Multimap<GdlVariable, Set<GdlConstant>> varDomainsByVar = ArrayListMultimap.create();
for (GdlLiteral literal : getSentences(rule, includeHead)) {
if (literal instanceof GdlSentence) {
GdlSentence sentence = (GdlSentence) literal;
SentenceForm form = SimpleSentenceForm.create(sentence);
SentenceFormDomain formWithDomain = domainModel.getDomain(form);
List<GdlTerm> tuple = GdlUtils.getTupleFromSentence(sentence);
for (int i = 0; i < tuple.size(); i++) {
GdlTerm term = tuple.get(i);
if (term instanceof GdlVariable) {
GdlVariable var = (GdlVariable) term;
Set<GdlConstant> domain = formWithDomain.getDomainForSlot(i);
varDomainsByVar.put(var, domain);
}
}
}
}
Map<GdlVariable, Set<GdlConstant>> varDomainByVar = combineDomains(varDomainsByVar);
return varDomainByVar;
}
public static Iterable<GdlLiteral> getSentences(GdlRule rule, VarDomainOpts includeHead) {
if (includeHead == VarDomainOpts.INCLUDE_HEAD) {
return Iterables.concat(ImmutableList.of(rule.getHead()), rule.getBody());
} else {
return rule.getBody();
}
}
private static Map<GdlVariable, Set<GdlConstant>> combineDomains(
Multimap<GdlVariable, Set<GdlConstant>> varDomainsByVar) {
return ImmutableMap.copyOf(Maps.transformValues(varDomainsByVar.asMap(),
new Function<Collection<Set<GdlConstant>>, Set<GdlConstant>>() {
@Override
public Set<GdlConstant> apply(Collection<Set<GdlConstant>> input) {
return intersectSets(input);
}
}));
}
private static <T> Set<T> intersectSets(
Collection<Set<T>> input) {
if (input.isEmpty()) {
throw new IllegalArgumentException("Can't take an intersection of no sets");
}
Set<T> result = null;
for (Set<T> set : input) {
if (result == null) {
result = Sets.newHashSet(set);
} else {
result.retainAll(set);
}
}
assert result != null;
return result;
}
}