UNPKG

24.2 kBJavaScriptView Raw
1'use strict';
2
3function factory(type, config, load, typed) {
4 var simplify = load(require('./simplify'));
5 var simplifyCore = load(require('./simplify/simplifyCore'));
6 var simplifyConstant = load(require('./simplify/simplifyConstant'));
7 var parse = load(require('../../expression/function/parse'));
8 var number = require('../../utils/number');
9 var ConstantNode = load(require('../../expression/node/ConstantNode'));
10 var OperatorNode = load(require('../../expression/node/OperatorNode'));
11 var SymbolNode = load(require('../../expression/node/SymbolNode'));
12
13 /**
14 * Transform a rationalizable expression in a rational fraction.
15 * If rational fraction is one variable polynomial then converts
16 * the numerator and denominator in canonical form, with decreasing
17 * exponents, returning the coefficients of numerator.
18 *
19 * Syntax:
20 *
21 * rationalize(expr)
22 * rationalize(expr, detailed)
23 * rationalize(expr, scope)
24 * rationalize(expr, scope, detailed)
25 *
26 * Examples:
27 *
28 * math.rationalize('sin(x)+y') // Error: There is an unsolved function call
29 * math.rationalize('2x/y - y/(x+1)') // (2*x^2-y^2+2*x)/(x*y+y)
30 * math.rationalize('(2x+1)^6')
31 * // 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1
32 * math.rationalize('2x/( (2x-1) / (3x+2) ) - 5x/ ( (3x+4) / (2x^2-5) ) + 3')
33 * // -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4)
34 * math.rationalize('x/(1-x)/(x-2)/(x-3)/(x-4) + 2x/ ( (1-2x)/(2-3x) )/ ((3-4x)/(4-5x) )') =
35 * // (-30*x^7+344*x^6-1506*x^5+3200*x^4-3472*x^3+1846*x^2-381*x)/
36 * // (-8*x^6+90*x^5-383*x^4+780*x^3-797*x^2+390*x-72)
37 *
38 * math.rationalize('x+x+x+y',{y:1}) // 3*x+1
39 * math.rationalize('x+x+x+y',{}) // 3*x+y
40 * ret = math.rationalize('x+x+x+y',{},true)
41 * // ret.expression=3*x+y, ret.variables = ["x","y"]
42 * ret = math.rationalize('-2+5x^2',{},true)
43 * // ret.expression=5*x^2-2, ret.variables = ["x"], ret.coefficients=[-2,0,5]
44 *
45 * See also:
46 *
47 * simplify
48 *
49 * @param {Node|string} expr The expression to check if is a polynomial expression
50 * @param {Object|boolean} optional scope of expression or true for already evaluated rational expression at input
51 * @param {Boolean} detailed optional True if return an object, false if return expression node (default)
52 *
53 * @return {Object | Expression Node} The rational polynomial of `expr` or na object
54 * {Object}
55 * {Expression Node} expression: node simplified expression
56 * {Expression Node} numerator: simplified numerator of expression
57 * {Expression Node | boolean} denominator: simplified denominator or false (if there is no denominator)
58 * {Array} variables: variable names
59 * {Array} coefficients: coefficients of numerator sorted by increased exponent
60 * {Expression Node} node simplified expression
61 *
62 */
63 var rationalize = typed('rationalize', {
64 'string': function string(expr) {
65 return rationalize(parse(expr), {}, false);
66 },
67
68 'string, boolean': function stringBoolean(expr, detailed) {
69 return rationalize(parse(expr), {}, detailed);
70 },
71
72 'string, Object': function stringObject(expr, scope) {
73 return rationalize(parse(expr), scope, false);
74 },
75
76 'string, Object, boolean': function stringObjectBoolean(expr, scope, detailed) {
77 return rationalize(parse(expr), scope, detailed);
78 },
79
80 'Node': function Node(expr) {
81 return rationalize(expr, {}, false);
82 },
83
84 'Node, boolean': function NodeBoolean(expr, detailed) {
85 return rationalize(expr, {}, detailed);
86 },
87
88 'Node, Object': function NodeObject(expr, scope) {
89 return rationalize(expr, scope, false);
90 },
91
92 'Node, Object, boolean': function NodeObjectBoolean(expr, scope, detailed) {
93 var polyRet = polynomial(expr, scope, true); // Check if expression is a rationalizable polynomial
94 var nVars = polyRet.variables.length;
95 expr = polyRet.expression;
96
97 if (nVars >= 1) {
98 // If expression in not a constant
99 var setRules = rulesRationalize(); // Rules for change polynomial in near canonical form
100 expr = expandPower(expr); // First expand power of polynomials (cannot be made from rules!)
101 var sBefore = void 0; // Previous expression
102
103 while (true) {
104 // Apply alternately successive division rules and distr.div.rules
105 expr = simplify(expr, setRules.firstRules); // Apply the initial rules, including succ div rules
106 expr = simplify(expr, setRules.distrDivRules); // and distr.div.rules until no more changes
107
108 var s = expr.toString();
109 if (s === sBefore) break; // No changes : end of the loop
110
111 sBefore = s;
112 }
113
114 expr = simplify(expr, setRules.firstRulesAgain);
115 expr = simplify(expr, setRules.finalRules); // Apply final rules
116 } // NVars >= 1
117
118 var coefficients = [];
119 var retRationalize = {};
120
121 if (expr.type === 'OperatorNode' && expr.isBinary() && expr.op === '/') {
122 // Separate numerator from denominator
123 if (nVars === 1) {
124 expr.args[0] = polyToCanonical(expr.args[0], coefficients);
125 expr.args[1] = polyToCanonical(expr.args[1]);
126 }
127 if (detailed) {
128 retRationalize.numerator = expr.args[0];
129 retRationalize.denominator = expr.args[1];
130 }
131 } else {
132 if (nVars === 1) {
133 expr = polyToCanonical(expr, coefficients);
134 }
135 if (detailed) {
136 retRationalize.numerator = expr;
137 retRationalize.denominator = null;
138 }
139 }
140 // nVars
141
142 if (!detailed) return expr;
143 retRationalize.coefficients = coefficients;
144 retRationalize.variables = polyRet.variables;
145 retRationalize.expression = expr;
146 return retRationalize;
147 } // ^^^^^^^ end of rationalize ^^^^^^^^
148 }); // end of typed rationalize
149
150 /**
151 * Function to simplify an expression using an optional scope and
152 * return it if the expression is a polynomial expression, i.e.
153 * an expression with one or more variables and the operators
154 * +, -, *, and ^, where the exponent can only be a positive integer.
155 *
156 * Syntax:
157 *
158 * polynomial(expr,scope,extended)
159 *
160 * @param {Node | string} expr The expression to simplify and check if is polynomial expression
161 * @param {object} scope Optional scope for expression simplification
162 * @param {boolean} extended Optional. Default is false. When true allows divide operator.
163 *
164 *
165 * @return {Object}
166 * {Object} node: node simplified expression
167 * {Array} variables: variable names
168 */
169 function polynomial(expr, scope, extended) {
170 var variables = [];
171 var node = simplify(expr, scope); // Resolves any variables and functions with all defined parameters
172 extended = !!extended;
173
174 var oper = '+-*' + (extended ? '/' : '');
175 recPoly(node);
176 var retFunc = {};
177 retFunc.expression = node;
178 retFunc.variables = variables;
179 return retFunc;
180
181 // -------------------------------------------------------------------------------------------------------
182
183 /**
184 * Function to simplify an expression using an optional scope and
185 * return it if the expression is a polynomial expression, i.e.
186 * an expression with one or more variables and the operators
187 * +, -, *, and ^, where the exponent can only be a positive integer.
188 *
189 * Syntax:
190 *
191 * recPoly(node)
192 *
193 *
194 * @param {Node} node The current sub tree expression in recursion
195 *
196 * @return nothing, throw an exception if error
197 */
198 function recPoly(node) {
199 var tp = node.type; // node type
200 if (tp === 'FunctionNode') {
201 // No function call in polynomial expression
202 throw new Error('There is an unsolved function call');
203 } else if (tp === 'OperatorNode') {
204 if (node.op === '^' && node.isBinary()) {
205 if (node.args[1].op === '-' && node.args[1].isUnary()) {
206 if (node.args[1].args[0].type !== 'ConstantNode' || !number.isInteger(parseFloat(node.args[1].args[0].value))) {
207 throw new Error('There is a non-integer exponent');
208 } else {
209 recPoly(node.args[0]);
210 }
211 } else if (node.args[1].type !== 'ConstantNode' || !number.isInteger(parseFloat(node.args[1].value))) {
212 throw new Error('There is a non-integer exponent');
213 } else {
214 recPoly(node.args[0]);
215 }
216 } else {
217 if (oper.indexOf(node.op) === -1) {
218 throw new Error('Operator ' + node.op + ' invalid in polynomial expression');
219 }
220 for (var i = 0; i < node.args.length; i++) {
221 recPoly(node.args[i]);
222 }
223 } // type of operator
224 } else if (tp === 'SymbolNode') {
225 var name = node.name; // variable name
226 var pos = variables.indexOf(name);
227 if (pos === -1) {
228 // new variable in expression
229 variables.push(name);
230 }
231 } else if (tp === 'ParenthesisNode') {
232 recPoly(node.content);
233 } else if (tp !== 'ConstantNode') {
234 throw new Error('type ' + tp + ' is not allowed in polynomial expression');
235 }
236 } // end of recPoly
237 } // end of polynomial
238
239 // ---------------------------------------------------------------------------------------
240 /**
241 * Return a rule set to rationalize an polynomial expression in rationalize
242 *
243 * Syntax:
244 *
245 * rulesRationalize()
246 *
247 * @return {array} rule set to rationalize an polynomial expression
248 */
249 function rulesRationalize() {
250 var oldRules = [simplifyCore, // sCore
251 { l: 'n+n', r: '2*n' }, { l: 'n+-n', r: '0' }, simplifyConstant, // sConstant
252 { l: 'n*(n1^-1)', r: 'n/n1' }, { l: 'n*n1^-n2', r: 'n/n1^n2' }, { l: 'n1^-1', r: '1/n1' }, { l: 'n1^-n2', r: '1/n1^n2' }, { l: 'n*(n1/n2)', r: '(n*n1)/n2' }, { l: '1*n', r: 'n' }];
253
254 var rulesFirst = [{ l: '(-n1)/(-n2)', r: 'n1/n2' }, // Unary division
255 { l: '(-n1)*(-n2)', r: 'n1*n2' }, // Unary multiplication
256 { l: 'n1--n2', r: 'n1+n2' }, // '--' elimination
257 { l: 'n1-n2', r: 'n1+(-n2)' }, // Subtraction turn into add with un�ry minus
258 { l: '(n1+n2)*n3', r: '(n1*n3 + n2*n3)' }, // Distributive 1
259 { l: 'n1*(n2+n3)', r: '(n1*n2+n1*n3)' }, // Distributive 2
260 { l: 'c1*n + c2*n', r: '(c1+c2)*n' }, // Joining constants
261 { l: '-v*-c', r: 'c*v' }, // Inversion constant and variable 1
262 { l: '-v*c', r: '-c*v' }, // Inversion constant and variable 2
263 { l: 'v*-c', r: '-c*v' }, // Inversion constant and variable 3
264 { l: 'v*c', r: 'c*v' }, // Inversion constant and variable 4
265 { l: '-(-n1*n2)', r: '(n1*n2)' }, // Unary propagation
266 { l: '-(n1*n2)', r: '(-n1*n2)' }, // Unary propagation
267 { l: '-(-n1+n2)', r: '(n1-n2)' }, // Unary propagation
268 { l: '-(n1+n2)', r: '(-n1-n2)' }, // Unary propagation
269 { l: '(n1^n2)^n3', r: '(n1^(n2*n3))' }, // Power to Power
270 { l: '-(-n1/n2)', r: '(n1/n2)' }, // Division and Unary
271 { l: '-(n1/n2)', r: '(-n1/n2)' }]; // Divisao and Unary
272
273 var rulesDistrDiv = [{ l: '(n1/n2 + n3/n4)', r: '((n1*n4 + n3*n2)/(n2*n4))' }, // Sum of fractions
274 { l: '(n1/n2 + n3)', r: '((n1 + n3*n2)/n2)' }, // Sum fraction with number 1
275 { l: '(n1 + n2/n3)', r: '((n1*n3 + n2)/n3)' }]; // Sum fraction with number 1
276
277 var rulesSucDiv = [{ l: '(n1/(n2/n3))', r: '((n1*n3)/n2)' }, // Division simplification
278 { l: '(n1/n2/n3)', r: '(n1/(n2*n3))' }];
279
280 var setRules = {}; // rules set in 4 steps.
281
282 // All rules => infinite loop
283 // setRules.allRules =oldRules.concat(rulesFirst,rulesDistrDiv,rulesSucDiv)
284
285 setRules.firstRules = oldRules.concat(rulesFirst, rulesSucDiv); // First rule set
286 setRules.distrDivRules = rulesDistrDiv; // Just distr. div. rules
287 setRules.sucDivRules = rulesSucDiv; // Jus succ. div. rules
288 setRules.firstRulesAgain = oldRules.concat(rulesFirst); // Last rules set without succ. div.
289
290 // Division simplification
291
292 // Second rule set.
293 // There is no aggregate expression with parentesis, but the only variable can be scattered.
294 setRules.finalRules = [simplifyCore, // simplify.rules[0]
295 { l: 'n*-n', r: '-n^2' }, // Joining multiply with power 1
296 { l: 'n*n', r: 'n^2' }, // Joining multiply with power 2
297 simplifyConstant, // simplify.rules[14] old 3rd index in oldRules
298 { l: 'n*-n^n1', r: '-n^(n1+1)' }, // Joining multiply with power 3
299 { l: 'n*n^n1', r: 'n^(n1+1)' }, // Joining multiply with power 4
300 { l: 'n^n1*-n^n2', r: '-n^(n1+n2)' }, // Joining multiply with power 5
301 { l: 'n^n1*n^n2', r: 'n^(n1+n2)' }, // Joining multiply with power 6
302 { l: 'n^n1*-n', r: '-n^(n1+1)' }, // Joining multiply with power 7
303 { l: 'n^n1*n', r: 'n^(n1+1)' }, // Joining multiply with power 8
304 { l: 'n^n1/-n', r: '-n^(n1-1)' }, // Joining multiply with power 8
305 { l: 'n^n1/n', r: 'n^(n1-1)' }, // Joining division with power 1
306 { l: 'n/-n^n1', r: '-n^(1-n1)' }, // Joining division with power 2
307 { l: 'n/n^n1', r: 'n^(1-n1)' }, // Joining division with power 3
308 { l: 'n^n1/-n^n2', r: 'n^(n1-n2)' }, // Joining division with power 4
309 { l: 'n^n1/n^n2', r: 'n^(n1-n2)' }, // Joining division with power 5
310 { l: 'n1+(-n2*n3)', r: 'n1-n2*n3' }, // Solving useless parenthesis 1
311 { l: 'v*(-c)', r: '-c*v' }, // Solving useless unary 2
312 { l: 'n1+-n2', r: 'n1-n2' }, // Solving +- together (new!)
313 { l: 'v*c', r: 'c*v' }, // inversion constant with variable
314 { l: '(n1^n2)^n3', r: '(n1^(n2*n3))' // Power to Power
315
316 }];
317 return setRules;
318 } // End rulesRationalize
319
320 // ---------------------------------------------------------------------------------------
321 /**
322 * Expand recursively a tree node for handling with expressions with exponents
323 * (it's not for constants, symbols or functions with exponents)
324 * PS: The other parameters are internal for recursion
325 *
326 * Syntax:
327 *
328 * expandPower(node)
329 *
330 * @param {Node} node Current expression node
331 * @param {node} parent Parent current node inside the recursion
332 * @param (int} Parent number of chid inside the rercursion
333 *
334 * @return {node} node expression with all powers expanded.
335 */
336 function expandPower(node, parent, indParent) {
337 var tp = node.type;
338 var internal = arguments.length > 1; // TRUE in internal calls
339
340 if (tp === 'OperatorNode' && node.isBinary()) {
341 var does = false;
342 var val = void 0;
343 if (node.op === '^') {
344 // First operator: Parenthesis or UnaryMinus
345 if ((node.args[0].type === 'ParenthesisNode' || node.args[0].type === 'OperatorNode') && node.args[1].type === 'ConstantNode') {
346 // Second operator: Constant
347 val = parseFloat(node.args[1].value);
348 does = val >= 2 && number.isInteger(val);
349 }
350 }
351
352 if (does) {
353 // Exponent >= 2
354 // Before:
355 // operator A --> Subtree
356 // parent pow
357 // constant
358 //
359 if (val > 2) {
360 // Exponent > 2,
361 // AFTER: (exponent > 2)
362 // operator A --> Subtree
363 // parent *
364 // deep clone (operator A --> Subtree
365 // pow
366 // constant - 1
367 //
368 var nEsqTopo = node.args[0];
369 var nDirTopo = new OperatorNode('^', 'pow', [node.args[0].cloneDeep(), new ConstantNode(val - 1)]);
370 node = new OperatorNode('*', 'multiply', [nEsqTopo, nDirTopo]);
371 } else {
372 // Expo = 2 - no power
373 // AFTER: (exponent = 2)
374 // operator A --> Subtree
375 // parent oper
376 // deep clone (operator A --> Subtree)
377 //
378 node = new OperatorNode('*', 'multiply', [node.args[0], node.args[0].cloneDeep()]);
379 }
380
381 if (internal) {
382 // Change parent references in internal recursive calls
383 if (indParent === 'content') {
384 parent.content = node;
385 } else {
386 parent.args[indParent] = node;
387 }
388 }
389 } // does
390 } // binary OperatorNode
391
392 if (tp === 'ParenthesisNode') {
393 // Recursion
394 expandPower(node.content, node, 'content');
395 } else if (tp !== 'ConstantNode' && tp !== 'SymbolNode') {
396 for (var i = 0; i < node.args.length; i++) {
397 expandPower(node.args[i], node, i);
398 }
399 }
400
401 if (!internal) {
402 // return the root node
403 return node;
404 }
405 } // End expandPower
406
407 // ---------------------------------------------------------------------------------------
408 /**
409 * Auxilary function for rationalize
410 * Convert near canonical polynomial in one variable in a canonical polynomial
411 * with one term for each exponent in decreasing order
412 *
413 * Syntax:
414 *
415 * polyToCanonical(node [, coefficients])
416 *
417 * @param {Node | string} expr The near canonical polynomial expression to convert in a a canonical polynomial expression
418 *
419 * The string or tree expression needs to be at below syntax, with free spaces:
420 * ( (^(-)? | [+-]? )cte (*)? var (^expo)? | cte )+
421 * Where 'var' is one variable with any valid name
422 * 'cte' are real numeric constants with any value. It can be omitted if equal than 1
423 * 'expo' are integers greater than 0. It can be omitted if equal than 1.
424 *
425 * @param {array} coefficients Optional returns coefficients sorted by increased exponent
426 *
427 *
428 * @return {node} new node tree with one variable polynomial or string error.
429 */
430 function polyToCanonical(node, coefficients) {
431 if (coefficients === undefined) {
432 coefficients = [];
433 } // coefficients.
434
435 coefficients[0] = 0; // index is the exponent
436 var o = {};
437 o.cte = 1;
438 o.oper = '+';
439
440 // fire: mark with * or ^ when finds * or ^ down tree, reset to "" with + and -.
441 // It is used to deduce the exponent: 1 for *, 0 for "".
442 o.fire = '';
443
444 var maxExpo = 0; // maximum exponent
445 var varname = ''; // variable name
446
447 recurPol(node, null, o);
448 maxExpo = coefficients.length - 1;
449 var first = true;
450 var no = void 0;
451
452 for (var i = maxExpo; i >= 0; i--) {
453 if (coefficients[i] === 0) continue;
454 var n1 = new ConstantNode(first ? coefficients[i] : Math.abs(coefficients[i]));
455 var op = coefficients[i] < 0 ? '-' : '+';
456
457 if (i > 0) {
458 // Is not a constant without variable
459 var n2 = new SymbolNode(varname);
460 if (i > 1) {
461 var n3 = new ConstantNode(i);
462 n2 = new OperatorNode('^', 'pow', [n2, n3]);
463 }
464 if (coefficients[i] === -1 && first) {
465 n1 = new OperatorNode('-', 'unaryMinus', [n2]);
466 } else if (Math.abs(coefficients[i]) === 1) {
467 n1 = n2;
468 } else {
469 n1 = new OperatorNode('*', 'multiply', [n1, n2]);
470 }
471 }
472
473 if (first) {
474 no = n1;
475 } else if (op === '+') {
476 no = new OperatorNode('+', 'add', [no, n1]);
477 } else {
478 no = new OperatorNode('-', 'subtract', [no, n1]);
479 }
480
481 first = false;
482 } // for
483
484 if (first) {
485 return new ConstantNode(0);
486 } else {
487 return no;
488 }
489
490 /**
491 * Recursive auxilary function inside polyToCanonical for
492 * converting expression in canonical form
493 *
494 * Syntax:
495 *
496 * recurPol(node, noPai, obj)
497 *
498 * @param {Node} node The current subpolynomial expression
499 * @param {Node | Null} noPai The current parent node
500 * @param {object} obj Object with many internal flags
501 *
502 * @return {} No return. If error, throws an exception
503 */
504 function recurPol(node, noPai, o) {
505 var tp = node.type;
506 if (tp === 'FunctionNode') {
507 // ***** FunctionName *****
508 // No function call in polynomial expression
509 throw new Error('There is an unsolved function call');
510 } else if (tp === 'OperatorNode') {
511 // ***** OperatorName *****
512 if ('+-*^'.indexOf(node.op) === -1) throw new Error('Operator ' + node.op + ' invalid');
513
514 if (noPai !== null) {
515 // -(unary),^ : children of *,+,-
516 if ((node.fn === 'unaryMinus' || node.fn === 'pow') && noPai.fn !== 'add' && noPai.fn !== 'subtract' && noPai.fn !== 'multiply') {
517 throw new Error('Invalid ' + node.op + ' placing');
518 }
519
520 // -,+,* : children of +,-
521 if ((node.fn === 'subtract' || node.fn === 'add' || node.fn === 'multiply') && noPai.fn !== 'add' && noPai.fn !== 'subtract') {
522 throw new Error('Invalid ' + node.op + ' placing');
523 }
524
525 // -,+ : first child
526 if ((node.fn === 'subtract' || node.fn === 'add' || node.fn === 'unaryMinus') && o.noFil !== 0) {
527 throw new Error('Invalid ' + node.op + ' placing');
528 }
529 } // Has parent
530
531 // Firers: ^,* Old: ^,&,-(unary): firers
532 if (node.op === '^' || node.op === '*') {
533 o.fire = node.op;
534 }
535
536 for (var _i = 0; _i < node.args.length; _i++) {
537 // +,-: reset fire
538 if (node.fn === 'unaryMinus') o.oper = '-';
539 if (node.op === '+' || node.fn === 'subtract') {
540 o.fire = '';
541 o.cte = 1; // default if there is no constant
542 o.oper = _i === 0 ? '+' : node.op;
543 }
544 o.noFil = _i; // number of son
545 recurPol(node.args[_i], node, o);
546 } // for in children
547 } else if (tp === 'SymbolNode') {
548 // ***** SymbolName *****
549 if (node.name !== varname && varname !== '') {
550 throw new Error('There is more than one variable');
551 }
552 varname = node.name;
553 if (noPai === null) {
554 coefficients[1] = 1;
555 return;
556 }
557
558 // ^: Symbol is First child
559 if (noPai.op === '^' && o.noFil !== 0) {
560 throw new Error('In power the variable should be the first parameter');
561 }
562
563 // *: Symbol is Second child
564 if (noPai.op === '*' && o.noFil !== 1) {
565 throw new Error('In multiply the variable should be the second parameter');
566 }
567
568 // Symbol: firers '',* => it means there is no exponent above, so it's 1 (cte * var)
569 if (o.fire === '' || o.fire === '*') {
570 if (maxExpo < 1) coefficients[1] = 0;
571 coefficients[1] += o.cte * (o.oper === '+' ? 1 : -1);
572 maxExpo = Math.max(1, maxExpo);
573 }
574 } else if (tp === 'ConstantNode') {
575 var valor = parseFloat(node.value);
576 if (noPai === null) {
577 coefficients[0] = valor;
578 return;
579 }
580 if (noPai.op === '^') {
581 // cte: second child of power
582 if (o.noFil !== 1) throw new Error('Constant cannot be powered');
583
584 if (!number.isInteger(valor) || valor <= 0) {
585 throw new Error('Non-integer exponent is not allowed');
586 }
587
588 for (var _i2 = maxExpo + 1; _i2 < valor; _i2++) {
589 coefficients[_i2] = 0;
590 }if (valor > maxExpo) coefficients[valor] = 0;
591 coefficients[valor] += o.cte * (o.oper === '+' ? 1 : -1);
592 maxExpo = Math.max(valor, maxExpo);
593 return;
594 }
595 o.cte = valor;
596
597 // Cte: firer '' => There is no exponent and no multiplication, so the exponent is 0.
598 if (o.fire === '') {
599 coefficients[0] += o.cte * (o.oper === '+' ? 1 : -1);
600 }
601 } else {
602 throw new Error('Type ' + tp + ' is not allowed');
603 }
604 } // End of recurPol
605 } // End of polyToCanonical
606
607 return rationalize;
608} // end of factory
609
610exports.name = 'rationalize';
611exports.factory = factory;
\No newline at end of file