/////////////////////////////////////////////////////////////////////// // STANFORD LOGIC GROUP // // General Game Playing Project // // // // Sample Player Implementation // // // // (c) 2007. See LICENSE and CONTRIBUTORS. // /////////////////////////////////////////////////////////////////////// /** * */ package stanfordlogic.knowledge; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import stanfordlogic.gdl.SymbolTable; import stanfordlogic.prover.GroundFact; import stanfordlogic.prover.Substitution; import stanfordlogic.prover.TermFunction; import stanfordlogic.prover.VariableFact; /** * A basic knowledge base implementation. Uses a mapping of relation * name to set of things true in that relation. * * <p> * For example: * * <pre> * true * |- init(1,1,b) ; init(1,2;x) ; init(1,3,o) ; ... * succ * |- 1,2 ; 2,3 ; 3,4 ; ... * </pre> * * @author Based on code by Team Camembert: David Haley, Pierre-Yves Laligand */ public class BasicKB extends KnowledgeBase { private Map<Integer, Set<GroundFact>> database_; private int numFacts_; public BasicKB( ) { database_ = new TreeMap<Integer, Set<GroundFact>>(); numFacts_ = 0; } @Override public void clear() { numFacts_ = 0; database_.clear(); } @Override public int getNumFacts() { return numFacts_; } @Override public boolean isTrue( GroundFact fact ) { return getFacts( fact.getRelationName() ).contains(fact); } @Override public void setTrue( GroundFact fact ) { Set<GroundFact> facts = getFacts( fact.getRelationName() ); // increment numFacts if the element was actually added if ( facts.add( fact ) ) numFacts_ ++; } @Override public void setFalse( GroundFact fact ) { Set<GroundFact> facts = getFacts( fact.getRelationName() ); // decrement numFacts if the element was actually removed if ( facts.remove( fact ) ) numFacts_ --; } /** * Get the facts for a given token of a given arity. * * Note that a fact is really just a row in a table. For a relation of arity * 3 named 'cell', we could have as a fact (cell 1 2 x) which would mean * that the fact as represented here in the code would be [1,2,x]. * * @param token * The token whose facts to get. * * @return A list of facts for the token/arity. */ private Set<GroundFact> getFacts( int token ) { Set<GroundFact> facts; facts = database_.get( token ); // Make sure that this entry in the database exists if ( facts == null ) { facts = new TreeSet<GroundFact>(); database_.put( token, facts ); } return facts; } private class FactsIterator implements Iterator<GroundFact> { private Iterator<Integer> relationIterator_; private Iterator<GroundFact> currentIterator_ = null; private FactsIterator() { relationIterator_ = database_.keySet().iterator(); advanceIterator(); } private void advanceIterator() { if ( relationIterator_.hasNext() ) currentIterator_ = database_.get(relationIterator_.next()).iterator(); else currentIterator_ = null; } public boolean hasNext() { if ( currentIterator_ == null ) return false; else { if ( currentIterator_.hasNext() ) return true; else { advanceIterator(); return hasNext(); } } } public GroundFact next() { // Get the current element return currentIterator_.next(); } public void remove() { throw new UnsupportedOperationException("Can't remove from NaiveKB iteration"); } } @Override public Iterator<GroundFact> getIterator() { return new FactsIterator(); } @Override public void stateToGdl( PrintStream target, SymbolTable symtab ) { // iterate over all facts, printing them out for ( Set<GroundFact> facts : database_.values() ) { for ( GroundFact f : facts ) f.printToStream( target, symtab ); } } @Override public List<GroundFact> getFacts(boolean sorted) { List<GroundFact> c = new ArrayList<GroundFact>(); // iterate through all facts, adding them to the collection for ( Set<GroundFact> facts : database_.values() ) { for ( GroundFact f : facts ) c.add( f ); } if ( sorted ) Collections.sort(c); return c; } @Override public List<Substitution> getUnifiable(VariableFact fact) { List<Substitution> result = new ArrayList<Substitution>(); Set<GroundFact> facts = database_.get(fact.getRelationName()); if( facts == null ) return result; if(fact.getArity() > 0 && fact.getTerm(0) instanceof TermFunction) { for(GroundFact nFact : facts) { // THINK: do we really want to get getArity() > 0 here? // maybe the variable fact should bind to a 0-arity function. // THINK: write a junit test case for this. if(nFact.getArity() > 0 && nFact.getTerm(0) instanceof TermFunction) { if(((TermFunction) nFact.getTerm(0)).functionName_ == ((TermFunction) fact.getTerm(0)).functionName_) { Substitution s = fact.unify(nFact); if ( s != null ) result.add(s); } } } } else { for(GroundFact nFact : facts) { Substitution s = fact.unify(nFact); if ( s != null ) result.add( s ); } } return result; } @Override public boolean equals(Object other) { if(! (other instanceof BasicKB)) return false; List<GroundFact> mine = getFacts(); List<GroundFact> his = ((BasicKB) other).getFacts(); if(mine.size() != his.size()) return false; for(int i=0; i<mine.size(); i++ ) { if(!mine.get(i).equals(his.get(i))) return false; } return true; } }