/*******************************************************************************
* Copyright (c) 2017
*
* 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 smile.symbolic;
import smile.symbolic.internal.*;
import java.util.Queue;
import java.util.ArrayList;
import java.util.Stack;
import java.util.LinkedList;
import java.util.Iterator;
/**
* This class represents a binary tree that represents an expression
* such that each node itself is an Expression and contains either
* one or two children, depending on if that Expression is a
* UnaryOperation or a BinaryOperation, respectively.
*
* @author Ernest DeFoy
* @see
* Wikipedia: Binary expression tree
*/
public class ExpressionTree {
private Expression root;
private String var;
private double val;
private ArrayList tokens;
public ExpressionTree() {
init("x", new ArrayList<>());
}
public ExpressionTree(String var, ArrayList tokens) {
init(var, tokens);
}
public Expression getRoot() {
return root;
}
public double getVal() {
return val;
}
public ArrayList getTokens() {
return tokens;
}
public void printTree() {
Queue currentLevel = new LinkedList();
Queue nextLevel = new LinkedList();
currentLevel.add(root);
while (!currentLevel.isEmpty()) {
Iterator iter = currentLevel.iterator();
while (iter.hasNext()) {
Expression currentNode = iter.next();
if (currentNode.getLeftChild() != null) {
nextLevel.add(currentNode.getLeftChild());
}
if (currentNode.getRightChild() != null) {
nextLevel.add(currentNode.getRightChild());
}
System.out.print(currentNode.getType() + " ");
}
System.out.println();
currentLevel = nextLevel;
nextLevel = new LinkedList();
}
System.out.println("==================");
}
public void init(String var, ArrayList tokens) {
this.var = var;
this.val = 0;
this.tokens = tokens;
root = constructTree(tokens);
}
public void reduce() {
root = root.reduce();
}
public void derive() {
root = root.derive();
}
public void derive(double val) {
derive();
// val = root.evalulate(val);
}
public String toString() {
return createInfix(root);
}
//creates string representing infix expression
public String createInfix(Expression root)
{
String str = "";
String closeParen = "";
String leftOpenParen = "";
String leftCloseParen = "";
if(root == null) {
return str;
}
if (ExpressionParser.isOperand(root.getType(), var)) {
str += root.getType();
}
else if(root.getType().equals("$")) {
str += "-";
}
else if(ExpressionParser.isFunction(root.getType())) { // does not include unary minus
str += root.getType();
str += "(";
closeParen = ")";
}
else { // is operator
int parentPrecedence = ExpressionParser.getPrecedence(root.getType());
str += root.getType();
if(ExpressionParser.isOperator(root.getLeftChild().getType()) && (ExpressionParser.getPrecedence(root.getLeftChild().getType()) < parentPrecedence)) {
leftOpenParen = "(";
leftCloseParen = ")";
}
else if(ExpressionParser.isOperator(root.getRightChild().getType()) && (ExpressionParser.getPrecedence(root.getRightChild().getType()) < parentPrecedence)) {
str += "(";
closeParen = ")";
}
}
return leftOpenParen + createInfix(root.getLeftChild()) + leftCloseParen + str + createInfix(root.getRightChild()) + closeParen;
}
// reads the "tokens" in order from the list and builds a tree
public Expression constructTree(ArrayList postTokens)
{
Expression root = null;
Stack nodes = new Stack<>();
for(String str: postTokens)
{
if(str.isEmpty()){
continue;
}
if(str.matches("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?")) {
nodes.push(new Constant(Double.parseDouble(str)));
}
else if(str.equals(var)) {
nodes.push(new Variable(var));
}
else if(!nodes.isEmpty() && ExpressionParser.isFunction(str)) {
Expression function = matchFunc(str, nodes.pop());
nodes.push(function);
}
else if(!nodes.isEmpty() && str.equals("$")) {
Expression unaryMinus = new Negation(nodes.pop());
nodes.push(unaryMinus);
}
else if(!nodes.isEmpty()){
Expression right = nodes.pop();
Expression binaryOperator = matchOperator(str, nodes.pop(), right);
nodes.push(binaryOperator);
}
}
if(!nodes.isEmpty())
root = nodes.pop();
return root;
}
public Expression matchFunc(String str, Expression exp) {
switch(str) {
case "ln":
return new NaturalLogarithm(exp);
case "log":
return new Logarithm(exp);
case "sin":
return new Sine(exp);
case "cos":
return new Cosine(exp);
case "tan":
return new Tangent(exp);
case "csc":
return new Cosecant(exp);
case "sec":
return new Secant(exp);
case "cot":
return new Cotangent(exp);
default: System.out.println("BINARYEXPRESSIONTREE: Ambiguous function: " + str + " " + str.isEmpty());
return null;
}
}
public Expression matchOperator(String str, Expression left, Expression right) {
switch(str) {
case "+":
return new Sum(left, right);
case "-":
return new Difference(left, right);
case "*":
return new Product(left, right);
case "/":
return new Quotient(left, right);
case "^":
return new Exponent(left, right);
default: System.out.println("BINARYEXPRESSIONTREE: Ambiguous operator: " + str + " " + str.isEmpty());
return null;
}
}
}
Ads help maintain this website.