Пример #1
0
 /**
  * Generate LaTeX code for an ExpressionNode
  *
  * Create a string giving LaTeX code for an ExpressionNode `(x op y)`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  * ### Typesetting rules:
  *
  * - Adds parantheses around each operand, if needed. (I.e. if their precedence
  *   lower than that of the current Node.) For example, the AST `(^ (+ 1 2) 3)`
  *   generates `(1+2)^3` but `(+ (^ 1 2) 3)` generates `1^2+3` as expected.
  * - Multiplications are typeset implicitly `(* x y)` returns `xy` or using
  *   `\cdot` if the first factor is a FunctionNode or the (left operand) in the
  *   second factor is a NumberNode, so `(* x 2)` return `x \cdot 2` and `(* (sin x) x)`
  *   return `\sin x \cdot x` (but `(* x (sin x))` returns `x\sin x`)
  * - Divisions are typeset using `\frac`
  * - Exponentiation adds braces around the power when needed.
  *
  * @param ExpressionNode $node AST to be typeset
  * @retval string
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $left = $node->getLeft();
     $leftValue = $this->parenthesize($left, $node);
     $operator = $node->getOperator();
     $right = $node->getRight();
     if ($operator == '*') {
         $operator = '';
         if ($left instanceof FunctionNode || $right instanceof NumberNode || $right instanceof IntegerNode || $right instanceof RationalNode || $right instanceof ExpressionNode && $right->getLeft() instanceof NumberNode) {
             $operator = '\\cdot ';
         }
     }
     if ($right) {
         $rightValue = $this->parenthesize($right, $node);
         switch ($operator) {
             case '/':
                 // No parantheses needed
                 return '\\frac{' . $left->accept($this) . '}{' . $right->accept($this) . '}';
             case '^':
                 return $leftValue . '^' . $this->bracesNeeded($right);
             default:
                 return "{$leftValue}{$operator}{$rightValue}";
         }
     }
     return "{$operator}{$leftValue}";
 }
Пример #2
0
 /**
  * Generate ASCII output code for an ExpressionNode
  *
  * Create a string giving ASCII output representing an ExpressionNode `(x op y)`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  *
  * @param ExpressionNode $node AST to be typeset
  * @retval string
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $operator = $node->getOperator();
     $left = $node->getLeft();
     $right = $node->getRight();
     switch ($operator) {
         case '+':
             $leftValue = $left->accept($this);
             $rightValue = $this->parenthesize($right, $node);
             return "{$leftValue}+{$rightValue}";
         case '-':
             if ($right) {
                 // Binary minus
                 $leftValue = $left->accept($this);
                 $rightValue = $this->parenthesize($right, $node);
                 return "{$leftValue}-{$rightValue}";
             } else {
                 // Unary minus
                 $leftValue = $this->parenthesize($left, $node);
                 return "-{$leftValue}";
             }
         case '*':
         case '/':
             $leftValue = $this->parenthesize($left, $node, '', false);
             $rightValue = $this->parenthesize($right, $node, '', true);
             return "{$leftValue}{$operator}{$rightValue}";
         case '^':
             $leftValue = $this->parenthesize($left, $node, '', true);
             $rightValue = $this->parenthesize($right, $node, '', false);
             return "{$leftValue}{$operator}{$rightValue}";
     }
 }
Пример #3
0
 /**
  * Print an ExpressionNode.
  *
  * @param ExpressionNode $node
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $leftValue = $node->getLeft()->accept($this);
     $operator = $node->getOperator();
     // The operator and the right side are optional, remember?
     if (!$operator) {
         return "{$leftValue}";
     }
     $right = $node->getRight();
     if ($right) {
         $rightValue = $node->getRight()->accept($this);
         return "({$operator}, {$leftValue}, {$rightValue})";
     } else {
         return "({$operator}, {$leftValue})";
     }
 }
Пример #4
0
 /**
  * Generate ASCII output code for an ExpressionNode
  *
  * Create a string giving ASCII output representing an ExpressionNode `(x op y)`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  *
  * @param ExpressionNode $node AST to be typeset
  * @retval string
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $left = $node->getLeft();
     $leftValue = $this->parenthesize($left, $node);
     $operator = $node->getOperator();
     $right = $node->getRight();
     if ($right) {
         $rightValue = $this->parenthesize($right, $node);
         switch ($operator) {
             case '^':
                 return $leftValue . '^' . $this->bracesNeeded($right);
             default:
                 return "{$leftValue}{$operator}{$rightValue}";
         }
     }
     return "{$operator}{$leftValue}";
 }
Пример #5
0
 /**
  * Generate LaTeX code for an ExpressionNode
  *
  * Create a string giving LaTeX code for an ExpressionNode `(x op y)`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  * ### Typesetting rules:
  *
  * - Adds parentheses around each operand, if needed. (I.e. if their precedence
  *   lower than that of the current Node.) For example, the AST `(^ (+ 1 2) 3)`
  *   generates `(1+2)^3` but `(+ (^ 1 2) 3)` generates `1^2+3` as expected.
  * - Multiplications are typeset implicitly `(* x y)` returns `xy` or using
  *   `\cdot` if the first factor is a FunctionNode or the (left operand) in the
  *   second factor is a NumberNode, so `(* x 2)` return `x \cdot 2` and `(* (sin x) x)`
  *   return `\sin x \cdot x` (but `(* x (sin x))` returns `x\sin x`)
  * - Divisions are typeset using `\frac`
  * - Exponentiation adds braces around the power when needed.
  *
  * @param ExpressionNode $node AST to be typeset
  * @retval string
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $operator = $node->getOperator();
     $left = $node->getLeft();
     $right = $node->getRight();
     switch ($operator) {
         case '+':
             $leftValue = $left->accept($this);
             $rightValue = $this->parenthesize($right, $node);
             return "{$leftValue}+{$rightValue}";
         case '-':
             if ($right) {
                 // Binary minus
                 $leftValue = $left->accept($this);
                 $rightValue = $this->parenthesize($right, $node);
                 return "{$leftValue}-{$rightValue}";
             } else {
                 // Unary minus
                 $leftValue = $this->parenthesize($left, $node);
                 return "-{$leftValue}";
             }
         case '*':
             $operator = '';
             if ($left instanceof FunctionNode || $right instanceof NumberNode || $right instanceof IntegerNode || $right instanceof RationalNode || $right instanceof ExpressionNode && $right->getLeft() instanceof NumberNode) {
                 $operator = '\\cdot ';
             }
             $leftValue = $this->parenthesize($left, $node);
             $rightValue = $this->parenthesize($right, $node);
             return "{$leftValue}{$operator}{$rightValue}";
         case '/':
             return '\\frac{' . $left->accept($this) . '}{' . $right->accept($this) . '}';
         case '^':
             $leftValue = $this->parenthesize($left, $node, '', true);
             return $leftValue . '^' . $this->bracesNeeded($right);
     }
 }
Пример #6
0
 /**
  * Evaluate an ExpressionNode
  *
  * Computes the value of an ExpressionNode `x op y`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  * @throws UnknownOperatorException if the operator is something other than
  *      `+`, `-`, `*`, `/` or `^`
  *
  * @param ExpressionNode $node AST to be evaluated
  * @retval float
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $operator = $node->getOperator();
     $leftValue = $node->getLeft()->accept($this);
     if ($node->getRight()) {
         $rightValue = $node->getRight()->accept($this);
     } else {
         $rightValue = null;
     }
     // Perform the right operation based on the operator
     switch ($operator) {
         case '+':
             return $leftValue + $rightValue;
         case '-':
             return $rightValue === null ? -$leftValue : $leftValue - $rightValue;
         case '*':
             return $rightValue * $leftValue;
         case '/':
             if ($rightValue == 0) {
                 throw new DivisionByZeroException();
             }
             return $leftValue / $rightValue;
         case '^':
             return pow($leftValue, $rightValue);
         default:
             throw new UnknownOperatorException($operator);
     }
 }
Пример #7
0
 /**
  * Evaluate an ExpressionNode
  *
  * Computes the value of an ExpressionNode `x op y`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  * @throws UnknownOperatorException if the operator is something other than
  *      `+`, `-`, `*`, `/` or `^`
  *
  * @param ExpressionNode $node AST to be evaluated
  * @retval float
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $operator = $node->getOperator();
     $a = $node->getLeft()->accept($this);
     if ($node->getRight()) {
         $b = $node->getRight()->accept($this);
     } else {
         $b = null;
     }
     // Perform the right operation based on the operator
     switch ($operator) {
         case '+':
             return Complex::add($a, $b);
         case '-':
             if ($b === null) {
                 return Complex::mul($a, -1);
             }
             return Complex::sub($a, $b);
         case '*':
             return Complex::mul($a, $b);
         case '/':
             return Complex::div($a, $b);
         case '^':
             // This needs to be improved.
             return Complex::pow($a, $b);
         default:
             throw new UnknownOperatorException($operator);
     }
 }
Пример #8
0
 /**
  * Differentiate an ExpressionNode
  *
  * Using the usual rules for differentiating, create an ExpressionNode
  * giving an AST correctly representing the derivative `(x op y)'`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  * ### Differentiation rules:
  *
  * - \\( (f+g)' = f' + g' \\)
  * - \\( (f-g) ' = f' - g' \\)
  * - \\( (-f)' = -f' \\)
  * - \\( (f*g)' = f'g + f g' \\)
  * - \\( (f/g)' = (f' g - f g')/g^2 \\)
  * - \\( (f^g)' = f^g  (g' \\log(f) + g/f) \\) with a simpler expression when g is a NumberNode
  *
  * @throws UnknownOperatorException if the operator is something other than
  *      `+`, `-`, `*`, `/` or `^`
  *
  * @param ExpressionNode $node AST to be differentiated
  * @retval Node
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $operator = $node->getOperator();
     $leftValue = $node->getLeft()->accept($this);
     if ($node->getRight()) {
         $rightValue = $node->getRight()->accept($this);
     } else {
         $rightValue = null;
     }
     // Perform the right operation based on the operator
     switch ($operator) {
         case '+':
             return $this->nodeFactory->addition($leftValue, $rightValue);
         case '-':
             return $this->nodeFactory->subtraction($leftValue, $rightValue);
             // Product rule (fg)' = fg' + f'g
         // Product rule (fg)' = fg' + f'g
         case '*':
             return $this->nodeFactory->addition($this->nodeFactory->multiplication($node->getLeft(), $rightValue), $this->nodeFactory->multiplication($leftValue, $node->getRight()));
             // Quotient rule (f/g)' = (f'g - fg')/g^2
         // Quotient rule (f/g)' = (f'g - fg')/g^2
         case '/':
             $term1 = $this->nodeFactory->multiplication($leftValue, $node->getRight());
             $term2 = $this->nodeFactory->multiplication($node->getLeft(), $rightValue);
             $numerator = $this->nodeFactory->subtraction($term1, $term2);
             $denominator = $this->nodeFactory->exponentiation($node->getRight(), new IntegerNode(2));
             return $this->nodeFactory->division($numerator, $denominator);
             // f^g = exp(g log(f)), so (f^g)' = f^g (g'log(f) + g/f)
         // f^g = exp(g log(f)), so (f^g)' = f^g (g'log(f) + g/f)
         case '^':
             $base = $node->getLeft();
             $exponent = $node->getRight();
             if ($exponent instanceof IntegerNode || $exponent instanceof NumberNode) {
                 $power = $exponent->getValue();
                 $fpow = $this->nodeFactory->exponentiation($base, $power - 1);
                 return $this->nodeFactory->multiplication($power, $this->nodeFactory->multiplication($fpow, $leftValue));
             } elseif ($exponent instanceof RationalNode) {
                 $newPower = new RationalNode($exponent->getNumerator() - $exponent->getDenominator(), $exponent->getDenominator());
                 $fpow = $this->nodeFactory->exponentiation($base, $newPower);
                 return $this->nodeFactory->multiplication($exponent, $this->nodeFactory->multiplication($fpow, $leftValue));
             } else {
                 $term1 = $this->nodeFactory->multiplication($rightValue, new FunctionNode('log', $node->getLeft()));
                 $term2 = $this->nodeFactory->division($node->getRight(), $node->getLeft());
                 $factor2 = $this->nodeFactory->addition($term1, $term2);
                 return $this->nodeFactory->multiplication($node, $factor2);
             }
         default:
             throw new UnknownOperatorException($operator);
     }
 }
Пример #9
0
 /**
  * Evaluate an ExpressionNode
  *
  * Computes the value of an ExpressionNode `x op y`
  * where `op` is one of `+`, `-`, `*`, `/` or `^`
  *
  * @throws UnknownOperatorException if the operator is something other than
  *      `+`, `-`, `*`, `/` or `^`
  *
  * @param ExpressionNode $node AST to be evaluated
  * @retval float
  */
 public function visitExpressionNode(ExpressionNode $node)
 {
     $operator = $node->getOperator();
     $a = $node->getLeft()->accept($this);
     if ($node->getRight()) {
         $b = $node->getRight()->accept($this);
     } else {
         $b = null;
     }
     // Perform the right operation based on the operator
     switch ($operator) {
         case '+':
             $p = $a->getNumerator() * $b->getDenominator() + $a->getDenominator() * $b->getNumerator();
             $q = $a->getDenominator() * $b->getDenominator();
             return new RationalNode($p, $q);
         case '-':
             if ($b === null) {
                 return new RationalNode(-$a->getNumerator(), $a->getDenominator());
             }
             $p = $a->getNumerator() * $b->getDenominator() - $a->getDenominator() * $b->getNumerator();
             $q = $a->getDenominator() * $b->getDenominator();
             return new RationalNode($p, $q);
         case '*':
             $p = $a->getNumerator() * $b->getNumerator();
             $q = $a->getDenominator() * $b->getDenominator();
             return new RationalNode($p, $q);
         case '/':
             if ($b->getNumerator() == 0) {
                 throw new DivisionByZeroException();
             }
             $p = $a->getNumerator() * $b->getDenominator();
             $q = $a->getDenominator() * $b->getNumerator();
             return new RationalNode($p, $q);
         case '^':
             return $this->rpow($a, $b);
         default:
             throw new UnknownOperatorException($operator);
     }
 }
Пример #10
0
 /**
  * Simplify the given ExpressionNode, using the appropriate factory.
  *
  * @param ExpressionNode $node
  * @retval Node Simplified version of the input
  */
 public function simplify(ExpressionNode $node)
 {
     switch ($node->getOperator()) {
         case '+':
             return $this->addition($node->getLeft(), $node->getRight());
         case '-':
             return $this->subtraction($node->getLeft(), $node->getRight());
         case '*':
             return $this->multiplication($node->getLeft(), $node->getRight());
         case '/':
             return $this->division($node->getLeft(), $node->getRight());
         case '^':
             return $this->exponentiation($node->getLeft(), $node->getRight());
     }
 }
Пример #11
0
 public function testCanCreateTemporaryUnaryMinusNode()
 {
     $node = new ExpressionNode(null, '~', null);
     $this->assertEquals($node->getOperator(), '~');
     $this->assertNull($node->getRight());
     $this->assertNull($node->getLeft());
     $this->assertEquals($node->getPrecedence(), 25);
 }