///////////////////////////////////////////////////////////////////////
// STANFORD LOGIC GROUP //
// General Game Playing Project //
// //
// Sample Player Implementation //
// //
// (c) 2007. See LICENSE and CONTRIBUTORS. //
///////////////////////////////////////////////////////////////////////
/**
*
*/
package stanfordlogic.prover;
import java.util.Arrays;
import java.util.Map;
import stanfordlogic.gdl.SymbolTable;
/**
*
* @author Based on code by Team Camembert: David Haley, Pierre-Yves Laligand
*/
public class TermFunction extends Term
{
final public int functionName_;
protected Term [] arguments_; // these arguments are either variables or objects
final private int totalColumns_;
final private static Term [] EMPTY_ARGS = new Term[0];
private boolean hasVariables_;
public TermFunction(int funcName, Term [] args)
{
this(true, funcName, args);
}
public TermFunction(boolean cloneCols, int funcName, Term [] args)
{
functionName_ = funcName;
if ( args == null )
{
arguments_ = EMPTY_ARGS;
hasVariables_ = false;
}
else
{
// Check if any of the term arguments are variables
boolean vars = false;
for ( Term t : args )
{
if ( t.hasVariables() )
vars = true;
}
hasVariables_ = vars;
if ( cloneCols )
arguments_ = args.clone();
else
arguments_ = args;
}
// Compute the total columns needed
int total = 1; // 1 for the name
for ( Term t: arguments_ )
total += t.getTotalColumns();
totalColumns_ = total;
}
public int getArity()
{
return arguments_.length;
}
public int getName()
{
return functionName_;
}
public Term getTerm(int whichOne)
{
return arguments_[whichOne];
}
@Override
public int getTotalColumns()
{
// Only need one column: object name
return totalColumns_;
}
protected void updateHasVariables()
{
boolean vars = false;
for ( Term t : arguments_ )
{
if ( t.hasVariables() )
vars = true;
}
hasVariables_ = vars;
}
@Override
public Term clone()
{
Term [] args = new Term[arguments_.length];
for ( int i = 0; i < arguments_.length; i++ )
args[i] = arguments_[i].clone();
return new TermFunction(false, functionName_, args);
}
@Override
public Term applySubstitution( Substitution sigma )
{
Term [] args = new Term [arguments_.length];
for ( int i = 0; i < arguments_.length; i++ )
args[i] = arguments_[i].applySubstitution(sigma);
return new TermFunction(false, functionName_, args);
}
@Override
protected int compareTo( TermFunction t )
{
int comp = functionName_ - t.functionName_;
if ( comp != 0 )
return Integer.signum( comp );
// At this point, function names are equal
comp = arguments_.length - t.arguments_.length;
if ( comp != 0 )
return Integer.signum( comp );
// At this point, both term-functions have same number of arguments
for ( int i = 0; i < arguments_.length; i++ )
{
comp = arguments_[i].compareTo( t.arguments_[i] );
if ( comp != 0 )
return comp;
}
// At this point, the term-functions are equal.
return 0;
}
@Override
public boolean equals( Object obj )
{
if ( obj instanceof TermFunction == false )
return false;
TermFunction func = (TermFunction) obj;
return functionName_ == func.functionName_
&& Arrays.equals( arguments_, func.arguments_ );
}
@Override
protected int compareTo( TermObject t )
{
// Obj < Func < Var
return 1;
}
@Override
protected int compareTo( TermVariable t )
{
// Obj < Func < Var
return -1;
}
@Override
public boolean canMapVariables( Term other, Map<TermVariable, TermVariable> varMap )
{
if ( other instanceof TermFunction == false )
return false;
TermFunction tf = (TermFunction) other;
if ( getName() != tf.getName() || getArity() != tf.getArity() )
return false;
for ( int i = 0; i < getArity(); i++ )
{
if ( getTerm(i).canMapVariables( tf.getTerm(i), varMap ) == false )
return false;
}
return true;
}
@Override
public String toString( SymbolTable symtab )
{
StringBuilder sb = new StringBuilder();
sb.append('(');
sb.append(symtab.get(functionName_));
if ( arguments_.length > 0 )
sb.append( ' ' );
// Print all but the last argument
int i;
for ( i = 0; i < arguments_.length-1; i++ )
{
sb.append( arguments_[i].toString(symtab) );
sb.append( ' ' );
}
// Print the last argument
sb.append( arguments_[i].toString(symtab) );
sb.append(')');
return sb.toString();
}
@Override
public boolean hasVariables()
{
return hasVariables_;
}
@Override
public boolean hasTermFunction( int functionName )
{
if ( functionName_ == functionName )
return true;
for ( Term t : arguments_ )
if ( t.hasTermFunction(functionName) )
return true;
return false;
}
@Override
public boolean hasVariable( int varName )
{
for (Term t: arguments_) {
if (t.hasVariable(varName)) {
return true;
}
}
return false;
}
@Override
public Term uniquefy( Map<TermVariable, TermVariable> newVarMap )
{
Term [] newArgs = new Term [arguments_.length];
for ( int i = 0; i < arguments_.length; i++ )
newArgs[i] = arguments_[i].uniquefy(newVarMap);
return new TermFunction(false, functionName_, newArgs);
}
@Override
public boolean mgu( Term t, Substitution subsSoFar )
{
if ( t instanceof TermObject )
{
// Cannot map functions to constants.
return false;
}
else if ( t instanceof TermVariable )
{
// Reverse the problem; the TermVariable class handles this
return ((TermVariable) t).mgu(this, subsSoFar);
}
else if ( t instanceof TermFunction )
{
TermFunction f = (TermFunction) t;
// Make sure that our function names are equal
if ( functionName_ != f.functionName_ )
return false;
// Make sure arities are the same
if ( getArity() != f.getArity() )
return false;
// Finally, make sure we can get the mgu of all arguments
for ( int i = 0; i < getArity(); i++ )
{
if ( arguments_[i].mgu( f.arguments_[i], subsSoFar) == false )
return false;
}
// All good!
return true;
}
else
{
throw new IllegalArgumentException(
"TermFunction.mgu: Don't know how to handle term of type "
+ t.getClass().getName() );
}
}
/**
* Checks whether the function contains references to the input variable.
* Used for unification of a variable and a function ('occurs' check).
*
* @param variable The variable whose presence to check for.
* @return True if <tt>variable</tt> appears anywhere within the function's arguments.
*/
public boolean hasVariable(TermVariable variable)
{
for ( int i = 0; i < getArity(); i++ )
{
if(arguments_[i] instanceof TermVariable)
{
if(((TermVariable) arguments_[i]).equals(variable))
return true;
}
else if(arguments_[i] instanceof TermFunction)
{
if(((TermFunction) arguments_[i]).hasVariable(variable))
return true;
}
}
return false;
}
}