simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

derivative.js (24853B)


      1 "use strict";
      2 
      3 Object.defineProperty(exports, "__esModule", {
      4   value: true
      5 });
      6 exports.createDerivative = void 0;
      7 
      8 var _is = require("../../utils/is.js");
      9 
     10 var _factory = require("../../utils/factory.js");
     11 
     12 var name = 'derivative';
     13 var dependencies = ['typed', 'config', 'parse', 'simplify', 'equal', 'isZero', 'numeric', 'ConstantNode', 'FunctionNode', 'OperatorNode', 'ParenthesisNode', 'SymbolNode'];
     14 var createDerivative = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
     15   var typed = _ref.typed,
     16       config = _ref.config,
     17       parse = _ref.parse,
     18       simplify = _ref.simplify,
     19       equal = _ref.equal,
     20       isZero = _ref.isZero,
     21       numeric = _ref.numeric,
     22       ConstantNode = _ref.ConstantNode,
     23       FunctionNode = _ref.FunctionNode,
     24       OperatorNode = _ref.OperatorNode,
     25       ParenthesisNode = _ref.ParenthesisNode,
     26       SymbolNode = _ref.SymbolNode;
     27 
     28   /**
     29    * Takes the derivative of an expression expressed in parser Nodes.
     30    * The derivative will be taken over the supplied variable in the
     31    * second parameter. If there are multiple variables in the expression,
     32    * it will return a partial derivative.
     33    *
     34    * This uses rules of differentiation which can be found here:
     35    *
     36    * - [Differentiation rules (Wikipedia)](https://en.wikipedia.org/wiki/Differentiation_rules)
     37    *
     38    * Syntax:
     39    *
     40    *     derivative(expr, variable)
     41    *     derivative(expr, variable, options)
     42    *
     43    * Examples:
     44    *
     45    *     math.derivative('x^2', 'x')                     // Node {2 * x}
     46    *     math.derivative('x^2', 'x', {simplify: false})  // Node {2 * 1 * x ^ (2 - 1)
     47    *     math.derivative('sin(2x)', 'x'))                // Node {2 * cos(2 * x)}
     48    *     math.derivative('2*x', 'x').evaluate()          // number 2
     49    *     math.derivative('x^2', 'x').evaluate({x: 4})    // number 8
     50    *     const f = math.parse('x^2')
     51    *     const x = math.parse('x')
     52    *     math.derivative(f, x)                           // Node {2 * x}
     53    *
     54    * See also:
     55    *
     56    *     simplify, parse, evaluate
     57    *
     58    * @param  {Node | string} expr           The expression to differentiate
     59    * @param  {SymbolNode | string} variable The variable over which to differentiate
     60    * @param  {{simplify: boolean}} [options]
     61    *                         There is one option available, `simplify`, which
     62    *                         is true by default. When false, output will not
     63    *                         be simplified.
     64    * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode}    The derivative of `expr`
     65    */
     66   var derivative = typed('derivative', {
     67     'Node, SymbolNode, Object': function NodeSymbolNodeObject(expr, variable, options) {
     68       var constNodes = {};
     69       constTag(constNodes, expr, variable.name);
     70 
     71       var res = _derivative(expr, constNodes);
     72 
     73       return options.simplify ? simplify(res) : res;
     74     },
     75     'Node, SymbolNode': function NodeSymbolNode(expr, variable) {
     76       return this(expr, variable, {
     77         simplify: true
     78       });
     79     },
     80     'string, SymbolNode': function stringSymbolNode(expr, variable) {
     81       return this(parse(expr), variable);
     82     },
     83     'string, SymbolNode, Object': function stringSymbolNodeObject(expr, variable, options) {
     84       return this(parse(expr), variable, options);
     85     },
     86     'string, string': function stringString(expr, variable) {
     87       return this(parse(expr), parse(variable));
     88     },
     89     'string, string, Object': function stringStringObject(expr, variable, options) {
     90       return this(parse(expr), parse(variable), options);
     91     },
     92     'Node, string': function NodeString(expr, variable) {
     93       return this(expr, parse(variable));
     94     },
     95     'Node, string, Object': function NodeStringObject(expr, variable, options) {
     96       return this(expr, parse(variable), options);
     97     } // TODO: replace the 8 signatures above with 4 as soon as typed-function supports optional arguments
     98 
     99     /* TODO: implement and test syntax with order of derivatives -> implement as an option {order: number}
    100     'Node, SymbolNode, ConstantNode': function (expr, variable, {order}) {
    101       let res = expr
    102       for (let i = 0; i < order; i++) {
    103         let constNodes = {}
    104         constTag(constNodes, expr, variable.name)
    105         res = _derivative(res, constNodes)
    106       }
    107       return res
    108     }
    109     */
    110 
    111   });
    112   derivative._simplify = true;
    113 
    114   derivative.toTex = function (deriv) {
    115     return _derivTex.apply(null, deriv.args);
    116   }; // FIXME: move the toTex method of derivative to latex.js. Difficulty is that it relies on parse.
    117   // NOTE: the optional "order" parameter here is currently unused
    118 
    119 
    120   var _derivTex = typed('_derivTex', {
    121     'Node, SymbolNode': function NodeSymbolNode(expr, x) {
    122       if ((0, _is.isConstantNode)(expr) && (0, _is.typeOf)(expr.value) === 'string') {
    123         return _derivTex(parse(expr.value).toString(), x.toString(), 1);
    124       } else {
    125         return _derivTex(expr.toString(), x.toString(), 1);
    126       }
    127     },
    128     'Node, ConstantNode': function NodeConstantNode(expr, x) {
    129       if ((0, _is.typeOf)(x.value) === 'string') {
    130         return _derivTex(expr, parse(x.value));
    131       } else {
    132         throw new Error("The second parameter to 'derivative' is a non-string constant");
    133       }
    134     },
    135     'Node, SymbolNode, ConstantNode': function NodeSymbolNodeConstantNode(expr, x, order) {
    136       return _derivTex(expr.toString(), x.name, order.value);
    137     },
    138     'string, string, number': function stringStringNumber(expr, x, order) {
    139       var d;
    140 
    141       if (order === 1) {
    142         d = '{d\\over d' + x + '}';
    143       } else {
    144         d = '{d^{' + order + '}\\over d' + x + '^{' + order + '}}';
    145       }
    146 
    147       return d + "\\left[".concat(expr, "\\right]");
    148     }
    149   });
    150   /**
    151    * Does a depth-first search on the expression tree to identify what Nodes
    152    * are constants (e.g. 2 + 2), and stores the ones that are constants in
    153    * constNodes. Classification is done as follows:
    154    *
    155    *   1. ConstantNodes are constants.
    156    *   2. If there exists a SymbolNode, of which we are differentiating over,
    157    *      in the subtree it is not constant.
    158    *
    159    * @param  {Object} constNodes  Holds the nodes that are constant
    160    * @param  {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
    161    * @param  {string} varName     Variable that we are differentiating
    162    * @return {boolean}  if node is constant
    163    */
    164   // TODO: can we rewrite constTag into a pure function?
    165 
    166 
    167   var constTag = typed('constTag', {
    168     'Object, ConstantNode, string': function ObjectConstantNodeString(constNodes, node) {
    169       constNodes[node] = true;
    170       return true;
    171     },
    172     'Object, SymbolNode, string': function ObjectSymbolNodeString(constNodes, node, varName) {
    173       // Treat other variables like constants. For reasoning, see:
    174       //   https://en.wikipedia.org/wiki/Partial_derivative
    175       if (node.name !== varName) {
    176         constNodes[node] = true;
    177         return true;
    178       }
    179 
    180       return false;
    181     },
    182     'Object, ParenthesisNode, string': function ObjectParenthesisNodeString(constNodes, node, varName) {
    183       return constTag(constNodes, node.content, varName);
    184     },
    185     'Object, FunctionAssignmentNode, string': function ObjectFunctionAssignmentNodeString(constNodes, node, varName) {
    186       if (node.params.indexOf(varName) === -1) {
    187         constNodes[node] = true;
    188         return true;
    189       }
    190 
    191       return constTag(constNodes, node.expr, varName);
    192     },
    193     'Object, FunctionNode | OperatorNode, string': function ObjectFunctionNodeOperatorNodeString(constNodes, node, varName) {
    194       if (node.args.length > 0) {
    195         var isConst = constTag(constNodes, node.args[0], varName);
    196 
    197         for (var i = 1; i < node.args.length; ++i) {
    198           isConst = constTag(constNodes, node.args[i], varName) && isConst;
    199         }
    200 
    201         if (isConst) {
    202           constNodes[node] = true;
    203           return true;
    204         }
    205       }
    206 
    207       return false;
    208     }
    209   });
    210   /**
    211    * Applies differentiation rules.
    212    *
    213    * @param  {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node
    214    * @param  {Object} constNodes  Holds the nodes that are constant
    215    * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode}    The derivative of `expr`
    216    */
    217 
    218   var _derivative = typed('_derivative', {
    219     'ConstantNode, Object': function ConstantNodeObject(node) {
    220       return createConstantNode(0);
    221     },
    222     'SymbolNode, Object': function SymbolNodeObject(node, constNodes) {
    223       if (constNodes[node] !== undefined) {
    224         return createConstantNode(0);
    225       }
    226 
    227       return createConstantNode(1);
    228     },
    229     'ParenthesisNode, Object': function ParenthesisNodeObject(node, constNodes) {
    230       return new ParenthesisNode(_derivative(node.content, constNodes));
    231     },
    232     'FunctionAssignmentNode, Object': function FunctionAssignmentNodeObject(node, constNodes) {
    233       if (constNodes[node] !== undefined) {
    234         return createConstantNode(0);
    235       }
    236 
    237       return _derivative(node.expr, constNodes);
    238     },
    239     'FunctionNode, Object': function FunctionNodeObject(node, constNodes) {
    240       if (node.args.length !== 1) {
    241         funcArgsCheck(node);
    242       }
    243 
    244       if (constNodes[node] !== undefined) {
    245         return createConstantNode(0);
    246       }
    247 
    248       var arg0 = node.args[0];
    249       var arg1;
    250       var div = false; // is output a fraction?
    251 
    252       var negative = false; // is output negative?
    253 
    254       var funcDerivative;
    255 
    256       switch (node.name) {
    257         case 'cbrt':
    258           // d/dx(cbrt(x)) = 1 / (3x^(2/3))
    259           div = true;
    260           funcDerivative = new OperatorNode('*', 'multiply', [createConstantNode(3), new OperatorNode('^', 'pow', [arg0, new OperatorNode('/', 'divide', [createConstantNode(2), createConstantNode(3)])])]);
    261           break;
    262 
    263         case 'sqrt':
    264         case 'nthRoot':
    265           // d/dx(sqrt(x)) = 1 / (2*sqrt(x))
    266           if (node.args.length === 1) {
    267             div = true;
    268             funcDerivative = new OperatorNode('*', 'multiply', [createConstantNode(2), new FunctionNode('sqrt', [arg0])]);
    269           } else if (node.args.length === 2) {
    270             // Rearrange from nthRoot(x, a) -> x^(1/a)
    271             arg1 = new OperatorNode('/', 'divide', [createConstantNode(1), node.args[1]]); // Is a variable?
    272 
    273             constNodes[arg1] = constNodes[node.args[1]];
    274             return _derivative(new OperatorNode('^', 'pow', [arg0, arg1]), constNodes);
    275           }
    276 
    277           break;
    278 
    279         case 'log10':
    280           arg1 = createConstantNode(10);
    281 
    282         /* fall through! */
    283 
    284         case 'log':
    285           if (!arg1 && node.args.length === 1) {
    286             // d/dx(log(x)) = 1 / x
    287             funcDerivative = arg0.clone();
    288             div = true;
    289           } else if (node.args.length === 1 && arg1 || node.args.length === 2 && constNodes[node.args[1]] !== undefined) {
    290             // d/dx(log(x, c)) = 1 / (x*ln(c))
    291             funcDerivative = new OperatorNode('*', 'multiply', [arg0.clone(), new FunctionNode('log', [arg1 || node.args[1]])]);
    292             div = true;
    293           } else if (node.args.length === 2) {
    294             // d/dx(log(f(x), g(x))) = d/dx(log(f(x)) / log(g(x)))
    295             return _derivative(new OperatorNode('/', 'divide', [new FunctionNode('log', [arg0]), new FunctionNode('log', [node.args[1]])]), constNodes);
    296           }
    297 
    298           break;
    299 
    300         case 'pow':
    301           constNodes[arg1] = constNodes[node.args[1]]; // Pass to pow operator node parser
    302 
    303           return _derivative(new OperatorNode('^', 'pow', [arg0, node.args[1]]), constNodes);
    304 
    305         case 'exp':
    306           // d/dx(e^x) = e^x
    307           funcDerivative = new FunctionNode('exp', [arg0.clone()]);
    308           break;
    309 
    310         case 'sin':
    311           // d/dx(sin(x)) = cos(x)
    312           funcDerivative = new FunctionNode('cos', [arg0.clone()]);
    313           break;
    314 
    315         case 'cos':
    316           // d/dx(cos(x)) = -sin(x)
    317           funcDerivative = new OperatorNode('-', 'unaryMinus', [new FunctionNode('sin', [arg0.clone()])]);
    318           break;
    319 
    320         case 'tan':
    321           // d/dx(tan(x)) = sec(x)^2
    322           funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('sec', [arg0.clone()]), createConstantNode(2)]);
    323           break;
    324 
    325         case 'sec':
    326           // d/dx(sec(x)) = sec(x)tan(x)
    327           funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('tan', [arg0.clone()])]);
    328           break;
    329 
    330         case 'csc':
    331           // d/dx(csc(x)) = -csc(x)cot(x)
    332           negative = true;
    333           funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('cot', [arg0.clone()])]);
    334           break;
    335 
    336         case 'cot':
    337           // d/dx(cot(x)) = -csc(x)^2
    338           negative = true;
    339           funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('csc', [arg0.clone()]), createConstantNode(2)]);
    340           break;
    341 
    342         case 'asin':
    343           // d/dx(asin(x)) = 1 / sqrt(1 - x^2)
    344           div = true;
    345           funcDerivative = new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])])]);
    346           break;
    347 
    348         case 'acos':
    349           // d/dx(acos(x)) = -1 / sqrt(1 - x^2)
    350           div = true;
    351           negative = true;
    352           funcDerivative = new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])])]);
    353           break;
    354 
    355         case 'atan':
    356           // d/dx(atan(x)) = 1 / (x^2 + 1)
    357           div = true;
    358           funcDerivative = new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)]);
    359           break;
    360 
    361         case 'asec':
    362           // d/dx(asec(x)) = 1 / (|x|*sqrt(x^2 - 1))
    363           div = true;
    364           funcDerivative = new OperatorNode('*', 'multiply', [new FunctionNode('abs', [arg0.clone()]), new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])])]);
    365           break;
    366 
    367         case 'acsc':
    368           // d/dx(acsc(x)) = -1 / (|x|*sqrt(x^2 - 1))
    369           div = true;
    370           negative = true;
    371           funcDerivative = new OperatorNode('*', 'multiply', [new FunctionNode('abs', [arg0.clone()]), new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])])]);
    372           break;
    373 
    374         case 'acot':
    375           // d/dx(acot(x)) = -1 / (x^2 + 1)
    376           div = true;
    377           negative = true;
    378           funcDerivative = new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)]);
    379           break;
    380 
    381         case 'sinh':
    382           // d/dx(sinh(x)) = cosh(x)
    383           funcDerivative = new FunctionNode('cosh', [arg0.clone()]);
    384           break;
    385 
    386         case 'cosh':
    387           // d/dx(cosh(x)) = sinh(x)
    388           funcDerivative = new FunctionNode('sinh', [arg0.clone()]);
    389           break;
    390 
    391         case 'tanh':
    392           // d/dx(tanh(x)) = sech(x)^2
    393           funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('sech', [arg0.clone()]), createConstantNode(2)]);
    394           break;
    395 
    396         case 'sech':
    397           // d/dx(sech(x)) = -sech(x)tanh(x)
    398           negative = true;
    399           funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('tanh', [arg0.clone()])]);
    400           break;
    401 
    402         case 'csch':
    403           // d/dx(csch(x)) = -csch(x)coth(x)
    404           negative = true;
    405           funcDerivative = new OperatorNode('*', 'multiply', [node, new FunctionNode('coth', [arg0.clone()])]);
    406           break;
    407 
    408         case 'coth':
    409           // d/dx(coth(x)) = -csch(x)^2
    410           negative = true;
    411           funcDerivative = new OperatorNode('^', 'pow', [new FunctionNode('csch', [arg0.clone()]), createConstantNode(2)]);
    412           break;
    413 
    414         case 'asinh':
    415           // d/dx(asinh(x)) = 1 / sqrt(x^2 + 1)
    416           div = true;
    417           funcDerivative = new FunctionNode('sqrt', [new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])]);
    418           break;
    419 
    420         case 'acosh':
    421           // d/dx(acosh(x)) = 1 / sqrt(x^2 - 1); XXX potentially only for x >= 1 (the real spectrum)
    422           div = true;
    423           funcDerivative = new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])]);
    424           break;
    425 
    426         case 'atanh':
    427           // d/dx(atanh(x)) = 1 / (1 - x^2)
    428           div = true;
    429           funcDerivative = new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])]);
    430           break;
    431 
    432         case 'asech':
    433           // d/dx(asech(x)) = -1 / (x*sqrt(1 - x^2))
    434           div = true;
    435           negative = true;
    436           funcDerivative = new OperatorNode('*', 'multiply', [arg0.clone(), new FunctionNode('sqrt', [new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])])])]);
    437           break;
    438 
    439         case 'acsch':
    440           // d/dx(acsch(x)) = -1 / (|x|*sqrt(x^2 + 1))
    441           div = true;
    442           negative = true;
    443           funcDerivative = new OperatorNode('*', 'multiply', [new FunctionNode('abs', [arg0.clone()]), new FunctionNode('sqrt', [new OperatorNode('+', 'add', [new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)]), createConstantNode(1)])])]);
    444           break;
    445 
    446         case 'acoth':
    447           // d/dx(acoth(x)) = -1 / (1 - x^2)
    448           div = true;
    449           negative = true;
    450           funcDerivative = new OperatorNode('-', 'subtract', [createConstantNode(1), new OperatorNode('^', 'pow', [arg0.clone(), createConstantNode(2)])]);
    451           break;
    452 
    453         case 'abs':
    454           // d/dx(abs(x)) = abs(x)/x
    455           funcDerivative = new OperatorNode('/', 'divide', [new FunctionNode(new SymbolNode('abs'), [arg0.clone()]), arg0.clone()]);
    456           break;
    457 
    458         case 'gamma': // Needs digamma function, d/dx(gamma(x)) = gamma(x)digamma(x)
    459 
    460         default:
    461           throw new Error('Function "' + node.name + '" is not supported by derivative, or a wrong number of arguments is passed');
    462       }
    463 
    464       var op, func;
    465 
    466       if (div) {
    467         op = '/';
    468         func = 'divide';
    469       } else {
    470         op = '*';
    471         func = 'multiply';
    472       }
    473       /* Apply chain rule to all functions:
    474          F(x)  = f(g(x))
    475          F'(x) = g'(x)*f'(g(x)) */
    476 
    477 
    478       var chainDerivative = _derivative(arg0, constNodes);
    479 
    480       if (negative) {
    481         chainDerivative = new OperatorNode('-', 'unaryMinus', [chainDerivative]);
    482       }
    483 
    484       return new OperatorNode(op, func, [chainDerivative, funcDerivative]);
    485     },
    486     'OperatorNode, Object': function OperatorNodeObject(node, constNodes) {
    487       if (constNodes[node] !== undefined) {
    488         return createConstantNode(0);
    489       }
    490 
    491       if (node.op === '+') {
    492         // d/dx(sum(f(x)) = sum(f'(x))
    493         return new OperatorNode(node.op, node.fn, node.args.map(function (arg) {
    494           return _derivative(arg, constNodes);
    495         }));
    496       }
    497 
    498       if (node.op === '-') {
    499         // d/dx(+/-f(x)) = +/-f'(x)
    500         if (node.isUnary()) {
    501           return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes)]);
    502         } // Linearity of differentiation, d/dx(f(x) +/- g(x)) = f'(x) +/- g'(x)
    503 
    504 
    505         if (node.isBinary()) {
    506           return new OperatorNode(node.op, node.fn, [_derivative(node.args[0], constNodes), _derivative(node.args[1], constNodes)]);
    507         }
    508       }
    509 
    510       if (node.op === '*') {
    511         // d/dx(c*f(x)) = c*f'(x)
    512         var constantTerms = node.args.filter(function (arg) {
    513           return constNodes[arg] !== undefined;
    514         });
    515 
    516         if (constantTerms.length > 0) {
    517           var nonConstantTerms = node.args.filter(function (arg) {
    518             return constNodes[arg] === undefined;
    519           });
    520           var nonConstantNode = nonConstantTerms.length === 1 ? nonConstantTerms[0] : new OperatorNode('*', 'multiply', nonConstantTerms);
    521           var newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes));
    522           return new OperatorNode('*', 'multiply', newArgs);
    523         } // Product Rule, d/dx(f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x)
    524 
    525 
    526         return new OperatorNode('+', 'add', node.args.map(function (argOuter) {
    527           return new OperatorNode('*', 'multiply', node.args.map(function (argInner) {
    528             return argInner === argOuter ? _derivative(argInner, constNodes) : argInner.clone();
    529           }));
    530         }));
    531       }
    532 
    533       if (node.op === '/' && node.isBinary()) {
    534         var arg0 = node.args[0];
    535         var arg1 = node.args[1]; // d/dx(f(x) / c) = f'(x) / c
    536 
    537         if (constNodes[arg1] !== undefined) {
    538           return new OperatorNode('/', 'divide', [_derivative(arg0, constNodes), arg1]);
    539         } // Reciprocal Rule, d/dx(c / f(x)) = -c(f'(x)/f(x)^2)
    540 
    541 
    542         if (constNodes[arg0] !== undefined) {
    543           return new OperatorNode('*', 'multiply', [new OperatorNode('-', 'unaryMinus', [arg0]), new OperatorNode('/', 'divide', [_derivative(arg1, constNodes), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])])]);
    544         } // Quotient rule, d/dx(f(x) / g(x)) = (f'(x)g(x) - f(x)g'(x)) / g(x)^2
    545 
    546 
    547         return new OperatorNode('/', 'divide', [new OperatorNode('-', 'subtract', [new OperatorNode('*', 'multiply', [_derivative(arg0, constNodes), arg1.clone()]), new OperatorNode('*', 'multiply', [arg0.clone(), _derivative(arg1, constNodes)])]), new OperatorNode('^', 'pow', [arg1.clone(), createConstantNode(2)])]);
    548       }
    549 
    550       if (node.op === '^' && node.isBinary()) {
    551         var _arg = node.args[0];
    552         var _arg2 = node.args[1];
    553 
    554         if (constNodes[_arg] !== undefined) {
    555           // If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1
    556           if ((0, _is.isConstantNode)(_arg) && (isZero(_arg.value) || equal(_arg.value, 1))) {
    557             return createConstantNode(0);
    558           } // d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x)
    559 
    560 
    561           return new OperatorNode('*', 'multiply', [node, new OperatorNode('*', 'multiply', [new FunctionNode('log', [_arg.clone()]), _derivative(_arg2.clone(), constNodes)])]);
    562         }
    563 
    564         if (constNodes[_arg2] !== undefined) {
    565           if ((0, _is.isConstantNode)(_arg2)) {
    566             // If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0
    567             if (isZero(_arg2.value)) {
    568               return createConstantNode(0);
    569             } // Ignore exponent; f(x)^1 = f(x)
    570 
    571 
    572             if (equal(_arg2.value, 1)) {
    573               return _derivative(_arg, constNodes);
    574             }
    575           } // Elementary Power Rule, d/dx(f(x)^c) = c*f'(x)*f(x)^(c-1)
    576 
    577 
    578           var powMinusOne = new OperatorNode('^', 'pow', [_arg.clone(), new OperatorNode('-', 'subtract', [_arg2, createConstantNode(1)])]);
    579           return new OperatorNode('*', 'multiply', [_arg2.clone(), new OperatorNode('*', 'multiply', [_derivative(_arg, constNodes), powMinusOne])]);
    580         } // Functional Power Rule, d/dx(f^g) = f^g*[f'*(g/f) + g'ln(f)]
    581 
    582 
    583         return new OperatorNode('*', 'multiply', [new OperatorNode('^', 'pow', [_arg.clone(), _arg2.clone()]), new OperatorNode('+', 'add', [new OperatorNode('*', 'multiply', [_derivative(_arg, constNodes), new OperatorNode('/', 'divide', [_arg2.clone(), _arg.clone()])]), new OperatorNode('*', 'multiply', [_derivative(_arg2, constNodes), new FunctionNode('log', [_arg.clone()])])])]);
    584       }
    585 
    586       throw new Error('Operator "' + node.op + '" is not supported by derivative, or a wrong number of arguments is passed');
    587     }
    588   });
    589   /**
    590    * Ensures the number of arguments for a function are correct,
    591    * and will throw an error otherwise.
    592    *
    593    * @param {FunctionNode} node
    594    */
    595 
    596 
    597   function funcArgsCheck(node) {
    598     // TODO add min, max etc
    599     if ((node.name === 'log' || node.name === 'nthRoot' || node.name === 'pow') && node.args.length === 2) {
    600       return;
    601     } // There should be an incorrect number of arguments if we reach here
    602     // Change all args to constants to avoid unidentified
    603     // symbol error when compiling function
    604 
    605 
    606     for (var i = 0; i < node.args.length; ++i) {
    607       node.args[i] = createConstantNode(0);
    608     }
    609 
    610     node.compile().evaluate();
    611     throw new Error('Expected TypeError, but none found');
    612   }
    613   /**
    614    * Helper function to create a constant node with a specific type
    615    * (number, BigNumber, Fraction)
    616    * @param {number} value
    617    * @param {string} [valueType]
    618    * @return {ConstantNode}
    619    */
    620 
    621 
    622   function createConstantNode(value, valueType) {
    623     return new ConstantNode(numeric(value, valueType || config.number));
    624   }
    625 
    626   return derivative;
    627 });
    628 exports.createDerivative = createDerivative;