package util.prover.aima;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import util.gdl.grammar.Gdl;
import util.gdl.grammar.GdlDistinct;
import util.gdl.grammar.GdlLiteral;
import util.gdl.grammar.GdlNot;
import util.gdl.grammar.GdlOr;
import util.gdl.grammar.GdlRule;
import util.gdl.grammar.GdlSentence;
import util.prover.Prover;
import util.prover.aima.cache.ProverCache;
import util.prover.aima.knowledge.KnowledgeBase;
import util.prover.aima.renamer.VariableRenamer;
import util.prover.aima.substituter.Substituter;
import util.prover.aima.substitution.Substitution;
import util.prover.aima.unifier.Unifier;
public final class AimaProver extends Prover
{
private final KnowledgeBase knowledgeBase;
public AimaProver(Set<Gdl> description)
{
knowledgeBase = new KnowledgeBase(description);
}
private Set<GdlSentence> ask(GdlSentence query, Set<GdlSentence> context, boolean askOne)
{
LinkedList<GdlLiteral> goals = new LinkedList<GdlLiteral>();
goals.add(query);
Set<Substitution> answers = new HashSet<Substitution>();
ask(goals, new KnowledgeBase(context), new Substitution(), new ProverCache(), new VariableRenamer(), askOne, answers);
Set<GdlSentence> results = new HashSet<GdlSentence>();
for (Substitution theta : answers)
{
results.add(Substituter.substitute(query, theta));
}
return results;
}
private void ask(LinkedList<GdlLiteral> goals, KnowledgeBase context, Substitution theta, ProverCache cache, VariableRenamer renamer, boolean askOne, Set<Substitution> results)
{
if (goals.size() == 0)
{
results.add(theta);
}
else
{
GdlLiteral literal = goals.removeFirst();
GdlLiteral qPrime = Substituter.substitute(literal, theta);
if (qPrime instanceof GdlDistinct)
{
GdlDistinct distinct = (GdlDistinct) qPrime;
askDistinct(distinct, goals, context, theta, cache, renamer, askOne, results);
}
else if (qPrime instanceof GdlNot)
{
GdlNot not = (GdlNot) qPrime;
askNot(not, goals, context, theta, cache, renamer, askOne, results);
}
else if (qPrime instanceof GdlOr)
{
GdlOr or = (GdlOr) qPrime;
askOr(or, goals, context, theta, cache, renamer, askOne, results);
}
else
{
GdlSentence sentence = (GdlSentence) qPrime;
askSentence(sentence, goals, context, theta, cache, renamer, askOne, results);
}
goals.addFirst(literal);
}
}
@Override
public Set<GdlSentence> askAll(GdlSentence query, Set<GdlSentence> context)
{
return ask(query, context, false);
}
private void askDistinct(GdlDistinct distinct, LinkedList<GdlLiteral> goals, KnowledgeBase context, Substitution theta, ProverCache cache, VariableRenamer renamer, boolean askOne, Set<Substitution> results)
{
if (!distinct.getArg1().equals(distinct.getArg2()))
{
ask(goals, context, theta, cache, renamer, askOne, results);
}
}
private void askNot(GdlNot not, LinkedList<GdlLiteral> goals, KnowledgeBase context, Substitution theta, ProverCache cache, VariableRenamer renamer, boolean askOne, Set<Substitution> results)
{
LinkedList<GdlLiteral> notGoals = new LinkedList<GdlLiteral>();
notGoals.add(not.getBody());
Set<Substitution> notResults = new HashSet<Substitution>();
ask(notGoals, context, theta, cache, renamer, true, notResults);
if (notResults.size() == 0)
{
ask(goals, context, theta, cache, renamer, askOne, results);
}
}
@Override
public GdlSentence askOne(GdlSentence query, Set<GdlSentence> context)
{
Set<GdlSentence> results = ask(query, context, true);
return (results.size() > 0) ? results.iterator().next() : null;
}
private void askOr(GdlOr or, LinkedList<GdlLiteral> goals, KnowledgeBase context, Substitution theta, ProverCache cache, VariableRenamer renamer, boolean askOne, Set<Substitution> results)
{
for (int i = 0; i < or.arity(); i++)
{
goals.addFirst(or.get(i));
ask(goals, context, theta, cache, renamer, askOne, results);
goals.removeFirst();
if (askOne && (results.size() > 0))
{
break;
}
}
}
private void askSentence(GdlSentence sentence, LinkedList<GdlLiteral> goals, KnowledgeBase context, Substitution theta, ProverCache cache, VariableRenamer renamer, boolean askOne, Set<Substitution> results)
{
if (!cache.contains(sentence))
{
List<GdlRule> candidates = new ArrayList<GdlRule>();
candidates.addAll(knowledgeBase.fetch(sentence));
candidates.addAll(context.fetch(sentence));
Set<Substitution> sentenceResults = new HashSet<Substitution>();
for (GdlRule rule : candidates)
{
GdlRule r = renamer.rename(rule);
Substitution thetaPrime = Unifier.unify(r.getHead(), sentence);
if (thetaPrime != null)
{
LinkedList<GdlLiteral> sentenceGoals = new LinkedList<GdlLiteral>();
for (int i = 0; i < r.arity(); i++)
{
sentenceGoals.add(r.get(i));
}
ask(sentenceGoals, context, theta.compose(thetaPrime), cache, renamer, false, sentenceResults);
}
}
cache.put(sentence, sentenceResults);
}
for (Substitution thetaPrime : cache.get(sentence))
{
ask(goals, context, theta.compose(thetaPrime), cache, renamer, askOne, results);
if (askOne && (results.size() > 0))
{
break;
}
}
}
@Override
public boolean prove(GdlSentence query, Set<GdlSentence> context)
{
return askOne(query, context) != null;
}
}