/*
* Copyright 2005-2008 Axel Kramer (axelclk@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matheclipse.parser.client.eval;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.matheclipse.parser.client.Parser;
import org.matheclipse.parser.client.SyntaxError;
import org.matheclipse.parser.client.ast.ASTNode;
import org.matheclipse.parser.client.ast.FunctionNode;
import org.matheclipse.parser.client.ast.NumberNode;
import org.matheclipse.parser.client.ast.SymbolNode;
import org.matheclipse.parser.client.math.ArithmeticMathException;
import org.matheclipse.parser.client.operator.ASTNodeFactory;
/**
* Evaluate math expressions to double numbers.
*
*/
public class DoubleEvaluator {
private static final boolean DEBUG = false;
public static double EPSILON = 1.0e-15;
private static Map SYMBOL_DOUBLE_MAP;
private static Map SYMBOL_BOOLEAN_MAP;
private static Map FUNCTION_DOUBLE_MAP;
private static Map FUNCTION_BOOLEAN_MAP;
private IDoubleCallbackFunction fCallbackFunction = null;
/**
* A callback function for unknown function names.
*
* @return the callback function
*/
public IDoubleCallbackFunction getCallbackFunction() {
return fCallbackFunction;
}
/**
* Set a callback function for unknown function names.
*
* @param callbackFunction
* the callback function to set
*/
public void setCallbackFunction(IDoubleCallbackFunction callbackFunction) {
fCallbackFunction = callbackFunction;
}
static class ArcTanFunction implements IDouble1Function, IDouble2Function {
public double evaluate(double arg1) {
return Math.atan(arg1);
}
public double evaluate(double arg1, double arg2) {
return Math.atan2(arg1, arg2);
}
}
static class LogFunction implements IDouble1Function, IDouble2Function {
public double evaluate(double arg1) {
return Math.log(arg1);
}
public double evaluate(double base, double z) {
return Math.log(z) / Math.log(base);
}
}
static class CompoundExpressionFunction implements IDoubleFunction {
public double evaluate(DoubleEvaluator engine, FunctionNode function) {
double result = Double.NaN;
int end = function.size();
for (int i = 1; i < end; i++) {
result = engine.evaluateNode(function.getNode(i));
if (DEBUG) {
System.out.println(result);
}
}
return result;
}
}
static class SetFunction implements IDoubleFunction {
public double evaluate(DoubleEvaluator engine, FunctionNode function) {
if (function.size() != 3) {
throw new ArithmeticMathException("SetFunction#evaluate(DoubleEvaluator,FunctionNode) needs 2 arguments: "
+ function.toString());
}
if (!(function.getNode(1) instanceof SymbolNode)) {
throw new ArithmeticMathException(
"SetFunction#evaluate(DoubleEvaluator,FunctionNode) symbol required on the left hand side: "
+ function.toString());
}
String variableName = ((SymbolNode) function.getNode(1)).getString();
double result = engine.evaluateNode(function.getNode(2));
IDoubleValue dv = engine.getVariable(variableName);
if (dv == null) {
dv = new DoubleVariable(result);
} else {
dv.setValue(result);
}
engine.defineVariable(variableName, dv);
return result;
}
}
static class MaxFunction implements IDoubleFunction, IDouble2Function {
public double evaluate(double arg1, double arg2) {
return Math.max(arg1, arg2);
}
public double evaluate(DoubleEvaluator engine, FunctionNode function) {
double result = Double.MIN_VALUE;
double temp;
int end = function.size();
for (int i = 1; i < end; i++) {
temp = Math.max(result, engine.evaluateNode(function.getNode(i)));
if (temp > result) {
result = temp;
}
}
return result;
}
}
static class MinFunction implements IDoubleFunction, IDouble2Function {
public double evaluate(double arg1, double arg2) {
return Math.min(arg1, arg2);
}
public double evaluate(DoubleEvaluator engine, FunctionNode function) {
double result = Double.MAX_VALUE;
double temp;
int end = function.size();
for (int i = 1; i < end; i++) {
temp = Math.min(result, engine.evaluateNode(function.getNode(i)));
if (temp < result) {
result = temp;
}
}
return result;
}
}
static class PlusFunction implements IDoubleFunction, IDouble2Function {
public double evaluate(double arg1, double arg2) {
return arg1 + arg2;
}
public double evaluate(DoubleEvaluator engine, FunctionNode function) {
double result = 0.0;
for (int i = 1; i < function.size(); i++) {
result += engine.evaluateNode(function.getNode(i));
}
return result;
}
}
static class TimesFunction implements IDoubleFunction, IDouble2Function {
public double evaluate(double arg1, double arg2) {
return arg1 * arg2;
}
public double evaluate(DoubleEvaluator engine, FunctionNode function) {
double result = 1.0;
for (int i = 1; i < function.size(); i++) {
result *= engine.evaluateNode(function.getNode(i));
}
return result;
}
}
static {
SYMBOL_DOUBLE_MAP = new ConcurrentHashMap();
SYMBOL_DOUBLE_MAP.put("Catalan", new Double(0.91596559417721901505460351493238411077414937428167));
SYMBOL_DOUBLE_MAP.put("Degree", new Double(Math.PI / 180));
SYMBOL_DOUBLE_MAP.put("E", new Double(Math.E));
SYMBOL_DOUBLE_MAP.put("Pi", new Double(Math.PI));
SYMBOL_DOUBLE_MAP.put("EulerGamma", new Double(0.57721566490153286060651209008240243104215933593992));
SYMBOL_DOUBLE_MAP.put("Glaisher", new Double(1.2824271291006226368753425688697917277676889273250));
SYMBOL_DOUBLE_MAP.put("GoldenRatio", new Double(1.6180339887498948482045868343656381177203091798058));
SYMBOL_DOUBLE_MAP.put("Khinchin", new Double(2.6854520010653064453097148354817956938203822939945));
SYMBOL_BOOLEAN_MAP = new ConcurrentHashMap();
SYMBOL_BOOLEAN_MAP.put("False", Boolean.FALSE);
SYMBOL_BOOLEAN_MAP.put("True", Boolean.TRUE);
FUNCTION_BOOLEAN_MAP = new ConcurrentHashMap();
FUNCTION_BOOLEAN_MAP.put("And", new IBooleanBoolean2Function() {
public boolean evaluate(boolean arg1, boolean arg2) {
return arg1 && arg2;
}
});
FUNCTION_BOOLEAN_MAP.put("Not", new IBooleanBoolean1Function() {
public boolean evaluate(boolean arg1) {
return !arg1;
}
});
FUNCTION_BOOLEAN_MAP.put("Or", new IBooleanBoolean2Function() {
public boolean evaluate(boolean arg1, boolean arg2) {
return arg1 || arg2;
}
});
FUNCTION_BOOLEAN_MAP.put("Equal", new IBooleanDouble2Function() {
public boolean evaluate(double arg1, double arg2) {
return Math.abs(arg1 - arg2) < EPSILON;
}
});
FUNCTION_BOOLEAN_MAP.put("Greater", new IBooleanDouble2Function() {
public boolean evaluate(double arg1, double arg2) {
return arg1 > arg2;
}
});
FUNCTION_BOOLEAN_MAP.put("GreaterEqual", new IBooleanDouble2Function() {
public boolean evaluate(double arg1, double arg2) {
return arg1 >= arg2;
}
});
FUNCTION_BOOLEAN_MAP.put("Less", new IBooleanDouble2Function() {
public boolean evaluate(double arg1, double arg2) {
return arg1 < arg2;
}
});
FUNCTION_BOOLEAN_MAP.put("LessEqual", new IBooleanDouble2Function() {
public boolean evaluate(double arg1, double arg2) {
return arg1 <= arg2;
}
});
FUNCTION_BOOLEAN_MAP.put("Unequal", new IBooleanDouble2Function() {
public boolean evaluate(double arg1, double arg2) {
return !(Math.abs(arg1 - arg2) < EPSILON);
}
});
FUNCTION_DOUBLE_MAP = new ConcurrentHashMap();
FUNCTION_DOUBLE_MAP.put("ArcTan", new ArcTanFunction());
FUNCTION_DOUBLE_MAP.put("CompoundExpression", new CompoundExpressionFunction());
FUNCTION_DOUBLE_MAP.put("Set", new SetFunction());
FUNCTION_DOUBLE_MAP.put("Log", new LogFunction());
FUNCTION_DOUBLE_MAP.put("Max", new MaxFunction());
FUNCTION_DOUBLE_MAP.put("Min", new MinFunction());
FUNCTION_DOUBLE_MAP.put("Plus", new PlusFunction());
FUNCTION_DOUBLE_MAP.put("Times", new TimesFunction());
//
// Functions with 0 argument
//
FUNCTION_DOUBLE_MAP.put("Random", new IDouble0Function() {
public double evaluate() {
return Math.random();
}
});
//
// Functions with 1 argument
//
FUNCTION_DOUBLE_MAP.put("ArcCos", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.acos(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("ArcSin", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.asin(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Ceiling", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.ceil(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Cos", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.cos(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Cosh", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.cosh(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Exp", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.exp(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Floor", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.floor(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Round", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.round(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Sign", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.signum(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Sin", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.sin(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Sinh", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.sinh(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Sqrt", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.sqrt(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Tan", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.tan(arg1);
}
});
FUNCTION_DOUBLE_MAP.put("Tanh", new IDouble1Function() {
public double evaluate(double arg1) {
return Math.tanh(arg1);
}
});
//
// Functions with 2 arguments
//
FUNCTION_DOUBLE_MAP.put("Power", new IDouble2Function() {
public double evaluate(double arg1, double arg2) {
return Math.pow(arg1, arg2);
}
});
}
private Map fVariableMap;
private Map fBooleanVariables;
private ASTNode fNode;
private final boolean fRelaxedSyntax;
private final ASTNodeFactory fASTFactory;
public DoubleEvaluator() {
this(null, false);
}
public DoubleEvaluator(boolean relaxedSyntax) {
this(null, relaxedSyntax);
}
public DoubleEvaluator(ASTNode node, boolean relaxedSyntax) {
fASTFactory = new ASTNodeFactory(relaxedSyntax);
fVariableMap = new HashMap();
fBooleanVariables = new HashMap();
fNode = node;
fRelaxedSyntax = relaxedSyntax;
if (fRelaxedSyntax) {
if (SYMBOL_DOUBLE_MAP.get("pi") == null) {
// init tables for relaxed mode
for (String key : SYMBOL_DOUBLE_MAP.keySet()) {
SYMBOL_DOUBLE_MAP.put(key.toLowerCase(), SYMBOL_DOUBLE_MAP.get(key));
}
for (String key : SYMBOL_BOOLEAN_MAP.keySet()) {
SYMBOL_BOOLEAN_MAP.put(key.toLowerCase(), SYMBOL_BOOLEAN_MAP.get(key));
}
for (String key : FUNCTION_DOUBLE_MAP.keySet()) {
FUNCTION_DOUBLE_MAP.put(key.toLowerCase(), FUNCTION_DOUBLE_MAP.get(key));
}
for (String key : FUNCTION_BOOLEAN_MAP.keySet()) {
FUNCTION_BOOLEAN_MAP.put(key.toLowerCase(), FUNCTION_BOOLEAN_MAP.get(key));
}
}
}
}
/**
* Parse the given expression String and store the resulting
* ASTNode in this DoubleEvaluator
*
* @param expression
* @return
* @throws SyntaxError
*/
public ASTNode parse(String expression) {
Parser p;
if (fRelaxedSyntax) {
p = new Parser(ASTNodeFactory.RELAXED_STYLE_FACTORY, true);
} else {
p = new Parser(ASTNodeFactory.MMA_STYLE_FACTORY, false);
}
fNode = p.parse(expression);
if (fNode instanceof FunctionNode) {
fNode = optimizeFunction((FunctionNode) fNode);
}
return fNode;
}
/**
* Parse the given expression String and return the resulting
* ASTNode
*
* @param expression
* @return
* @throws SyntaxError
*/
public static ASTNode parseNode(String expression, boolean relaxedSyntax) {
DoubleEvaluator doubleEvaluator = new DoubleEvaluator(relaxedSyntax);
return doubleEvaluator.parse(expression);
}
/**
* Parse the given expression String and evaluate it to a
* double value
*
* @param expression
* @return
* @throws SyntaxError
*/
public double evaluate(String expression) {
Parser p;
if (fRelaxedSyntax) {
p = new Parser(ASTNodeFactory.RELAXED_STYLE_FACTORY, true);
} else {
p = new Parser(ASTNodeFactory.MMA_STYLE_FACTORY, false);
}
fNode = p.parse(expression);
if (fNode instanceof FunctionNode) {
fNode = optimizeFunction((FunctionNode) fNode);
}
return evaluateNode(fNode);
}
/**
* Reevaluate the expression (possibly after a new Variable
* assignment)
*
* @param Expression
* @return
* @throws SyntaxError
*/
public double evaluate() {
if (fNode == null) {
throw new SyntaxError(0, 0, 0, " ", "No parser input defined", 1);
}
return evaluateNode(fNode);
}
/**
* Evaluate an already parsed in abstract syntax tree node into a
* double number value.
*
* @param node
* abstract syntax tree node
*
* @return the evaluated double number
*
* @throws ArithmeticMathException
* if the node cannot be evaluated.
*/
public double evaluateNode(final ASTNode node) {
if (node instanceof DoubleNode) {
return ((DoubleNode) node).doubleValue();
}
if (node instanceof FunctionNode) {
return evaluateFunction((FunctionNode) node);
}
if (node instanceof SymbolNode) {
IDoubleValue v = fVariableMap.get(node.toString());
if (v != null) {
return v.getValue();
}
Double dbl = SYMBOL_DOUBLE_MAP.get(node.toString());
if (dbl != null) {
return dbl.doubleValue();
}
} else if (node instanceof NumberNode) {
return ((NumberNode) node).doubleValue();
}
throw new ArithmeticMathException("EvalDouble#evaluate(ASTNode) not possible for: " + node.toString());
}
/**
* Evaluate an already parsed in FunctionNode into a
* souble number value.
*
* @param functionNode
* @return
*
* @throws ArithmeticMathException
* if the functionNode cannot be evaluated.
*/
public double evaluateFunction(final FunctionNode functionNode) {
if (functionNode.size() > 0 && functionNode.getNode(0) instanceof SymbolNode) {
String symbol = functionNode.getNode(0).toString();
if (symbol.equals("If") || (fRelaxedSyntax && symbol.equalsIgnoreCase("if"))) {
if (functionNode.size() == 3) {
if (evaluateNodeLogical(functionNode.getNode(1))) {
return evaluateNode(functionNode.getNode(2));
}
} else if (functionNode.size() == 4) {
if (evaluateNodeLogical(functionNode.getNode(1))) {
return evaluateNode(functionNode.getNode(2));
} else {
return evaluateNode(functionNode.getNode(3));
}
}
} else {
Object obj = FUNCTION_DOUBLE_MAP.get(symbol);
if (obj instanceof IDoubleFunction) {
return ((IDoubleFunction) obj).evaluate(this, functionNode);
}
if (functionNode.size() == 1) {
if (obj instanceof IDouble0Function) {
return ((IDouble0Function) obj).evaluate();
}
} else if (functionNode.size() == 2) {
if (obj instanceof IDouble1Function) {
return ((IDouble1Function) obj).evaluate(evaluateNode(functionNode.getNode(1)));
}
} else if (functionNode.size() == 3) {
if (obj instanceof IDouble2Function) {
return ((IDouble2Function) obj).evaluate(evaluateNode(functionNode.getNode(1)),
evaluateNode(functionNode.getNode(2)));
}
}
if (fCallbackFunction != null) {
double doubleArgs[] = new double[functionNode.size() - 1];
for (int i = 0; i < doubleArgs.length; i++) {
doubleArgs[i] = evaluateNode(functionNode.getNode(i + 1));
}
return fCallbackFunction.evaluate(this, functionNode, doubleArgs);
}
}
}
throw new ArithmeticMathException("EvalDouble#evaluateFunction(FunctionNode) not possible for: " + functionNode.toString());
}
/**
* Check if the given symbol is a SymbolNode and test if the
* names are equal.
*
* @param symbol1
* @param symbol2Name
* @return
*/
public boolean isSymbol(SymbolNode symbol1, String symbol2Name) {
if (fRelaxedSyntax) {
return symbol1.getString().equalsIgnoreCase(symbol2Name);
}
return symbol1.getString().equals(symbol2Name);
}
/**
* Check if the given symbol is a SymbolNode and test if the
* names are equal.
*
* @param symbol1
* @param symbol2
* @return
*/
public boolean isSymbol(SymbolNode symbol1, SymbolNode symbol2) {
if (fRelaxedSyntax) {
return symbol1.getString().equalsIgnoreCase(symbol2.getString());
}
return symbol1.equals(symbol2);
}
/**
*
* @param node
* @param var
* @return
*/
public ASTNode derivative(final ASTNode node, String var) {
SymbolNode sym = fASTFactory.createSymbol(var);
return derivative(node, sym);
}
/**
*
* TODO: add more derivation rules
*
* @param node
* @param var
* @return
*/
public ASTNode derivative(final ASTNode node, SymbolNode var) {
if (node.isFree(var)) {
return new DoubleNode(0.0);
}
if (node instanceof FunctionNode) {
FunctionNode f = (FunctionNode) node;
if (f.size() > 1 && f.getNode(0) instanceof SymbolNode) {
SymbolNode head = (SymbolNode) f.getNode(0);
if (f.size() == 2) {
ASTNode arg1Derived = derivative(f.getNode(1), var);
if (isSymbol(head, "Exp")) {
FunctionNode fun = new FunctionNode(fASTFactory.createSymbol("Exp"));
fun.add(f.getNode(1));
return getDerivativeResult(arg1Derived, fun);
}
if (isSymbol(head, "Cos")) {
FunctionNode fun = new FunctionNode(fASTFactory.createSymbol("Times"));
fun.add(new DoubleNode(-1.0));
fun.add(new FunctionNode(fASTFactory.createSymbol("Cos"), f.getNode(1)));
return getDerivativeResult(arg1Derived, fun);
}
if (isSymbol(head, "Sin")) {
FunctionNode fun = new FunctionNode(fASTFactory.createSymbol("Cos"));
fun.add(f.getNode(1));
return getDerivativeResult(arg1Derived, fun);
}
} else if (f.size() == 3 && isSymbol(head, "Power")) {
if (f.get(2).isFree(var)) {// derive x^r
ASTNode arg1Derived = derivative(f.getNode(1), var);
// (r-1)
FunctionNode exponent = fASTFactory.createFunction(fASTFactory.createSymbol("Plus"), new DoubleNode(-1.0),
f.get(2));
// r*x^(r-1)
FunctionNode fun = fASTFactory.createFunction(fASTFactory.createSymbol("Times"), f.get(2),
fASTFactory.createFunction(fASTFactory.createSymbol("Power"), f.get(1), exponent));
return getDerivativeResult(arg1Derived, fun);
}
if (f.get(1).isFree(var)) {// derive a^x
ASTNode arg2Derived = derivative(f.getNode(2), var);
// log(a) * a^x
FunctionNode fun = fASTFactory.createFunction(fASTFactory.createSymbol("Times"),
fASTFactory.createFunction(fASTFactory.createSymbol("Log"), f.get(1)), f);
return getDerivativeResult(arg2Derived, fun);
}
} else {
if (isSymbol(head, "Plus")) {
FunctionNode result = new FunctionNode(f.getNode(0));
for (int i = 1; i < f.size(); i++) {
ASTNode deriv = derivative(f.getNode(i), var);
if (!deriv.equals(new DoubleNode(0.0))) {
result.add(deriv);
}
}
return result;
}
if (isSymbol(head, "Times")) {
FunctionNode plusResult = new FunctionNode(fASTFactory.createSymbol("Plus"));
for (int i = 1; i < f.size(); i++) {
FunctionNode timesResult = new FunctionNode(f.getNode(0));
boolean valid = true;
for (int j = 1; j < f.size(); j++) {
if (j == i) {
ASTNode deriv = derivative(f.getNode(j), var);
if (deriv.equals(new DoubleNode(0.0))) {
valid = false;
} else {
timesResult.add(deriv);
}
} else {
timesResult.add(f.getNode(j));
}
}
if (valid) {
plusResult.add(timesResult);
}
}
return plusResult;
}
}
}
return new FunctionNode(new SymbolNode("D"), node, var);
// return evaluateFunction((FunctionNode) node);
}
if (node instanceof SymbolNode) {
if (isSymbol((SymbolNode) node, var)) {
return new DoubleNode(1.0);
}
IDoubleValue v = fVariableMap.get(node.toString());
if (v != null) {
return new DoubleNode(0.0);
}
Double dbl = SYMBOL_DOUBLE_MAP.get(node.toString());
if (dbl != null) {
return new DoubleNode(0.0);
}
return new DoubleNode(0.0);
} else if (node instanceof NumberNode) {
return new DoubleNode(0.0);
}
throw new ArithmeticMathException("EvalDouble#evaluate(ASTNode) not possible for: " + node.toString());
}
private ASTNode getDerivativeResult(ASTNode arg1Derived, FunctionNode fun) {
if (!arg1Derived.equals(new DoubleNode(1.0))) {
FunctionNode res = new FunctionNode(fASTFactory.createSymbol("Times"));
res.add(arg1Derived);
res.add(fun);
return res;
}
return fun;
}
public boolean evaluateNodeLogical(final ASTNode node) {
if (node instanceof FunctionNode) {
return evaluateFunctionLogical((FunctionNode) node);
}
if (node instanceof SymbolNode) {
BooleanVariable v = fBooleanVariables.get(node.toString());
if (v != null) {
return v.getValue();
}
Boolean boole = SYMBOL_BOOLEAN_MAP.get(node.toString());
if (boole != null) {
return boole.booleanValue();
}
}
throw new ArithmeticMathException("EvalDouble#evaluateNodeLogical(ASTNode) not possible for: " + node.toString());
}
public boolean evaluateFunctionLogical(final FunctionNode functionNode) {
if (functionNode.size() > 0 && functionNode.getNode(0) instanceof SymbolNode) {
String symbol = functionNode.getNode(0).toString();
if (functionNode.size() == 2) {
Object obj = FUNCTION_BOOLEAN_MAP.get(symbol);
if (obj instanceof IBooleanBoolean1Function) {
return ((IBooleanBoolean1Function) obj).evaluate(evaluateNodeLogical(functionNode.getNode(1)));
}
} else if (functionNode.size() == 3) {
Object obj = FUNCTION_BOOLEAN_MAP.get(symbol);
if (obj instanceof IBooleanDouble2Function) {
return ((IBooleanDouble2Function) obj).evaluate(evaluateNode(functionNode.getNode(1)),
evaluateNode(functionNode.getNode(2)));
} else if (obj instanceof IBooleanBoolean2Function) {
return ((IBooleanBoolean2Function) obj).evaluate(evaluateNodeLogical(functionNode.getNode(1)),
evaluateNodeLogical(functionNode.getNode(2)));
}
// } else {
// Object obj = FUNCTION_BOOLEAN_MAP.get(symbol);
// if (obj instanceof IBooleanDoubleFunction) {
// return ((IBooleanDoubleFunction) obj).evaluate(this,
// functionNode);
// }
}
}
throw new ArithmeticMathException("EvalDouble#evaluateFunctionLogical(FunctionNode) not possible for: "
+ functionNode.toString());
}
/**
* Optimize an already parsed in functionNode into an
* ASTNode.
*
* @param functionNode
* @return
*
*/
public ASTNode optimizeFunction(final FunctionNode functionNode) {
if (functionNode.size() > 0) {
boolean doubleOnly = true;
ASTNode node;
for (int i = 1; i < functionNode.size(); i++) {
node = functionNode.getNode(i);
if (node instanceof NumberNode) {
functionNode.set(i, new DoubleNode(((NumberNode) functionNode.getNode(i)).doubleValue()));
} else if (functionNode.getNode(i) instanceof FunctionNode) {
ASTNode optNode = optimizeFunction((FunctionNode) functionNode.getNode(i));
if (!(optNode instanceof DoubleNode)) {
doubleOnly = false;
}
functionNode.set(i, optNode);
} else if (node instanceof SymbolNode) {
Double dbl = SYMBOL_DOUBLE_MAP.get(node.toString());
if (dbl != null) {
functionNode.set(i, new DoubleNode(dbl.doubleValue()));
} else {
doubleOnly = false;
}
} else {
doubleOnly = false;
}
}
if (doubleOnly) {
try {
return new DoubleNode(evaluateFunction(functionNode));
} catch (Exception e) {
}
}
}
return functionNode;
}
/**
* Define a value for a given variable name.
*
* @param variableName
* @param value
*/
public void defineVariable(String variableName, double value) {
if (fRelaxedSyntax) {
fVariableMap.put(variableName.toLowerCase(), new DoubleVariable(value));
} else {
fVariableMap.put(variableName, new DoubleVariable(value));
}
}
/**
* Define a value for a given variable name.
*
* @param variableName
* @param value
*/
public void defineVariable(String variableName, IDoubleValue value) {
if (fRelaxedSyntax) {
fVariableMap.put(variableName.toLowerCase(), value);
} else {
fVariableMap.put(variableName, value);
}
}
/**
* Define a value for a given variable name.
*
* @param variableName
* @param value
*/
public void defineVariable(String variableName) {
if (fRelaxedSyntax) {
fVariableMap.put(variableName.toLowerCase(), new DoubleVariable(0.0));
} else {
fVariableMap.put(variableName, new DoubleVariable(0.0));
}
}
/**
* Returns the double variable value to which the specified variableName is
* mapped, or {@code null} if this map contains no mapping for the
* variableName.
*
* @param variableName
* @return
*/
public IDoubleValue getVariable(String variableName) {
if (fRelaxedSyntax) {
return fVariableMap.get(variableName.toLowerCase());
} else {
return fVariableMap.get(variableName);
}
}
/**
* Define a boolean value for a given variable name.
*
* @param variableName
* @param value
*/
public void defineVariable(String variableName, BooleanVariable value) {
if (fRelaxedSyntax) {
fBooleanVariables.put(variableName.toLowerCase(), value);
} else {
fBooleanVariables.put(variableName, value);
}
}
/**
* Clear all defined variables for this evaluator.
*/
public void clearVariables() {
fVariableMap.clear();
fBooleanVariables.clear();
}
/**
* Get the variable names from the given expression.
*
* @param expression
* @param result
* a set which contains the variable names
*/
public void getVariables(String expression, Set result) {
Parser p;
if (fRelaxedSyntax) {
p = new Parser(ASTNodeFactory.RELAXED_STYLE_FACTORY, true);
} else {
p = new Parser(ASTNodeFactory.MMA_STYLE_FACTORY, false);
}
ASTNode node = p.parse(expression);
getVariables(node, result);
}
/**
* Get the variable names from the given AST node.
*
* @param node
* an already parsed AST node
* @param result
* a set which contains the variable names
*/
public static void getVariables(final ASTNode node, Set result) {
if (node instanceof FunctionNode) {
FunctionNode functionNode = (FunctionNode) node;
if (functionNode.size() > 0 && functionNode.getNode(0) instanceof SymbolNode) {
for (int i = 1; i < functionNode.size(); i++) {
getVariables(functionNode.getNode(i), result);
}
}
}
if (node instanceof SymbolNode) {
Object obj = SYMBOL_DOUBLE_MAP.get(node.toString());
if (obj == null) {
obj = SYMBOL_BOOLEAN_MAP.get(node.toString());
if (obj == null) {
result.add(node.toString());
}
}
}
}
}
Ads help maintain this website.