Example #1
0
 public function testCanCompareFunctionNodes()
 {
     $node = new FunctionNode('sin', new VariableNode('x'));
     $other = new NumberNode(1);
     $this->assertFalse($node->compareTo(null));
     $this->assertFalse($node->compareTo($other));
     $this->assertTrue($node->compareTo($node));
     $this->assertFalse($node->compareTo(new FunctionNode('cos', new VariableNode('x'))));
 }
Example #2
0
 /**
  * Print a FunctionNode.
  *
  * @param FunctionNode $node
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $functionName = $node->getName();
     $operand = $node->getOperand()->accept($this);
     return "{$functionName}({$operand})";
 }
Example #3
0
 /**
  * Evaluate a FunctionNode
  *
  * Computes the value of a FunctionNode `f(x)`, where f is
  * an elementary function recognized by StdMathLexer and StdMathParser.
  *
  * @see \MathParser\Lexer\StdMathLexer StdMathLexer
  * @see \MathParser\StdMathParser StdMathParser
  * @throws UnknownFunctionException if the function respresented by the
  *      FunctionNode is *not* recognized.
  *
  * @param FunctionNode $node AST to be evaluated
  * @retval float
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $inner = $node->getOperand()->accept($this);
     switch ($node->getName()) {
         // Trigonometric functions
         case 'sin':
             return sin($inner);
         case 'cos':
             return cos($inner);
         case 'tan':
             return tan($inner);
         case 'cot':
             return 1 / tan($inner);
             // Inverse trigonometric functions
         // Inverse trigonometric functions
         case 'arcsin':
             return asin($inner);
         case 'arccos':
             return acos($inner);
         case 'arctan':
             return atan($inner);
         case 'arccot':
             return pi() / 2 - atan($inner);
             // Exponentials and logarithms
         // Exponentials and logarithms
         case 'exp':
             return exp($inner);
         case 'log':
             return log($inner);
         case 'lg':
             return log10($inner);
             // Powers
         // Powers
         case 'sqrt':
             return sqrt($inner);
             // Hyperbolic functions
         // Hyperbolic functions
         case 'sinh':
             return sinh($inner);
         case 'cosh':
             return cosh($inner);
         case 'tanh':
             return tanh($inner);
         case 'coth':
             return 1 / tanh($inner);
             // Inverse hyperbolic functions
         // Inverse hyperbolic functions
         case 'arsinh':
             return asinh($inner);
         case 'arcosh':
             return acosh($inner);
         case 'artanh':
             return atanh($inner);
         case 'arcoth':
             return atanh(1 / $inner);
         default:
             throw new UnknownFunctionException($node->getName());
     }
 }
 /**
  * Evaluate a FunctionNode
  *
  * Computes the value of a FunctionNode `f(x)`, where f is
  * an elementary function recognized by StdMathLexer and StdMathParser.
  *
  * @see \MathParser\Lexer\StdMathLexer StdMathLexer
  * @see \MathParser\StdMathParser StdMathParser
  * @throws UnknownFunctionException if the function respresented by the
  *      FunctionNode is *not* recognized.
  *
  * @param FunctionNode $node AST to be evaluated
  * @retval float
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $z = $node->getOperand()->accept($this);
     $a = $z->r();
     $b = $z->i();
     switch ($node->getName()) {
         // Trigonometric functions
         case 'sin':
             return Complex::sin($z);
         case 'cos':
             return Complex::cos($z);
         case 'tan':
             return Complex::tan($z);
         case 'cot':
             return Complex::cot($z);
             // Inverse trigonometric functions
         // Inverse trigonometric functions
         case 'arcsin':
             return Complex::arcsin($z);
         case 'arccos':
             return Complex::arccos($z);
         case 'arctan':
             return Complex::arctan($z);
         case 'arccot':
             return Complex::arccot($z);
         case 'sinh':
             return Complex::sinh($z);
         case 'cosh':
             return Complex::cosh($z);
         case 'tanh':
             return Complex::tanh($z);
         case 'coth':
             return Complex::div(1, Complex::tanh($z));
         case 'arsinh':
             return Complex::arsinh($z);
         case 'arcosh':
             return Complex::arcosh($z);
         case 'artanh':
             return Complex::artanh($z);
         case 'arcoth':
             return Complex::div(1, Complex::artanh($z));
         case 'exp':
             return Complex::exp($z);
         case 'log':
             return Complex::log($z);
         case 'lg':
             return Complex::div(Complex::log($z), M_LN10);
         case 'sqrt':
             return Complex::sqrt($z);
         case 'abs':
             return new Complex($z->abs(), 0);
         case 'arg':
             return new Complex($z->arg(), 0);
         case 're':
             return new Complex($z->r(), 0);
         case 'im':
             return new Complex($z->i(), 0);
         case 'conj':
             return new Complex($z->r(), -$z->i());
         default:
             throw new UnknownFunctionException($node->getName());
     }
     return new FunctionNode($node->getName(), $inner);
 }
Example #5
0
 /**
  * Differentiate a FunctionNode
  *
  * Create an ExpressionNode giving an AST correctly representing the
  * derivative `f'` where `f` is an elementary function.
  *
  * ### Differentiation rules:
  *
  * * \\( \\sin(f(x))' = f'(x)  \\cos(f(x)) \\)
  * * \\( \\cos(f(x))' = -f'(x)  \\sin(f(x)) \\)
  * * \\( \\tan(f(x))' = f'(x) (1 + \\tan(f(x))^2 \\)
  * * \\( \\operatorname{cot}(f(x))' = f'(x) (-1 - \\operatorname{cot}(f(x))^2 \\)
  * * \\( \\arcsin(f(x))' = f'(x) / \\sqrt{1-f(x)^2} \\)
  * * \\( \\arccos(f(x))' = -f'(x) / \\sqrt{1-f(x)^2} \\)
  * * \\( \\arctan(f(x))' = f'(x) / (1+f(x)^2) \\)
  * * \\( \\operatorname{arccot}(f(x))' = -f'(x) / (1+f(x)^2) \\)
  * * \\( \\exp(f(x))' = f'(x) \\exp(f(x)) \\)
  * * \\( \\log(f(x))' = f'(x) / f(x) \\)
  * * \\( \\ln(f(x))' = f'(x) / (\\log(10) * f(x)) \\)
  * * \\( \\sqrt{f(x)}' = f'(x) / (2 \\sqrt{f(x)} \\)
  * * \\( \\sinh(f(x))' = f'(x) \\cosh(f(x)) \\)
  * * \\( \\cosh(f(x))' = f'(x) \\sinh(f(x)) \\)
  * * \\( \\tanh(f(x))' = f'(x) (1-\\tanh(f(x))^2) \\)
  * * \\( \\operatorname{coth}(f(x))' = f'(x) (1-\\operatorname{coth}(f(x))^2) \\)
  * * \\( \\operatorname{arsinh}(f(x))' = f'(x) / \\sqrt{f(x)^2+1} \\)
  * * \\( \\operatorname{arcosh}(f(x))' = f'(x) / \\sqrt{f(x)^2-1} \\)
  * * \\( \\operatorname{artanh}(f(x))' = f'(x) (1-f(x)^2) \\)
  * * \\( \\operatorname{arcoth}(f(x))' = f'(x) (1-f(x)^2) \\)
  *
  * @throws UnknownFunctionException if the function name doesn't match
  *          one of the above
  *
  * @param FunctionNode $node AST to be differentiated
  * @retval Node
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $inner = $node->getOperand()->accept($this);
     $arg = $node->getOperand();
     switch ($node->getName()) {
         case 'sin':
             $df = new FunctionNode('cos', $arg);
             break;
         case 'cos':
             $sin = new FunctionNode('sin', $arg);
             $df = $this->nodeFactory->unaryMinus($sin);
             break;
         case 'tan':
             $tansquare = $this->nodeFactory->exponentiation($node, 2);
             $df = $this->nodeFactory->addition(1, $tansquare);
             break;
         case 'cot':
             $cotsquare = $this->nodeFactory->exponentiation($node, 2);
             $df = $this->nodeFactory->subtraction($this->nodeFactory->unaryMinus(1), $cotsquare);
             break;
         case 'arcsin':
             $denom = new FunctionNode('sqrt', $this->nodeFactory->subtraction(1, $this->nodeFactory->exponentiation($arg, 2)));
             return $this->nodeFactory->division($inner, $denom);
         case 'arccos':
             $denom = new FunctionNode('sqrt', $this->nodeFactory->subtraction(1, $this->nodeFactory->exponentiation($arg, 2)));
             return $this->nodeFactory->division($this->nodeFactory->unaryMinus($inner), $denom);
         case 'arctan':
             $denom = $this->nodeFactory->addition(1, $this->nodeFactory->exponentiation($arg, 2));
             return $this->nodeFactory->division($inner, $denom);
         case 'arccot':
             $denom = $this->nodeFactory->addition(1, $this->nodeFactory->exponentiation($arg, 2));
             $df = $this->nodeFactory->unaryMinus($this->nodeFactory->division(1, $denom));
             break;
         case 'exp':
             $df = new FunctionNode('exp', $arg);
             break;
         case 'log':
             return $this->nodeFactory->division($inner, $arg);
         case 'lg':
             $denominator = $this->nodeFactory->multiplication(new FunctionNode('log', new IntegerNode(10)), $arg);
             return $this->nodeFactory->division($inner, $denominator);
         case 'sqrt':
             $denom = $this->nodeFactory->multiplication(2, $node);
             return $this->nodeFactory->division($inner, $denom);
         case 'sinh':
             $df = new FunctionNode('cosh', $arg);
             break;
         case 'cosh':
             $df = new FunctionNode('sinh', $arg);
             break;
         case 'tanh':
             $tanhsquare = $this->nodeFactory->exponentiation(new FunctionNode('tanh', $arg), 2);
             $df = $this->nodeFactory->subtraction(1, $tanhsquare);
             break;
         case 'coth':
             $cothsquare = $this->nodeFactory->exponentiation(new FunctionNode('coth', $arg), 2);
             $df = $this->nodeFactory->subtraction(1, $cothsquare);
             break;
         case 'arsinh':
             $temp = $this->nodeFactory->addition($this->nodeFactory->exponentiation($arg, 2), 1);
             return $this->nodeFactory->division($inner, new FunctionNode('sqrt', $temp));
         case 'arcosh':
             $temp = $this->nodeFactory->subtraction($this->nodeFactory->exponentiation($arg, 2), 1);
             return $this->nodeFactory->division($inner, new FunctionNode('sqrt', $temp));
         case 'artanh':
         case 'arcoth':
             $denominator = $this->nodeFactory->subtraction(1, $this->nodeFactory->exponentiation($arg, 2));
             return $this->nodeFactory->division($inner, $denominator);
         case 'abs':
             $df = new FunctionNode('sgn', $arg);
             break;
         default:
             throw new UnknownFunctionException($node->getName());
     }
     return $this->nodeFactory->multiplication($inner, $df);
 }
Example #6
0
 public function visitFunctionNode(FunctionNode $node)
 {
     $functionName = $node->getName();
     if ($functionName == '!' || $functionName == '!!') {
         return $this->visitFactorialNode($node);
     }
     $operand = $node->getOperand()->accept($this);
     return "{$functionName}({$operand})";
 }
 /**
  * Evaluate a FunctionNode
  *
  * Computes the value of a FunctionNode `f(x)`, where f is
  * an elementary function recognized by StdMathLexer and StdMathParser.
  *
  * @see \MathParser\Lexer\StdMathLexer StdMathLexer
  * @see \MathParser\StdMathParser StdMathParser
  * @throws UnknownFunctionException if the function respresented by the
  *      FunctionNode is *not* recognized.
  *
  * @param FunctionNode $node AST to be evaluated
  * @retval float
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $inner = $node->getOperand()->accept($this);
     switch ($node->getName()) {
         // Trigonometric functions
         case 'sin':
         case 'cos':
         case 'tan':
         case 'cot':
         case 'arcsin':
         case 'arccos':
         case 'arctan':
         case 'arccot':
         case 'exp':
         case 'log':
         case 'lg':
         case 'sinh':
         case 'cosh':
         case 'tanh':
         case 'coth':
         case 'arsinh':
         case 'arcosh':
         case 'artanh':
         case 'arcoth':
             throw new \UnexpectedValueException();
             // Powers
         // Powers
         case 'sqrt':
             return $this->rpow($inner, new RationalNode(1, 2));
         default:
             throw new UnknownFunctionException($node->getName());
     }
 }
Example #8
0
 /**
  * Generate LaTeX code for a FunctionNode
  *
  * Create a string giving LaTeX code for a functionNode.
  *
  * ### Typesetting rules:
  *
  * - `sqrt(op)` is typeset as `\sqrt{op}
  * - `exp(op)` is either typeset as `e^{op}`, if `op` is a simple
  *      expression or as `\exp(op)` for more complicated operands.
  *
  * @param FunctionNode $node AST to be typeset
  * @retval string
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $functionName = $node->getName();
     $operand = $this->parenthesize($node->getOperand(), new ExpressionNode(null, '*', null), ' ');
     switch ($functionName) {
         case 'sqrt':
             return "\\{$functionName}{" . $node->getOperand()->accept($this) . '}';
         case 'exp':
             $operand = $node->getOperand();
             if ($operand->complexity() < 6) {
                 return 'e^' . $this->bracesNeeded($operand);
             }
             // Operand is complex, typset using \exp instead
             return '\\exp(' . $operand->accept($this) . ')';
         case 'sin':
         case 'cos':
         case 'tan':
         case 'arcsin':
         case 'arccos':
         case 'arctan':
             break;
         case 'log':
             $functionName = 'ln';
             break;
         case 'abs':
             $operand = $node->getOperand();
             return '\\lvert ' . $operand->accept($this) . '\\rvert ';
         case '!':
         case '!!':
             return $this->visitFactorialNode($node);
         default:
             $functionName = 'operatorname{' . $functionName . '}';
     }
     return "\\{$functionName}{$operand}";
 }
Example #9
0
 public function testCanCompareUnaryMinus()
 {
     $node = new FunctionNode('sin', new ExpressionNode(new VariableNode('x'), '-', null));
     $other = new FunctionNode('sin', new ExpressionNode(new VariableNode('a'), '-', null));
     $this->assertTrue($node->compareTo($node));
     $this->assertTrue($other->compareTo($other));
     $this->assertFalse($node->compareTo($other));
     $this->assertFalse($other->compareTo($node));
 }
 /**
  * Evaluate a FunctionNode
  *
  * Computes the value of a FunctionNode `f(x)`, where f is
  * an elementary function recognized by StdMathLexer and StdMathParser.
  *
  * @see \MathParser\Lexer\StdMathLexer StdMathLexer
  * @see \MathParser\StdMathParser StdMathParser
  * @throws UnknownFunctionException if the function respresented by the
  *      FunctionNode is *not* recognized.
  *
  * @param FunctionNode $node AST to be evaluated
  * @retval float
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $inner = $node->getOperand()->accept($this);
     switch ($node->getName()) {
         // Trigonometric functions
         case 'sin':
         case 'cos':
         case 'tan':
         case 'cot':
         case 'arcsin':
         case 'arccos':
         case 'arctan':
         case 'arccot':
         case 'exp':
         case 'log':
         case 'lg':
         case 'sinh':
         case 'cosh':
         case 'tanh':
         case 'coth':
         case 'arsinh':
         case 'arcosh':
         case 'artanh':
         case 'arcoth':
             throw new \UnexpectedValueException("Expecting rational expression");
         case 'abs':
             return new RationalNode(abs($inner->getNumerator()), $inner->getDenominator());
         case 'sgn':
             if ($inner->getNumerator() >= 0) {
                 return new RationalNode(1, 0);
             } else {
                 return new RationalNode(-1, 0);
             }
             // Powers
         // Powers
         case 'sqrt':
             return $this->rpow($inner, new RationalNode(1, 2));
         case '!':
             if ($inner->getDenominator() == 1 && $inner->getNumerator() >= 0) {
                 return new RationalNode(Math::Factorial($inner->getNumerator()), 1);
             }
             throw new \UnexpectedValueException("Expecting positive integer (factorial)");
         case '!!':
             if ($inner->getDenominator() == 1 && $inner->getNumerator() >= 0) {
                 return new RationalNode(Math::SemiFactorial($inner->getNumerator()), 1);
             }
             throw new \UnexpectedValueException("Expecting positive integer (factorial)");
         default:
             throw new UnknownFunctionException($node->getName());
     }
 }
Example #11
0
 /**
  * Evaluate a FunctionNode
  *
  * Computes the value of a FunctionNode `f(x)`, where f is
  * an elementary function recognized by StdMathLexer and StdMathParser.
  *
  * @see \MathParser\Lexer\StdMathLexer StdMathLexer
  * @see \MathParser\StdMathParser StdMathParser
  * @throws UnknownFunctionException if the function respresented by the
  *      FunctionNode is *not* recognized.
  *
  * @param FunctionNode $node AST to be evaluated
  * @retval float
  */
 public function visitFunctionNode(FunctionNode $node)
 {
     $inner = $node->getOperand()->accept($this);
     switch ($node->getName()) {
         // Trigonometric functions
         case 'sin':
             return sin($inner);
         case 'cos':
             return cos($inner);
         case 'tan':
             return tan($inner);
         case 'cot':
             return 1 / tan($inner);
             // Trigonometric functions, argument in degrees
         // Trigonometric functions, argument in degrees
         case 'sind':
             return sin(deg2rad($inner));
         case 'cosd':
             return cos(deg2rad($inner));
         case 'tand':
             return tan(deg2rad($inner));
         case 'cotd':
             return 1 / tan(deg2rad($inner));
             // Inverse trigonometric functions
         // Inverse trigonometric functions
         case 'arcsin':
             return asin($inner);
         case 'arccos':
             return acos($inner);
         case 'arctan':
             return atan($inner);
         case 'arccot':
             return pi() / 2 - atan($inner);
             // Exponentials and logarithms
         // Exponentials and logarithms
         case 'exp':
             return exp($inner);
         case 'log':
             return log($inner);
         case 'lg':
             return log10($inner);
             // Powers
         // Powers
         case 'sqrt':
             return sqrt($inner);
             // Hyperbolic functions
         // Hyperbolic functions
         case 'sinh':
             return sinh($inner);
         case 'cosh':
             return cosh($inner);
         case 'tanh':
             return tanh($inner);
         case 'coth':
             return 1 / tanh($inner);
             // Inverse hyperbolic functions
         // Inverse hyperbolic functions
         case 'arsinh':
             return asinh($inner);
         case 'arcosh':
             return acosh($inner);
         case 'artanh':
             return atanh($inner);
         case 'arcoth':
             return atanh(1 / $inner);
         case 'abs':
             return abs($inner);
         case 'sgn':
             return $inner >= 0 ? 1 : 0;
         case '!':
             $logGamma = Math::logGamma(1 + $inner);
             return exp($logGamma);
         case '!!':
             if (round($inner) != $inner) {
                 throw new \UnexpectedValueException("Expecting positive integer (semifactorial)");
             }
             return Math::SemiFactorial($inner);
         default:
             throw new UnknownFunctionException($node->getName());
     }
 }