///////////////////////////////////////////////////////////////////////
// STANFORD LOGIC GROUP //
// General Game Playing Project //
// //
// Sample Player Implementation //
// //
// (c) 2007. See LICENSE and CONTRIBUTORS. //
///////////////////////////////////////////////////////////////////////
/**
*
*/
package stanfordlogic.prover;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import stanfordlogic.gdl.Parser;
import stanfordlogic.gdl.SymbolTable;
import stanfordlogic.knowledge.KnowledgeBase;
/**
*
* @author Based on code by Team Camembert: David Haley, Pierre-Yves Laligand
*/
public abstract class AbstractReasoner
{
final protected KnowledgeBase kb_;
protected Map<Integer, List<Implication>> rules_;
protected Implication [] rulesArray_;
final protected Parser parser_;
final protected SymbolTable symbolTable_;
final protected static Substitution EMPTY_SUB = new Substitution();
final protected static List<Substitution> EMPTY_SUB_LIST =
new ArrayList<Substitution>(Arrays.asList(new Substitution [] { EMPTY_SUB }));
//////////////////////////////////
// Flags for optimization etc. //
//////////////////////////////////
// TODO think of some optimizations :-)
/////////////////////////////////////////////////////////////////////////////
/**
* Create a reasoner using <tt>kb</tt> as static knowledge.
*
* <p>This constructor takes caree of the common initialization. It is private,
* and so only callable by constructors exposed to subclasses.
*
* <p><i>Note</i>: we use the parser, and not just the symbol table, to
* have quick access to the reserved tokens.
*
* @param kb The static knowledge.
* @param p The parser whose symbol table to refer to.
*/
private AbstractReasoner(KnowledgeBase kb, Parser p)
{
kb_ = kb;
parser_ = p;
symbolTable_ = p.getSymbolTable();
}
/**
* Create a reasoner using <tt>kb</tt> for static knowledge and <tt>rules</tt> for
* the collection of knowledge rules.
*
* @param kb The static knowledge.
* @param rules The rules indexed by the head's relation name.
* @param p The parser whose symbol table to refer to.
*/
protected AbstractReasoner(KnowledgeBase kb, Map<Integer, List<Implication>> rules, Parser p)
{
this(kb, p);
rules_ = rules;
List<Implication> allRules = new ArrayList<Implication>();
for (List<Implication> r : rules.values())
allRules.addAll(r);
rulesArray_ = allRules.toArray( new Implication [] {} );
}
/**
* Create a reasoner using <tt>kb</tt> for static knowledge and <tt>rules</tt> for
* the collection of knowledge rules. Converts the rules list to an index mapping
* rule head relation name to list of rules with that name as the head.
*
* @param kb The static knowledge.
* @param rules The list of rules.
* @param p The parser whose symbol table to refer to.
*/
protected AbstractReasoner(KnowledgeBase kb, List<Implication> rules, Parser p)
{
this(kb, p);
rulesArray_ = rules.toArray( new Implication [] {} );
rules_ = new TreeMap<Integer, List<Implication>>();
// Construct the indexed rule table
for ( Implication r : rules )
{
int relName = r.getConsequent().getRelationName();
List<Implication> sublist = rules_.get(relName);
if ( sublist == null )
{
sublist = new ArrayList<Implication>();
rules_.put(relName, sublist);
}
sublist.add(r);
}
}
final public SymbolTable getSymbolTable()
{
return symbolTable_;
}
public GroundFact getAnAnswer(Fact question)
{
ProofContext context = ProofContext.makeDummy(parser_);
return getAnAnswer(question, context);
}
public List<GroundFact> getAllAnswers(Fact question)
{
ProofContext context = ProofContext.makeDummy(parser_);
return getAllAnswers(question, context);
}
/**
* Try to prove a single fact. If provable, returns what was proved;
* if not provable, returns <tt>null</tt>.
*
* <p>For example, if you pass in a variable fact, such as (legal xplayer ?x),
* you will get back either <tt>null</tt> or (e.g.) (legal xplayer noop).
*
* @param question The question ('fact') to prove.
* @param context
* @return
*/
abstract public GroundFact getAnAnswer(Fact question, ProofContext context);
abstract public List<GroundFact> getAllAnswers(Fact question, ProofContext context);
abstract public Iterable<GroundFact> getAllAnswersIterable(Fact question, ProofContext context);
/**
* Return true if <tt>ground</tt> is true in the current proof context.
*
* @param ground
* The ground to check for.
* @param context
* The proof context in which to find the ground. (Provides
* additional knowledge.)
* @return True if the reasoner can find a proof (i.e. existence) for
* <tt>ground</tt>.
*/
protected boolean findGround( GroundFact ground, ProofContext context )
{
// Special case for distinct
if (isDistinctFact(ground)) {
return checkDistinct(ground);
}
return kb_.isTrue(ground) || context.isTrue(ground);
}
protected List<Substitution> getUnifiableGrounds(VariableFact varFact, ProofContext context)
{
List<Substitution> grounds = kb_.getUnifiable(varFact);
List<Substitution> moreUnifiable = context.getUnifiableGrounds(varFact);
if (moreUnifiable != null) {
grounds.addAll(moreUnifiable);
}
return grounds;
}
/**
* Check if two terms are distinct. (The terms checked are columns 0 and 1
* of the argument.)
*
* @param ground The distinct relation.
*
* @return True if the two terms are distinct.
*/
protected boolean checkDistinct(GroundFact ground)
{
if ( ground.getTerm(0).equals(ground.getTerm(1)) )
return false;
else
return true;
}
final private static List<Implication> EMPTY_RULE_LIST = new ArrayList<Implication>(0);
/**
* Get all rules that have fact <tt>f</tt> at their head.
*
* @param f Fact for which to find rules.
* @return An array of rules with fact <tt>f</tt> at their head.
*/
public List<Implication> getRules(Fact f)
{
List<Implication> rules;
rules = rules_.get(f.getRelationName());
if ( rules == null )
return EMPTY_RULE_LIST;
else
return rules;
}
public boolean isDistinctFact(Fact f)
{
return f.getRelationName() == parser_.TOK_DISTINCT;
}
public boolean isDoesFact(Fact f)
{
return f.getRelationName() == parser_.TOK_DOES;
}
}