Skip to content

Instantly share code, notes, and snippets.

@Thar0l
Last active April 12, 2016 12:50
Show Gist options
  • Save Thar0l/6cff054d8046bbf87fbcc6b0fbd821ef to your computer and use it in GitHub Desktop.
Save Thar0l/6cff054d8046bbf87fbcc6b0fbd821ef to your computer and use it in GitHub Desktop.
package com.company;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import org.scilab.forge.jlatexmath.TeXConstants;
import org.scilab.forge.jlatexmath.TeXFormula;
import org.scilab.forge.jlatexmath.TeXIcon;
import javax.imageio.ImageIO;
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.io.File;
import java.io.IOException;
enum NodeType {
operation,
constant,
variable,
function
}
enum MathOperation {
plus,
minus,
multiply,
divide,
power
}
enum Function {
ln,
sin,
cos
}
class Node {
private double value;
private NodeType type;
private MathOperation operation;
private Function function;
private Node left;
private Node right;
private int id;
static private int nextid = 0;
Node() {
type = NodeType.variable;
left = null;
right = null;
id = nextid;
nextid++;
}
Node(double value) {
type = NodeType.constant;
this.value = value;
left = null;
right = null;
id = nextid;
nextid++;
}
Node(MathOperation operation) {
this.operation = operation;
this.type = NodeType.operation;
left = null;
right = null;
id = nextid;
nextid++;
}
Node (Function function) {
this.function = function;
this.type = NodeType.function;
left = null;
right = null;
id = nextid;
nextid++;
}
Node getLeft() {
return left;
}
Node getRight() {
return right;
}
void addLeft(Node item) {
left = item;
}
void addRight(Node item) {
right = item;
}
NodeType getType() {
return type;
}
double getValue() {
return value;
}
MathOperation getOperation() {
return operation;
}
Function getFunction() {
return function;
}
void setFunction(Function function) {
this.function = function;
}
void setValue(double value) {
this.value = value;
}
int getId() {
return id;
}
void setType(NodeType type) {
this.type = type;
}
void setOperation(MathOperation operation)
{
this.operation = operation;
}
Node copy() {
Node item = new Node(0);
item.type = type;
item.operation = operation;
item.value = value;
item.function = function;
if (left != null) {
item.addLeft(left.copy());
}
if (right != null) {
item.addRight(right.copy());
}
return item;
}
void set(Node node) {
this.type = node.type;
this.operation = node.operation;
this.function = node.function;
this.value = node.value;
this.left = node.left;
this.right = node.right;
}
public static MathOperation StringToOperation(String str) {
if (str.equals("*")) {
return MathOperation.multiply;
}
if (str.equals("/")) {
return MathOperation.divide;
}
if (str.equals("^")) {
return MathOperation.power;
}
if (str.equals("+")) {
return MathOperation.plus;
}
if (str.equals("-")) {
return MathOperation.minus;
}
return MathOperation.plus;
}
public static Function StringToFunction(String str) {
if (str.equals("ln")) {
return Function.ln;
}
if (str.equals("sin")) {
return Function.sin;
}
if (str.equals("cos")) {
return Function.cos;
}
return Function.ln;
}
public static String OperationToString(MathOperation operation) {
switch (operation)
{
case plus:
return "+";
case minus:
return "-";
case power:
return "^";
case multiply:
return "*";
case divide:
return "/";
}
return "?";
}
public static String FunctionToString(Function function) {
switch (function) {
case ln:
return "ln";
case sin:
return "sin";
case cos:
return "cos";
}
return "?";
}
public int getDeep() {
int l = 0;
int r = 0;
if (this.getLeft() != null) {
l = this.getLeft().getDeep();
}
if (this.getRight() != null) {
r = this.getRight().getDeep();
}
return Math.max(l+1,r+1);
}
public boolean equal(Node node) {
if (this.type != node.type) {
return false;
}
switch (this.type) {
case variable:
return true;
case constant:
return (this.value == node.value);
case function:
return this.getLeft().equal(node.getLeft());
case operation:
return (this.getLeft().equal(node.getLeft()) && (this.getRight().equal(node.getRight())) );
}
return false;
}
}
class Tree {
private Node root;
private String logstr;
public Tree(Node node) {
root = node;
logstr = "";
}
public Tree(Node node, String logstr) {
this.root = node;
this.logstr = logstr;
}
public Tree(String str) {
logstr = "";
logstr = "\\mbox{Generating tree from string: }\\mbox{ " + str + "}\\\\";
String[] parts = str.split("\\s+");
str = "";
for (String part : parts) {
str += part;
}
root = parseString(str, 0);
logstr += "\\mbox{Generated: }" + buildLatex(root) + "\\\\";
}
public Tree(Tree tree) {
this.logstr = tree.logstr;
this.root = tree.root.copy();
}
public void saveImage(String filename) {
String latex = buildLatex(root);
TeXFormula formula = new TeXFormula(latex);
TeXIcon icon = formula.new TeXIconBuilder().setStyle(TeXConstants.STYLE_DISPLAY).setSize(22).build();
icon.setInsets(new Insets(5, 5, 5, 5));
BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
g2.setColor(Color.white);
g2.fillRect(0,0,icon.getIconWidth(),icon.getIconHeight());
JLabel jl = new JLabel();
jl.setForeground(new Color(0, 0, 0));
icon.paintIcon(jl, g2, 0, 0);
try {
File file = new File(filename+".png");
ImageIO.write(image, "png", file.getAbsoluteFile());
} catch (Exception e) {
e.printStackTrace();
}
}
public Image getImage() {
String latex = buildLatex(root);
TeXFormula formula = new TeXFormula(latex);
TeXIcon icon = formula.new TeXIconBuilder().setStyle(TeXConstants.STYLE_DISPLAY).setSize(18).build();
icon.setInsets(new Insets(5, 5, 5, 5));
BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
g2.setColor(Color.white);
g2.fillRect(0,0,icon.getIconWidth(),icon.getIconHeight());
JLabel jl = new JLabel();
jl.setForeground(new Color(0, 0, 0));
icon.paintIcon(jl, g2, 0, 0);
return image;
}
public void logImage(String filename) {
String latex = logstr;
TeXFormula formula = new TeXFormula(latex);
TeXIcon icon = formula.new TeXIconBuilder().setStyle(TeXConstants.STYLE_DISPLAY).setSize(22).build();
icon.setInsets(new Insets(5, 5, 5, 5));
BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
g2.setColor(Color.white);
g2.fillRect(0,0,icon.getIconWidth(),icon.getIconHeight());
JLabel jl = new JLabel();
jl.setForeground(new Color(0, 0, 0));
icon.paintIcon(jl, g2, 0, 0);
try {
File file = new File(filename+".png");
ImageIO.write(image, "png", file.getAbsoluteFile());
} catch (Exception e) {
e.printStackTrace();
}
}
public void optimise() {
logstr += "\\mbox{Expression to optimise: }" + buildLatex(root) + "\\\\";
while (simplify(root)) {
logstr += "\\mbox{optimised: }" + buildLatex(root) + "\\\\";
}
while(upVars(root)) {
logstr += "\\mbox{variables positions optimised: }" + buildLatex(root) + "\\\\";
}
while (simplify(root)) {
logstr += "\\mbox{optimised: }" + buildLatex(root) + "\\\\";
}
while (swapArgs(root)) {
logstr += "\\mbox{optimised: }" + buildLatex(root) + "\\\\";
}
logstr += "\\mbox{Optimisation result: }" + buildLatex(root) + "\\\\";
}
public Tree differentiate() {
logstr += "\\mbox{Expression to differentiate: }" + buildLatex(root) + "\\\\";
Tree result = this;
d(result.root);
logstr += "\\mbox{Differentiation result: }" + buildLatex(root) + "\\\\";
return result;
}
public double calculate(double value) {
return calc(root, value);
}
private Node parseString(String str, int opIndex) {
String[] ops = {"+", "-", "*", "/", "^"};
int index = str.indexOf(ops[opIndex]);
while (index > 0) {
String left = str.substring(0, index);
String right = str.substring(index + 1, str.length());
if ( (countBrackets(left) == 0) && (countBrackets(right) == 0)) {
break;
}
index = str.indexOf(ops[opIndex], index+1);
}
if (index >= 0) {
String left = str.substring(0, index);
String right = str.substring(index + 1, str.length());
Node root = new Node(Node.StringToOperation(ops[opIndex]));
root.addLeft(parseString(left, 0));
root.addRight(parseString(right, 0));
return root;
} else if (opIndex <= ops.length - 2) {
return parseString(str, opIndex + 1);
} else if ((str.charAt(0) == '(') && (str.charAt(str.length()-1) == ')')) {
return parseString(str.substring(1,str.length()-1), 0);
} else if (str.equals("x")) {
return new Node();
} else if (isDouble(str)) {
return new Node(Double.parseDouble(str));
} else {
return parseFunction(str);
}
}
private static int countBrackets(String str)
{
int count = 0;
for (int i = 0; i < str.length(); i++)
{
if (str.charAt(i) == '(') {
count++;
}
if (str.charAt(i) == ')') {
count--;
}
}
return count;
}
private static boolean isDouble(String str){
try {
Double.parseDouble(str);
return true;
} catch (Exception e) {
return false;
}
}
private Node parseFunction(String str) {
String[] functions = {"ln", "sin", "cos"};
String name = str.substring(0, str.indexOf("("));
Node root = new Node(Node.StringToFunction(name));
root.addLeft(parseString(str.substring(str.indexOf("(")+1, str.length()-1), 0));
return root;
}
private String buildLatex(Node node) {
String result = "";
if (node != null) {
if (node.getType() == NodeType.variable) {
result += "x";
} else if (node.getType() == NodeType.constant) {
if (((int) (node.getValue())) == node.getValue()) {
result += (int) (node.getValue());
} else {
result += node.getValue();
}
} else if (node.getType() == NodeType.function) {
result += "{" + Node.FunctionToString(node.getFunction()) + "(" + buildLatex(node.getLeft()) + ")}";
} else {
switch (node.getOperation()) {
case plus:
result += "{" + buildLatex(node.getLeft()) + "+" + buildLatex(node.getRight()) + "}";
break;
case minus:
result += "{" + buildLatex(node.getLeft()) + "-";
if ((node.getRight().getDeep() > 1) && (node.getRight().getType() == NodeType.operation) && ((node.getRight().getOperation() == MathOperation.plus) || (node.getRight().getOperation() == MathOperation.minus))) {
result += "{(";
}
result += buildLatex(node.getRight());
if ((node.getRight().getDeep() > 1) && (node.getRight().getType() == NodeType.operation) && ((node.getRight().getOperation() == MathOperation.plus) || (node.getRight().getOperation() == MathOperation.minus))) {
result += ")}";
}
result += "}";
break;
case multiply:
result += "{{";
if ((node.getLeft().getDeep() > 1) && (node.getLeft().getType() == NodeType.operation) && ((node.getLeft().getOperation() == MathOperation.plus) || (node.getLeft().getOperation() == MathOperation.minus))) {
result += "(";
}
result += buildLatex(node.getLeft());
if ((node.getLeft().getDeep() > 1) && (node.getLeft().getType() == NodeType.operation) && ((node.getLeft().getOperation() == MathOperation.plus) || (node.getLeft().getOperation() == MathOperation.minus))) {
result += ")";
}
if (node.getLeft().getType() == NodeType.constant) {
if ((node.getRight().getType() == NodeType.function) || (node.getRight().getType() == NodeType.variable)) {
result += "}{";
} else if ((node.getRight().getType() == NodeType.operation) && (node.getRight().getOperation() == MathOperation.power) && (node.getRight().getLeft().getType() == NodeType.variable)) {
result += "}{";
} else if ((node.getRight().getDeep() > 1) && (node.getRight().getType() == NodeType.operation) && ((node.getRight().getOperation() == MathOperation.plus) || (node.getRight().getOperation() == MathOperation.minus))) {
result += "}{";
} else {
result += "}\\times{";
}
} else if (node.getRight().getType() == NodeType.constant) {
if ((node.getLeft().getDeep() > 1) && (node.getLeft().getType() == NodeType.operation) && ((node.getLeft().getOperation() == MathOperation.plus) || (node.getLeft().getOperation() == MathOperation.minus))) {
result += "}{";
} else {
result += "}\\times{";
}
} else {
result += "}\\times{";
}
if ((node.getRight().getDeep() > 1) && (node.getRight().getType() == NodeType.operation) && ((node.getRight().getOperation() == MathOperation.plus) || (node.getRight().getOperation() == MathOperation.minus))) {
result += "(";
}
result += buildLatex(node.getRight());
if ((node.getRight().getDeep() > 1) && (node.getRight().getType() == NodeType.operation) && ((node.getRight().getOperation() == MathOperation.plus) || (node.getRight().getOperation() == MathOperation.minus))) {
result += ")";
}
result += "}}";
break;
case divide:
result += "{\\frac{" + buildLatex(node.getLeft()) + "}{" + buildLatex(node.getRight()) + "}}";
break;
case power:
result += "{";
if (node.getLeft().getDeep() > 1) {
result += "{(";
}
result += buildLatex(node.getLeft());
if (node.getLeft().getDeep() > 1) {
result += ")}";
}
result += "^{" + buildLatex(node.getRight()) + "}}";
break;
}
}
}
return result;
}
private boolean simplify(Node item) {
if (item != null) {
//logstr += "\\mbox{Optimising: }" + buildLatex(item) + "\\\\";
if ((item.getLeft() != null) && (item.getRight() != null) && (item.getLeft().getType() == NodeType.constant) && (item.getRight().getType() == NodeType.constant)) {
Node old = item.copy();
double left = item.getLeft().getValue();
double right = item.getRight().getValue();
double temp = 0;
switch (item.getOperation()) {
case plus:
temp = left + right;
break;
case minus:
temp = left - right;
break;
case multiply:
temp = left * right;
break;
case divide:
temp = left / right;
break;
case power:
temp = Math.pow(left, right);
break;
}
item.setType(NodeType.constant);
item.setValue(temp);
item.addLeft(null);
item.addRight(null);
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.power) && (item.getRight().getType() == NodeType.constant) && (item.getRight().getValue() == 1)) {
Node old = item.copy();
item.set(item.getLeft());
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.power) && (item.getRight().getType() == NodeType.constant) && (item.getRight().getValue() == 0)) {
Node old = item.copy();
item.set(new Node(1));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.power) && (item.getLeft().getType() == NodeType.constant) && (item.getLeft().getValue() == 0)) {
Node old = item.copy();
item.set(new Node(0));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.power) && (item.getLeft().getType() == NodeType.constant) && (item.getLeft().getValue() == 1)) {
Node old = item.copy();
item.set(new Node(1));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.multiply) && (item.getRight().getType() == NodeType.constant) && (item.getRight().getValue() == 0)) {
Node old = item.copy();
item.set(new Node(0));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.multiply) && (item.getLeft().getType() == NodeType.constant) && (item.getLeft().getValue() == 0)) {
Node old = item.copy();
item.set(new Node(0));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.multiply) && (item.getRight().getType() == NodeType.constant) && (item.getRight().getValue() == 1)) {
Node old = item.copy();
item.set(item.getLeft());
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.multiply) && (item.getLeft().getType() == NodeType.constant) && (item.getLeft().getValue() == 1)) {
Node old = item.copy();
item.set(item.getRight());
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.divide) && (item.getLeft().getType() == NodeType.constant) && (item.getLeft().getValue() == 0)) {
Node old = item.copy();
item.set(new Node(0));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.plus) && (item.getRight().getType() == NodeType.constant) && (item.getRight().getValue() == 0)) {
Node old = item.copy();
item.set(item.getLeft());
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.plus) && (item.getLeft().getType() == NodeType.constant) && (item.getLeft().getValue() == 0)) {
Node old = item.copy();
item.set(item.getRight());
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.minus) && (item.getRight().getType() == NodeType.constant) && (item.getRight().getValue() == 0)) {
Node old = item.copy();
item.set(item.getLeft());
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.minus) && (item.getLeft().getType() == NodeType.constant) && (item.getLeft().getValue() == 0)) {
Node old = item.copy();
item.setOperation(MathOperation.multiply);
item.addLeft(new Node(-1));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.minus) && (item.getLeft().getType() == NodeType.variable) && (item.getRight().getType() == NodeType.variable)) {
Node old = item.copy();
item.set(new Node(0));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.divide) && (item.getLeft().getType() == NodeType.variable) && (item.getRight().getType() == NodeType.variable)) {
Node old = item.copy();
item.set(new Node(1));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.plus) && (item.getLeft().getType() == NodeType.variable) && (item.getRight().getType() == NodeType.variable)) {
Node old = item.copy();
item.setOperation(MathOperation.multiply);
item.addLeft(new Node(2));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.multiply) && (item.getLeft().getType() == NodeType.variable) && (item.getRight().getType() == NodeType.variable)) {
Node old = item.copy();
item.setOperation(MathOperation.power);
item.addRight(new Node(2));
Log(old, item, "optimisation: ");
return true;
} else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.minus) && (item.getRight().getType() == NodeType.constant) && (item.getRight().getValue() < 0)) {
Node old = item.copy();
item.setOperation(MathOperation.plus);
item.getRight().setValue(-item.getRight().getValue());
Log(old, item, "optimisation: ");
return true;
} /*else if ((item.getType() == NodeType.operation) && (item.getOperation() == MathOperation.multiply) && (item.getLeft().getType() == NodeType.variable) && (item.getRight().getType() == NodeType.operation) && (item.getRight().getOperation() == MathOperation.power) && (item.getRight().getLeft().getType() == NodeType.variable)) {
Node old = item.copy();
item.setOperation(MathOperation.power);
item.addLeft(new Node());
item.addRight(new Node(MathOperation.plus));
item.getRight().addLeft(old.getRight().getRight());
item.getRight().addRight(new Node(1));
Log(old, item, "optimisation: ");
return true;
} */else {
return simplify(item.getLeft()) || simplify(item.getRight());
}
}
return false;
}
private boolean upVars(Node item) {
boolean result = false;
if (item != null) {
if (item.getType() == NodeType.operation) {
Node left = item.getLeft();
Node right = item.getRight();
if ((left.getType() == NodeType.operation) && (item.getOperation() == left.getOperation()) && ((item.getOperation() == MathOperation.multiply) || (item.getOperation() == MathOperation.plus))) {
if (right.getType() == NodeType.constant) {
if (left.getLeft().getType() != NodeType.constant) {
Node old = item.copy();
Node temp = right.copy();
right.set(left.getLeft().copy());
left.getLeft().set(temp);
Log(old, item, "moving: ");
result = true;
} else if (left.getRight().getType() != NodeType.constant) {
Node old = item.copy();
Node temp = right.copy();
right.set(left.getRight().copy());
left.getRight().set(temp);
Log(old, item, "moving: ");
result = true;
}
}
} else if ((right.getType() == NodeType.operation) && (item.getOperation() == right.getOperation()) && ((item.getOperation() == MathOperation.multiply) || (item.getOperation() == MathOperation.plus))) {
if (left.getType() == NodeType.constant) {
if (right.getLeft().getType() != NodeType.constant) {
Node old = item.copy();
Node temp = left.copy();
left.set(right.getLeft().copy());
right.getLeft().set(temp);
Log(old, item, "moving: ");
result = true;
} else if (right.getRight().getType() != NodeType.constant) {
Node old = item.copy();
Node temp = left.copy();
left.set(right.getRight().copy());
right.getRight().set(temp);
Log(old, item, "moving: ");
result = true;
}
}
}
}
result = result | upVars(item.getLeft());
result = result | upVars(item.getRight());
}
return result;
}
private boolean swapArgs(Node item) {
boolean result = false;
if (item != null) {
if ((item.getType() == NodeType.operation) && ((item.getOperation() == MathOperation.multiply) /*|| (item.getOperation() == MathOperation.plus)*/)) {
if ((item.getRight().getType() == NodeType.constant) && (item.getLeft().getType() != NodeType.constant)) {
Node old = item.copy();
Node temp = item.getRight().copy();
item.getRight().set(item.getLeft().copy());
item.getLeft().set(temp);
Log(old, item, "Swapping: ");
result = true;
}
}
result = result | swapArgs(item.getLeft());
result = result | swapArgs(item.getRight());
}
return result;
}
private double calc(Node item, double value) {
if (item != null) {
if (item.getType() == NodeType.operation) {
switch (item.getOperation()) {
case plus:
return calc(item.getLeft(), value) + calc(item.getRight(), value);
case minus:
return calc(item.getLeft(), value) - calc(item.getRight(), value);
case multiply:
return calc(item.getLeft(), value) * calc(item.getRight(), value);
case divide:
return calc(item.getLeft(), value) / calc(item.getRight(), value);
case power:
return Math.pow(calc(item.getLeft(), value), calc(item.getRight(), value));
}
} else if (item.getType() == NodeType.function) {
switch (item.getFunction()) {
case ln:
return Math.log(calc(item.getLeft(), value));
case sin:
return Math.sin(calc(item.getLeft(), value));
case cos:
return Math.cos(calc(item.getLeft(), value));
}
} else if (item.getType() == NodeType.constant){
return item.getValue();
} else if (item.getType() == NodeType.variable) {
return value;
}
}
return Double.NaN;
}
private void d(Node item)
{
if (item != null) {
logstr += "\\mbox{Differentiating: }" + buildLatex(item) + "\\\\";
if (item.getType() == NodeType.constant) {
Node old = item.copy();
item.setValue(0);
Log(old, item, "\\frac{d}{dx}");
}
if (item.getType() == NodeType.variable) {
Node old = item.copy();
item.setType(NodeType.constant);
item.setValue(1);
Log(old, item, "\\frac{d}{dx}");
}
if (item.getType() == NodeType.operation) {
Node old = item.copy();
Node left = null;
Node right = null;
Node temp = null;
switch (item.getOperation()) {
case plus:
case minus:
d(item.getLeft());
d(item.getRight());
break;
case multiply:
item.setOperation(MathOperation.plus);
left = new Node(MathOperation.multiply);
left.addLeft(item.getLeft().copy());
left.addRight(item.getRight().copy());
right = new Node(MathOperation.multiply);
right.addLeft(item.getLeft().copy());
right.addRight(item.getRight().copy());
item.addLeft(left);
item.addRight(right);
d(left.getRight());
d(right.getLeft());
logstr += "\\mbox{as " + "\\frac{d}{dx} (u*v) = u*\\frac{dv}{dx} + v*\\frac{du}{dx}" + " so}\\\\";
break;
case divide:
right = new Node(MathOperation.power);
right.addLeft(item.getRight().copy());
right.addRight(new Node(2));
temp = new Node(MathOperation.multiply);
temp.addLeft(item.getLeft().copy());
temp.addRight(item.getRight().copy());
left = new Node(MathOperation.minus);
left.addLeft(temp.copy());
left.addRight(temp.copy());
item.addLeft(left);
item.addRight(right);
d(item.getLeft().getLeft().getRight());
d(item.getLeft().getRight().getLeft());
logstr += "\\mbox{as " + "\\frac{d}{dx} (\\frac{u}{v}) = \\frac{u*\\frac{dv}{dx} + v*\\frac{du}{dx}}{v^{2}}" + " so}\\\\";
break;
case power:
right = new Node(MathOperation.multiply);
right.addLeft(new Node(MathOperation.power));
right.getLeft().addLeft(item.getLeft().copy());
right.getLeft().addRight(item.getRight().copy());
right.addRight(new Node(MathOperation.multiply));
right.getRight().addLeft(new Node(Function.ln));
right.getRight().getLeft().addLeft(item.getLeft().copy());
right.getRight().addRight(item.getRight().copy());
temp = new Node(MathOperation.power);
temp.addLeft(item.getLeft().copy());
temp.addRight(new Node(MathOperation.minus));
temp.getRight().addLeft(item.getRight().copy());
temp.getRight().addRight(new Node(1));
left = new Node(MathOperation.multiply);
left.addLeft(item.getRight().copy());
left.addRight(new Node(MathOperation.multiply));
left.getRight().addLeft(temp);
left.getRight().addRight(item.getLeft().copy());
item.setType(NodeType.operation);
item.setOperation(MathOperation.plus);
item.addLeft(left);
item.addRight(right);
d(item.getLeft().getRight().getRight());
d(item.getRight().getRight().getRight());
logstr += "\\mbox{as " + "\\frac{d}{dx} (u^{v}) = v*u^{v-1}*\\frac{du}{dx}+u^{v}*ln(u)*\\frac{dv}{dx}" + " so}\\\\";
break;
}
Log(old, item, "\\frac{d}{dx}");
} else if (item.getType() == NodeType.function) {
Node left = null;
Node right = null;
Node temp = null;
Node old = item.copy();
switch (item.getFunction()) {
case ln:
left = new Node(MathOperation.divide);
left.addLeft(new Node(1));
left.addRight(item.getLeft().copy());
right = item.getLeft().copy();
item.setType(NodeType.operation);
item.setOperation(MathOperation.multiply);
item.addLeft(left);
item.addRight(right);
d(item.getRight());
break;
case sin:
left= new Node(Function.cos);
left.addLeft(item.getLeft().copy());
right = item.getLeft().copy();
item.setType(NodeType.operation);
item.setOperation(MathOperation.multiply);
item.addLeft(left);
item.addRight(right);
d(item.getRight());
break;
case cos:
left = new Node(-1);
temp = new Node(Function.sin);
temp.addLeft(item.getLeft().copy());
right = new Node(MathOperation.multiply);
right.addLeft(temp);
right.addRight(item.getLeft().copy());
item.setType(NodeType.operation);
item.setOperation(MathOperation.multiply);
item.addLeft(left);
item.addRight(right);
d(item.getRight().getRight());
break;
}
Log(old, item, "\\frac{d}{dx}");
}
}
}
private void Log(Node node0, Node node1, String str) {
logstr += str + " (" + buildLatex(node0) + ") = " + buildLatex(node1) + "\\\\";
}
}
public class Main extends Applet {
private Button buttonParse;
private Button buttonDiff;
private Button buttonOpt;
private TextField inputString;
private Panel panel;
private boolean drawIn;
private boolean drawInOpt;
private boolean drawOut;
private boolean drawOutOpt;
private Tree tree_in;
private Tree tree_in_opt;
private Tree tree_out;
private Tree tree_out_opt;
private String oldstr;
public void init() {
setLayout(new FlowLayout());
buttonParse = new Button("Parse");
buttonOpt = new Button("optimise");
buttonDiff = new Button("Differentiate");
inputString = new TextField("((1+2+3-4*5/2+3^2)*x^4)/(3*x^3+x/x+x^5)", 60);
//Rectangle r = new Rectangle(100,100,200,200);
panel = new Panel();
//panel.setBounds(r);
buttonOpt.setEnabled(false);
buttonDiff.setEnabled(false);
add(inputString);
add(buttonParse);
add(buttonOpt);
add(buttonDiff);
add(panel);
buttonParse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
oldstr = inputString.getText();
tree_in = new Tree(inputString.getText());
tree_in_opt = null;
tree_out = null;
tree_out_opt = null;
drawIn = true;
buttonOpt.setEnabled(true);
buttonDiff.setEnabled(true);
repaint();
}
});
buttonOpt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
/*if (tree_out_opt != null) {
tree_out_opt.optimise();
drawOutOpt = true;
} else*/
if (tree_out != null) {
tree_out_opt = new Tree(tree_out);
tree_out_opt.optimise();
drawOutOpt = true;
} else if (tree_in != null) {
tree_in_opt = new Tree(tree_in);
tree_in_opt.optimise();
drawInOpt = true;
}
repaint();
}
});
buttonDiff.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (tree_in_opt != null) {
tree_out = new Tree(tree_in_opt);
} else {
tree_out = new Tree(tree_in);
}
tree_out = tree_out.differentiate();
tree_out_opt = null;
drawOut = true;
repaint();
}
});
inputString.addTextListener(new TextListener() {
@Override
public void textValueChanged(TextEvent e) {
boolean changed = oldstr.equals(inputString.getText());
buttonOpt.setEnabled(changed);
buttonDiff.setEnabled(changed);
drawIn = (changed && (tree_in != null));
drawInOpt = (changed &&(tree_in_opt != null));
drawOut = (changed && (tree_out != null));
drawOutOpt = (changed &&(tree_out_opt != null));
repaint();
}
});
tree_in = null;
tree_in_opt = null;
tree_out = null;
drawIn = false;
drawOut = false;
drawInOpt = false;
drawOutOpt = false;
oldstr = "";
}
public void paint(Graphics g) {
if ((drawIn) && (tree_in != null)) {
Image image = tree_in.getImage();
g.drawImage(image, 50, 150, panel);
}
if ((drawInOpt) && (tree_in_opt != null)) {
Image image = tree_in_opt.getImage();
g.drawImage(image, 50, 300, panel);
}
if ((drawOut) && (tree_out != null)) {
Image image = tree_out.getImage();
g.drawImage(image, 50, 450, panel);
}
if ((drawOutOpt) && (tree_out_opt != null)) {
Image image = tree_out_opt.getImage();
g.drawImage(image, 50, 600, panel);
}
g.drawRect(10, 115, 1800, 145);
g.drawString("Input:", 20, 140);
g.drawRect(10, 265, 1800, 145);
g.drawString("Optimised Input:", 20, 290);
g.drawRect(10, 415, 1800, 145);
g.drawString("Output:", 20, 440);
g.drawRect(10, 565, 1800, 145);
g.drawString("Optimised Output:", 20, 590);
}
public static void main(String[] args) {
String str = "((1+2+3-4*5/2+3^2)*x^4)/(3*x^3+x/x+x^5)";
Tree t = new Tree(str);
t.saveImage("out-1-input");
t.optimise();
t.saveImage("out-2-optimised_input");
Tree r = t.differentiate();
r.saveImage("out-3-differentiated");
r.optimise();
r.saveImage("out-4-optimised_result");
r.logImage("log");
/*
Node root = new Node(MathOperation.multiply);
root.addLeft(new Node());
root.addRight(new Node(MathOperation.plus));
root.getRight().addLeft(new Node(1));
root.getRight().addRight(new Node(1));
System.out.println(root.equal(root));
System.out.println(root.getLeft().equal(root.getRight()));
System.out.println(root.getRight().getLeft().equal(root.getRight().getRight()));*/
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment