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')))); }
/** * Print a FunctionNode. * * @param FunctionNode $node */ public function visitFunctionNode(FunctionNode $node) { $functionName = $node->getName(); $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': 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); }
/** * 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); }
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()); } }
/** * 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}"; }
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()); } }
/** * 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()); } }