/*
* Copyright 2006, United States Government as represented by the Administrator
* for the National Aeronautics and Space Administration. No copyright is
* claimed in the United States under Title 17, U.S. Code. All Other Rights
* Reserved.
*/
package gov.nasa.ial.mde.solver.symbolic;
import gov.nasa.ial.mde.util.Comparison;
import gov.nasa.ial.mde.util.MathUtil;
import gov.nasa.ial.mde.util.SortedKeyStrings;
import gov.nasa.ial.mde.util.StringSplitter;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* The <code>Expression</code> represents an equation expression.
*
* @author Dr. Robert Shelton
* @version 1.0
* @since 1.0
*/
public class Expression extends ProtoExpression implements Comparison {
/**
* Constructs an Expression given an expression as a String.
*
* @param s expression as a String.
*/
public Expression(String s) {
elaborate(new ParseNode(s));
} // end Expression
/**
* Constructs an Expression given a parse node.
*
* @param r a parse node.
*/
public Expression(ParseNode r) {
switch (r.operator) {
case Action.U_MINUS :
{
ParseNode p = new ParseNode(1, Action.SUM);
p.children[0] = r;
elaborate(p);
return;
} // end case
case Action.RECIPROCAL :
{
ParseNode p = new ParseNode(2, Action.PRODUCT);
p.children[0] = new ParseNode("1");
p.children[1] = r;
elaborate(p);
return;
} // end case
default :
elaborate(r);
} // end switch
} // end Expression
private void elaborate(ParseNode newRoot) {
(root = newRoot).doParent();
if (root.badFlag)
return;
variables = new Hashtable<Object, Hashtable>();
legalVariables = new Hashtable<String, Integer>();
knowns = new Hashtable<String, Double>();
knowns.put("pi", new Double(Math.PI));
knowns.put("Pi", new Double(Math.PI));
knowns.put("PI", new Double(Math.PI));
parameters = new Hashtable<String, Double>();
make_legalVariables();
fixImpliedMultiplication(root);
if (find_variables(root) == null) {
theValue = null;
variables = null;
legalVariables = null;
knowns = null;
parameters = null;
root = null;
return;
} // end if
Hashtable h = (Hashtable) (variables.get(root));
Enumeration k = h.keys();
while (k.hasMoreElements()) {
String var = (String)k.nextElement();
//System.out.println(var);
Double t = (Double)knowns.get(var);
//System.out.println(t);
if (t == null)
continue;
Vector v = (Vector)h.get(var);
Enumeration e = v.elements();
while (e.hasMoreElements()) {
ParseNode pn = (ParseNode)e.nextElement();
pn.value = t;
} // end while
} // end while
for (Enumeration e = variables.keys(); e.hasMoreElements();) {
Object r;
h = (Hashtable) (variables.get(r = e.nextElement()));
for (k = knowns.keys(); k.hasMoreElements();)
h.remove(k.nextElement());
variables.put(r, h);
} // end for
condenseConstants(root);
if ((theValue = root.value) != null) {
valueString = MathUtil.trimDouble(theValue.doubleValue(), 12);
} // end if
else
valueString = null;
varStrings = new SortedKeyStrings((Hashtable) (variables.get(root))).theKeys;
} // end elaborate
private void make_legalVariables() {
int i = 0;
Enumeration<String> k = knowns.keys();
while (k.hasMoreElements()){
legalVariables.put(k.nextElement(), new Integer(i++));
}
legalVariables.put("alpha", new Integer(i++));
legalVariables.put("beta", new Integer(i++));
legalVariables.put("gamma", new Integer(i++));
legalVariables.put("delta", new Integer(i++));
legalVariables.put("phi", new Integer(i++));
legalVariables.put("lambda", new Integer(i++));
legalVariables.put("theta", new Integer(i++));
char[] varString = new char[1];
int c;
for (c = 'A'; c <= 'Z'; c++) {
varString[0] = (char)c;
legalVariables.put(new String(varString), new Integer(i++));
} // end for c
for (c = 'a'; c <= 'z'; c++) {
varString[0] = (char)c;
legalVariables.put(new String(varString), new Integer(i++));
} // end for c
} // end make_legalVariables
private void fixImpliedMultiplication(ParseNode r) {
int i;
if (r.operator == Action.NO_OP) {
if (legalVariables.get(r.theString) != null)
return;
Vector<String> v = splitIM(r.theString);
if (v.size() == 1)
return;
r.operator = Action.PRODUCT;
r.children = new ParseNode[v.size()];
Enumeration<String> e = v.elements();
for (i = 0; e.hasMoreElements(); i++)
r.children[i] = new ParseNode((String)e.nextElement());
} // end if
else if (r.operator == Action.POWER) {
int n0 = 0, n1 = 1;
ParseNode r0 = r.children[0], r1 = r.children[1];
StringBuffer b0 = new StringBuffer(), b1 = new StringBuffer();
if (r0.operator == Action.NO_OP) {
Vector<String> v = splitIM(r0.theString);
if ((n0 = v.size() - 1) < 0) {
root.badFlag = true;
return;
} // end if
for (i = 0; i < n0; i++)
b0.append((String)v.elementAt(i) + "*");
b0.append((String)v.elementAt(n0) + "^");
} // end if
else
b0.append(new Expression(r0).toString() + "^");
switch (r1.operator) {
case Action.NO_OP :
{
Vector<String> v = splitIM(r1.theString);
if ((n1 = v.size()) < 1) {
root.badFlag = true;
return;
} // end if
b1.append((String)v.elementAt(0));
if (n1 > 1)
b1.append("*");
for (i = 1; i < n1; i++)
b1.append((String)v.elementAt(i));
break;
} // end block
case Action.PRODUCT :
case Action.SUM :
b1.append("(" + new Expression(r1).toString() + ")");
break;
default :
b1.append(new Expression(r1).toString());
} // end switch
if (n0 == 0 && n1 == 1)
return;
ParseNode t = new Expression(b0.toString() + b1.toString()).root;
if (t == null) {
root.badFlag = true;
return;
} // end if
r.children = t.children;
r.operator = t.operator;
} // end if
else
for (i = 0; i < r.children.length; i++)
fixImpliedMultiplication(r.children[i]);
} // end fixImpliedMultiplication
private Vector<String> splitIM(String u) {
Enumeration<String> k = legalVariables.keys();
String[] vars = new StringSplitter(this).multiSplit(k, u);
Vector<String> v = new Vector<String>();
for (int i = 0; i < vars.length; i++) {
if (vars[i].trim().length() == 0)
continue;
v.addElement(vars[i]);
} // end for i
return v;
} // end splitIM
private static void combine(Hashtable h1, Hashtable h2) {
Enumeration k1 = h1.keys();
Vector v1, v2;
Object r;
while (k1.hasMoreElements()) {
v1 = (Vector)h1.get(r = k1.nextElement());
if ((v2 = (Vector)h2.get(r)) != null) {
Enumeration e = v1.elements();
while (e.hasMoreElements())
v2.addElement(e.nextElement());
} // end if
else
v2 = v1;
h2.put(r, v2);
} // end while
} // end combine
private Hashtable<String,Vector> find_variables(ParseNode r) {
Hashtable<String, Vector> leavesOfR = new Hashtable<String, Vector>();
//System.out.println("in find_varibles");
if (r.operator == Action.NO_OP) { // no children
if (legalVariables.get(r.theString) != null) {
Vector<ParseNode> v = new Vector<ParseNode>();
v.addElement(r);
leavesOfR.put(r.theString, v);
} // end if
else
try {
r.value = new Double(r.theString);
} // end try
catch (NumberFormatException NFE) {
return null;
} //end catch
} // end if operator
else {
Hashtable childLeaves;
for (int i = 0; i < r.children.length; i++) {
if ((childLeaves = find_variables(r.children[i])) == null)
return null;
combine(childLeaves, leavesOfR);
} // end for i
} // end else
variables.put(r, leavesOfR);
return leavesOfR;
} // end find_variables
private void condenseConstants(ParseNode r) {
if (r.value != null)
return;
Hashtable h = (Hashtable)variables.get(r);
if (h.isEmpty()) {
r.value = new Double(r.eval());
return;
} // end if
if (r.children != null)
for (int i = 0; i < r.children.length; i++)
condenseConstants(r.children[i]);
} // end condenseConstants
/* (non-Javadoc)
* @see gov.nasa.ial.mde.util.Comparison#compare(java.lang.Object, java.lang.Object)
*/
public int compare(Object a, Object b) {
StringSplitter s1 = (StringSplitter)a;
StringSplitter s2 = (StringSplitter)b;
int i = ((Integer)legalVariables.get(s1.pieces[1])).intValue();
int j = ((Integer)legalVariables.get(s2.pieces[1])).intValue();
return i - j;
} // end compare
/**
* Returns true if the expression is valid, or false if it is not.
*
* @return true if the expression is valid, or false if it is not.
*/
public boolean isValid() {
if (root == null)
return false;
if (root.badFlag)
return false;
return true;
} // end isValid
private String showSum(ParseNode r) {
if (r.children == null)
return null;
if (r.children.length == 0)
return "";
String s = "";
for (int i = 0; i < r.children.length; i++) {
ParseNode t = r.children[i];
if (t.operator == Action.U_MINUS) {
s = s + " -";
t = t.children[0];
} // end if
else
s = s + " +";
if (t.operator == Action.SUM)
s = s + "(" + showTerm(t) + ")";
else
s = s + showTerm(t);
} // end for i
s = s.trim();
if (s.indexOf("+") == 0)
s = s.substring(1).trim();
return s;
} // end showSum
private String showProd(ParseNode r) {
boolean needsParens=false;
if (r.children == null)
return null;
if (r.children.length == 0)
return "";
String s = "";
for (int i = 0; i < r.children.length; i++) {
ParseNode t = r.children[i];
if (t.operator == Action.RECIPROCAL) {
s = s + "/";
t = t.children[0];
needsParens = true;
} // end if
else
s = s + "*";
if (t.operator == Action.SUM)
s = s + "(" + showSum(t) + ")";
else
if (needsParens)
s = s + "(" + showTerm(t) + ")";
else
s = s+showTerm(t);
} // end for i
s = s.trim();
if (s.indexOf("*") == 0)
s = s.substring(1).trim();
return s;
} // end showProd
private String showPower(ParseNode r) {
if (r.children == null)
return null;
if (r.children.length != 2)
return null;
String base, power;
if (r.children[0].operator != Action.NO_OP)
base = "(" + showTerm(r.children[0]) + ")";
else
base = showTerm(r.children[0]);
if (r.children[1].operator != Action.NO_OP)
power = "(" + showTerm(r.children[1]) + ")";
else
power = showTerm(r.children[1]);
return base + "^" + power;
} // end showPower
private String showFunction(ParseNode r) {
if (r.children == null)
return null;
if (r.children.length != 1)
return null;
return (Action.FNAMES[r.operator] + "(" + showTerm(r.children[0]) + ")");
} // end showFunction
private String showTerm(ParseNode r) {
if (r == null)
return "";
String s;
Double D;
switch (r.operator) {
case Action.NO_OP :
s = r.theString.trim();
if ((D = (Double)parameters.get(s.toLowerCase())) != null) {
if (D.doubleValue() < 0.0)
return "(" + D.toString() + ")";
return D.toString();
} // end if
return s;
case Action.U_MINUS :
return null;
case Action.SUM :
return showSum(r);
case Action.RECIPROCAL :
return null;
case Action.PRODUCT :
return showProd(r);
case Action.POWER :
return showPower(r);
case Action.SQRT :
case Action.EXPONENTIAL :
case Action.LOG :
case Action.SINE :
case Action.COSINE :
case Action.TANGENT :
case Action.ABS :
return showFunction(r);
default :
return null;
} // end switch
} // end showTerm
/**
* Returns true if the expression is simple, false otherwise.
*
* @return true if the expression is simple, false otherwise.
*/
public boolean isSimple() {
return ((root.operator == Action.NO_OP) && (varStrings.length == 1));
} // end isSimple
/**
* Computes the product of this expression with the specified expression.
*
* @param other the other expression.
* @return the product of this expression with the specified expression.
*/
public Expression product(Expression other) {
ParseNode p = new ParseNode(2, Action.PRODUCT);
p.children[0] = root;
p.children[1] = other.root;
return new Expression(p);
} // end product
/**
* Computes the sum of this expression with the specified expression.
*
* @param other the other expression.
* @return the sum of this expression with the specified expression.
*/
public Expression sum(Expression other) {
ParseNode p = new ParseNode(2, Action.SUM);
p.children[0] = root;
p.children[1] = other.root;
return new Expression(p);
} // end sum
/**
* Returns the negated expression.
*
* @param other the expression to negate.
* @return the negated expression.
*/
public static Expression negate(Expression other) {
/*
* remove unnecessary minus signs if the expression is already negated, just remove the
* existing minus sign
*/
if (other.root.operator == Action.SUM)
if (other.root.children.length == 1)
if (other.root.children[0].operator == Action.U_MINUS) {
ParseNode p = new ParseNode(1, Action.SUM);
p.children[0] = other.root.children[0].children[0];
return new Expression(p);
} // end if
ParseNode p = new ParseNode(1, Action.SUM);
p.children[0] = new ParseNode(1, Action.U_MINUS);
p.children[0].children[0] = other.root;
return new Expression(p);
} // end negate
/**
* Returns the reciprocal of the specified expression.
*
* @param other the expression to process.
* @return the reciprocal of the expression.
*/
public static Expression reciprocal(Expression other) {
if (other.root.operator == Action.PRODUCT)
if (other.root.children.length == 1)
if (other.root.children[0].operator == Action.RECIPROCAL) {
ParseNode p = new ParseNode(1, Action.PRODUCT);
p.children[0] = other.root.children[0].children[0];
return new Expression(p);
} // end if
ParseNode p = new ParseNode(2, Action.PRODUCT);
p.children[0] = new ParseNode("1");
p.children[1] = new ParseNode(1, Action.RECIPROCAL);
p.children[1].children[0] = other.root;
return new Expression(p);
} // end reciprocal
/**
* Returns the difference between this expression and the specified expression.
*
* @param other the other expression.
* @return the difference between this expression and the specified expression.
*/
public Expression difference(Expression other) {
return sum(negate(other));
} // end difference
/**
* Returns the quotient of this expression and the specified expression.
*
* @param other the expression to process.
* @return the quotient of this expression and the specified expression.
*/
public Expression quotient(Expression other) {
ParseNode p = new ParseNode(2, Action.PRODUCT);
p.children[0] = root;
p.children[1] = new ParseNode(1, Action.RECIPROCAL);
p.children[1].children[0] = other.root;
return new Expression(p);
} // end quotient
/**
* Returns a string representation of the expression.
*
* @return a string representation of the expression.
*/
public String toString() {
String r = showTerm(root);
/*
* r = r+"\nVariables:\n"; Enumeration k = ((Hashtable)(variables.get(root))).keys();
*
* while (k.hasMoreElements()) r = r + (String)k.nextElement() +"\n";
*/
return r;
} // end toString
public static void main(String[] args) {
//Expression e = new Expression(StringSplitter.combineArgs(args));
Expression e= new Expression("sin(x)+2");
if (e.isValid()) {
Hashtable h = new Hashtable();
h.put("x", new Double(7.0));
e.parameters.put("a", new Double(2.0));
e.parameters.put("m", new Double(-3.0));
System.out.println("E = " + e.toString());
System.out.println("Value = " + e.evaluate(h));
} // end if
else
System.out.println("No dice");
} // end main
} // end class Expression