123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823 |
- import { isInteger } from '../../utils/number.js';
- import { factory } from '../../utils/factory.js';
- var name = 'rationalize';
- var dependencies = ['config', 'typed', 'equal', 'isZero', 'add', 'subtract', 'multiply', 'divide', 'pow', 'parse', 'simplifyConstant', 'simplifyCore', 'simplify', '?bignumber', '?fraction', 'mathWithTransform', 'matrix', 'AccessorNode', 'ArrayNode', 'ConstantNode', 'FunctionNode', 'IndexNode', 'ObjectNode', 'OperatorNode', 'SymbolNode', 'ParenthesisNode'];
- export var createRationalize = /* #__PURE__ */factory(name, dependencies, _ref => {
- var {
- config,
- typed,
- equal,
- isZero,
- add,
- subtract,
- multiply,
- divide,
- pow,
- parse,
- simplifyConstant,
- simplifyCore,
- simplify,
- fraction,
- bignumber,
- mathWithTransform,
- matrix,
- AccessorNode,
- ArrayNode,
- ConstantNode,
- FunctionNode,
- IndexNode,
- ObjectNode,
- OperatorNode,
- SymbolNode,
- ParenthesisNode
- } = _ref;
- /**
- * Transform a rationalizable expression in a rational fraction.
- * If rational fraction is one variable polynomial then converts
- * the numerator and denominator in canonical form, with decreasing
- * exponents, returning the coefficients of numerator.
- *
- * Syntax:
- *
- * rationalize(expr)
- * rationalize(expr, detailed)
- * rationalize(expr, scope)
- * rationalize(expr, scope, detailed)
- *
- * Examples:
- *
- * math.rationalize('sin(x)+y')
- * // Error: There is an unsolved function call
- * math.rationalize('2x/y - y/(x+1)')
- * // (2*x^2-y^2+2*x)/(x*y+y)
- * math.rationalize('(2x+1)^6')
- * // 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1
- * math.rationalize('2x/( (2x-1) / (3x+2) ) - 5x/ ( (3x+4) / (2x^2-5) ) + 3')
- * // -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4)
- * math.rationalize('x/(1-x)/(x-2)/(x-3)/(x-4) + 2x/ ( (1-2x)/(2-3x) )/ ((3-4x)/(4-5x) )') =
- * // (-30*x^7+344*x^6-1506*x^5+3200*x^4-3472*x^3+1846*x^2-381*x)/
- * // (-8*x^6+90*x^5-383*x^4+780*x^3-797*x^2+390*x-72)
- *
- * math.rationalize('x+x+x+y',{y:1}) // 3*x+1
- * math.rationalize('x+x+x+y',{}) // 3*x+y
- *
- * const ret = math.rationalize('x+x+x+y',{},true)
- * // ret.expression=3*x+y, ret.variables = ["x","y"]
- * const ret = math.rationalize('-2+5x^2',{},true)
- * // ret.expression=5*x^2-2, ret.variables = ["x"], ret.coefficients=[-2,0,5]
- *
- * See also:
- *
- * simplify
- *
- * @param {Node|string} expr The expression to check if is a polynomial expression
- * @param {Object|boolean} optional scope of expression or true for already evaluated rational expression at input
- * @param {Boolean} detailed optional True if return an object, false if return expression node (default)
- *
- * @return {Object | Node} The rational polynomial of `expr` or an object
- * `{expression, numerator, denominator, variables, coefficients}`, where
- * `expression` is a `Node` with the node simplified expression,
- * `numerator` is a `Node` with the simplified numerator of expression,
- * `denominator` is a `Node` or `boolean` with the simplified denominator or `false` (if there is no denominator),
- * `variables` is an array with variable names,
- * and `coefficients` is an array with coefficients of numerator sorted by increased exponent
- * {Expression Node} node simplified expression
- *
- */
- function _rationalize(expr) {
- var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
- var detailed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
- var setRules = rulesRationalize(); // Rules for change polynomial in near canonical form
- var polyRet = polynomial(expr, scope, true, setRules.firstRules); // Check if expression is a rationalizable polynomial
- var nVars = polyRet.variables.length;
- var noExactFractions = {
- exactFractions: false
- };
- var withExactFractions = {
- exactFractions: true
- };
- expr = polyRet.expression;
- if (nVars >= 1) {
- // If expression in not a constant
- expr = expandPower(expr); // First expand power of polynomials (cannot be made from rules!)
- var sBefore; // Previous expression
- var rules;
- var eDistrDiv = true;
- var redoInic = false;
- // Apply the initial rules, including succ div rules:
- expr = simplify(expr, setRules.firstRules, {}, noExactFractions);
- var s;
- while (true) {
- // Alternate applying successive division rules and distr.div.rules
- // until there are no more changes:
- rules = eDistrDiv ? setRules.distrDivRules : setRules.sucDivRules;
- expr = simplify(expr, rules, {}, withExactFractions);
- eDistrDiv = !eDistrDiv; // Swap between Distr.Div and Succ. Div. Rules
- s = expr.toString();
- if (s === sBefore) {
- break; // No changes : end of the loop
- }
- redoInic = true;
- sBefore = s;
- }
- if (redoInic) {
- // Apply first rules again without succ div rules (if there are changes)
- expr = simplify(expr, setRules.firstRulesAgain, {}, noExactFractions);
- }
- // Apply final rules:
- expr = simplify(expr, setRules.finalRules, {}, noExactFractions);
- } // NVars >= 1
- var coefficients = [];
- var retRationalize = {};
- if (expr.type === 'OperatorNode' && expr.isBinary() && expr.op === '/') {
- // Separate numerator from denominator
- if (nVars === 1) {
- expr.args[0] = polyToCanonical(expr.args[0], coefficients);
- expr.args[1] = polyToCanonical(expr.args[1]);
- }
- if (detailed) {
- retRationalize.numerator = expr.args[0];
- retRationalize.denominator = expr.args[1];
- }
- } else {
- if (nVars === 1) {
- expr = polyToCanonical(expr, coefficients);
- }
- if (detailed) {
- retRationalize.numerator = expr;
- retRationalize.denominator = null;
- }
- }
- // nVars
- if (!detailed) return expr;
- retRationalize.coefficients = coefficients;
- retRationalize.variables = polyRet.variables;
- retRationalize.expression = expr;
- return retRationalize;
- }
- return typed(name, {
- Node: _rationalize,
- 'Node, boolean': (expr, detailed) => _rationalize(expr, {}, detailed),
- 'Node, Object': _rationalize,
- 'Node, Object, boolean': _rationalize
- }); // end of typed rationalize
- /**
- * Function to simplify an expression using an optional scope and
- * return it if the expression is a polynomial expression, i.e.
- * an expression with one or more variables and the operators
- * +, -, *, and ^, where the exponent can only be a positive integer.
- *
- * Syntax:
- *
- * polynomial(expr,scope,extended, rules)
- *
- * @param {Node | string} expr The expression to simplify and check if is polynomial expression
- * @param {object} scope Optional scope for expression simplification
- * @param {boolean} extended Optional. Default is false. When true allows divide operator.
- * @param {array} rules Optional. Default is no rule.
- *
- *
- * @return {Object}
- * {Object} node: node simplified expression
- * {Array} variables: variable names
- */
- function polynomial(expr, scope, extended, rules) {
- var variables = [];
- var node = simplify(expr, rules, scope, {
- exactFractions: false
- }); // Resolves any variables and functions with all defined parameters
- extended = !!extended;
- var oper = '+-*' + (extended ? '/' : '');
- recPoly(node);
- var retFunc = {};
- retFunc.expression = node;
- retFunc.variables = variables;
- return retFunc;
- // -------------------------------------------------------------------------------------------------------
- /**
- * Function to simplify an expression using an optional scope and
- * return it if the expression is a polynomial expression, i.e.
- * an expression with one or more variables and the operators
- * +, -, *, and ^, where the exponent can only be a positive integer.
- *
- * Syntax:
- *
- * recPoly(node)
- *
- *
- * @param {Node} node The current sub tree expression in recursion
- *
- * @return nothing, throw an exception if error
- */
- function recPoly(node) {
- var tp = node.type; // node type
- if (tp === 'FunctionNode') {
- // No function call in polynomial expression
- throw new Error('There is an unsolved function call');
- } else if (tp === 'OperatorNode') {
- if (node.op === '^') {
- // TODO: handle negative exponents like in '1/x^(-2)'
- if (node.args[1].type !== 'ConstantNode' || !isInteger(parseFloat(node.args[1].value))) {
- throw new Error('There is a non-integer exponent');
- } else {
- recPoly(node.args[0]);
- }
- } else {
- if (oper.indexOf(node.op) === -1) {
- throw new Error('Operator ' + node.op + ' invalid in polynomial expression');
- }
- for (var i = 0; i < node.args.length; i++) {
- recPoly(node.args[i]);
- }
- } // type of operator
- } else if (tp === 'SymbolNode') {
- var _name = node.name; // variable name
- var pos = variables.indexOf(_name);
- if (pos === -1) {
- // new variable in expression
- variables.push(_name);
- }
- } else if (tp === 'ParenthesisNode') {
- recPoly(node.content);
- } else if (tp !== 'ConstantNode') {
- throw new Error('type ' + tp + ' is not allowed in polynomial expression');
- }
- } // end of recPoly
- } // end of polynomial
- // ---------------------------------------------------------------------------------------
- /**
- * Return a rule set to rationalize an polynomial expression in rationalize
- *
- * Syntax:
- *
- * rulesRationalize()
- *
- * @return {array} rule set to rationalize an polynomial expression
- */
- function rulesRationalize() {
- var oldRules = [simplifyCore,
- // sCore
- {
- l: 'n+n',
- r: '2*n'
- }, {
- l: 'n+-n',
- r: '0'
- }, simplifyConstant,
- // sConstant
- {
- l: 'n*(n1^-1)',
- r: 'n/n1'
- }, {
- l: 'n*n1^-n2',
- r: 'n/n1^n2'
- }, {
- l: 'n1^-1',
- r: '1/n1'
- }, {
- l: 'n*(n1/n2)',
- r: '(n*n1)/n2'
- }, {
- l: '1*n',
- r: 'n'
- }];
- var rulesFirst = [{
- l: '(-n1)/(-n2)',
- r: 'n1/n2'
- },
- // Unary division
- {
- l: '(-n1)*(-n2)',
- r: 'n1*n2'
- },
- // Unary multiplication
- {
- l: 'n1--n2',
- r: 'n1+n2'
- },
- // '--' elimination
- {
- l: 'n1-n2',
- r: 'n1+(-n2)'
- },
- // Subtraction turn into add with un�ry minus
- {
- l: '(n1+n2)*n3',
- r: '(n1*n3 + n2*n3)'
- },
- // Distributive 1
- {
- l: 'n1*(n2+n3)',
- r: '(n1*n2+n1*n3)'
- },
- // Distributive 2
- {
- l: 'c1*n + c2*n',
- r: '(c1+c2)*n'
- },
- // Joining constants
- {
- l: 'c1*n + n',
- r: '(c1+1)*n'
- },
- // Joining constants
- {
- l: 'c1*n - c2*n',
- r: '(c1-c2)*n'
- },
- // Joining constants
- {
- l: 'c1*n - n',
- r: '(c1-1)*n'
- },
- // Joining constants
- {
- l: 'v/c',
- r: '(1/c)*v'
- },
- // variable/constant (new!)
- {
- l: 'v/-c',
- r: '-(1/c)*v'
- },
- // variable/constant (new!)
- {
- l: '-v*-c',
- r: 'c*v'
- },
- // Inversion constant and variable 1
- {
- l: '-v*c',
- r: '-c*v'
- },
- // Inversion constant and variable 2
- {
- l: 'v*-c',
- r: '-c*v'
- },
- // Inversion constant and variable 3
- {
- l: 'v*c',
- r: 'c*v'
- },
- // Inversion constant and variable 4
- {
- l: '-(-n1*n2)',
- r: '(n1*n2)'
- },
- // Unary propagation
- {
- l: '-(n1*n2)',
- r: '(-n1*n2)'
- },
- // Unary propagation
- {
- l: '-(-n1+n2)',
- r: '(n1-n2)'
- },
- // Unary propagation
- {
- l: '-(n1+n2)',
- r: '(-n1-n2)'
- },
- // Unary propagation
- {
- l: '(n1^n2)^n3',
- r: '(n1^(n2*n3))'
- },
- // Power to Power
- {
- l: '-(-n1/n2)',
- r: '(n1/n2)'
- },
- // Division and Unary
- {
- l: '-(n1/n2)',
- r: '(-n1/n2)'
- }]; // Divisao and Unary
- var rulesDistrDiv = [{
- l: '(n1/n2 + n3/n4)',
- r: '((n1*n4 + n3*n2)/(n2*n4))'
- },
- // Sum of fractions
- {
- l: '(n1/n2 + n3)',
- r: '((n1 + n3*n2)/n2)'
- },
- // Sum fraction with number 1
- {
- l: '(n1 + n2/n3)',
- r: '((n1*n3 + n2)/n3)'
- }]; // Sum fraction with number 1
- var rulesSucDiv = [{
- l: '(n1/(n2/n3))',
- r: '((n1*n3)/n2)'
- },
- // Division simplification
- {
- l: '(n1/n2/n3)',
- r: '(n1/(n2*n3))'
- }];
- var setRules = {}; // rules set in 4 steps.
- // All rules => infinite loop
- // setRules.allRules =oldRules.concat(rulesFirst,rulesDistrDiv,rulesSucDiv)
- setRules.firstRules = oldRules.concat(rulesFirst, rulesSucDiv); // First rule set
- setRules.distrDivRules = rulesDistrDiv; // Just distr. div. rules
- setRules.sucDivRules = rulesSucDiv; // Jus succ. div. rules
- setRules.firstRulesAgain = oldRules.concat(rulesFirst); // Last rules set without succ. div.
- // Division simplification
- // Second rule set.
- // There is no aggregate expression with parentesis, but the only variable can be scattered.
- setRules.finalRules = [simplifyCore,
- // simplify.rules[0]
- {
- l: 'n*-n',
- r: '-n^2'
- },
- // Joining multiply with power 1
- {
- l: 'n*n',
- r: 'n^2'
- },
- // Joining multiply with power 2
- simplifyConstant,
- // simplify.rules[14] old 3rd index in oldRules
- {
- l: 'n*-n^n1',
- r: '-n^(n1+1)'
- },
- // Joining multiply with power 3
- {
- l: 'n*n^n1',
- r: 'n^(n1+1)'
- },
- // Joining multiply with power 4
- {
- l: 'n^n1*-n^n2',
- r: '-n^(n1+n2)'
- },
- // Joining multiply with power 5
- {
- l: 'n^n1*n^n2',
- r: 'n^(n1+n2)'
- },
- // Joining multiply with power 6
- {
- l: 'n^n1*-n',
- r: '-n^(n1+1)'
- },
- // Joining multiply with power 7
- {
- l: 'n^n1*n',
- r: 'n^(n1+1)'
- },
- // Joining multiply with power 8
- {
- l: 'n^n1/-n',
- r: '-n^(n1-1)'
- },
- // Joining multiply with power 8
- {
- l: 'n^n1/n',
- r: 'n^(n1-1)'
- },
- // Joining division with power 1
- {
- l: 'n/-n^n1',
- r: '-n^(1-n1)'
- },
- // Joining division with power 2
- {
- l: 'n/n^n1',
- r: 'n^(1-n1)'
- },
- // Joining division with power 3
- {
- l: 'n^n1/-n^n2',
- r: 'n^(n1-n2)'
- },
- // Joining division with power 4
- {
- l: 'n^n1/n^n2',
- r: 'n^(n1-n2)'
- },
- // Joining division with power 5
- {
- l: 'n1+(-n2*n3)',
- r: 'n1-n2*n3'
- },
- // Solving useless parenthesis 1
- {
- l: 'v*(-c)',
- r: '-c*v'
- },
- // Solving useless unary 2
- {
- l: 'n1+-n2',
- r: 'n1-n2'
- },
- // Solving +- together (new!)
- {
- l: 'v*c',
- r: 'c*v'
- },
- // inversion constant with variable
- {
- l: '(n1^n2)^n3',
- r: '(n1^(n2*n3))'
- } // Power to Power
- ];
- return setRules;
- } // End rulesRationalize
- // ---------------------------------------------------------------------------------------
- /**
- * Expand recursively a tree node for handling with expressions with exponents
- * (it's not for constants, symbols or functions with exponents)
- * PS: The other parameters are internal for recursion
- *
- * Syntax:
- *
- * expandPower(node)
- *
- * @param {Node} node Current expression node
- * @param {node} parent Parent current node inside the recursion
- * @param (int} Parent number of chid inside the rercursion
- *
- * @return {node} node expression with all powers expanded.
- */
- function expandPower(node, parent, indParent) {
- var tp = node.type;
- var internal = arguments.length > 1; // TRUE in internal calls
- if (tp === 'OperatorNode' && node.isBinary()) {
- var does = false;
- var val;
- if (node.op === '^') {
- // First operator: Parenthesis or UnaryMinus
- if ((node.args[0].type === 'ParenthesisNode' || node.args[0].type === 'OperatorNode') && node.args[1].type === 'ConstantNode') {
- // Second operator: Constant
- val = parseFloat(node.args[1].value);
- does = val >= 2 && isInteger(val);
- }
- }
- if (does) {
- // Exponent >= 2
- // Before:
- // operator A --> Subtree
- // parent pow
- // constant
- //
- if (val > 2) {
- // Exponent > 2,
- // AFTER: (exponent > 2)
- // operator A --> Subtree
- // parent *
- // deep clone (operator A --> Subtree
- // pow
- // constant - 1
- //
- var nEsqTopo = node.args[0];
- var nDirTopo = new OperatorNode('^', 'pow', [node.args[0].cloneDeep(), new ConstantNode(val - 1)]);
- node = new OperatorNode('*', 'multiply', [nEsqTopo, nDirTopo]);
- } else {
- // Expo = 2 - no power
- // AFTER: (exponent = 2)
- // operator A --> Subtree
- // parent oper
- // deep clone (operator A --> Subtree)
- //
- node = new OperatorNode('*', 'multiply', [node.args[0], node.args[0].cloneDeep()]);
- }
- if (internal) {
- // Change parent references in internal recursive calls
- if (indParent === 'content') {
- parent.content = node;
- } else {
- parent.args[indParent] = node;
- }
- }
- } // does
- } // binary OperatorNode
- if (tp === 'ParenthesisNode') {
- // Recursion
- expandPower(node.content, node, 'content');
- } else if (tp !== 'ConstantNode' && tp !== 'SymbolNode') {
- for (var i = 0; i < node.args.length; i++) {
- expandPower(node.args[i], node, i);
- }
- }
- if (!internal) {
- // return the root node
- return node;
- }
- } // End expandPower
- // ---------------------------------------------------------------------------------------
- /**
- * Auxilary function for rationalize
- * Convert near canonical polynomial in one variable in a canonical polynomial
- * with one term for each exponent in decreasing order
- *
- * Syntax:
- *
- * polyToCanonical(node [, coefficients])
- *
- * @param {Node | string} expr The near canonical polynomial expression to convert in a a canonical polynomial expression
- *
- * The string or tree expression needs to be at below syntax, with free spaces:
- * ( (^(-)? | [+-]? )cte (*)? var (^expo)? | cte )+
- * Where 'var' is one variable with any valid name
- * 'cte' are real numeric constants with any value. It can be omitted if equal than 1
- * 'expo' are integers greater than 0. It can be omitted if equal than 1.
- *
- * @param {array} coefficients Optional returns coefficients sorted by increased exponent
- *
- *
- * @return {node} new node tree with one variable polynomial or string error.
- */
- function polyToCanonical(node, coefficients) {
- if (coefficients === undefined) {
- coefficients = [];
- } // coefficients.
- coefficients[0] = 0; // index is the exponent
- var o = {};
- o.cte = 1;
- o.oper = '+';
- // fire: mark with * or ^ when finds * or ^ down tree, reset to "" with + and -.
- // It is used to deduce the exponent: 1 for *, 0 for "".
- o.fire = '';
- var maxExpo = 0; // maximum exponent
- var varname = ''; // variable name
- recurPol(node, null, o);
- maxExpo = coefficients.length - 1;
- var first = true;
- var no;
- for (var i = maxExpo; i >= 0; i--) {
- if (coefficients[i] === 0) continue;
- var n1 = new ConstantNode(first ? coefficients[i] : Math.abs(coefficients[i]));
- var op = coefficients[i] < 0 ? '-' : '+';
- if (i > 0) {
- // Is not a constant without variable
- var n2 = new SymbolNode(varname);
- if (i > 1) {
- var n3 = new ConstantNode(i);
- n2 = new OperatorNode('^', 'pow', [n2, n3]);
- }
- if (coefficients[i] === -1 && first) {
- n1 = new OperatorNode('-', 'unaryMinus', [n2]);
- } else if (Math.abs(coefficients[i]) === 1) {
- n1 = n2;
- } else {
- n1 = new OperatorNode('*', 'multiply', [n1, n2]);
- }
- }
- if (first) {
- no = n1;
- } else if (op === '+') {
- no = new OperatorNode('+', 'add', [no, n1]);
- } else {
- no = new OperatorNode('-', 'subtract', [no, n1]);
- }
- first = false;
- } // for
- if (first) {
- return new ConstantNode(0);
- } else {
- return no;
- }
- /**
- * Recursive auxilary function inside polyToCanonical for
- * converting expression in canonical form
- *
- * Syntax:
- *
- * recurPol(node, noPai, obj)
- *
- * @param {Node} node The current subpolynomial expression
- * @param {Node | Null} noPai The current parent node
- * @param {object} obj Object with many internal flags
- *
- * @return {} No return. If error, throws an exception
- */
- function recurPol(node, noPai, o) {
- var tp = node.type;
- if (tp === 'FunctionNode') {
- // ***** FunctionName *****
- // No function call in polynomial expression
- throw new Error('There is an unsolved function call');
- } else if (tp === 'OperatorNode') {
- // ***** OperatorName *****
- if ('+-*^'.indexOf(node.op) === -1) throw new Error('Operator ' + node.op + ' invalid');
- if (noPai !== null) {
- // -(unary),^ : children of *,+,-
- if ((node.fn === 'unaryMinus' || node.fn === 'pow') && noPai.fn !== 'add' && noPai.fn !== 'subtract' && noPai.fn !== 'multiply') {
- throw new Error('Invalid ' + node.op + ' placing');
- }
- // -,+,* : children of +,-
- if ((node.fn === 'subtract' || node.fn === 'add' || node.fn === 'multiply') && noPai.fn !== 'add' && noPai.fn !== 'subtract') {
- throw new Error('Invalid ' + node.op + ' placing');
- }
- // -,+ : first child
- if ((node.fn === 'subtract' || node.fn === 'add' || node.fn === 'unaryMinus') && o.noFil !== 0) {
- throw new Error('Invalid ' + node.op + ' placing');
- }
- } // Has parent
- // Firers: ^,* Old: ^,&,-(unary): firers
- if (node.op === '^' || node.op === '*') {
- o.fire = node.op;
- }
- for (var _i = 0; _i < node.args.length; _i++) {
- // +,-: reset fire
- if (node.fn === 'unaryMinus') o.oper = '-';
- if (node.op === '+' || node.fn === 'subtract') {
- o.fire = '';
- o.cte = 1; // default if there is no constant
- o.oper = _i === 0 ? '+' : node.op;
- }
- o.noFil = _i; // number of son
- recurPol(node.args[_i], node, o);
- } // for in children
- } else if (tp === 'SymbolNode') {
- // ***** SymbolName *****
- if (node.name !== varname && varname !== '') {
- throw new Error('There is more than one variable');
- }
- varname = node.name;
- if (noPai === null) {
- coefficients[1] = 1;
- return;
- }
- // ^: Symbol is First child
- if (noPai.op === '^' && o.noFil !== 0) {
- throw new Error('In power the variable should be the first parameter');
- }
- // *: Symbol is Second child
- if (noPai.op === '*' && o.noFil !== 1) {
- throw new Error('In multiply the variable should be the second parameter');
- }
- // Symbol: firers '',* => it means there is no exponent above, so it's 1 (cte * var)
- if (o.fire === '' || o.fire === '*') {
- if (maxExpo < 1) coefficients[1] = 0;
- coefficients[1] += o.cte * (o.oper === '+' ? 1 : -1);
- maxExpo = Math.max(1, maxExpo);
- }
- } else if (tp === 'ConstantNode') {
- var valor = parseFloat(node.value);
- if (noPai === null) {
- coefficients[0] = valor;
- return;
- }
- if (noPai.op === '^') {
- // cte: second child of power
- if (o.noFil !== 1) throw new Error('Constant cannot be powered');
- if (!isInteger(valor) || valor <= 0) {
- throw new Error('Non-integer exponent is not allowed');
- }
- for (var _i2 = maxExpo + 1; _i2 < valor; _i2++) {
- coefficients[_i2] = 0;
- }
- if (valor > maxExpo) coefficients[valor] = 0;
- coefficients[valor] += o.cte * (o.oper === '+' ? 1 : -1);
- maxExpo = Math.max(valor, maxExpo);
- return;
- }
- o.cte = valor;
- // Cte: firer '' => There is no exponent and no multiplication, so the exponent is 0.
- if (o.fire === '') {
- coefficients[0] += o.cte * (o.oper === '+' ? 1 : -1);
- }
- } else {
- throw new Error('Type ' + tp + ' is not allowed');
- }
- } // End of recurPol
- } // End of polyToCanonical
- });
|