Ejemplo n.º 1
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})";
     }
 }
Ejemplo n.º 2
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);
     }
 }
Ejemplo n.º 3
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);
     }
 }
Ejemplo n.º 4
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);
     }
 }
Ejemplo n.º 5
0
 public function parenthesize(Node $node, ExpressionNode $cutoff, $prepend = '', $conservative = false)
 {
     $text = $node->accept($this);
     if ($node instanceof ExpressionNode) {
         // Second term is a unary minus
         if ($node->getOperator() == '-' && $node->getRight() == null) {
             return "({$text})";
         }
         if ($cutoff->getOperator() == '-' && $node->lowerPrecedenceThan($cutoff)) {
             return "({$text})";
         }
         if ($conservative) {
             // Add parentheses more liberally for / and ^ operators,
             // so that e.g. x/(y*z) is printed correctly
             if ($cutoff->getOperator() == '/' && $node->lowerPrecedenceThan($cutoff)) {
                 return "({$text})";
             }
             if ($cutoff->getOperator() == '^' && $node->getOperator() == '^') {
                 return "({$text})";
             }
         }
         if ($node->strictlyLowerPrecedenceThan($cutoff)) {
             return "({$text})";
         }
     }
     if (($node instanceof NumberNode || $node instanceof IntegerNode || $node instanceof RationalNode) && $node->getValue() < 0) {
         return "({$text})";
     }
     // Treat rational numbers as divisions on printing
     if ($node instanceof RationalNode && $node->getDenominator() != 1) {
         $fakeNode = new ExpressionNode($node->getNumerator(), '/', $node->getDenominator());
         if ($fakeNode->lowerPrecedenceThan($cutoff)) {
             return "({$text})";
         }
     }
     return "{$prepend}{$text}";
 }
Ejemplo n.º 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();
     $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);
     }
 }
Ejemplo n.º 7
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());
     }
 }
Ejemplo n.º 8
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);
 }