package org.matheclipse.core.patternmatching;
import java.io.Serializable;
import org.matheclipse.core.builtin.function.Condition;
import org.matheclipse.core.builtin.function.Module;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.exception.ConditionException;
import org.matheclipse.core.eval.exception.ReturnException;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.ISymbol;
public class PatternMatcherAndEvaluator extends PatternMatcher implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2241135467123931061L;
private IExpr fRightHandSide;
private ISymbol fSetSymbol;
/**
*
* @param setSymbol
* the symbol which defines this pattern-matching rule (i.e. Set,
* SetDelayed,...)
* @param leftHandSide
* could contain pattern expressions for "pattern-matching"
* @param rightHandSide
* the result which should be evaluated if the "pattern-matching"
* succeeds
*/
public PatternMatcherAndEvaluator(final ISymbol setSymbol, final IExpr leftHandSide, final IExpr rightHandSide) {
super(leftHandSide);
fSetSymbol = setSymbol;
fRightHandSide = rightHandSide;
}
@Override
public Object clone() throws CloneNotSupportedException {
PatternMatcherAndEvaluator v = (PatternMatcherAndEvaluator) super.clone();
v.fRightHandSide = fRightHandSide;
v.fSetSymbol = fSetSymbol;
return v;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof PatternMatcherAndEvaluator) {
PatternMatcherAndEvaluator pm = (PatternMatcherAndEvaluator) obj;
// don't compare fSetSymbol here
if (super.equals(pm)) {
// return equivalentRHS(fRightHandSide, pm.fRightHandSide);
if (fRightHandSide.isCondition()) {
if (pm.fRightHandSide.isCondition()) {
return equivalentRHS(fRightHandSide.getAt(2), pm.fRightHandSide.getAt(2), fPatternMap, pm.fPatternMap);
}
return false;
} else if (pm.fRightHandSide.isCondition()) {
return false;
} else if (fRightHandSide.isModule()) {
if (pm.fRightHandSide.isModule()) {
return equivalentRHS(fRightHandSide.getAt(2), pm.fRightHandSide.getAt(2), fPatternMap, pm.fPatternMap);
}
return false;
} else if (pm.fRightHandSide.isModule()) {
return false;
}
return true;
}
}
return false;
}
/**
* Check if the two expressions are equivalent. (i.e. f[x_,y_]
* is equivalent to f[a_,b_] )
*
* @param patternExpr1
* @param patternExpr2
* @param pm1
* TODO
* @param pm2
* TODO
* @return
*/
private static boolean equivalentRHS(final IExpr patternExpr1, final IExpr patternExpr2, final PatternMap pm1,
final PatternMap pm2) {
if (patternExpr1.isCondition()) {
if (patternExpr2.isCondition()) {
return equivalentRHS(patternExpr1.getAt(2), patternExpr2.getAt(2), pm1, pm2);
}
return false;
} else if (patternExpr2.isCondition()) {
return false;
} else if (patternExpr1.isModule()) {
if (patternExpr2.isModule()) {
return equivalentRHS(patternExpr1.getAt(2), patternExpr2.getAt(2), pm1, pm2);
}
return false;
} else if (patternExpr2.isModule()) {
return false;
}
// TODO refine equivalent for RHS symbols which are patterns on the LHS.
return equivalent(patternExpr1, patternExpr2);
}
@Override
public int hashCode() {
return super.hashCode() * 53;
}
/**
* Check if the condition for the right-hand-sides
* Module[] or Condition[] expressions evaluates to
* true.
*
* @return true if the right-hand-sides condition is fulfilled.
*/
@Override
public boolean checkRHSCondition(EvalEngine engine) {
if (!(fRightHandSide.isModule() || fRightHandSide.isCondition())) {
return true;
}
if (!fPatternMap.isAllPatternsAssigned()) {
return true;
}
IExpr substConditon = fPatternMap.substitutePatternSymbols(fRightHandSide);
if (substConditon.isCondition()) {
return Condition.checkCondition(substConditon.getAt(1), substConditon.getAt(2), engine);
} else if (substConditon.isModule()) {
return Module.checkModuleCondition(substConditon.getAt(1), substConditon.getAt(2), engine);
}
return true;
}
/**
* Match the (left-hand-side) pattern with the given expression. If true
* evaluate the right-hand-side for the determined values of the patterns
*
* @param ee
* @param evalExpr
* @return
*/
@Override
public IExpr eval(final IExpr lhsEvalExpr) {
// if(fRightHandSide.isAST("Condition")) {
// System.out.println("2:"+fRightHandSide);
// }
if (isRuleWithoutPatterns()) {
// no patterns found match equally:
if (fLhsPatternExpr.equals(lhsEvalExpr)) {
IExpr result = fRightHandSide;
try {
IExpr temp = F.eval(result);
if (temp != null) {
return temp;
}
return result;
} catch (final ConditionException e) {
return null;
} catch (final ReturnException e) {
return e.getValue();
}
}
if (!(fLhsPatternExpr.isOrderlessAST() && lhsEvalExpr.isOrderlessAST())) {
if (!(fLhsPatternExpr.isFlatAST() && lhsEvalExpr.isFlatAST())) {
return null;
}
// TODO implement equals matching for special cases, if the AST
// is
// Orderless or Flat
}
}
if (fLhsPatternExpr.isAST() && lhsEvalExpr.isAST()) {
fPatternMap.initPattern();
IExpr result = evalAST((IAST) fLhsPatternExpr, (IAST) lhsEvalExpr, fRightHandSide, new StackMatcher());
if (result != null) {
return result;
}
}
fPatternMap.initPattern();
if (matchExpr(fLhsPatternExpr, lhsEvalExpr)) {
IExpr result = fPatternMap.substitutePatternSymbols(fRightHandSide);
try {
result = F.eval(result);
} catch (final ConditionException e) {
return null;
} catch (final ReturnException e) {
result = e.getValue();
}
return result;
}
return null;
}
@Override
public IExpr getRHS() {
return fRightHandSide;
}
public ISymbol getSetSymbol() {
return fSetSymbol;
}
}
Ads help maintain this website.