package org.matheclipse.core.generic;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import org.matheclipse.core.convert.AST2Expr;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.exception.WrongArgumentType;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.core.patternmatching.PatternMatcherAndEvaluator;
import org.matheclipse.parser.client.Parser;
import org.matheclipse.parser.client.ast.ASTNode;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
public class Functors {
private static class AppendFunctor implements Function {
protected final IAST fAST;
/**
*
* @param ast
* the AST which should be cloned in the {@code apply} method
*/
public AppendFunctor(final IAST ast) {
fAST = ast;
}
@Override
public IExpr apply(final IExpr arg) {
final IAST ast = fAST.clone();
ast.add(arg);
return ast;
}
}
private static class ApplyFunctor implements Function {
final IExpr fConstant;
public ApplyFunctor(IExpr constant) {
this.fConstant = constant;
}
@Override
public IExpr apply(final IExpr arg) {
IAST result = null;
if (arg.isAST()) {
result = ((IAST) arg).clone();
result.set(0, fConstant);
}
return result;
}
}
private static class EvalArgFunctor implements Function {
EvalEngine fEngine;
IAST fAST;
int fPosition;
/**
* Create a functor which evaluates the given ast as a
* function with the argument at the given position
* replaced in the apply() method.
*
* @param ast
* the function which should be evaluated
* @param position
* the position at which the argument should be replaced
* @param engine
* the current evaluation engine
* @return
*/
public EvalArgFunctor(IAST ast, int position, EvalEngine engine) {
this.fEngine = engine;
this.fAST = ast;
fPosition = position;
}
@Override
public IExpr apply(final IExpr arg) {
IAST ast = fAST.clone();
ast.set(fPosition, arg);
return fEngine.evaluate(ast);
}
}
private static class CollectFunctor implements Function {
protected Collection super IExpr> resultCollection;
/**
*
* @param ast
* the AST which should be cloned in the {@code apply} method
*/
public CollectFunctor(Collection super IExpr> resultCollection) {
this.resultCollection = resultCollection;
}
@Override
public IExpr apply(final IExpr arg) {
resultCollection.add(arg);
return null;
}
}
private static class ConstantFunctor implements Function {
final IExpr fConstant;
public ConstantFunctor(final IExpr expr) {
fConstant = expr;
}
@Override
public IExpr apply(final IExpr arg) {
return fConstant;
}
}
private static class ReplaceArgFunctor implements Function {
private final IAST fConstant;
private final int fPosition;
/**
*
* @param ast
* the complete AST which should be cloned in the
* {@code apply} method
* @param position
* the position which should be replaced in the
* apply() method.
*/
public ReplaceArgFunctor(final IAST ast, int position) {
fConstant = ast;
fPosition = position;
}
@Override
public IExpr apply(final IExpr arg) {
final IAST ast = fConstant.clone();
ast.set(fPosition, arg);
return ast;
}
}
private static class ReplaceAllFunctor implements Function {
private final IAST fConstant;
private final IExpr fLHS;
/**
*
* @param ast
* the complete AST which should be cloned in the
* {@code apply} method
* @param position
* the position which should be replaced in the
* apply() method.
*/
public ReplaceAllFunctor(final IAST ast, IExpr lhs) {
fConstant = ast;
fLHS = lhs;
}
@Override
public IExpr apply(final IExpr arg) {
return fConstant.replaceAll(F.Rule(fLHS, arg));
}
}
private static class RulesFunctor implements Function {
private final Map extends IExpr, ? extends IExpr> fEqualRules;
/**
*
* @param plusAST
* the complete AST which should be cloned in the
* {@code apply} method
* @param position
* the position which should be replaced in the
* apply() method.
*/
public RulesFunctor(Map extends IExpr, ? extends IExpr> rulesMap) {
fEqualRules = rulesMap;
}
@Override
public IExpr apply(final IExpr arg) {
return fEqualRules.get(arg);
}
}
private static class RulesPatternFunctor implements Function {
private final Map fEqualRules;
private final List fMatchers;
/**
*
* @param plusAST
* the complete AST which should be cloned in the
* {@code apply} method
* @param position
* the position which should be replaced in the
* apply() method.
*/
public RulesPatternFunctor(Map equalRules, List matchers) {
fEqualRules = equalRules;
fMatchers = matchers;
}
@Override
public IExpr apply(final IExpr arg) {
IExpr temp = fEqualRules.get(arg);
if (temp != null) {
return temp;
}
for (int i = 0; i < fMatchers.size(); i++) {
temp = fMatchers.get(i).eval(arg);
if (temp != null) {
return temp;
}
}
return null;
}
}
private static class ScanFunctor implements Function {
protected final IAST fAST;
protected Collection super IExpr> resultCollection;
/**
*
* @param ast
* the AST which should be cloned in the {@code apply} method
*/
public ScanFunctor(final IAST ast, Collection super IExpr> resultCollection) {
fAST = ast;
this.resultCollection = resultCollection;
}
@Override
public IExpr apply(final IExpr arg) {
final IAST ast = fAST.clone();
ast.add(arg);
resultCollection.add(ast);
return null;
}
}
/**
* Return a function which clones the given AST and appends the argument to
* the cloned AST in the apply() method. The clone is then
* appended to the result collection.
*
* @param ast
* the AST which should be cloned and appended to in the
* {@code apply} method
* @param resultCollection
* the collection to which the cloned AST will be appended
* @return
*/
public static Function scan(@Nonnull final IAST ast, @Nonnull Collection super IExpr> resultCollection) {
return new ScanFunctor(ast, resultCollection);
}
/**
* Return a function which clones the given AST and appends the argument to
* the cloned AST in the apply() method.
*
* @param ast
* the AST which should be cloned in the {@code apply} method
* @return
*/
public static Function append(@Nonnull IAST ast) {
return new AppendFunctor(ast);
}
/**
* Create a functor which evaluates the given ast as a function
* with the argument at the given position replaced in the
* apply() method.
*
* @param ast
* the function which should be evaluated
* @param position
* the position at which the argument should be replaced
* @param engine
* the current evaluation engine
* @return
*/
public static Function evalArg(@Nonnull IAST ast, int position, @Nonnull EvalEngine engine) {
return new EvalArgFunctor(ast, position, engine);
}
/**
* Return a function which clones the argument, if it is of type AST and
* sets the header to the given expr. expr is
* typically a symbol.
*
* @param expr
* @return
*/
public static Function apply(@Nonnull IExpr expr) {
return new ApplyFunctor(expr);
}
public static Function collect(@Nonnull Collection super IExpr> resultCollection) {
return new CollectFunctor(resultCollection);
}
/**
* Return a function which returns the given expression in the
* apply() method.
*
* @param expr
* @return
*/
public static Function constant(@Nonnull IExpr expr) {
return new ConstantFunctor(expr);
}
/**
* Create a functor, which replaces all (sub-)expressions in
* ast which equals lhs with the argument of the
* functors apply() method.
*
* @param ast
* an AST which contains the lhs as a placeholder in
* it's subexpressions.
* @param lhs
* left-hand-side of a Rule(lhs,...)
* @return
*/
public static Function replaceAll(@Nonnull IAST ast, @Nonnull IExpr lhs) {
return new ReplaceAllFunctor(ast, lhs);
}
/**
* Create a functor, which replaces the argument at the first position in
* the ast with the argument of the functors
* apply() method.
*
* @param ast
* an AST where the first argument is replaced with the argument
* of the functors apply() method.
* @return
*/
public static Function replace1st(@Nonnull IAST ast) {
return new ReplaceArgFunctor(ast, 1);
}
/**
* Create a functor, which replaces the argument at the second position in
* the ast with the argument of the functors
* apply() method.
*
* @param ast
* an AST where the second argument is replaced with the argument
* of the functors apply() method.
* @return
*/
public static Function replace2nd(@Nonnull IAST ast) {
return new ReplaceArgFunctor(ast, 2);
}
/**
* Create a functor, which replaces the argument at the given position in
* the ast with the argument of the functors
* apply() method.
*
* @param ast
* an AST where the element at the given position is
* replaced with the argument of the functors
* apply() method.
* @param position
* the position of the element, which should be replaced in the
* ast.
* @return
*/
public static Function replaceArg(@Nonnull IAST ast, int position) {
return new ReplaceArgFunctor(ast, position);
}
/**
* Create a functor from the given map, which calls the
* rulesMap.get() in the functors applymethod.
*
* @param rulesMap
* @return
*/
public static Function rules(Map extends IExpr, ? extends IExpr> rulesMap) {
return new RulesFunctor(rulesMap);
}
/**
* Create a functor from the given rules. All strings in
* strRules are parsed in internal rules form.
*
* @param strRules
* array of rules of the form "x->y"
* @return
* @throws WrongArgumentType
*/
public static Function rules(@Nonnull String[] strRules) throws WrongArgumentType {
IAST astRules = F.List();
final Parser parser = new Parser();
final EvalEngine engine = EvalEngine.get();
for (String str : strRules) {
final ASTNode parsedAST = parser.parse(str);
IExpr expr = AST2Expr.CONST.convert(parsedAST);
expr = engine.evaluate(expr);
astRules.add(expr);
}
return rules(astRules);
}
/**
* Create a functor from the given rules. If astRules is a
* List[] object, the elements of the list are taken as the
* rules of the form Rule[lhs, rhs], otherwise the
* astRules itself is taken as the Rule[lhs, rhs].
*
* @param astRules
* @return
* @throws WrongArgumentType
*/
public static Function rules(@Nonnull IAST astRules) throws WrongArgumentType {
Map equalRules = new HashMap();
List matchers = new ArrayList();
if (astRules.isList()) {
// assuming multiple rules in a list
IAST rule;
for (final IExpr expr : astRules) {
if (expr.isRuleAST()) {
rule = (IAST) expr;
addRuleToCollection(equalRules, matchers, rule);
} else {
throw new WrongArgumentType(astRules, astRules, -1, "Rule expression (x->y) expected: ");
}
}
} else {
if (astRules.isRuleAST()) {
addRuleToCollection(equalRules, matchers, astRules);
} else {
throw new WrongArgumentType(astRules, astRules, -1, "Rule expression (x->y) expected: ");
}
}
if (matchers.size() > 0) {
return new RulesPatternFunctor(equalRules, matchers);
}
return rules(equalRules);
}
private static Predicate PATTERNQ_PREDICATE = new Predicate() {
@Override
public boolean apply(IExpr input) {
return input.isPattern();
}
};
private static void addRuleToCollection(Map equalRules, List matchers, IAST rule) {
if (rule.get(1).isFree(PATTERNQ_PREDICATE, true)) {
if (rule.get(1).isOrderlessAST() || rule.get(1).isFlatAST()) {
matchers.add(new PatternMatcherAndEvaluator(F.SetDelayed, rule.get(1), rule.get(2)));
return;
}
equalRules.put(rule.get(1), rule.get(2));
} else {
matchers.add(new PatternMatcherAndEvaluator(F.SetDelayed, rule.get(1), rule.get(2)));
}
}
private Functors() {
}
}
Ads help maintain this website.