package de.tu_dresden.inf.ggp06_2.resolver;
import java.util.ArrayList;
import java.util.List;
import de.tu_dresden.inf.ggp06_2.resolver.scope.RuleScope;
import de.tu_dresden.inf.ggp06_2.simulator.flags.TimerFlag;
/**
*
* @author Nick (initial author of JavaProver )
* @author Ingo Keller - General Game Playing course student at TUD
* @author Arsen Kostenko - General Game Playing course student at TUD
*
*/
public abstract class Term extends Expression {
/**
* @return Returning 'this' whatever it is: atom or variable.
*/
@Override
public Term firstOperand() {
return this;
}
/**
* @return No second operand for terms. Returning null.
*/
@Override
public Term secondOperand() {
return null;
}
/**
* <code>Term</code> class is actually second one that that meke use
* of GDL rules scopes by getting similar expressions from them.
* Trick about <code>Term</code> is that there might be implication
* consequences (take <i>"terminal"</i> for instance)
* and single predicates (both static and dynamic) recieved
* after matching with existing data. So major trick is a kind of branching.
* Another point is that <code>chain</code> method is looking for all
* possible resolutions. Here is a step by step behavior:
* <ol>
* <li> ask current GDL scope for similar predicates.</li>
* <li> iterate through each of the predicates:
* <ol>
* <li> check type of expression being currently iterated
* <ol>
* <li> if an implication happens to be retrieved:
* <ol>
* <li> ask it's consiquence for a MGU</li>
* <li> proceed to <code>chain</code> of the premises (those are
* stored in an <code>ExpressionList</code></li>
* <li> store the result</li>
* </ol></li>
* <li> otherwise just as for an MGU with iterated expression</li>
* </ol></li>
* <li> store any non-empty results</li>
* </ol>
* </li>
* <li> if no results were accumulated, assume it as resolution failure
* and return empty list of substitutions</li>
* </ol>
*
* @see de.tu_dresden.inf.ggp06_2.resolver.Predicate#chainBody(Substitution, RuleScope, TimerFlag) Predicate.chainBody
* @see de.tu_dresden.inf.ggp06_2.resolver.ExpressionList#chain(Substitution, RuleScope, TimerFlag) ExpressionList.chain
* @param sigma Current state of resolution
* @param scope Scope of GDL rules used for resolution
* @param flag Timer flag, which is checked before every step of resolution.
* @return Returns list of substitutions that were produced during resolution
* procedure.
* @throws InterruptedException This exception is thrown once time expires during
* procedure.
*/
@Override
protected List<Substitution> chainBody( Substitution sigma,
RuleScope scope,
TimerFlag flag )
throws InterruptedException {
// First: Check for memoized values
if ( scope.isDisproven(this) )
return new ArrayList<Substitution>();
else if ( scope.isProven(this) )
return scope.getProven(sigma, this);
// Second: calculate substitutions
List<Substitution> answers = chainSimilarExpressions( sigma, scope, flag );
// Third: store result for future.
if ( !answers.isEmpty() )
scope.setProven( this, answers );
else
scope.setDisproven(this);
return answers;
}
/**
* This private method acts only as an entry point for <code>chain</code>
* method. It hides all the stuff specific to getting similar expressions
* from the rules scope and iterating over them. Implemented only for the
* sake of readability.
*
* @see de.tu_dresden.inf.ggp06_2.resolver.Term#chainBody(Substitution, RuleScope, TimerFlag) chainBody
* @param sigma Current state of resolution
* @param scope Scope of GDL rules used for resolution
* @param flag Timer flag, which is checked before every step of resolution.
* @return Returns list of substitutions that were produced during resolution
* procedure.
* @throws InterruptedException This exception is thrown once time expires during
* procedure.
*/
private List<Substitution> chainSimilarExpressions( Substitution sigma,
RuleScope scope,
TimerFlag flag )
throws InterruptedException {
List<Substitution> answers = new ArrayList<Substitution>();
ExpressionList candidates = scope.getSimilarExpressions(this);
for (Expression anExpression : candidates) {
if (anExpression instanceof Implication) {
chainImplication(
sigma, scope, flag,
answers, (Implication) anExpression );
} else {
Substitution psi = mgu(anExpression, sigma);
if (null != psi)
answers.add(psi);
}
}
return answers;
}
/**
* This private method acts only as an entry point for
* <code>chainSimilarExpressions</code> method
* It takes care of handling any implications that appear during iteration.
* Implemented for the sake of readability only.
*
* @see de.tu_dresden.inf.ggp06_2.resolver.Term#chainSimilarExpressions(Substitution, RuleScope, TimerFlag) chainSimilarExpressions
* @param sigma Current state of resolution
* @param scope Scope of GDL rules used for resolution
* @param flag Timer flag, which is checked before every step of resolution.
* @param accumulator List of substitutions that actually accumulates any
* successful results
* @param imp Current implication to be resolved.
* @throws InterruptedException This exception is thrown once time expires during
* procedure.
*/
private void chainImplication(
Substitution sigma, RuleScope scope, TimerFlag flag,
List<Substitution> accumulator, Implication imp)
throws InterruptedException {
if ( flag.interrupted() ) throw Const.interrupt;
Substitution gamma = mgu(imp.getConsequence(), sigma);
if (gamma != null) {
List<Substitution> psis = imp.getPremises().chain(gamma, scope, flag);
if (psis.size() != 0)
accumulator.addAll(psis);
}
}
/**
* Trick about <code>Term</code> is that there might be implication consequences
* and single predicates (both static and dynamic) recieved after matching
* with existing data. So major trick is a kind of branching. Here is a step
* by step behavior:
* <ol>
* <li> ask current GDL scope for similar predicates.</li>
* <li> iterate through each of the predicates:
* <ol>
* <li>if an implication happens to be retrieved, ask it's
* consiquence for a MGU, and proceed to <code>chainOne</code>
* of the premises (those are stored in an
* <code>ExpressionList</code></li>
* <li>otherwise just ask for an MGU with iterated expression</li>
* <li>if any of iterations produces non-empty result - return it</li>
* </ol>
* </li>
* <li> if no results were returned, assume it as resolution failure
* and return null</li>
* </ol>
*
* @see de.tu_dresden.inf.ggp06_2.resolver.Term#mgu(Expression, Substitution) mgu
* @see de.tu_dresden.inf.ggp06_2.resolver.ExpressionList#chainOne(Substitution, RuleScope, TimerFlag) ExpressionList.chainOne
* @param sigma Current state of resolution
* @param scope Scope of GDL rules used for resolution
* @param flag Timer flag, which is checked before every step of resolution.
* @return Returns one (first) substitution that was produced during resolution
* procedure.
* @throws InterruptedException This exception is thrown once time expires during
* procedure.
*/
@Override
protected Substitution chainOneBody( Substitution sigma,
RuleScope scope,
TimerFlag flag )
throws InterruptedException {
// Check for memoized values
if ( scope.isProven(this) )
return scope.getProven(sigma, this).get(0);
else if ( scope.isDisproven(this) )
return null;
ExpressionList candidates = scope.getSimilarExpressions(this);
Substitution psi;
for (Expression anExpression : candidates) {
if (anExpression instanceof Implication) {
psi = chainOneImplication(
sigma, scope,
flag, (Implication) anExpression );
} else {
psi = mgu(anExpression, sigma);
}
if (psi != null) {
return psi;
}
}
// Memoize failure
scope.setDisproven(this);
return null;
}
/**
* This method acts only as an entry point for <code>chainOne</code> method.
* It actually takes care of handling implication, if an implication
* happens among expression returned by scope.
*
* @see de.tu_dresden.inf.ggp06_2.resolver.Term#chainOne(Substitution, RuleScope, TimerFlag) chainOne
* @param sigma State of resolution
* @param scope GDL rules scope
* @param flag Timer flag
* @param imp Actual implication to resolve with
* @return Returns substitution that resolves current predicate to given
* implication, if there is any.
* @throws InterruptedException This exception is thrown once time expires during
* procedure.
*/
private Substitution chainOneImplication( Substitution sigma,
RuleScope scope,
TimerFlag flag,
Implication imp )
throws InterruptedException {
if ( flag.interrupted() ) throw Const.interrupt;
Substitution gamma = mgu( imp.getConsequence(), sigma );
if ( gamma != null )
return imp.getPremises().chainOne(gamma, scope, flag);
return null;
}
@Override
public int getOperandCount() {
return 0;
}
}