/////////////////////////////////////////////////////////////////////// // STANFORD LOGIC GROUP // // General Game Playing Project // // // // Sample Player Implementation // // // // (c) 2007. See LICENSE and CONTRIBUTORS. // /////////////////////////////////////////////////////////////////////// /** * */ package stanfordlogic.prover; import java.io.PrintStream; import java.util.Arrays; import java.util.Map; import stanfordlogic.gdl.GdlAtom; import stanfordlogic.gdl.GdlExpression; import stanfordlogic.gdl.GdlList; import stanfordlogic.gdl.SymbolTable; /** * */ public class GroundFact extends Fact implements Comparable<GroundFact> { final private boolean onlyTermObjects_; public GroundFact(int relationName) { this(false, relationName, (Term[]) null); } /** * Construct a fact of relation <tt>relationName</tt> with columns <tt>cols</tt> of * object constants. * * @param relationName The name of the relation. * @param cols The columns of this fact, all object constants. */ public GroundFact(int relationName, int ... cols) { super(relationName); if ( cols == null ) terms_ = EMPTY_TERMS; else { terms_ = new Term [cols.length]; for ( int i = 0; i < cols.length; i++ ) terms_[i] = TermObject.makeTermObject(cols[i]); } onlyTermObjects_ = true; } public GroundFact(int relationName, Term ... cols) { this(true, relationName, cols); } public GroundFact(boolean clone, int relationName, Term ... cols) { super(relationName); boolean onlyTermObjects = true; if ( cols == null ) terms_ = EMPTY_TERMS; else { if ( clone ) terms_ = cols.clone(); else terms_ = cols; // Assert that none of the columns have variables. for ( Term t : cols ) { if ( t.hasVariables() ) throw new IllegalArgumentException("GroundFact cannot be constructed with variables!"); if ( t instanceof TermObject == false ) onlyTermObjects = false; } } onlyTermObjects_ = onlyTermObjects; } /** * Construct a fact of relation <tt>relName</tt> with columns * <tt>cols</tt>. Takes strings as arguments, and uses symbol table * <tt>symTab</tt> to convert them to integer form. All columns must be * object constants. * * @param symTab * The symbol table for converting strings to token numbers. * @param relName * The name of the relation, to be converted using * <tt>symtab</tt>. * @param cols * The columns, to be converted using <tt>symtab</tt>, all * representing object constants. */ public GroundFact(SymbolTable symTab, String relName, String ... cols ) { super( symTab.get(relName) ); if ( cols == null || cols.length == 0 ) terms_ = EMPTY_TERMS; else { terms_ = new Term [cols.length]; for ( int i = 0; i < cols.length; i++ ) { terms_[i] = TermObject.makeTermObject( symTab.get( cols[i] ) ); } } onlyTermObjects_ = true; } /** * Construct a fact of arity zero from <tt>atom</tt>. The atom's token is * taken to be the relation name, and the fact has zero columns. * * @param atom The atom to build the fact from. */ public GroundFact(GdlAtom atom) { this( atom.getToken() ); } /** * Clone this ground fact, but with a new relation name. Keeps all columns * intact. * * @param newRelName The new name for the ground fact relation. * @return The cloned fact with the different name. */ public GroundFact clone(int newRelName) { // False means don't clone the terms. return new GroundFact(false, newRelName, this.terms_); } @Override public GroundFact applySubstitution( Substitution sigma ) { // Ground facts do not have variables, so there is nothing to do. return this; } @Override public boolean hasOnlyTermObjects() { return onlyTermObjects_; } @Override public boolean canMapVariables( Expression other ) { if ( other instanceof GroundFact == false ) return false; GroundFact gf = (GroundFact) other; if ( relationName_ != gf.relationName_ || getArity() != gf.getArity() ) return false; // For ground facts, no variables, so things must be straight equal. for ( int i = 0; i < getArity(); i++ ) { if ( getTerm(i).equals(gf.getTerm(i)) == false ) return false; } return true; } /** * Construct a fact from a GdlList. Note that the list <i>must</i> be * a list of atoms, in other words, there cannot be any nested lists. The fact * is constructed by taking the first element of the list as the fact's relation name, * and every subsequent element as a column. * * @param list The list to build the fact from. * * @throws IllegalAccessException when the passed list is not a list of atoms. * * @see cs227b.paulatim.gdl.GdlList * * @return A ground fact representing the data from the list. * */ public static GroundFact fromList(GdlList list) { int relName = ((GdlAtom) list.getElement(0)).getToken(); Term [] terms = new Term [list.getArity()]; for (int i = 0; i < list.getArity(); i++ ) terms[i] = Term.buildFromGdl( list.getElement(i+1) ); return new GroundFact(relName, terms); } public static GroundFact fromExpression(GdlExpression exp) { if ( exp instanceof GdlList ) return fromList( (GdlList) exp); else if ( exp instanceof GdlAtom ) return new GroundFact( (GdlAtom) exp ); // unknown expression type throw new IllegalArgumentException( "GroundFact.fromExpression: don't know how to handle expressions of type " + exp.getClass().getName() ); } @Override public void printToStream(PrintStream target, SymbolTable symtab) { target.print('('); target.print( symtab.get( relationName_ ) ); if ( terms_.length > 0 ) { target.print(' '); int i; for ( i = 0; i < terms_.length - 1; i++ ) { target.print( terms_[i].toString( symtab ) ); target.print( ' ' ); } target.print( terms_[i].toString( symtab ) ); } target.print(')'); } /** * Compare this fact to fact <tt>f</tt>. Facts are compared first * according to their relation name, second according to the number of * columns and finally according to the tokens in the columns. * * @param f * The fact to compare against. * @return -1 if <tt>this</tt> < <tt>f</tt><br> * 0 if <tt>this</tt> == <tt>f</tt><br> * 1 if <tt>this</tt> > <tt>f</tt> */ public int compareTo( GroundFact f ) { if ( this == f ) return 0; int comp = relationName_ - f.relationName_; if ( comp != 0 ) return (comp > 0) ? 1 : -1; // relation names are equal at this point comp = terms_.length - f.terms_.length; if ( comp != 0 ) return (comp > 0) ? 1 : -1; // column lengths are equal at this point for ( int i = 0; i < terms_.length; i++ ) { comp = terms_[i].compareTo(f.terms_[i]); if ( comp != 0 ) return comp; } // Both are equal at this point return 0; } @Override public boolean equals( Object obj ) { if ( this == obj ) return true; if ( obj instanceof GroundFact ) { GroundFact f = (GroundFact) obj; return relationName_ == f.relationName_ && Arrays.equals( terms_, f.terms_ ); } // Not equal. return false; } @Override public GroundFact uniquefy(Map<TermVariable, TermVariable> newVarMap) { // Nothing to do, by definition. return this; } @Override public Substitution unify( Fact f ) { // If this == f, then return a successful unification, using // an empty substitution; the facts are the same. if ( this.equals(f) ) return new Substitution(); // General case: use normal unify algorithm. return super.unify(f); } }