001: /*************************************************************************
002: * *
003: * 1) This source code file, in unmodified form, and compiled classes *
004: * derived from it can be used and distributed without restriction, *
005: * including for commercial use. (Attribution is not required *
006: * but is appreciated.) *
007: * *
008: * 2) Modified versions of this file can be made and distributed *
009: * provided: the modified versions are put into a Java package *
010: * different from the original package, edu.hws; modified *
011: * versions are distributed under the same terms as the original; *
012: * and the modifications are documented in comments. (Modification *
013: * here does not include simply making subclasses that belong to *
014: * a package other than edu.hws, which can be done without any *
015: * restriction.) *
016: * *
017: * David J. Eck *
018: * Department of Mathematics and Computer Science *
019: * Hobart and William Smith Colleges *
020: * Geneva, New York 14456, USA *
021: * Email: eck@hws.edu WWW: http://math.hws.edu/eck/ *
022: * *
023: *************************************************************************/package edu.hws.jcm.data;
024:
025: /**
026: * A "conditional expression" is an expression using the "?" operator, such as "(x > 0)? x : -x"
027: * or "x <> 3 ? 1 / (x - 3)". Note that the second case, which follows the ":", is optional.
028: * If not present, the expression has the value Double.NaN when the boolean condition evaluates
029: * to false. A ConditionalExpression object is generated by a parser when it encounters a
030: * "?" operator in the string it is parsing (provided the BOOLEANS option is turned on in that parser).
031: * <p>A ConditionalExpression object holds the two expressions that are the cases in a conditional expression.
032: * Note that the boolean condition is NOT stored in the ConditionalExpression object; it is part of
033: * the ExpressionProgram for the expression in which the conditional expression occurs.
034: * A ConditionalExpression is an ExpressionCommand, meaning that it can occur in an ExpressionProgram.
035: * When the apply() method in this class is called, the boolean condition has already been evaluated,
036: * and the result is on the top of the stack. The ConditionalExpression will look at this result
037: * and replace it with the value of one of the two expressions that it contains.
038: * <p>It is unlikely that there will be any reason for anyone to use or understand this class,
039: * except possibly as an example of an ExpressionCommand.
040: */
041: public class ConditionalExpression implements ExpressionCommand {
042:
043: private ExpressionProgram trueCase; // Expression to be evaluated if condition is true.
044:
045: private ExpressionProgram falseCase; // Expression to be evaluated if condition is false.
046:
047: // This can be null, representing the value Double.NaN.
048:
049: /**
050: * Create a ConditionalExpression object containing the two given expressions.
051: * trueCase must not be null, but falseCase can be null.
052: */
053: public ConditionalExpression(ExpressionProgram trueCase,
054: ExpressionProgram falseCase) {
055: this .trueCase = trueCase;
056: this .falseCase = falseCase;
057: }
058:
059: // ---------------- Methods from the ExpressionCommand interface -------------------------
060:
061: /**
062: * Apply this ConditionalExpression to the stack.
063: * (Get the top item from the stack. If it is non-zero (representing a boolean
064: * value of true), evaluate trueCase and put it's value on the stack. Otherwise,
065: * evaluate falseCase and put its value on the stack. If cases is non-null, record
066: * case values for the boolean condition and for the expression that is evaluated.)
067: */
068: public void apply(StackOfDouble stack, Cases cases) {
069: double test = stack.pop();
070: if (cases != null)
071: cases.addCase((int) test);
072: if (test != 0)
073: stack.push(trueCase.getValueWithCases(cases));
074: else if (falseCase != null)
075: stack.push(falseCase.getValueWithCases(cases));
076: else
077: stack.push(Double.NaN);
078: }
079:
080: /**
081: * Add commands to deriv that evaluate the derivative of this conditional expression with
082: * respect to the variable wrt. Assume that the ConditionalExpression Object
083: * occurs in the program prog at index myIndex.
084: * (The derivative of a conditional expression is another conditional expression.
085: * The boolean test for the derivative is the same as the test for this expression,
086: * so copy that test onto deriv. Than add a new ConditionalExpression object to deriv
087: * whose trueCase is the derivative of this.trueCase and whose falseCase is the derivative of
088: * this.falseCase.)
089: */
090: public void compileDerivative(ExpressionProgram prog, int myIndex,
091: ExpressionProgram deriv, Variable wrt) {
092: prog.copyExpression(myIndex - 1, deriv);
093: ExpressionProgram trueDeriv = (ExpressionProgram) trueCase
094: .derivative(wrt);
095: ExpressionProgram falseDeriv = (falseCase == null) ? null
096: : (ExpressionProgram) falseCase.derivative(wrt);
097: deriv.addCommandObject(new ConditionalExpression(trueDeriv,
098: falseDeriv));
099: }
100:
101: /**
102: * Assume that this ConditionalExpression object occurs in prog at index myIndex.
103: * Compute the total number of commands in prog used by the conditional expression,
104: * including the boolean test, which occurs in prog at position myIndex-1.
105: * (The number of commands in prog used by the conditional expression is 1 (for the
106: * ConditionalExpression object itself) plus the number of commands in the
107: * boolean condition.)
108: */
109: public int extent(ExpressionProgram prog, int myIndex) {
110: return 1 + prog.extent(myIndex - 1);
111: }
112:
113: /**
114: * Returns true if x occurs in either the trueCase or the falseCase expression.
115: */
116: public boolean dependsOn(Variable x) {
117: return trueCase.dependsOn(x)
118: || (falseCase != null && falseCase.dependsOn(x));
119: }
120:
121: /**
122: * Append the string representation of the expression (including the boolean
123: * condition) to the buffer. Assume that this ConditionalExpression occurs as
124: * a command in prog at index myIndex (so the boolean condition starts at index myIndex-1).
125: */
126: public void appendOutputString(ExpressionProgram prog, int myIndex,
127: StringBuffer buffer) {
128: buffer.append('(');
129: prog.appendOutputString(myIndex - 1, buffer);
130: buffer.append(") ? (");
131: buffer.append(trueCase.toString());
132: buffer.append(')');
133: if (falseCase != null) {
134: buffer.append(" : (");
135: buffer.append(falseCase.toString());
136: buffer.append(')');
137: }
138: }
139:
140: } // end class ConditionalExpression
|