nerdamer 1.1.13 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +184 -0
- package/README.md +293 -312
- package/dist/bundle.js +2 -0
- package/dist/bundle.js.LICENSE.txt +7 -0
- package/dist/parser.js +2 -0
- package/dist/parser.js.LICENSE.txt +7 -0
- package/docs-data/parser-functions.json +1960 -0
- package/index.d.ts +10 -426
- package/output/algebra/adapters.d.ts +33 -0
- package/output/algebra/adapters.js +109 -0
- package/output/algebra/algorithms/arith.d.ts +84 -0
- package/output/algebra/algorithms/arith.js +323 -0
- package/output/algebra/algorithms/factor.d.ts +3 -0
- package/output/algebra/algorithms/factor.js +5 -0
- package/output/algebra/algorithms/factorMultivariate.d.ts +23 -0
- package/output/algebra/algorithms/factorMultivariate.js +2393 -0
- package/output/algebra/algorithms/factorUnivariate.d.ts +72 -0
- package/output/algebra/algorithms/factorUnivariate.js +1072 -0
- package/output/algebra/algorithms/gcd.d.ts +22 -0
- package/output/algebra/algorithms/gcd.js +690 -0
- package/output/algebra/algorithms/groebnerBase.d.ts +157 -0
- package/output/algebra/algorithms/groebnerBase.js +1166 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.d.ts +137 -0
- package/output/algebra/algorithms/multiPoly/MultiPoly.js +346 -0
- package/output/algebra/algorithms/poly.d.ts +228 -0
- package/output/algebra/algorithms/poly.js +1299 -0
- package/output/algebra/algorithms/rational.d.ts +17 -0
- package/output/algebra/algorithms/rational.js +115 -0
- package/output/algebra/factor/factor.d.ts +62 -0
- package/output/algebra/factor/factor.js +158 -0
- package/output/algebra/gcd/gcd.d.ts +29 -0
- package/output/algebra/gcd/gcd.js +141 -0
- package/output/algebra/groebner.d.ts +21 -0
- package/output/algebra/groebner.js +42 -0
- package/output/algebra/partfrac.d.ts +19 -0
- package/output/algebra/partfrac.js +398 -0
- package/output/algebra/polynomialize.d.ts +20 -0
- package/output/algebra/polynomialize.js +24 -0
- package/output/algebra/simplify/complexsimp.d.ts +7 -0
- package/output/algebra/simplify/complexsimp.js +24 -0
- package/output/algebra/simplify/factorCommon.d.ts +13 -0
- package/output/algebra/simplify/factorCommon.js +136 -0
- package/output/algebra/simplify/funcsimp.d.ts +26 -0
- package/output/algebra/simplify/funcsimp.js +633 -0
- package/output/algebra/simplify/invtrigrewrite.d.ts +10 -0
- package/output/algebra/simplify/invtrigrewrite.js +96 -0
- package/output/algebra/simplify/ratsimp.d.ts +21 -0
- package/output/algebra/simplify/ratsimp.js +140 -0
- package/output/algebra/simplify/simplify.d.ts +25 -0
- package/output/algebra/simplify/simplify.js +228 -0
- package/output/algebra/simplify/trigreduce.d.ts +38 -0
- package/output/algebra/simplify/trigreduce.js +424 -0
- package/output/algebra/simplify/trigrewrite.d.ts +17 -0
- package/output/algebra/simplify/trigrewrite.js +156 -0
- package/output/algebra/simplify/trigsimp.d.ts +11 -0
- package/output/algebra/simplify/trigsimp.js +369 -0
- package/output/algebra/simplify/utils.d.ts +32 -0
- package/output/algebra/simplify/utils.js +56 -0
- package/output/algebra/utils.d.ts +32 -0
- package/output/algebra/utils.js +48 -0
- package/output/api/advanced.d.ts +7 -0
- package/output/api/advanced.js +18 -0
- package/output/api/algebra.d.ts +17 -0
- package/output/api/algebra.js +32 -0
- package/output/api/assumptions.d.ts +4 -0
- package/output/api/assumptions.js +11 -0
- package/output/api/calculus.d.ts +9 -0
- package/output/api/calculus.js +21 -0
- package/output/api/core.d.ts +17 -0
- package/output/api/core.js +41 -0
- package/output/api/debug.d.ts +16 -0
- package/output/api/debug.js +23 -0
- package/output/api/parser.d.ts +85 -0
- package/output/api/parser.js +16 -0
- package/output/api/solve.d.ts +10 -0
- package/output/api/solve.js +16 -0
- package/output/api/structures.d.ts +10 -0
- package/output/api/structures.js +22 -0
- package/output/calculus/derivative/diff.d.ts +30 -0
- package/output/calculus/derivative/diff.js +238 -0
- package/output/calculus/fresnel.d.ts +16 -0
- package/output/calculus/fresnel.js +39 -0
- package/output/calculus/integrate/byParts.d.ts +18 -0
- package/output/calculus/integrate/byParts.js +339 -0
- package/output/calculus/integrate/bySubstitution.d.ts +135 -0
- package/output/calculus/integrate/bySubstitution.js +411 -0
- package/output/calculus/integrate/integrate.d.ts +38 -0
- package/output/calculus/integrate/integrate.js +652 -0
- package/output/calculus/integrate/integrationTable.d.ts +2 -0
- package/output/calculus/integrate/integrationTable.js +914 -0
- package/output/calculus/integrate/utils.d.ts +28 -0
- package/output/calculus/integrate/utils.js +96 -0
- package/output/calculus/laplace/ilaplace.d.ts +31 -0
- package/output/calculus/laplace/ilaplace.js +192 -0
- package/output/calculus/laplace/ilaplaceTable.d.ts +2 -0
- package/output/calculus/laplace/ilaplaceTable.js +200 -0
- package/output/calculus/laplace/laplace.d.ts +22 -0
- package/output/calculus/laplace/laplace.js +109 -0
- package/output/calculus/laplace/laplaceTable.d.ts +2 -0
- package/output/calculus/laplace/laplaceTable.js +187 -0
- package/output/calculus/limit/limit.d.ts +35 -0
- package/output/calculus/limit/limit.js +1183 -0
- package/output/calculus/limit/limitsTable.d.ts +2 -0
- package/output/calculus/limit/limitsTable.js +7 -0
- package/output/core/Settings.d.ts +32 -0
- package/output/core/Settings.js +68 -0
- package/output/core/adapters.d.ts +18 -0
- package/output/core/adapters.js +40 -0
- package/output/core/classes/assumption/Assumption.d.ts +218 -0
- package/output/core/classes/assumption/Assumption.js +605 -0
- package/output/core/classes/assumption/assertiveFunctions.d.ts +6 -0
- package/output/core/classes/assumption/assertiveFunctions.js +64 -0
- package/output/core/classes/assumption/assume.d.ts +90 -0
- package/output/core/classes/assumption/assume.js +145 -0
- package/output/core/classes/collection/Collection.d.ts +107 -0
- package/output/core/classes/collection/Collection.js +231 -0
- package/output/core/classes/complex/Complex.d.ts +99 -0
- package/output/core/classes/complex/Complex.js +135 -0
- package/output/core/classes/decimalSet/DecimalSet.d.ts +226 -0
- package/output/core/classes/decimalSet/DecimalSet.js +453 -0
- package/output/core/classes/dictionary/Dictionary.d.ts +102 -0
- package/output/core/classes/dictionary/Dictionary.js +213 -0
- package/output/core/classes/equation/Equation.d.ts +256 -0
- package/output/core/classes/equation/Equation.js +350 -0
- package/output/core/classes/expression/CoeffObject.d.ts +100 -0
- package/output/core/classes/expression/CoeffObject.js +198 -0
- package/output/core/classes/expression/Expression.d.ts +1674 -0
- package/output/core/classes/expression/Expression.js +2332 -0
- package/output/core/classes/expression/analysis.d.ts +25 -0
- package/output/core/classes/expression/analysis.js +218 -0
- package/output/core/classes/expression/collect.d.ts +9 -0
- package/output/core/classes/expression/collect.js +49 -0
- package/output/core/classes/expression/format.d.ts +45 -0
- package/output/core/classes/expression/format.js +217 -0
- package/output/core/classes/expression/products.d.ts +23 -0
- package/output/core/classes/expression/products.js +115 -0
- package/output/core/classes/expression/shortcuts.d.ts +35 -0
- package/output/core/classes/expression/shortcuts.js +129 -0
- package/output/core/classes/expression/traversal.d.ts +31 -0
- package/output/core/classes/expression/traversal.js +216 -0
- package/output/core/classes/expression/trig.d.ts +25 -0
- package/output/core/classes/expression/trig.js +40 -0
- package/output/core/classes/expression/utils.d.ts +52 -0
- package/output/core/classes/expression/utils.js +189 -0
- package/output/core/classes/lookupTable/LookupTable.d.ts +12 -0
- package/output/core/classes/lookupTable/LookupTable.js +55 -0
- package/output/core/classes/matrix/Matrix.d.ts +227 -0
- package/output/core/classes/matrix/Matrix.js +889 -0
- package/output/core/classes/matrix/Sylvester.d.ts +11 -0
- package/output/core/classes/matrix/Sylvester.js +54 -0
- package/output/core/classes/matrix/functions.d.ts +26 -0
- package/output/core/classes/matrix/functions.js +52 -0
- package/output/core/classes/matrix/utils.d.ts +9 -0
- package/output/core/classes/matrix/utils.js +22 -0
- package/output/core/classes/parser/Parser.d.ts +480 -0
- package/output/core/classes/parser/Parser.js +1812 -0
- package/output/core/classes/parser/Token.d.ts +58 -0
- package/output/core/classes/parser/Token.js +137 -0
- package/output/core/classes/parser/constants.d.ts +160 -0
- package/output/core/classes/parser/constants.js +227 -0
- package/output/core/classes/parser/helpers.d.ts +21 -0
- package/output/core/classes/parser/helpers.js +42 -0
- package/output/core/classes/parser/operations/add.d.ts +15 -0
- package/output/core/classes/parser/operations/add.js +238 -0
- package/output/core/classes/parser/operations/comma.d.ts +7 -0
- package/output/core/classes/parser/operations/comma.js +11 -0
- package/output/core/classes/parser/operations/compare.d.ts +21 -0
- package/output/core/classes/parser/operations/compare.js +461 -0
- package/output/core/classes/parser/operations/divide.d.ts +2 -0
- package/output/core/classes/parser/operations/divide.js +72 -0
- package/output/core/classes/parser/operations/functions.d.ts +46 -0
- package/output/core/classes/parser/operations/functions.js +430 -0
- package/output/core/classes/parser/operations/multiply.d.ts +11 -0
- package/output/core/classes/parser/operations/multiply.js +321 -0
- package/output/core/classes/parser/operations/power.d.ts +48 -0
- package/output/core/classes/parser/operations/power.js +673 -0
- package/output/core/classes/parser/operations/subtract.d.ts +3 -0
- package/output/core/classes/parser/operations/subtract.js +35 -0
- package/output/core/classes/parser/preprocess.d.ts +14 -0
- package/output/core/classes/parser/preprocess.js +259 -0
- package/output/core/classes/parser/scripting/controlFlow.d.ts +121 -0
- package/output/core/classes/parser/scripting/controlFlow.js +355 -0
- package/output/core/classes/parser/scripting/evaluate.d.ts +10 -0
- package/output/core/classes/parser/scripting/evaluate.js +112 -0
- package/output/core/classes/parser/scripting/functions.d.ts +14 -0
- package/output/core/classes/parser/scripting/functions.js +59 -0
- package/output/core/classes/parser/scripting/scope.d.ts +35 -0
- package/output/core/classes/parser/scripting/scope.js +155 -0
- package/output/core/classes/parser/types.d.ts +125 -0
- package/output/core/classes/parser/types.js +2 -0
- package/output/core/classes/parser/wrappers/IndexedReference.d.ts +31 -0
- package/output/core/classes/parser/wrappers/IndexedReference.js +68 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.d.ts +24 -0
- package/output/core/classes/parser/wrappers/KeyValuePair.js +51 -0
- package/output/core/classes/polynomial/Polynomial.d.ts +500 -0
- package/output/core/classes/polynomial/Polynomial.js +1149 -0
- package/output/core/classes/polynomial/Term.d.ts +222 -0
- package/output/core/classes/polynomial/Term.js +430 -0
- package/output/core/classes/polynomial/functions.d.ts +69 -0
- package/output/core/classes/polynomial/functions.js +126 -0
- package/output/core/classes/polynomial/utils.d.ts +62 -0
- package/output/core/classes/polynomial/utils.js +206 -0
- package/output/core/classes/rational/Rational.d.ts +504 -0
- package/output/core/classes/rational/Rational.js +779 -0
- package/output/core/classes/seq/SEQ.d.ts +13 -0
- package/output/core/classes/seq/SEQ.js +137 -0
- package/output/core/classes/valuesSet/ValuesSet.d.ts +179 -0
- package/output/core/classes/valuesSet/ValuesSet.js +381 -0
- package/output/core/classes/vector/Vector.d.ts +222 -0
- package/output/core/classes/vector/Vector.js +497 -0
- package/output/core/classes/vector/functions.d.ts +28 -0
- package/output/core/classes/vector/functions.js +47 -0
- package/output/core/common/classes/MathematicalAggregate.d.ts +53 -0
- package/output/core/common/classes/MathematicalAggregate.js +140 -0
- package/output/core/common/classes/Scope.d.ts +62 -0
- package/output/core/common/classes/Scope.js +122 -0
- package/output/core/common/classes/StructuredEntity.d.ts +55 -0
- package/output/core/common/classes/StructuredEntity.js +151 -0
- package/output/core/common/common.d.ts +63 -0
- package/output/core/common/common.js +279 -0
- package/output/core/common/functions/functions.d.ts +14 -0
- package/output/core/common/functions/functions.js +33 -0
- package/output/core/common/functions/structuredEntityUtils.d.ts +27 -0
- package/output/core/common/functions/structuredEntityUtils.js +40 -0
- package/output/core/converters/BaseConverter.d.ts +97 -0
- package/output/core/converters/BaseConverter.js +405 -0
- package/output/core/converters/Converter.d.ts +111 -0
- package/output/core/converters/Converter.js +802 -0
- package/output/core/converters/Pattern.d.ts +71 -0
- package/output/core/converters/Pattern.js +302 -0
- package/output/core/dispatch.d.ts +34 -0
- package/output/core/dispatch.js +304 -0
- package/output/core/errors.d.ts +531 -0
- package/output/core/errors.js +621 -0
- package/output/core/functions/bigint/bigint.d.ts +121 -0
- package/output/core/functions/bigint/bigint.js +392 -0
- package/output/core/functions/bigint/primeFactor.d.ts +49 -0
- package/output/core/functions/bigint/primeFactor.js +267 -0
- package/output/core/functions/bigint/primes.d.ts +1 -0
- package/output/core/functions/bigint/primes.js +11 -0
- package/output/core/functions/build/definitions.d.ts +12 -0
- package/output/core/functions/build/definitions.js +133 -0
- package/output/core/functions/build/index.d.ts +32 -0
- package/output/core/functions/build/index.js +136 -0
- package/output/core/functions/complex.d.ts +90 -0
- package/output/core/functions/complex.js +482 -0
- package/output/core/functions/decimal.d.ts +24 -0
- package/output/core/functions/decimal.js +664 -0
- package/output/core/functions/expand/expand.d.ts +42 -0
- package/output/core/functions/expand/expand.js +376 -0
- package/output/core/functions/fresnelNumeric.d.ts +12 -0
- package/output/core/functions/fresnelNumeric.js +123 -0
- package/output/core/functions/numeric.d.ts +140 -0
- package/output/core/functions/numeric.js +790 -0
- package/output/core/functions/rationalNormalization.d.ts +11 -0
- package/output/core/functions/rationalNormalization.js +117 -0
- package/output/core/functions/setFunction.d.ts +19 -0
- package/output/core/functions/setFunction.js +75 -0
- package/output/core/functions/string.d.ts +26 -0
- package/output/core/functions/string.js +101 -0
- package/output/core/functions/subst.d.ts +90 -0
- package/output/core/functions/subst.js +498 -0
- package/output/core/functions/utils.d.ts +24 -0
- package/output/core/functions/utils.js +51 -0
- package/output/core/types.d.ts +48 -0
- package/output/core/types.js +2 -0
- package/output/index.d.ts +339 -0
- package/output/index.js +715 -0
- package/output/math/defint/defintDecimal.d.ts +37 -0
- package/output/math/defint/defintDecimal.js +320 -0
- package/output/math/defint/defintNative.d.ts +57 -0
- package/output/math/defint/defintNative.js +292 -0
- package/output/math/geometry.d.ts +8 -0
- package/output/math/geometry.js +32 -0
- package/output/math/math.d.ts +655 -0
- package/output/math/math.js +1811 -0
- package/output/math/trig.d.ts +518 -0
- package/output/math/trig.js +1444 -0
- package/output/math/trunc.d.ts +19 -0
- package/output/math/trunc.js +36 -0
- package/output/math/utils.d.ts +60 -0
- package/output/math/utils.js +180 -0
- package/output/solve/classes/DecimalMatrix.d.ts +17 -0
- package/output/solve/classes/DecimalMatrix.js +86 -0
- package/output/solve/classes/FunctionSolver.d.ts +135 -0
- package/output/solve/classes/FunctionSolver.js +433 -0
- package/output/solve/classes/MultivariateSolver.d.ts +84 -0
- package/output/solve/classes/MultivariateSolver.js +240 -0
- package/output/solve/classes/PolynomialSolver.d.ts +85 -0
- package/output/solve/classes/PolynomialSolver.js +292 -0
- package/output/solve/classes/SolutionSet.d.ts +153 -0
- package/output/solve/classes/SolutionSet.js +357 -0
- package/output/solve/classes/Solver.d.ts +17 -0
- package/output/solve/classes/Solver.js +132 -0
- package/output/solve/classes/SymbolicSolver.d.ts +74 -0
- package/output/solve/classes/SymbolicSolver.js +601 -0
- package/output/solve/linsolve.d.ts +51 -0
- package/output/solve/linsolve.js +225 -0
- package/output/solve/solve.d.ts +34 -0
- package/output/solve/solve.js +260 -0
- package/output/solve/solveSystem.d.ts +31 -0
- package/output/solve/solveSystem.js +290 -0
- package/output/solve/utils.d.ts +9 -0
- package/output/solve/utils.js +62 -0
- package/output/utils/array.d.ts +42 -0
- package/output/utils/array.js +98 -0
- package/output/utils/debug.d.ts +131 -0
- package/output/utils/debug.js +295 -0
- package/output/utils/decimal.d.ts +3 -0
- package/output/utils/decimal.js +16 -0
- package/output/utils/numeric.d.ts +14 -0
- package/output/utils/numeric.js +51 -0
- package/output/utils/object.d.ts +26 -0
- package/output/utils/object.js +56 -0
- package/package.json +213 -57
- package/.travis.yml +0 -3
- package/Algebra.js +0 -4568
- package/BREAKING_CHANGES.md +0 -5
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -14
- package/Calculus.js +0 -2675
- package/Extra.js +0 -622
- package/Solve.js +0 -1783
- package/all.js +0 -16
- package/all.min.js +0 -1
- package/gulpfile.js +0 -16
- package/index.html +0 -158
- package/license.txt +0 -19
- package/nerdamer.core.js +0 -12510
- package/spec/LaTeX.spec.js +0 -302
- package/spec/TeXConvert.spec.js +0 -8
- package/spec/algebra.spec.js +0 -287
- package/spec/basic_parser.spec.js +0 -134
- package/spec/build.spec.js +0 -131
- package/spec/calculus.spec.js +0 -183
- package/spec/core.spec.js +0 -2970
- package/spec/extra.spec.js +0 -54
- package/spec/solve.spec.js +0 -126
- package/spec/support/jasmine.json +0 -11
- package/spec/support/utils.js +0 -42
- package/spec/text.spec.js +0 -132
package/Algebra.js
DELETED
|
@@ -1,4568 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Author : Martin Donk
|
|
3
|
-
* Website : http://www.nerdamer.com
|
|
4
|
-
* Email : martin.r.donk@gmail.com
|
|
5
|
-
* License : MIT
|
|
6
|
-
* Source : https://github.com/jiggzson/nerdamer
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/* global module, Function */
|
|
10
|
-
|
|
11
|
-
if((typeof module) !== 'undefined') {
|
|
12
|
-
var nerdamer = require('./nerdamer.core.js');
|
|
13
|
-
require('./Calculus.js');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
(function () {
|
|
17
|
-
"use strict";
|
|
18
|
-
|
|
19
|
-
/*shortcuts*/
|
|
20
|
-
var core = nerdamer.getCore(),
|
|
21
|
-
_ = core.PARSER,
|
|
22
|
-
N = core.groups.N,
|
|
23
|
-
P = core.groups.P,
|
|
24
|
-
S = core.groups.S,
|
|
25
|
-
EX = core.groups.EX,
|
|
26
|
-
FN = core.groups.FN,
|
|
27
|
-
PL = core.groups.PL,
|
|
28
|
-
CP = core.groups.CP,
|
|
29
|
-
CB = core.groups.CB,
|
|
30
|
-
keys = core.Utils.keys,
|
|
31
|
-
even = core.Utils.even,
|
|
32
|
-
variables = core.Utils.variables,
|
|
33
|
-
format = core.Utils.format,
|
|
34
|
-
round = core.Utils.round,
|
|
35
|
-
Frac = core.Frac,
|
|
36
|
-
isInt = core.Utils.isInt,
|
|
37
|
-
Symbol = core.Symbol,
|
|
38
|
-
CONST_HASH = core.Settings.CONST_HASH,
|
|
39
|
-
math = core.Utils.importFunctions(),
|
|
40
|
-
evaluate = core.Utils.evaluate;
|
|
41
|
-
//*************** CLASSES ***************//
|
|
42
|
-
/**
|
|
43
|
-
* Converts a symbol into an equivalent polynomial arrays of
|
|
44
|
-
* the form [[coefficient_1, power_1],[coefficient_2, power_2], ... ]
|
|
45
|
-
* Univariate polymials only.
|
|
46
|
-
* @param {Symbol|Number} symbol
|
|
47
|
-
* @param {String} variable The variable name of the polynomial
|
|
48
|
-
* @param {int} order
|
|
49
|
-
*/
|
|
50
|
-
function Polynomial(symbol, variable, order) {
|
|
51
|
-
if(core.Utils.isSymbol(symbol)) {
|
|
52
|
-
this.parse(symbol);
|
|
53
|
-
this.variable = this.variable || variable;
|
|
54
|
-
}
|
|
55
|
-
else if(!isNaN(symbol)) {
|
|
56
|
-
order = order || 0;
|
|
57
|
-
if(variable === undefined)
|
|
58
|
-
throw new core.exceptions.InvalidVariableNameError('Polynomial expects a variable name when creating using order');
|
|
59
|
-
this.coeffs = [];
|
|
60
|
-
this.coeffs[order] = symbol;
|
|
61
|
-
this.fill(symbol);
|
|
62
|
-
}
|
|
63
|
-
else if(typeof symbol === 'string') {
|
|
64
|
-
this.parse(_.parse(symbol));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Creates a Polynomial given an array of coefficients
|
|
69
|
-
* @param {int[]} arr
|
|
70
|
-
* @param {String} variable
|
|
71
|
-
* @returns {Polynomial}
|
|
72
|
-
*/
|
|
73
|
-
Polynomial.fromArray = function (arr, variable) {
|
|
74
|
-
if(typeof variable === 'undefined')
|
|
75
|
-
throw new core.exceptions.InvalidVariableNameError('A variable name must be specified when creating polynomial from array');
|
|
76
|
-
var p = new Polynomial();
|
|
77
|
-
p.coeffs = arr;
|
|
78
|
-
p.variable = variable;
|
|
79
|
-
return p;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
Polynomial.fit = function (c1, c2, n, base, p, variable) {
|
|
83
|
-
//after having looped through and mod 10 the number to get the matching factor
|
|
84
|
-
var terms = new Array(p + 1),
|
|
85
|
-
t = n - c2;
|
|
86
|
-
terms[0] = c2; //the constants is assumed to be correct
|
|
87
|
-
//constant for x^p is also assumed know so add
|
|
88
|
-
terms[p] = c1;
|
|
89
|
-
t -= c1 * Math.pow(base, p);
|
|
90
|
-
//start fitting
|
|
91
|
-
for(var i = p - 1; i > 0; i--) {
|
|
92
|
-
var b = Math.pow(base, i), //we want as many wholes as possible
|
|
93
|
-
q = t / b,
|
|
94
|
-
sign = Math.sign(q);
|
|
95
|
-
var c = sign * Math.floor(Math.abs(q));
|
|
96
|
-
t -= c * b;
|
|
97
|
-
terms[i] = c;
|
|
98
|
-
}
|
|
99
|
-
if(t !== 0)
|
|
100
|
-
return null;
|
|
101
|
-
for(var i = 0; i < terms.length; i++)
|
|
102
|
-
terms[i] = new Frac(terms[i]);
|
|
103
|
-
|
|
104
|
-
return Polynomial.fromArray(terms, variable);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
Polynomial.prototype = {
|
|
108
|
-
/**
|
|
109
|
-
* Converts Symbol to Polynomial
|
|
110
|
-
* @param {Symbol} symbol
|
|
111
|
-
* @param {Array} c - a collector array
|
|
112
|
-
* @returns {Polynomial}
|
|
113
|
-
*/
|
|
114
|
-
parse: function (symbol, c) {
|
|
115
|
-
this.variable = variables(symbol)[0];
|
|
116
|
-
if(!symbol.isPoly())
|
|
117
|
-
throw core.exceptions.NerdamerTypeError('Polynomial Expected! Received ' + core.Utils.text(symbol));
|
|
118
|
-
c = c || [];
|
|
119
|
-
if(!symbol.power.absEquals(1))
|
|
120
|
-
symbol = _.expand(symbol);
|
|
121
|
-
|
|
122
|
-
if(symbol.group === core.groups.N) {
|
|
123
|
-
c[0] = symbol.multiplier;
|
|
124
|
-
}
|
|
125
|
-
else if(symbol.group === core.groups.S) {
|
|
126
|
-
c[symbol.power.toDecimal()] = symbol.multiplier;
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
for(var x in symbol.symbols) {
|
|
130
|
-
var sub = symbol.symbols[x],
|
|
131
|
-
p = sub.power;
|
|
132
|
-
if(core.Utils.isSymbol(p))
|
|
133
|
-
throw new core.exceptions.NerdamerTypeError('power cannot be a Symbol');
|
|
134
|
-
|
|
135
|
-
p = sub.group === N ? 0 : p.toDecimal();
|
|
136
|
-
if(sub.symbols) {
|
|
137
|
-
this.parse(sub, c);
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
c[p] = sub.multiplier;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
this.coeffs = c;
|
|
146
|
-
|
|
147
|
-
this.fill();
|
|
148
|
-
},
|
|
149
|
-
/**
|
|
150
|
-
* Fills in the holes in a polynomial with zeroes
|
|
151
|
-
* @param {Number} x - The number to fill the holes with
|
|
152
|
-
*/
|
|
153
|
-
fill: function (x) {
|
|
154
|
-
x = Number(x) || 0;
|
|
155
|
-
var l = this.coeffs.length;
|
|
156
|
-
for(var i = 0; i < l; i++) {
|
|
157
|
-
if(this.coeffs[i] === undefined) {
|
|
158
|
-
this.coeffs[i] = new Frac(x);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return this;
|
|
162
|
-
},
|
|
163
|
-
/**
|
|
164
|
-
* Removes higher order zeros or a specific coefficient
|
|
165
|
-
* @returns {Array}
|
|
166
|
-
*/
|
|
167
|
-
trim: function () {
|
|
168
|
-
var l = this.coeffs.length;
|
|
169
|
-
while(l--) {
|
|
170
|
-
var c = this.coeffs[l];
|
|
171
|
-
var equalsZero = c.equals(0);
|
|
172
|
-
if(c && equalsZero) {
|
|
173
|
-
if(l === 0)
|
|
174
|
-
break;
|
|
175
|
-
this.coeffs.pop();
|
|
176
|
-
}
|
|
177
|
-
else
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return this;
|
|
182
|
-
},
|
|
183
|
-
/*
|
|
184
|
-
* Returns polynomial mod p **currently fails**
|
|
185
|
-
* @param {Number} p
|
|
186
|
-
* @returns {Polynomial}
|
|
187
|
-
*/
|
|
188
|
-
modP: function (p) {
|
|
189
|
-
var l = this.coeffs.length;
|
|
190
|
-
for(var i = 0; i < l; i++) {
|
|
191
|
-
var c = this.coeffs[i];
|
|
192
|
-
if(c < 0) { //go borrow
|
|
193
|
-
var b; //a coefficient > 0
|
|
194
|
-
for(var j = i; j < l; j++) {//starting from where we left off
|
|
195
|
-
if(this.coeffs[j] > 0) {
|
|
196
|
-
b = this.coeffs[j];
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if(b) { //if such a coefficient exists
|
|
202
|
-
for(j; j > i; j--) { //go down the line and adjust using p
|
|
203
|
-
this.coeffs[j] = this.coeffs[j].subtract(new Frac(1));
|
|
204
|
-
this.coeffs[j - 1] = this.coeffs[j - 1].add(new Frac(p));
|
|
205
|
-
}
|
|
206
|
-
c = this.coeffs[i]; //reset c
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
var d = c.mod(p);
|
|
211
|
-
var w = c.subtract(d).divide(p);
|
|
212
|
-
if(!w.equals(0)) {
|
|
213
|
-
var up_one = i + 1;
|
|
214
|
-
var next = this.coeffs[up_one] || new Frac(0);
|
|
215
|
-
next = next.add(w);
|
|
216
|
-
this.coeffs[up_one] = new Frac(next);
|
|
217
|
-
this.coeffs[i] = new Frac(d);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return this;
|
|
222
|
-
},
|
|
223
|
-
/**
|
|
224
|
-
* Adds together 2 polynomials
|
|
225
|
-
* @param {Polynomial} poly
|
|
226
|
-
*/
|
|
227
|
-
add: function (poly) {
|
|
228
|
-
var l = Math.max(this.coeffs.length, poly.coeffs.length);
|
|
229
|
-
for(var i = 0; i < l; i++) {
|
|
230
|
-
var a = (this.coeffs[i] || new Frac(0)),
|
|
231
|
-
b = (poly.coeffs[i] || new Frac(0));
|
|
232
|
-
this.coeffs[i] = a.add(b);
|
|
233
|
-
}
|
|
234
|
-
return this;
|
|
235
|
-
},
|
|
236
|
-
/**
|
|
237
|
-
* Adds together 2 polynomials
|
|
238
|
-
* @param {Polynomial} poly
|
|
239
|
-
*/
|
|
240
|
-
subtract: function (poly) {
|
|
241
|
-
var l = Math.max(this.coeffs.length, poly.coeffs.length);
|
|
242
|
-
for(var i = 0; i < l; i++) {
|
|
243
|
-
var a = (this.coeffs[i] || new Frac(0)),
|
|
244
|
-
b = (poly.coeffs[i] || new Frac(0));
|
|
245
|
-
this.coeffs[i] = a.subtract(b);
|
|
246
|
-
}
|
|
247
|
-
return this;
|
|
248
|
-
},
|
|
249
|
-
divide: function (poly) {
|
|
250
|
-
var variable = this.variable,
|
|
251
|
-
dividend = core.Utils.arrayClone(this.coeffs),
|
|
252
|
-
divisor = core.Utils.arrayClone(poly.coeffs),
|
|
253
|
-
n = dividend.length,
|
|
254
|
-
mp = divisor.length - 1,
|
|
255
|
-
quotient = [];
|
|
256
|
-
|
|
257
|
-
//loop through the dividend
|
|
258
|
-
for(var i = 0; i < n; i++) {
|
|
259
|
-
var p = n - (i + 1);
|
|
260
|
-
//get the difference of the powers
|
|
261
|
-
var d = p - mp;
|
|
262
|
-
//get the quotient of the coefficients
|
|
263
|
-
var q = dividend[p].divide(divisor[mp]);
|
|
264
|
-
|
|
265
|
-
if(d < 0)
|
|
266
|
-
break;//the divisor is not greater than the dividend
|
|
267
|
-
//place it in the quotient
|
|
268
|
-
quotient[d] = q;
|
|
269
|
-
|
|
270
|
-
for(var j = 0; j <= mp; j++) {
|
|
271
|
-
//reduce the dividend
|
|
272
|
-
dividend[j + d] = dividend[j + d].subtract((divisor[j].multiply(q)));
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
//clean up
|
|
277
|
-
var p1 = Polynomial.fromArray(dividend, variable || 'x').trim(), //pass in x for safety
|
|
278
|
-
p2 = Polynomial.fromArray(quotient, variable || 'x');
|
|
279
|
-
return [p2, p1];
|
|
280
|
-
},
|
|
281
|
-
multiply: function (poly) {
|
|
282
|
-
var l1 = this.coeffs.length, l2 = poly.coeffs.length,
|
|
283
|
-
c = []; //array to be returned
|
|
284
|
-
for(var i = 0; i < l1; i++) {
|
|
285
|
-
var x1 = this.coeffs[i];
|
|
286
|
-
for(var j = 0; j < l2; j++) {
|
|
287
|
-
var k = i + j, //add the powers together
|
|
288
|
-
x2 = poly.coeffs[j],
|
|
289
|
-
e = c[k] || new Frac(0); //get the existing term from the new array
|
|
290
|
-
c[k] = e.add(x1.multiply(x2)); //multiply the coefficients and add to new polynomial array
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
this.coeffs = c;
|
|
294
|
-
return this;
|
|
295
|
-
},
|
|
296
|
-
/**
|
|
297
|
-
* Checks if a polynomial is zero
|
|
298
|
-
* @returns {Boolean}
|
|
299
|
-
*/
|
|
300
|
-
isZero: function () {
|
|
301
|
-
var l = this.coeffs.length;
|
|
302
|
-
for(var i = 0; i < l; i++) {
|
|
303
|
-
var e = this.coeffs[i];
|
|
304
|
-
if(!e.equals(0))
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
return true;
|
|
308
|
-
},
|
|
309
|
-
/**
|
|
310
|
-
* Substitutes in a number n into the polynomial p(n)
|
|
311
|
-
* @param {Number} n
|
|
312
|
-
* @returns {Frac}
|
|
313
|
-
*/
|
|
314
|
-
sub: function (n) {
|
|
315
|
-
var sum = new Frac(0), l = this.coeffs.length;
|
|
316
|
-
for(var i = 0; i < l; i++) {
|
|
317
|
-
var t = this.coeffs[i];
|
|
318
|
-
if(!t.equals(0))
|
|
319
|
-
sum = sum.add(t.multiply(new Frac(Math.pow(n, i))));
|
|
320
|
-
}
|
|
321
|
-
return sum;
|
|
322
|
-
},
|
|
323
|
-
/**
|
|
324
|
-
* Returns a clone of the polynomial
|
|
325
|
-
* @returns {Polynomial}
|
|
326
|
-
*/
|
|
327
|
-
clone: function () {
|
|
328
|
-
var p = new Polynomial();
|
|
329
|
-
p.coeffs = this.coeffs;
|
|
330
|
-
p.variable = this.variable;
|
|
331
|
-
return p;
|
|
332
|
-
},
|
|
333
|
-
/**
|
|
334
|
-
* Gets the degree of the polynomial
|
|
335
|
-
* @returns {Number}
|
|
336
|
-
*/
|
|
337
|
-
deg: function () {
|
|
338
|
-
this.trim();
|
|
339
|
-
return this.coeffs.length - 1;
|
|
340
|
-
},
|
|
341
|
-
/**
|
|
342
|
-
* Returns a lead coefficient
|
|
343
|
-
* @returns {Frac}
|
|
344
|
-
*/
|
|
345
|
-
lc: function () {
|
|
346
|
-
return this.coeffs[this.deg()].clone();
|
|
347
|
-
},
|
|
348
|
-
/**
|
|
349
|
-
* Converts polynomial into a monic polynomial
|
|
350
|
-
* @returns {Polynomial}
|
|
351
|
-
*/
|
|
352
|
-
monic: function () {
|
|
353
|
-
var lc = this.lc(), l = this.coeffs.length;
|
|
354
|
-
for(var i = 0; i < l; i++)
|
|
355
|
-
this.coeffs[i] = this.coeffs[i].divide(lc);
|
|
356
|
-
return this;
|
|
357
|
-
},
|
|
358
|
-
/**
|
|
359
|
-
* Returns the GCD of two polynomials
|
|
360
|
-
* @param {Polynomial} poly
|
|
361
|
-
* @returns {Polynomial}
|
|
362
|
-
*/
|
|
363
|
-
gcd: function (poly) {
|
|
364
|
-
//get the maximum power of each
|
|
365
|
-
var mp1 = this.coeffs.length - 1,
|
|
366
|
-
mp2 = poly.coeffs.length - 1,
|
|
367
|
-
T;
|
|
368
|
-
//swap so we always have the greater power first
|
|
369
|
-
if(mp1 < mp2) {
|
|
370
|
-
return poly.gcd(this);
|
|
371
|
-
}
|
|
372
|
-
var a = this;
|
|
373
|
-
|
|
374
|
-
while(!poly.isZero()) {
|
|
375
|
-
var t = poly.clone();
|
|
376
|
-
a = a.clone();
|
|
377
|
-
T = a.divide(t);
|
|
378
|
-
poly = T[1];
|
|
379
|
-
a = t;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
var gcd = core.Math2.QGCD.apply(null, a.coeffs);
|
|
383
|
-
if(!gcd.equals(1)) {
|
|
384
|
-
var l = a.coeffs.length;
|
|
385
|
-
for(var i = 0; i < l; i++) {
|
|
386
|
-
a.coeffs[i] = a.coeffs[i].divide(gcd);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return a;
|
|
390
|
-
},
|
|
391
|
-
/**
|
|
392
|
-
* Differentiates the polynomial
|
|
393
|
-
* @returns {Polynomial}
|
|
394
|
-
*/
|
|
395
|
-
diff: function () {
|
|
396
|
-
var new_array = [], l = this.coeffs.length;
|
|
397
|
-
for(var i = 1; i < l; i++)
|
|
398
|
-
new_array.push(this.coeffs[i].multiply(new Frac(i)));
|
|
399
|
-
this.coeffs = new_array;
|
|
400
|
-
return this;
|
|
401
|
-
},
|
|
402
|
-
/**
|
|
403
|
-
* Integrates the polynomial
|
|
404
|
-
* @returns {Polynomial}
|
|
405
|
-
*/
|
|
406
|
-
integrate: function () {
|
|
407
|
-
var new_array = [0], l = this.coeffs.length;
|
|
408
|
-
for(var i = 0; i < l; i++) {
|
|
409
|
-
var c = new Frac(i + 1);
|
|
410
|
-
new_array[c] = this.coeffs[i].divide(c);
|
|
411
|
-
}
|
|
412
|
-
this.coeffs = new_array;
|
|
413
|
-
return this;
|
|
414
|
-
},
|
|
415
|
-
/**
|
|
416
|
-
* Returns the Greatest common factor of the polynomial
|
|
417
|
-
* @param {bool} toPolynomial - true if a polynomial is wanted
|
|
418
|
-
* @returns {Frac|Polynomial}
|
|
419
|
-
*/
|
|
420
|
-
gcf: function (toPolynomial) {
|
|
421
|
-
//get the first nozero coefficient and returns its power
|
|
422
|
-
var fnz = function (a) {
|
|
423
|
-
for(var i = 0; i < a.length; i++)
|
|
424
|
-
if(!a[i].equals(0))
|
|
425
|
-
return i;
|
|
426
|
-
},
|
|
427
|
-
ca = [];
|
|
428
|
-
for(var i = 0; i < this.coeffs.length; i++) {
|
|
429
|
-
var c = this.coeffs[i];
|
|
430
|
-
if(!c.equals(0) && ca.indexOf(c) === -1)
|
|
431
|
-
ca.push(c);
|
|
432
|
-
}
|
|
433
|
-
var p = [core.Math2.QGCD.apply(undefined, ca), fnz(this.coeffs)].toDecimal();
|
|
434
|
-
|
|
435
|
-
if(toPolynomial) {
|
|
436
|
-
var parr = [];
|
|
437
|
-
parr[p[1] - 1] = p[0];
|
|
438
|
-
p = Polynomial.fromArray(parr, this.variable).fill();
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
return p;
|
|
442
|
-
},
|
|
443
|
-
/**
|
|
444
|
-
* Raises a polynomial P to a power p -> P^p. e.g. (x+1)^2
|
|
445
|
-
* @param {bool} incl_img - Include imaginary numbers
|
|
446
|
-
*/
|
|
447
|
-
quad: function (incl_img) {
|
|
448
|
-
var roots = [];
|
|
449
|
-
if(this.coeffs.length > 3)
|
|
450
|
-
throw new Error('Cannot calculate quadratic order of ' + (this.coeffs.length - 1));
|
|
451
|
-
if(this.coeffs.length === 0)
|
|
452
|
-
throw new Error('Polynomial array has no terms');
|
|
453
|
-
var a = this.coeffs[2] || 0, b = this.coeffs[1] || 0, c = this.coeffs[0];
|
|
454
|
-
var dsc = b * b - 4 * a * c;
|
|
455
|
-
if(dsc < 0 && !incl_img)
|
|
456
|
-
return roots;
|
|
457
|
-
else {
|
|
458
|
-
roots[0] = (-b + Math.sqrt(dsc)) / (2 * a);
|
|
459
|
-
roots[1] = (-b - Math.sqrt(dsc)) / (2 * a);
|
|
460
|
-
}
|
|
461
|
-
return roots;
|
|
462
|
-
},
|
|
463
|
-
/**
|
|
464
|
-
* Makes polynomial square free
|
|
465
|
-
* @returns {Array}
|
|
466
|
-
*/
|
|
467
|
-
squareFree: function () {
|
|
468
|
-
|
|
469
|
-
var a = this.clone(),
|
|
470
|
-
i = 1,
|
|
471
|
-
b = a.clone().diff(),
|
|
472
|
-
c = a.clone().gcd(b),
|
|
473
|
-
w = a.divide(c)[0];
|
|
474
|
-
var output = Polynomial.fromArray([new Frac(1)], a.variable);
|
|
475
|
-
while(!c.equalsNumber(1)) {
|
|
476
|
-
var y = w.gcd(c);
|
|
477
|
-
var z = w.divide(y)[0];
|
|
478
|
-
//one of the factors may have shown up since it's square but smaller than the
|
|
479
|
-
//one where finding
|
|
480
|
-
if(!z.equalsNumber(1) && i > 1) {
|
|
481
|
-
var t = z.clone();
|
|
482
|
-
for(var j = 1; j < i; j++)
|
|
483
|
-
t.multiply(z.clone());
|
|
484
|
-
z = t;
|
|
485
|
-
}
|
|
486
|
-
output = output.multiply(z);
|
|
487
|
-
i++;
|
|
488
|
-
w = y;
|
|
489
|
-
c = c.divide(y)[0];
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
return [output, w, i];
|
|
493
|
-
},
|
|
494
|
-
/**
|
|
495
|
-
* Converts polynomial to Symbol
|
|
496
|
-
* @returns {Symbol}
|
|
497
|
-
*/
|
|
498
|
-
toSymbol: function () {
|
|
499
|
-
var l = this.coeffs.length,
|
|
500
|
-
variable = this.variable;
|
|
501
|
-
if(l === 0)
|
|
502
|
-
return new core.Symbol(0);
|
|
503
|
-
var end = l - 1, str = '';
|
|
504
|
-
|
|
505
|
-
for(var i = 0; i < l; i++) {
|
|
506
|
-
//place the plus sign for all but the last one
|
|
507
|
-
var plus = i === end ? '' : '+',
|
|
508
|
-
e = this.coeffs[i];
|
|
509
|
-
if(!e.equals(0))
|
|
510
|
-
str += (e + '*' + variable + '^' + i + plus);
|
|
511
|
-
}
|
|
512
|
-
return _.parse(str);
|
|
513
|
-
},
|
|
514
|
-
/**
|
|
515
|
-
* Checks if polynomial is equal to a number
|
|
516
|
-
* @param {Number} x
|
|
517
|
-
* @returns {Boolean}
|
|
518
|
-
*/
|
|
519
|
-
equalsNumber: function (x) {
|
|
520
|
-
this.trim();
|
|
521
|
-
return this.coeffs.length === 1 && this.coeffs[0].toDecimal() === String(x);
|
|
522
|
-
},
|
|
523
|
-
toString: function () {
|
|
524
|
-
return this.toSymbol().toString();
|
|
525
|
-
}
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* TODO
|
|
530
|
-
* ===================================================================================
|
|
531
|
-
* THIS METHOD HAS A NASTY HIDDEN BUG. IT HAS INCONSISTENT RETURN TYPES PRIMARILY DUE TO
|
|
532
|
-
* WRONG ASSUMPTIONS AT THE BEGINNING. THE ASSUMPTION WAS THAT COEFFS WERE ALWAYS GOING BE NUMBERS
|
|
533
|
-
* NOT TAKING INTO ACCOUNT THAT IMAGINARY NUMBERS. FIXING THIS BREAKS WAY TOO MANY TESTS
|
|
534
|
-
* AT THEM MOMENT WHICH I DON'T HAVE TO FIX
|
|
535
|
-
* ===================================================================================
|
|
536
|
-
* If the symbols is of group PL or CP it will return the multipliers of each symbol
|
|
537
|
-
* as these are polynomial coefficients. CB symbols are glued together by multiplication
|
|
538
|
-
* so the symbol multiplier carries the coefficients for all contained symbols.
|
|
539
|
-
* For S it just returns it's own multiplier. This function doesn't care if it's a polynomial or not
|
|
540
|
-
* @param {Array} c The coefficient array
|
|
541
|
-
* @param {boolean} with_order
|
|
542
|
-
* @return {Array}
|
|
543
|
-
*/
|
|
544
|
-
Symbol.prototype.coeffs = function (c, with_order) {
|
|
545
|
-
if(with_order && !this.isPoly(true))
|
|
546
|
-
_.error('Polynomial expected when requesting coefficients with order');
|
|
547
|
-
c = c || [];
|
|
548
|
-
var s = this.clone().distributeMultiplier();
|
|
549
|
-
if(s.isComposite()) {
|
|
550
|
-
for(var x in s.symbols) {
|
|
551
|
-
var sub = s.symbols[x];
|
|
552
|
-
if(sub.isComposite()) {
|
|
553
|
-
sub.clone().distributeMultiplier().coeffs(c, with_order);
|
|
554
|
-
}
|
|
555
|
-
else {
|
|
556
|
-
if(with_order)
|
|
557
|
-
c[sub.isConstant() ? 0 : sub.power.toDecimal()] = sub.multiplier;
|
|
558
|
-
else {
|
|
559
|
-
c.push(sub.multiplier);
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
else {
|
|
565
|
-
if(with_order)
|
|
566
|
-
c[s.isConstant(true) ? 0 : s.power.toDecimal()] = s.multiplier;
|
|
567
|
-
else {
|
|
568
|
-
if(s.group === CB && s.isImaginary()) {
|
|
569
|
-
var m = new Symbol(s.multiplier);
|
|
570
|
-
s.each(function (x) {
|
|
571
|
-
//add the imaginary part
|
|
572
|
-
if(x.isConstant(true) || x.imaginary)
|
|
573
|
-
m = _.multiply(m, x);
|
|
574
|
-
});
|
|
575
|
-
c.push(m);
|
|
576
|
-
}
|
|
577
|
-
else
|
|
578
|
-
c.push(s.multiplier);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
//fill the holes
|
|
582
|
-
if(with_order) {
|
|
583
|
-
for(var i = 0; i < c.length; i++)
|
|
584
|
-
if(c[i] === undefined)
|
|
585
|
-
c[i] = new Symbol(0);
|
|
586
|
-
}
|
|
587
|
-
return c;
|
|
588
|
-
};
|
|
589
|
-
Symbol.prototype.tBase = function (map) {
|
|
590
|
-
if(typeof map === 'undefined')
|
|
591
|
-
throw new Error('Symbol.tBase requires a map object!');
|
|
592
|
-
var terms = [];
|
|
593
|
-
var symbols = this.collectSymbols(null, null, null, true),
|
|
594
|
-
l = symbols.length;
|
|
595
|
-
for(var i = 0; i < l; i++) {
|
|
596
|
-
var symbol = symbols[i],
|
|
597
|
-
g = symbol.group,
|
|
598
|
-
nterm = new MVTerm(symbol.multiplier, [], map);
|
|
599
|
-
if(g === CB) {
|
|
600
|
-
for(var x in symbol.symbols) {
|
|
601
|
-
var sym = symbol.symbols[x];
|
|
602
|
-
nterm.terms[map[x]] = sym.power;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
nterm.terms[map[symbol.value]] = symbol.power;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
terms.push(nterm.fill());
|
|
610
|
-
nterm.updateCount();
|
|
611
|
-
}
|
|
612
|
-
return terms;
|
|
613
|
-
};
|
|
614
|
-
Symbol.prototype.altVar = function (x) {
|
|
615
|
-
var m = this.multiplier.toString(), p = this.power.toString();
|
|
616
|
-
return (m === '1' ? '' : m + '*') + x + (p === '1' ? '' : '^' + p);
|
|
617
|
-
};
|
|
618
|
-
/**
|
|
619
|
-
* Checks to see if the symbols contain the same variables
|
|
620
|
-
* @param {Symbol} symbol
|
|
621
|
-
* @returns {Boolean}
|
|
622
|
-
*/
|
|
623
|
-
Symbol.prototype.sameVars = function (symbol) {
|
|
624
|
-
if(!(this.symbols || this.group === symbol.group))
|
|
625
|
-
return false;
|
|
626
|
-
for(var x in this.symbols) {
|
|
627
|
-
var a = this.symbols[x], b = symbol.symbols[x];
|
|
628
|
-
if(!b)
|
|
629
|
-
return false;
|
|
630
|
-
if(a.value !== b.value)
|
|
631
|
-
return false;
|
|
632
|
-
}
|
|
633
|
-
return true;
|
|
634
|
-
};
|
|
635
|
-
/**
|
|
636
|
-
* Groups the terms in a symbol with respect to a variable
|
|
637
|
-
* For instance the symbol {a*b^2*x^2+a*b*x^2+x+6} returns [6,1,a*b+a*b^2]
|
|
638
|
-
* @returns {Factors}
|
|
639
|
-
*/
|
|
640
|
-
Symbol.prototype.groupTerms = function (x) {
|
|
641
|
-
x = String(x);
|
|
642
|
-
var f, p, egrouped;
|
|
643
|
-
var grouped = [];
|
|
644
|
-
this.each(function (e) {
|
|
645
|
-
if(e.group === PL) {
|
|
646
|
-
egrouped = e.groupTerms(x);
|
|
647
|
-
for(var i = 0; i < egrouped.length; i++) {
|
|
648
|
-
var el = egrouped[i];
|
|
649
|
-
if(el)
|
|
650
|
-
grouped[i] = el;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
else {
|
|
654
|
-
f = core.Utils.decompose_fn(e, x, true);
|
|
655
|
-
p = f.x.value === x ? Number(f.x.power) : 0;
|
|
656
|
-
//check if there's an existing value
|
|
657
|
-
grouped[p] = _.add(grouped[p] || new Symbol(0), f.a);
|
|
658
|
-
}
|
|
659
|
-
});
|
|
660
|
-
return grouped;
|
|
661
|
-
};
|
|
662
|
-
/**
|
|
663
|
-
* Use this to collect Factors
|
|
664
|
-
* @returns {Symbol[]}
|
|
665
|
-
*/
|
|
666
|
-
Symbol.prototype.collectFactors = function () {
|
|
667
|
-
var factors = [];
|
|
668
|
-
if(this.group === CB)
|
|
669
|
-
this.each(function (x) {
|
|
670
|
-
factors.push(x.clone());
|
|
671
|
-
});
|
|
672
|
-
else
|
|
673
|
-
factors.push(this.clone());
|
|
674
|
-
return factors;
|
|
675
|
-
};
|
|
676
|
-
/**
|
|
677
|
-
* A container class for factors
|
|
678
|
-
* @returns {Factors}
|
|
679
|
-
*/
|
|
680
|
-
function Factors() {
|
|
681
|
-
this.factors = {};
|
|
682
|
-
this.length = 0;
|
|
683
|
-
}
|
|
684
|
-
;
|
|
685
|
-
Factors.prototype.getNumberSymbolics = function () {
|
|
686
|
-
var n = 0;
|
|
687
|
-
this.each(function (x) {
|
|
688
|
-
if(!x.isConstant(true))
|
|
689
|
-
n++;
|
|
690
|
-
});
|
|
691
|
-
return n;
|
|
692
|
-
};
|
|
693
|
-
/**
|
|
694
|
-
* Adds the factors to the factor object
|
|
695
|
-
* @param {Symbo} s
|
|
696
|
-
* @returns {Factors}
|
|
697
|
-
*/
|
|
698
|
-
Factors.prototype.add = function (s) {
|
|
699
|
-
if(s.equals(0))
|
|
700
|
-
return this; //nothing to add
|
|
701
|
-
|
|
702
|
-
//we don't want to carry -1 as a factor. If a factor already exists,
|
|
703
|
-
//then add the minus one to that factor and return.
|
|
704
|
-
if(s.equals(-1) && this.length > 0) {
|
|
705
|
-
var fo = core.Utils.firstObject(this.factors, null, true);
|
|
706
|
-
this.add(_.symfunction(core.Settings.PARENTHESIS, [fo.obj]).negate());
|
|
707
|
-
delete this.factors[fo.key];
|
|
708
|
-
this.length--;
|
|
709
|
-
return this;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
if(s.group === CB) {
|
|
713
|
-
var factors = this;
|
|
714
|
-
if(!s.multiplier.equals(1))
|
|
715
|
-
factors.add(new Symbol(s.multiplier));
|
|
716
|
-
s.each(function (x) {
|
|
717
|
-
factors.add(x);
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
else {
|
|
721
|
-
if(this.preAdd) //if a preAdd function was defined call it to do prep
|
|
722
|
-
s = this.preAdd(s);
|
|
723
|
-
if(this.pFactor) //if the symbol isn't linear add back the power
|
|
724
|
-
s = _.pow(s, new Symbol(this.pFactor));
|
|
725
|
-
|
|
726
|
-
var is_constant = s.isConstant();
|
|
727
|
-
if(is_constant && s.equals(1))
|
|
728
|
-
return this; //don't add 1
|
|
729
|
-
var v = is_constant ? s.value : s.text();
|
|
730
|
-
if(v in this.factors) {
|
|
731
|
-
this.factors[v] = _.multiply(this.factors[v], s);
|
|
732
|
-
//did the addition cancel out the existing factor? If so remove it and decrement the length
|
|
733
|
-
if(this.factors[v].equals(1)) {
|
|
734
|
-
delete this.factors[v];
|
|
735
|
-
this.length--;
|
|
736
|
-
}
|
|
737
|
-
}
|
|
738
|
-
else {
|
|
739
|
-
this.factors[v] = s;
|
|
740
|
-
this.length++;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
return this;
|
|
744
|
-
};
|
|
745
|
-
/**
|
|
746
|
-
* Converts the factor object to a Symbol
|
|
747
|
-
* @returns {Symbol}
|
|
748
|
-
*/
|
|
749
|
-
Factors.prototype.toSymbol = function () {
|
|
750
|
-
var factored = new Symbol(1);
|
|
751
|
-
var factors = Object.values(this.factors).sort(function (a, b) {
|
|
752
|
-
return a.group > b.group;
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
for(var i = 0, l = factors.length; i < l; i++) {
|
|
756
|
-
var f = factors[i];
|
|
757
|
-
|
|
758
|
-
//don't wrap group S or FN
|
|
759
|
-
var factor = f.power.equals(1) && f.fname !== '' /* don't wrap it twice */ ?
|
|
760
|
-
_.symfunction(core.PARENTHESIS, [f]) : f;
|
|
761
|
-
|
|
762
|
-
factored = _.multiply(factored, factor);
|
|
763
|
-
}
|
|
764
|
-
if(factored.fname === '')
|
|
765
|
-
factored = Symbol.unwrapPARENS(factored);
|
|
766
|
-
return factored;
|
|
767
|
-
};
|
|
768
|
-
/**
|
|
769
|
-
* Merges 2 factor objects into one
|
|
770
|
-
* @param {Factor} o
|
|
771
|
-
* @returns {Factors}
|
|
772
|
-
*/
|
|
773
|
-
Factors.prototype.merge = function (o) {
|
|
774
|
-
for(var x in o) {
|
|
775
|
-
if(x in this.factors)
|
|
776
|
-
this.factors[x] = _.multiply(this.factors[x], o[x]);
|
|
777
|
-
else
|
|
778
|
-
this.factors[x] = o[x];
|
|
779
|
-
}
|
|
780
|
-
return this;
|
|
781
|
-
};
|
|
782
|
-
/**
|
|
783
|
-
* The iterator for the factor object
|
|
784
|
-
* @param {Function} f - callback
|
|
785
|
-
* @returns {Factor}
|
|
786
|
-
*/
|
|
787
|
-
Factors.prototype.each = function (f) {
|
|
788
|
-
for(var x in this.factors) {
|
|
789
|
-
var factor = this.factors[x];
|
|
790
|
-
if(factor.fname === core.PARENTHESIS && factor.isLinear())
|
|
791
|
-
factor = factor.args[0];
|
|
792
|
-
f.call(this, factor, x);
|
|
793
|
-
}
|
|
794
|
-
return this;
|
|
795
|
-
};
|
|
796
|
-
/**
|
|
797
|
-
* Return the number of factors contained in the factor object
|
|
798
|
-
* @returns {int}
|
|
799
|
-
*/
|
|
800
|
-
Factors.prototype.count = function () {
|
|
801
|
-
return keys(this.factors).length;
|
|
802
|
-
};
|
|
803
|
-
/**
|
|
804
|
-
* Cleans up factors from -1
|
|
805
|
-
* @returns {undefined}
|
|
806
|
-
*/
|
|
807
|
-
Factors.prototype.clean = function () {
|
|
808
|
-
try {
|
|
809
|
-
var h = core.Settings.CONST_HASH;
|
|
810
|
-
if(this.factors[h].lessThan(0)) {
|
|
811
|
-
if(this.factors[h].equals(-1))
|
|
812
|
-
delete this.factors[h];
|
|
813
|
-
else
|
|
814
|
-
this.factors[h].negate();
|
|
815
|
-
this.each(function (x) {
|
|
816
|
-
x.negate();
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
catch(e) {
|
|
821
|
-
}
|
|
822
|
-
;
|
|
823
|
-
};
|
|
824
|
-
Factors.prototype.toString = function () {
|
|
825
|
-
return this.toSymbol().toString();
|
|
826
|
-
};
|
|
827
|
-
|
|
828
|
-
//a wrapper for performing multivariate division
|
|
829
|
-
function MVTerm(coeff, terms, map) {
|
|
830
|
-
this.terms = terms || [];
|
|
831
|
-
this.coeff = coeff;
|
|
832
|
-
this.map = map; //careful! all maps are the same object
|
|
833
|
-
this.sum = new core.Frac(0);
|
|
834
|
-
this.image = undefined;
|
|
835
|
-
}
|
|
836
|
-
;
|
|
837
|
-
MVTerm.prototype.updateCount = function () {
|
|
838
|
-
this.count = this.count || 0;
|
|
839
|
-
for(var i = 0; i < this.terms.length; i++) {
|
|
840
|
-
if(!this.terms[i].equals(0))
|
|
841
|
-
this.count++;
|
|
842
|
-
}
|
|
843
|
-
return this;
|
|
844
|
-
};
|
|
845
|
-
MVTerm.prototype.getVars = function () {
|
|
846
|
-
var vars = [];
|
|
847
|
-
for(var i = 0; i < this.terms.length; i++) {
|
|
848
|
-
var term = this.terms[i],
|
|
849
|
-
rev_map = this.getRevMap();
|
|
850
|
-
if(!term.equals(0))
|
|
851
|
-
vars.push(this.rev_map[i]);
|
|
852
|
-
}
|
|
853
|
-
return vars.join(' ');
|
|
854
|
-
};
|
|
855
|
-
MVTerm.prototype.len = function () {
|
|
856
|
-
if(typeof this.count === 'undefined') {
|
|
857
|
-
this.updateCount();
|
|
858
|
-
}
|
|
859
|
-
return this.count;
|
|
860
|
-
};
|
|
861
|
-
MVTerm.prototype.toSymbol = function (rev_map) {
|
|
862
|
-
rev_map = rev_map || this.getRevMap();
|
|
863
|
-
var symbol = new Symbol(this.coeff);
|
|
864
|
-
for(var i = 0; i < this.terms.length; i++) {
|
|
865
|
-
var v = rev_map[i],
|
|
866
|
-
t = this.terms[i];
|
|
867
|
-
if(t.equals(0) || v === CONST_HASH)
|
|
868
|
-
continue;
|
|
869
|
-
var mapped = new Symbol(v);
|
|
870
|
-
mapped.power = t;
|
|
871
|
-
symbol = _.multiply(symbol, mapped);
|
|
872
|
-
}
|
|
873
|
-
return symbol;
|
|
874
|
-
};
|
|
875
|
-
MVTerm.prototype.getRevMap = function () {
|
|
876
|
-
if(this.rev_map)
|
|
877
|
-
return this.rev_map;
|
|
878
|
-
var o = {};
|
|
879
|
-
for(var x in this.map)
|
|
880
|
-
o[this.map[x]] = x;
|
|
881
|
-
this.rev_map = o;
|
|
882
|
-
return o;
|
|
883
|
-
};
|
|
884
|
-
MVTerm.prototype.generateImage = function () {
|
|
885
|
-
this.image = this.terms.join(' ');
|
|
886
|
-
return this;
|
|
887
|
-
},
|
|
888
|
-
MVTerm.prototype.getImg = function () {
|
|
889
|
-
if(!this.image)
|
|
890
|
-
this.generateImage();
|
|
891
|
-
return this.image;
|
|
892
|
-
},
|
|
893
|
-
MVTerm.prototype.fill = function () {
|
|
894
|
-
var l = this.map.length;
|
|
895
|
-
for(var i = 0; i < l; i++) {
|
|
896
|
-
if(typeof this.terms[i] === 'undefined')
|
|
897
|
-
this.terms[i] = new core.Frac(0);
|
|
898
|
-
else {
|
|
899
|
-
this.sum = this.sum.add(this.terms[i]);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
return this;
|
|
903
|
-
};
|
|
904
|
-
MVTerm.prototype.divide = function (mvterm) {
|
|
905
|
-
var c = this.coeff.divide(mvterm.coeff),
|
|
906
|
-
l = this.terms.length,
|
|
907
|
-
new_mvterm = new MVTerm(c, [], this.map);
|
|
908
|
-
for(var i = 0; i < l; i++) {
|
|
909
|
-
new_mvterm.terms[i] = this.terms[i].subtract(mvterm.terms[i]);
|
|
910
|
-
new_mvterm.sum = new_mvterm.sum.add(new_mvterm.terms[i]);
|
|
911
|
-
}
|
|
912
|
-
return new_mvterm;
|
|
913
|
-
};
|
|
914
|
-
MVTerm.prototype.multiply = function (mvterm) {
|
|
915
|
-
var c = this.coeff.multiply(mvterm.coeff),
|
|
916
|
-
l = this.terms.length,
|
|
917
|
-
new_mvterm = new MVTerm(c, [], this.map);
|
|
918
|
-
for(var i = 0; i < l; i++) {
|
|
919
|
-
new_mvterm.terms[i] = this.terms[i].add(mvterm.terms[i]);
|
|
920
|
-
new_mvterm.sum = new_mvterm.sum.add(new_mvterm.terms[i]);
|
|
921
|
-
}
|
|
922
|
-
return new_mvterm;
|
|
923
|
-
};
|
|
924
|
-
MVTerm.prototype.isZero = function () {
|
|
925
|
-
return this.coeff.equals(0);
|
|
926
|
-
};
|
|
927
|
-
MVTerm.prototype.toString = function () {
|
|
928
|
-
return '{ coeff: ' + this.coeff.toString() + ', terms: [' +
|
|
929
|
-
this.terms.join(',') + ']: sum: ' + this.sum.toString() + ', count: ' + this.count + '}';
|
|
930
|
-
};
|
|
931
|
-
|
|
932
|
-
core.Utils.toMapObj = function (arr) {
|
|
933
|
-
var c = 0, o = {};
|
|
934
|
-
for(var i = 0; i < arr.length; i++) {
|
|
935
|
-
var v = arr[i];
|
|
936
|
-
if(typeof o[v] === 'undefined') {
|
|
937
|
-
o[v] = c;
|
|
938
|
-
c++;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
o.length = c;
|
|
942
|
-
return o;
|
|
943
|
-
};
|
|
944
|
-
core.Utils.filledArray = function (v, n, clss) {
|
|
945
|
-
var a = [];
|
|
946
|
-
while(n--) {
|
|
947
|
-
a[n] = clss ? new clss(v) : v;
|
|
948
|
-
}
|
|
949
|
-
return a;
|
|
950
|
-
};
|
|
951
|
-
core.Utils.arrSum = function (arr) {
|
|
952
|
-
var sum = 0, l = arr.length;
|
|
953
|
-
for(var i = 0; i < l; i++)
|
|
954
|
-
sum += arr[i];
|
|
955
|
-
return sum;
|
|
956
|
-
};
|
|
957
|
-
/**
|
|
958
|
-
* Determines if 2 arrays have intersecting elements.
|
|
959
|
-
* @param {Array} a
|
|
960
|
-
* @param {Array} b
|
|
961
|
-
* @returns {Boolean} True if a and b have intersecting elements.
|
|
962
|
-
*/
|
|
963
|
-
core.Utils.haveIntersection = function (a, b) {
|
|
964
|
-
var t;
|
|
965
|
-
if(b.length > a.length)
|
|
966
|
-
t = b, b = a, a = t; // indexOf to loop over shorter
|
|
967
|
-
return a.some(function (e) {
|
|
968
|
-
return b.indexOf(e) > -1;
|
|
969
|
-
});
|
|
970
|
-
};
|
|
971
|
-
/**
|
|
972
|
-
* Substitutes out functions as variables so they can be used in regular algorithms
|
|
973
|
-
* @param {Symbol} symbol
|
|
974
|
-
* @param {Object} map
|
|
975
|
-
* @returns {String} The expression string
|
|
976
|
-
*/
|
|
977
|
-
core.Utils.subFunctions = function (symbol, map) {
|
|
978
|
-
map = map || {};
|
|
979
|
-
var subbed = [];
|
|
980
|
-
symbol.each(function (x) {
|
|
981
|
-
if(x.group === FN || x.previousGroup === FN) {
|
|
982
|
-
//we need a new variable name so why not use one of the existing
|
|
983
|
-
var val = core.Utils.text(x, 'hash'), tvar = map[val];
|
|
984
|
-
if(!tvar) {
|
|
985
|
-
//generate a unique enough name
|
|
986
|
-
var t = x.fname + keys(map).length;
|
|
987
|
-
map[val] = t;
|
|
988
|
-
subbed.push(x.altVar(t));
|
|
989
|
-
}
|
|
990
|
-
else
|
|
991
|
-
subbed.push(x.altVar(tvar));
|
|
992
|
-
}
|
|
993
|
-
else if(x.group === CB || x.group === PL || x.group === CP) {
|
|
994
|
-
subbed.push(core.Utils.subFunctions(x, map));
|
|
995
|
-
}
|
|
996
|
-
else
|
|
997
|
-
subbed.push(x.text());
|
|
998
|
-
});
|
|
999
|
-
if(symbol.group === CP || symbol.group === PL)
|
|
1000
|
-
return symbol.altVar(core.Utils.inBrackets(subbed.join('+')));
|
|
1001
|
-
;
|
|
1002
|
-
if(symbol.group === CB)
|
|
1003
|
-
return symbol.altVar(core.Utils.inBrackets(subbed.join('*')));
|
|
1004
|
-
return symbol.text();
|
|
1005
|
-
};
|
|
1006
|
-
core.Utils.getFunctionsSubs = function (map) {
|
|
1007
|
-
var subs = {};
|
|
1008
|
-
//prepare substitutions
|
|
1009
|
-
for(var x in map)
|
|
1010
|
-
subs[map[x]] = _.parse(x);
|
|
1011
|
-
return subs;
|
|
1012
|
-
};
|
|
1013
|
-
|
|
1014
|
-
var __ = core.Algebra = {
|
|
1015
|
-
version: '1.4.6',
|
|
1016
|
-
proots: function (symbol, decp) {
|
|
1017
|
-
//the roots will be rounded up to 7 decimal places.
|
|
1018
|
-
//if this causes trouble you can explicitly pass in a different number of places
|
|
1019
|
-
//rarr for polynomial of power n is of format [n, coeff x^n, coeff x^(n-1), ..., coeff x^0]
|
|
1020
|
-
decp = decp || 7;
|
|
1021
|
-
var zeros = 0;
|
|
1022
|
-
var known_roots = [];
|
|
1023
|
-
var get_roots = function (rarr, powers, max) {
|
|
1024
|
-
var roots = calcroots(rarr, powers, max).concat(known_roots);
|
|
1025
|
-
for(var i = 0; i < zeros; i++)
|
|
1026
|
-
roots.unshift(0);
|
|
1027
|
-
return roots;
|
|
1028
|
-
};
|
|
1029
|
-
|
|
1030
|
-
if(symbol instanceof Symbol && symbol.isPoly()) {
|
|
1031
|
-
symbol.distributeMultiplier();
|
|
1032
|
-
//make it so the symbol has a constants as the lowest term
|
|
1033
|
-
if(symbol.group === PL) {
|
|
1034
|
-
var lowest_pow = core.Utils.arrayMin(keys(symbol.symbols));
|
|
1035
|
-
var lowest_symbol = symbol.symbols[lowest_pow].clone().toUnitMultiplier();
|
|
1036
|
-
symbol = _.expand(_.divide(symbol, lowest_symbol));
|
|
1037
|
-
known_roots.push(0); //add zero since this is a known root
|
|
1038
|
-
}
|
|
1039
|
-
if(symbol.group === core.groups.S) {
|
|
1040
|
-
return [0];
|
|
1041
|
-
}
|
|
1042
|
-
else if(symbol.group === core.groups.PL) {
|
|
1043
|
-
var powers = keys(symbol.symbols),
|
|
1044
|
-
minpower = core.Utils.arrayMin(powers),
|
|
1045
|
-
symbol = core.PARSER.divide(symbol, core.PARSER.parse(symbol.value + '^' + minpower));
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
var variable = keys(symbol.symbols).sort().pop(),
|
|
1049
|
-
sym = symbol.group === core.groups.PL ? symbol.symbols : symbol.symbols[variable],
|
|
1050
|
-
g = sym.group,
|
|
1051
|
-
powers = g === S ? [sym.power.toDecimal()] : keys(sym.symbols),
|
|
1052
|
-
rarr = [],
|
|
1053
|
-
max = core.Utils.arrayMax(powers); //maximum power and degree of polynomial to be solved
|
|
1054
|
-
|
|
1055
|
-
// Prepare the data
|
|
1056
|
-
for(var i = 1; i <= max; i++) {
|
|
1057
|
-
var c = 0; //if there is no power then the hole must be filled with a zero
|
|
1058
|
-
if(powers.indexOf(i + '') !== -1) {
|
|
1059
|
-
if(g === S) {
|
|
1060
|
-
c = sym.multiplier;
|
|
1061
|
-
}
|
|
1062
|
-
else {
|
|
1063
|
-
c = sym.symbols[i].multiplier;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
// Insert the coeffient but from the front
|
|
1067
|
-
rarr.unshift(c);
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
rarr.push(symbol.symbols[CONST_HASH].multiplier);
|
|
1071
|
-
|
|
1072
|
-
if(sym.group === S)
|
|
1073
|
-
rarr[0] = sym.multiplier;//the symbol maybe of group CP with one variable
|
|
1074
|
-
|
|
1075
|
-
return get_roots(rarr, powers, max);
|
|
1076
|
-
}
|
|
1077
|
-
else if(core.Utils.isArray(symbol)) {
|
|
1078
|
-
var parr = symbol;
|
|
1079
|
-
var rarr = [],
|
|
1080
|
-
powers = [],
|
|
1081
|
-
last_power = 0;
|
|
1082
|
-
for(var i = 0; i < parr.length; i++) {
|
|
1083
|
-
|
|
1084
|
-
var coeff = parr[i][0],
|
|
1085
|
-
pow = parr[i][1],
|
|
1086
|
-
d = pow - last_power - 1;
|
|
1087
|
-
//insert the zeros
|
|
1088
|
-
for(var j = 0; j < d; j++)
|
|
1089
|
-
rarr.unshift(0);
|
|
1090
|
-
|
|
1091
|
-
rarr.unshift(coeff);
|
|
1092
|
-
if(pow !== 0)
|
|
1093
|
-
powers.push(pow);
|
|
1094
|
-
last_power = pow;
|
|
1095
|
-
}
|
|
1096
|
-
var max = Math.max.apply(undefined, powers);
|
|
1097
|
-
|
|
1098
|
-
return get_roots(rarr, powers, max);
|
|
1099
|
-
}
|
|
1100
|
-
else {
|
|
1101
|
-
throw new core.exceptions.NerdamerTypeError('Cannot calculate roots. Symbol must be a polynomial!');
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
function calcroots(rarr, powers, max) {
|
|
1105
|
-
var MAXDEGREE = 100; // Degree of largest polynomial accepted by this script.
|
|
1106
|
-
|
|
1107
|
-
// Make a clone of the coefficients before appending the max power
|
|
1108
|
-
var p = rarr.slice(0);
|
|
1109
|
-
|
|
1110
|
-
// Divide the string up into its individual entries, which--presumably--are separated by whitespace
|
|
1111
|
-
rarr.unshift(max);
|
|
1112
|
-
|
|
1113
|
-
if(max > MAXDEGREE) {
|
|
1114
|
-
throw new core.exceptions.ValueLimitExceededError("This utility accepts polynomials of degree up to " + MAXDEGREE + ". ");
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
var zeroi = [], // Vector of imaginary components of roots
|
|
1118
|
-
degreePar = {}; // degreePar is a dummy variable for passing the parameter POLYDEGREE by reference
|
|
1119
|
-
degreePar.Degree = max;
|
|
1120
|
-
|
|
1121
|
-
for(i = 0; i < max; i++) {
|
|
1122
|
-
zeroi.push(0);
|
|
1123
|
-
}
|
|
1124
|
-
var zeror = zeroi.slice(0); // Vector of real components of roots
|
|
1125
|
-
|
|
1126
|
-
// Find the roots
|
|
1127
|
-
//--> Begin Jenkins-Traub
|
|
1128
|
-
|
|
1129
|
-
/*
|
|
1130
|
-
* A verbatim copy of Mr. David Binner's Jenkins-Traub port
|
|
1131
|
-
*/
|
|
1132
|
-
function QuadSD_ak1(NN, u, v, p, q, iPar) {
|
|
1133
|
-
// Divides p by the quadratic 1, u, v placing the quotient in q and the remainder in a, b
|
|
1134
|
-
// iPar is a dummy variable for passing in the two parameters--a and b--by reference
|
|
1135
|
-
q[0] = iPar.b = p[0];
|
|
1136
|
-
q[1] = iPar.a = -(u * iPar.b) + p[1];
|
|
1137
|
-
|
|
1138
|
-
for(var i = 2; i < NN; i++) {
|
|
1139
|
-
q[i] = -(u * iPar.a + v * iPar.b) + p[i];
|
|
1140
|
-
iPar.b = iPar.a;
|
|
1141
|
-
iPar.a = q[i];
|
|
1142
|
-
}
|
|
1143
|
-
return;
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
function calcSC_ak1(DBL_EPSILON, N, a, b, iPar, K, u, v, qk) {
|
|
1147
|
-
// This routine calculates scalar quantities used to compute the next K polynomial and
|
|
1148
|
-
// new estimates of the quadratic coefficients.
|
|
1149
|
-
// calcSC - integer variable set here indicating how the calculations are normalized
|
|
1150
|
-
// to avoid overflow.
|
|
1151
|
-
// iPar is a dummy variable for passing in the nine parameters--a1, a3, a7, c, d, e, f, g, and h --by reference
|
|
1152
|
-
|
|
1153
|
-
// sdPar is a dummy variable for passing the two parameters--c and d--into QuadSD_ak1 by reference
|
|
1154
|
-
var sdPar = new Object(),
|
|
1155
|
-
// TYPE = 3 indicates the quadratic is almost a factor of K
|
|
1156
|
-
dumFlag = 3;
|
|
1157
|
-
|
|
1158
|
-
// Synthetic division of K by the quadratic 1, u, v
|
|
1159
|
-
sdPar.b = sdPar.a = 0.0;
|
|
1160
|
-
QuadSD_ak1(N, u, v, K, qk, sdPar);
|
|
1161
|
-
iPar.c = sdPar.a;
|
|
1162
|
-
iPar.d = sdPar.b;
|
|
1163
|
-
|
|
1164
|
-
if(Math.abs(iPar.c) <= (100.0 * DBL_EPSILON * Math.abs(K[N - 1]))) {
|
|
1165
|
-
if(Math.abs(iPar.d) <= (100.0 * DBL_EPSILON * Math.abs(K[N - 2])))
|
|
1166
|
-
return dumFlag;
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
iPar.h = v * b;
|
|
1170
|
-
if(Math.abs(iPar.d) >= Math.abs(iPar.c)) {
|
|
1171
|
-
// TYPE = 2 indicates that all formulas are divided by d
|
|
1172
|
-
dumFlag = 2;
|
|
1173
|
-
iPar.e = a / (iPar.d);
|
|
1174
|
-
iPar.f = (iPar.c) / (iPar.d);
|
|
1175
|
-
iPar.g = u * b;
|
|
1176
|
-
iPar.a3 = (iPar.e) * ((iPar.g) + a) + (iPar.h) * (b / (iPar.d));
|
|
1177
|
-
iPar.a1 = -a + (iPar.f) * b;
|
|
1178
|
-
iPar.a7 = (iPar.h) + ((iPar.f) + u) * a;
|
|
1179
|
-
}
|
|
1180
|
-
else {
|
|
1181
|
-
// TYPE = 1 indicates that all formulas are divided by c;
|
|
1182
|
-
dumFlag = 1;
|
|
1183
|
-
iPar.e = a / (iPar.c);
|
|
1184
|
-
iPar.f = (iPar.d) / (iPar.c);
|
|
1185
|
-
iPar.g = (iPar.e) * u;
|
|
1186
|
-
iPar.a3 = (iPar.e) * a + ((iPar.g) + (iPar.h) / (iPar.c)) * b;
|
|
1187
|
-
iPar.a1 = -(a * ((iPar.d) / (iPar.c))) + b;
|
|
1188
|
-
iPar.a7 = (iPar.g) * (iPar.d) + (iPar.h) * (iPar.f) + a;
|
|
1189
|
-
}
|
|
1190
|
-
return dumFlag;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
function nextK_ak1(DBL_EPSILON, N, tFlag, a, b, iPar, K, qk, qp) {
|
|
1194
|
-
// Computes the next K polynomials using the scalars computed in calcSC_ak1
|
|
1195
|
-
// iPar is a dummy variable for passing in three parameters--a1, a3, and a7
|
|
1196
|
-
var temp;
|
|
1197
|
-
if(tFlag == 3) { // Use unscaled form of the recurrence
|
|
1198
|
-
K[1] = K[0] = 0.0;
|
|
1199
|
-
for(var i = 2; i < N; i++) {
|
|
1200
|
-
K[i] = qk[i - 2];
|
|
1201
|
-
}
|
|
1202
|
-
return;
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
temp = ((tFlag == 1) ? b : a);
|
|
1206
|
-
if(Math.abs(iPar.a1) > (10.0 * DBL_EPSILON * Math.abs(temp))) {
|
|
1207
|
-
// Use scaled form of the recurrence
|
|
1208
|
-
iPar.a7 /= iPar.a1;
|
|
1209
|
-
iPar.a3 /= iPar.a1;
|
|
1210
|
-
K[0] = qp[0];
|
|
1211
|
-
K[1] = -(qp[0] * iPar.a7) + qp[1];
|
|
1212
|
-
for(var i = 2; i < N; i++)
|
|
1213
|
-
K[i] = -(qp[i - 1] * iPar.a7) + qk[i - 2] * iPar.a3 + qp[i];
|
|
1214
|
-
}
|
|
1215
|
-
else {
|
|
1216
|
-
// If a1 is nearly zero, then use a special form of the recurrence
|
|
1217
|
-
K[0] = 0.0;
|
|
1218
|
-
K[1] = -(qp[0] * iPar.a7);
|
|
1219
|
-
for(var i = 2; i < N; i++) {
|
|
1220
|
-
K[i] = -(qp[i - 1] * iPar.a7) + qk[i - 2] * iPar.a3;
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
return;
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
function newest_ak1(tFlag, iPar, a, a1, a3, a7, b, c, d, f, g, h, u, v, K, N, p) {
|
|
1227
|
-
// Compute new estimates of the quadratic coefficients using the scalars computed in calcSC_ak1
|
|
1228
|
-
// iPar is a dummy variable for passing in the two parameters--uu and vv--by reference
|
|
1229
|
-
// iPar.a = uu, iPar.b = vv
|
|
1230
|
-
|
|
1231
|
-
var a4, a5, b1, b2, c1, c2, c3, c4, temp;
|
|
1232
|
-
iPar.b = iPar.a = 0.0;// The quadratic is zeroed
|
|
1233
|
-
|
|
1234
|
-
if(tFlag != 3) {
|
|
1235
|
-
if(tFlag != 2) {
|
|
1236
|
-
a4 = a + u * b + h * f;
|
|
1237
|
-
a5 = c + (u + v * f) * d;
|
|
1238
|
-
}
|
|
1239
|
-
else {
|
|
1240
|
-
a4 = (a + g) * f + h;
|
|
1241
|
-
a5 = (f + u) * c + v * d;
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
// Evaluate new quadratic coefficients
|
|
1245
|
-
b1 = -(K[N - 1] / p[N]);
|
|
1246
|
-
b2 = -(K[N - 2] + b1 * p[N - 1]) / p[N];
|
|
1247
|
-
c1 = v * b2 * a1;
|
|
1248
|
-
c2 = b1 * a7;
|
|
1249
|
-
c3 = b1 * b1 * a3;
|
|
1250
|
-
c4 = -(c2 + c3) + c1;
|
|
1251
|
-
temp = -c4 + a5 + b1 * a4;
|
|
1252
|
-
if(temp != 0.0) {
|
|
1253
|
-
iPar.a = -((u * (c3 + c2) + v * (b1 * a1 + b2 * a7)) / temp) + u;
|
|
1254
|
-
iPar.b = v * (1.0 + c4 / temp);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
return;
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
function Quad_ak1(a, b1, c, iPar) {
|
|
1261
|
-
// Calculates the zeros of the quadratic a*Z^2 + b1*Z + c
|
|
1262
|
-
// The quadratic formula, modified to avoid overflow, is used to find the larger zero if the
|
|
1263
|
-
// zeros are real and both zeros are complex. The smaller real zero is found directly from
|
|
1264
|
-
// the product of the zeros c/a.
|
|
1265
|
-
|
|
1266
|
-
// iPar is a dummy variable for passing in the four parameters--sr, si, lr, and li--by reference
|
|
1267
|
-
|
|
1268
|
-
var b, d, e;
|
|
1269
|
-
iPar.sr = iPar.si = iPar.lr = iPar.li = 0.0;
|
|
1270
|
-
|
|
1271
|
-
if(a == 0) {
|
|
1272
|
-
iPar.sr = ((b1 != 0) ? -(c / b1) : iPar.sr);
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
if(c == 0) {
|
|
1276
|
-
iPar.lr = -(b1 / a);
|
|
1277
|
-
return;
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
// Compute discriminant avoiding overflow
|
|
1281
|
-
b = b1 / 2.0;
|
|
1282
|
-
if(Math.abs(b) < Math.abs(c)) {
|
|
1283
|
-
e = ((c >= 0) ? a : -a);
|
|
1284
|
-
e = -e + b * (b / Math.abs(c));
|
|
1285
|
-
d = Math.sqrt(Math.abs(e)) * Math.sqrt(Math.abs(c));
|
|
1286
|
-
}
|
|
1287
|
-
else {
|
|
1288
|
-
e = -((a / b) * (c / b)) + 1.0;
|
|
1289
|
-
d = Math.sqrt(Math.abs(e)) * (Math.abs(b));
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
if(e >= 0) {
|
|
1293
|
-
// Real zeros
|
|
1294
|
-
d = ((b >= 0) ? -d : d);
|
|
1295
|
-
iPar.lr = (-b + d) / a;
|
|
1296
|
-
iPar.sr = ((iPar.lr != 0) ? (c / (iPar.lr)) / a : iPar.sr);
|
|
1297
|
-
}
|
|
1298
|
-
else {
|
|
1299
|
-
// Complex conjugate zeros
|
|
1300
|
-
iPar.lr = iPar.sr = -(b / a);
|
|
1301
|
-
iPar.si = Math.abs(d / a);
|
|
1302
|
-
iPar.li = -(iPar.si);
|
|
1303
|
-
}
|
|
1304
|
-
return;
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
function QuadIT_ak1(DBL_EPSILON, N, iPar, uu, vv, qp, NN, sdPar, p, qk, calcPar, K) {
|
|
1308
|
-
// Variable-shift K-polynomial iteration for a quadratic factor converges only if the
|
|
1309
|
-
// zeros are equimodular or nearly so.
|
|
1310
|
-
// iPar is a dummy variable for passing in the five parameters--NZ, lzi, lzr, szi, and szr--by reference
|
|
1311
|
-
// sdPar is a dummy variable for passing the two parameters--a and b--in by reference
|
|
1312
|
-
// calcPar is a dummy variable for passing the nine parameters--a1, a3, a7, c, d, e, f, g, and h --in by reference
|
|
1313
|
-
|
|
1314
|
-
// qPar is a dummy variable for passing the four parameters--szr, szi, lzr, and lzi--into Quad_ak1 by reference
|
|
1315
|
-
var qPar = new Object(),
|
|
1316
|
-
ee, mp, omp, relstp, t, u, ui, v, vi, zm,
|
|
1317
|
-
i, j = 0, tFlag, triedFlag = 0; // Integer variables
|
|
1318
|
-
|
|
1319
|
-
iPar.NZ = 0;// Number of zeros found
|
|
1320
|
-
u = uu; // uu and vv are coefficients of the starting quadratic
|
|
1321
|
-
v = vv;
|
|
1322
|
-
|
|
1323
|
-
do {
|
|
1324
|
-
qPar.li = qPar.lr = qPar.si = qPar.sr = 0.0;
|
|
1325
|
-
Quad_ak1(1.0, u, v, qPar);
|
|
1326
|
-
iPar.szr = qPar.sr;
|
|
1327
|
-
iPar.szi = qPar.si;
|
|
1328
|
-
iPar.lzr = qPar.lr;
|
|
1329
|
-
iPar.lzi = qPar.li;
|
|
1330
|
-
|
|
1331
|
-
// Return if roots of the quadratic are real and not close to multiple or nearly
|
|
1332
|
-
// equal and of opposite sign.
|
|
1333
|
-
if(Math.abs(Math.abs(iPar.szr) - Math.abs(iPar.lzr)) > 0.01 * Math.abs(iPar.lzr))
|
|
1334
|
-
break;
|
|
1335
|
-
|
|
1336
|
-
// Evaluate polynomial by quadratic synthetic division
|
|
1337
|
-
|
|
1338
|
-
QuadSD_ak1(NN, u, v, p, qp, sdPar);
|
|
1339
|
-
|
|
1340
|
-
mp = Math.abs(-((iPar.szr) * (sdPar.b)) + (sdPar.a)) + Math.abs((iPar.szi) * (sdPar.b));
|
|
1341
|
-
|
|
1342
|
-
// Compute a rigorous bound on the rounding error in evaluating p
|
|
1343
|
-
|
|
1344
|
-
zm = Math.sqrt(Math.abs(v));
|
|
1345
|
-
ee = 2.0 * Math.abs(qp[0]);
|
|
1346
|
-
t = -((iPar.szr) * (sdPar.b));
|
|
1347
|
-
|
|
1348
|
-
for(i = 1; i < N; i++) {
|
|
1349
|
-
ee = ee * zm + Math.abs(qp[i]);
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
ee = ee * zm + Math.abs(t + sdPar.a);
|
|
1353
|
-
ee = (9.0 * ee + 2.0 * Math.abs(t) - 7.0 * (Math.abs((sdPar.a) + t) + zm * Math.abs((sdPar.b)))) * DBL_EPSILON;
|
|
1354
|
-
|
|
1355
|
-
// Iteration has converged sufficiently if the polynomial value is less than 20 times this bound
|
|
1356
|
-
if(mp <= 20.0 * ee) {
|
|
1357
|
-
iPar.NZ = 2;
|
|
1358
|
-
break;
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
j++;
|
|
1362
|
-
// Stop iteration after 20 steps
|
|
1363
|
-
if(j > 20)
|
|
1364
|
-
break;
|
|
1365
|
-
if(j >= 2) {
|
|
1366
|
-
if((relstp <= 0.01) && (mp >= omp) && (!triedFlag)) {
|
|
1367
|
-
// A cluster appears to be stalling the convergence. Five fixed shift
|
|
1368
|
-
// steps are taken with a u, v close to the cluster.
|
|
1369
|
-
relstp = ((relstp < DBL_EPSILON) ? Math.sqrt(DBL_EPSILON) : Math.sqrt(relstp));
|
|
1370
|
-
u -= u * relstp;
|
|
1371
|
-
v += v * relstp;
|
|
1372
|
-
|
|
1373
|
-
QuadSD_ak1(NN, u, v, p, qp, sdPar);
|
|
1374
|
-
for(i = 0; i < 5; i++) {
|
|
1375
|
-
tFlag = calcSC_ak1(DBL_EPSILON, N, sdPar.a, sdPar.b, calcPar, K, u, v, qk);
|
|
1376
|
-
nextK_ak1(DBL_EPSILON, N, tFlag, sdPar.a, sdPar.b, calcPar, K, qk, qp);
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
triedFlag = 1;
|
|
1380
|
-
j = 0;
|
|
1381
|
-
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
omp = mp;
|
|
1385
|
-
|
|
1386
|
-
// Calculate next K polynomial and new u and v
|
|
1387
|
-
tFlag = calcSC_ak1(DBL_EPSILON, N, sdPar.a, sdPar.b, calcPar, K, u, v, qk);
|
|
1388
|
-
nextK_ak1(DBL_EPSILON, N, tFlag, sdPar.a, sdPar.b, calcPar, K, qk, qp);
|
|
1389
|
-
tFlag = calcSC_ak1(DBL_EPSILON, N, sdPar.a, sdPar.b, calcPar, K, u, v, qk);
|
|
1390
|
-
newest_ak1(tFlag, sdPar, sdPar.a, calcPar.a1, calcPar.a3, calcPar.a7, sdPar.b, calcPar.c, calcPar.d, calcPar.f, calcPar.g, calcPar.h, u, v, K, N, p);
|
|
1391
|
-
ui = sdPar.a;
|
|
1392
|
-
vi = sdPar.b;
|
|
1393
|
-
|
|
1394
|
-
// If vi is zero, the iteration is not converging
|
|
1395
|
-
if(vi != 0) {
|
|
1396
|
-
relstp = Math.abs((-v + vi) / vi);
|
|
1397
|
-
u = ui;
|
|
1398
|
-
v = vi;
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
while(vi != 0);
|
|
1402
|
-
return;
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
function RealIT_ak1(DBL_EPSILON, iPar, sdPar, N, p, NN, qp, K, qk) {
|
|
1406
|
-
// Variable-shift H-polynomial iteration for a real zero
|
|
1407
|
-
// sss - starting iterate = sdPar.a
|
|
1408
|
-
// NZ - number of zeros found = iPar.NZ
|
|
1409
|
-
// dumFlag - flag to indicate a pair of zeros near real axis, returned to iFlag
|
|
1410
|
-
|
|
1411
|
-
var ee, kv, mp, ms, omp, pv, s, t,
|
|
1412
|
-
dumFlag, i, j, nm1 = N - 1; // Integer variables
|
|
1413
|
-
|
|
1414
|
-
iPar.NZ = j = dumFlag = 0;
|
|
1415
|
-
s = sdPar.a;
|
|
1416
|
-
|
|
1417
|
-
for(; ; ) {
|
|
1418
|
-
pv = p[0];
|
|
1419
|
-
|
|
1420
|
-
// Evaluate p at s
|
|
1421
|
-
qp[0] = pv;
|
|
1422
|
-
for(i = 1; i < NN; i++) {
|
|
1423
|
-
qp[i] = pv = pv * s + p[i];
|
|
1424
|
-
}
|
|
1425
|
-
mp = Math.abs(pv);
|
|
1426
|
-
|
|
1427
|
-
// Compute a rigorous bound on the error in evaluating p
|
|
1428
|
-
ms = Math.abs(s);
|
|
1429
|
-
ee = 0.5 * Math.abs(qp[0]);
|
|
1430
|
-
for(i = 1; i < NN; i++) {
|
|
1431
|
-
ee = ee * ms + Math.abs(qp[i]);
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
// Iteration has converged sufficiently if the polynomial value is less than
|
|
1435
|
-
// 20 times this bound
|
|
1436
|
-
if(mp <= 20.0 * DBL_EPSILON * (2.0 * ee - mp)) {
|
|
1437
|
-
iPar.NZ = 1;
|
|
1438
|
-
iPar.szr = s;
|
|
1439
|
-
iPar.szi = 0.0;
|
|
1440
|
-
break;
|
|
1441
|
-
}
|
|
1442
|
-
j++;
|
|
1443
|
-
// Stop iteration after 10 steps
|
|
1444
|
-
if(j > 10)
|
|
1445
|
-
break;
|
|
1446
|
-
|
|
1447
|
-
if(j >= 2) {
|
|
1448
|
-
if((Math.abs(t) <= 0.001 * Math.abs(-t + s)) && (mp > omp)) {
|
|
1449
|
-
// A cluster of zeros near the real axis has been encountered.
|
|
1450
|
-
// Return with iFlag set to initiate a quadratic iteration.
|
|
1451
|
-
dumFlag = 1;
|
|
1452
|
-
iPar.a = s;
|
|
1453
|
-
break;
|
|
1454
|
-
} // End if ((fabs(t) <= 0.001*fabs(s - t)) && (mp > omp))
|
|
1455
|
-
} //End if (j >= 2)
|
|
1456
|
-
|
|
1457
|
-
// Return if the polynomial value has increased significantly
|
|
1458
|
-
omp = mp;
|
|
1459
|
-
|
|
1460
|
-
// Compute t, the next polynomial and the new iterate
|
|
1461
|
-
qk[0] = kv = K[0];
|
|
1462
|
-
for(i = 1; i < N; i++) {
|
|
1463
|
-
qk[i] = kv = kv * s + K[i];
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
if(Math.abs(kv) > Math.abs(K[nm1]) * 10.0 * DBL_EPSILON) {
|
|
1467
|
-
// Use the scaled form of the recurrence if the value of K at s is non-zero
|
|
1468
|
-
t = -(pv / kv);
|
|
1469
|
-
K[0] = qp[0];
|
|
1470
|
-
for(i = 1; i < N; i++) {
|
|
1471
|
-
K[i] = t * qk[i - 1] + qp[i];
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
else {
|
|
1475
|
-
// Use unscaled form
|
|
1476
|
-
K[0] = 0.0;
|
|
1477
|
-
for(i = 1; i < N; i++)
|
|
1478
|
-
K[i] = qk[i - 1];
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
kv = K[0];
|
|
1482
|
-
for(i = 1; i < N; i++) {
|
|
1483
|
-
kv = kv * s + K[i];
|
|
1484
|
-
}
|
|
1485
|
-
t = ((Math.abs(kv) > (Math.abs(K[nm1]) * 10.0 * DBL_EPSILON)) ? -(pv / kv) : 0.0);
|
|
1486
|
-
s += t;
|
|
1487
|
-
}
|
|
1488
|
-
return dumFlag;
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
function Fxshfr_ak1(DBL_EPSILON, MDP1, L2, sr, v, K, N, p, NN, qp, u, iPar) {
|
|
1492
|
-
|
|
1493
|
-
// Computes up to L2 fixed shift K-polynomials, testing for convergence in the linear or
|
|
1494
|
-
// quadratic case. Initiates one of the variable shift iterations and returns with the
|
|
1495
|
-
// number of zeros found.
|
|
1496
|
-
// L2 limit of fixed shift steps
|
|
1497
|
-
// iPar is a dummy variable for passing in the five parameters--NZ, lzi, lzr, szi, and szr--by reference
|
|
1498
|
-
// NZ number of zeros found
|
|
1499
|
-
var sdPar = new Object(), // sdPar is a dummy variable for passing the two parameters--a and b--into QuadSD_ak1 by reference
|
|
1500
|
-
calcPar = new Object(),
|
|
1501
|
-
// calcPar is a dummy variable for passing the nine parameters--a1, a3, a7, c, d, e, f, g, and h --into calcSC_ak1 by reference
|
|
1502
|
-
|
|
1503
|
-
qk = new Array(MDP1),
|
|
1504
|
-
svk = new Array(MDP1),
|
|
1505
|
-
a, b, betas, betav, oss, ots, otv, ovv, s, ss, ts, tss, tv, tvv, ui, vi, vv,
|
|
1506
|
-
fflag, i, iFlag = 1, j, spass, stry, tFlag, vpass, vtry; // Integer variables
|
|
1507
|
-
|
|
1508
|
-
iPar.NZ = 0;
|
|
1509
|
-
betav = betas = 0.25;
|
|
1510
|
-
oss = sr;
|
|
1511
|
-
ovv = v;
|
|
1512
|
-
|
|
1513
|
-
//Evaluate polynomial by synthetic division
|
|
1514
|
-
sdPar.b = sdPar.a = 0.0;
|
|
1515
|
-
QuadSD_ak1(NN, u, v, p, qp, sdPar);
|
|
1516
|
-
a = sdPar.a;
|
|
1517
|
-
b = sdPar.b;
|
|
1518
|
-
calcPar.h = calcPar.g = calcPar.f = calcPar.e = calcPar.d = calcPar.c = calcPar.a7 = calcPar.a3 = calcPar.a1 = 0.0;
|
|
1519
|
-
tFlag = calcSC_ak1(DBL_EPSILON, N, a, b, calcPar, K, u, v, qk);
|
|
1520
|
-
|
|
1521
|
-
for(j = 0; j < L2; j++) {
|
|
1522
|
-
fflag = 1;
|
|
1523
|
-
|
|
1524
|
-
// Calculate next K polynomial and estimate v
|
|
1525
|
-
nextK_ak1(DBL_EPSILON, N, tFlag, a, b, calcPar, K, qk, qp);
|
|
1526
|
-
tFlag = calcSC_ak1(DBL_EPSILON, N, a, b, calcPar, K, u, v, qk);
|
|
1527
|
-
|
|
1528
|
-
// Use sdPar for passing in uu and vv instead of defining a brand-new variable.
|
|
1529
|
-
// sdPar.a = ui, sdPar.b = vi
|
|
1530
|
-
newest_ak1(tFlag, sdPar, a, calcPar.a1, calcPar.a3, calcPar.a7, b, calcPar.c, calcPar.d, calcPar.f, calcPar.g, calcPar.h, u, v, K, N, p);
|
|
1531
|
-
ui = sdPar.a;
|
|
1532
|
-
vv = vi = sdPar.b;
|
|
1533
|
-
|
|
1534
|
-
// Estimate s
|
|
1535
|
-
ss = ((K[N - 1] != 0.0) ? -(p[N] / K[N - 1]) : 0.0);
|
|
1536
|
-
ts = tv = 1.0;
|
|
1537
|
-
|
|
1538
|
-
if((j != 0) && (tFlag != 3)) {
|
|
1539
|
-
// Compute relative measures of convergence of s and v sequences
|
|
1540
|
-
tv = ((vv != 0.0) ? Math.abs((vv - ovv) / vv) : tv);
|
|
1541
|
-
ts = ((ss != 0.0) ? Math.abs((ss - oss) / ss) : ts);
|
|
1542
|
-
|
|
1543
|
-
// If decreasing, multiply the two most recent convergence measures
|
|
1544
|
-
tvv = ((tv < otv) ? tv * otv : 1.0);
|
|
1545
|
-
tss = ((ts < ots) ? ts * ots : 1.0);
|
|
1546
|
-
|
|
1547
|
-
// Compare with convergence criteria
|
|
1548
|
-
vpass = ((tvv < betav) ? 1 : 0);
|
|
1549
|
-
spass = ((tss < betas) ? 1 : 0);
|
|
1550
|
-
|
|
1551
|
-
if((spass) || (vpass)) {
|
|
1552
|
-
|
|
1553
|
-
// At least one sequence has passed the convergence test.
|
|
1554
|
-
// Store variables before iterating
|
|
1555
|
-
|
|
1556
|
-
for(i = 0; i < N; i++) {
|
|
1557
|
-
svk[i] = K[i];
|
|
1558
|
-
}
|
|
1559
|
-
s = ss;
|
|
1560
|
-
|
|
1561
|
-
// Choose iteration according to the fastest converging sequence
|
|
1562
|
-
|
|
1563
|
-
stry = vtry = 0;
|
|
1564
|
-
|
|
1565
|
-
for(; ; ) {
|
|
1566
|
-
if((fflag && ((fflag = 0) == 0)) && ((spass) && (!vpass || (tss < tvv)))) {
|
|
1567
|
-
;// Do nothing. Provides a quick "short circuit".
|
|
1568
|
-
}
|
|
1569
|
-
else {
|
|
1570
|
-
QuadIT_ak1(DBL_EPSILON, N, iPar, ui, vi, qp, NN, sdPar, p, qk, calcPar, K);
|
|
1571
|
-
a = sdPar.a;
|
|
1572
|
-
b = sdPar.b;
|
|
1573
|
-
|
|
1574
|
-
if((iPar.NZ) > 0)
|
|
1575
|
-
return;
|
|
1576
|
-
|
|
1577
|
-
// Quadratic iteration has failed. Flag that it has been tried and decrease the
|
|
1578
|
-
// convergence criterion
|
|
1579
|
-
iFlag = vtry = 1;
|
|
1580
|
-
betav *= 0.25;
|
|
1581
|
-
|
|
1582
|
-
// Try linear iteration if it has not been tried and the s sequence is converging
|
|
1583
|
-
if(stry || (!spass)) {
|
|
1584
|
-
iFlag = 0;
|
|
1585
|
-
}
|
|
1586
|
-
else {
|
|
1587
|
-
for(i = 0; i < N; i++)
|
|
1588
|
-
K[i] = svk[i];
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
//fflag = 0;
|
|
1592
|
-
if(iFlag != 0) {
|
|
1593
|
-
// Use sdPar for passing in s instead of defining a brand-new variable.
|
|
1594
|
-
// sdPar.a = s
|
|
1595
|
-
sdPar.a = s;
|
|
1596
|
-
iFlag = RealIT_ak1(DBL_EPSILON, iPar, sdPar, N, p, NN, qp, K, qk);
|
|
1597
|
-
s = sdPar.a;
|
|
1598
|
-
|
|
1599
|
-
if((iPar.NZ) > 0)
|
|
1600
|
-
return;
|
|
1601
|
-
|
|
1602
|
-
// Linear iteration has failed. Flag that it has been tried and decrease the
|
|
1603
|
-
// convergence criterion
|
|
1604
|
-
stry = 1;
|
|
1605
|
-
betas *= 0.25;
|
|
1606
|
-
|
|
1607
|
-
if(iFlag != 0) {
|
|
1608
|
-
// If linear iteration signals an almost double real zero, attempt quadratic iteration
|
|
1609
|
-
ui = -(s + s);
|
|
1610
|
-
vi = s * s;
|
|
1611
|
-
continue;
|
|
1612
|
-
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
|
|
1616
|
-
// Restore variables
|
|
1617
|
-
for(i = 0; i < N; i++)
|
|
1618
|
-
K[i] = svk[i];
|
|
1619
|
-
|
|
1620
|
-
// Try quadratic iteration if it has not been tried and the v sequence is converging
|
|
1621
|
-
if(!vpass || vtry)
|
|
1622
|
-
break; // Break out of infinite for loop
|
|
1623
|
-
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
// Re-compute qp and scalar values to continue the second stage
|
|
1627
|
-
|
|
1628
|
-
QuadSD_ak1(NN, u, v, p, qp, sdPar);
|
|
1629
|
-
a = sdPar.a;
|
|
1630
|
-
b = sdPar.b;
|
|
1631
|
-
|
|
1632
|
-
tFlag = calcSC_ak1(DBL_EPSILON, N, a, b, calcPar, K, u, v, qk);
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
ovv = vv;
|
|
1636
|
-
oss = ss;
|
|
1637
|
-
otv = tv;
|
|
1638
|
-
ots = ts;
|
|
1639
|
-
}
|
|
1640
|
-
return;
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
function rpSolve(degPar, p, zeror, zeroi) {
|
|
1644
|
-
var N = degPar.Degree,
|
|
1645
|
-
RADFAC = 3.14159265358979323846 / 180, // Degrees-to-radians conversion factor = PI/180
|
|
1646
|
-
LB2 = Math.LN2, // Dummy variable to avoid re-calculating this value in loop below
|
|
1647
|
-
MDP1 = degPar.Degree + 1,
|
|
1648
|
-
K = new Array(MDP1),
|
|
1649
|
-
pt = new Array(MDP1),
|
|
1650
|
-
qp = new Array(MDP1),
|
|
1651
|
-
temp = new Array(MDP1),
|
|
1652
|
-
// qPar is a dummy variable for passing the four parameters--sr, si, lr, and li--by reference
|
|
1653
|
-
qPar = new Object(),
|
|
1654
|
-
// Fxshfr_Par is a dummy variable for passing parameters by reference : NZ, lzi, lzr, szi, szr);
|
|
1655
|
-
Fxshfr_Par = new Object(),
|
|
1656
|
-
bnd, DBL_EPSILON, df, dx, factor, ff, moduli_max, moduli_min, sc, x, xm,
|
|
1657
|
-
aa, bb, cc, sr, t, u, xxx,
|
|
1658
|
-
j, jj, l, NM1, NN, zerok;// Integer variables
|
|
1659
|
-
|
|
1660
|
-
// Calculate the machine epsilon and store in the variable DBL_EPSILON.
|
|
1661
|
-
// To calculate this value, just use existing variables rather than create new ones that will be used only for this code block
|
|
1662
|
-
aa = 1.0;
|
|
1663
|
-
do {
|
|
1664
|
-
DBL_EPSILON = aa;
|
|
1665
|
-
aa /= 2;
|
|
1666
|
-
bb = 1.0 + aa;
|
|
1667
|
-
}
|
|
1668
|
-
while(bb > 1.0);
|
|
1669
|
-
|
|
1670
|
-
var LO = Number.MIN_VALUE / DBL_EPSILON,
|
|
1671
|
-
cosr = Math.cos(94.0 * RADFAC), // = -0.069756474
|
|
1672
|
-
sinr = Math.sin(94.0 * RADFAC), // = 0.99756405
|
|
1673
|
-
xx = Math.sqrt(0.5), // = 0.70710678
|
|
1674
|
-
yy = -xx;
|
|
1675
|
-
|
|
1676
|
-
Fxshfr_Par.NZ = j = 0;
|
|
1677
|
-
Fxshfr_Par.szr = Fxshfr_Par.szi = Fxshfr_Par.lzr = Fxshfr_Par.lzi = 0.0;
|
|
1678
|
-
|
|
1679
|
-
// Remove zeros at the origin, if any
|
|
1680
|
-
while(p[N] == 0) {
|
|
1681
|
-
zeror[j] = zeroi[j] = 0;
|
|
1682
|
-
N--;
|
|
1683
|
-
j++;
|
|
1684
|
-
}
|
|
1685
|
-
NN = N + 1;
|
|
1686
|
-
|
|
1687
|
-
// >>>>> Begin Main Loop <<<<<
|
|
1688
|
-
while(N >= 1) { // Main loop
|
|
1689
|
-
// Start the algorithm for one zero
|
|
1690
|
-
if(N <= 2) {
|
|
1691
|
-
// Calculate the final zero or pair of zeros
|
|
1692
|
-
if(N < 2) {
|
|
1693
|
-
zeror[degPar.Degree - 1] = -(p[1] / p[0]);
|
|
1694
|
-
zeroi[degPar.Degree - 1] = 0;
|
|
1695
|
-
}
|
|
1696
|
-
else {
|
|
1697
|
-
qPar.li = qPar.lr = qPar.si = qPar.sr = 0.0;
|
|
1698
|
-
Quad_ak1(p[0], p[1], p[2], qPar);
|
|
1699
|
-
zeror[degPar.Degree - 2] = qPar.sr;
|
|
1700
|
-
zeroi[degPar.Degree - 2] = qPar.si;
|
|
1701
|
-
zeror[degPar.Degree - 1] = qPar.lr;
|
|
1702
|
-
zeroi[degPar.Degree - 1] = qPar.li;
|
|
1703
|
-
}
|
|
1704
|
-
break;
|
|
1705
|
-
}
|
|
1706
|
-
|
|
1707
|
-
// Find the largest and smallest moduli of the coefficients
|
|
1708
|
-
moduli_max = 0.0;
|
|
1709
|
-
moduli_min = Number.MAX_VALUE;
|
|
1710
|
-
|
|
1711
|
-
for(i = 0; i < NN; i++) {
|
|
1712
|
-
x = Math.abs(p[i]);
|
|
1713
|
-
if(x > moduli_max)
|
|
1714
|
-
moduli_max = x;
|
|
1715
|
-
if((x != 0) && (x < moduli_min))
|
|
1716
|
-
moduli_min = x;
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
|
-
// Scale if there are large or very small coefficients
|
|
1720
|
-
// Computes a scale factor to multiply the coefficients of the polynomial. The scaling
|
|
1721
|
-
// is done to avoid overflow and to avoid undetected underflow interfering with the
|
|
1722
|
-
// convergence criterion.
|
|
1723
|
-
// The factor is a power of the base.
|
|
1724
|
-
sc = LO / moduli_min;
|
|
1725
|
-
|
|
1726
|
-
if(((sc <= 1.0) && (moduli_max >= 10)) || ((sc > 1.0) && (Number.MAX_VALUE / sc >= moduli_max))) {
|
|
1727
|
-
sc = ((sc == 0) ? Number.MIN_VALUE : sc);
|
|
1728
|
-
l = Math.floor(Math.log(sc) / LB2 + 0.5);
|
|
1729
|
-
factor = Math.pow(2.0, l);
|
|
1730
|
-
if(factor != 1.0) {
|
|
1731
|
-
for(i = 0; i < NN; i++)
|
|
1732
|
-
p[i] *= factor;
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
|
-
// Compute lower bound on moduli of zeros
|
|
1737
|
-
for(var i = 0; i < NN; i++)
|
|
1738
|
-
pt[i] = Math.abs(p[i]);
|
|
1739
|
-
pt[N] = -(pt[N]);
|
|
1740
|
-
NM1 = N - 1;
|
|
1741
|
-
|
|
1742
|
-
// Compute upper estimate of bound
|
|
1743
|
-
x = Math.exp((Math.log(-pt[N]) - Math.log(pt[0])) / N);
|
|
1744
|
-
|
|
1745
|
-
if(pt[NM1] != 0) {
|
|
1746
|
-
// If Newton step at the origin is better, use it
|
|
1747
|
-
xm = -pt[N] / pt[NM1];
|
|
1748
|
-
x = ((xm < x) ? xm : x);
|
|
1749
|
-
}
|
|
1750
|
-
|
|
1751
|
-
// Chop the interval (0, x) until ff <= 0
|
|
1752
|
-
xm = x;
|
|
1753
|
-
do {
|
|
1754
|
-
x = xm;
|
|
1755
|
-
xm = 0.1 * x;
|
|
1756
|
-
ff = pt[0];
|
|
1757
|
-
for(var i = 1; i < NN; i++) {
|
|
1758
|
-
ff = ff * xm + pt[i];
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
while(ff > 0); // End do-while loop
|
|
1762
|
-
|
|
1763
|
-
dx = x;
|
|
1764
|
-
// Do Newton iteration until x converges to two decimal places
|
|
1765
|
-
|
|
1766
|
-
do {
|
|
1767
|
-
df = ff = pt[0];
|
|
1768
|
-
for(var i = 1; i < N; i++) {
|
|
1769
|
-
ff = x * ff + pt[i];
|
|
1770
|
-
df = x * df + ff;
|
|
1771
|
-
} // End for i
|
|
1772
|
-
ff = x * ff + pt[N];
|
|
1773
|
-
dx = ff / df;
|
|
1774
|
-
x -= dx;
|
|
1775
|
-
}
|
|
1776
|
-
while(Math.abs(dx / x) > 0.005); // End do-while loop
|
|
1777
|
-
|
|
1778
|
-
bnd = x;
|
|
1779
|
-
|
|
1780
|
-
// Compute the derivative as the initial K polynomial and do 5 steps with no shift
|
|
1781
|
-
for(var i = 1; i < N; i++)
|
|
1782
|
-
K[i] = (N - i) * p[i] / N;
|
|
1783
|
-
K[0] = p[0];
|
|
1784
|
-
aa = p[N];
|
|
1785
|
-
bb = p[NM1];
|
|
1786
|
-
zerok = ((K[NM1] == 0) ? 1 : 0);
|
|
1787
|
-
|
|
1788
|
-
for(jj = 0; jj < 5; jj++) {
|
|
1789
|
-
cc = K[NM1];
|
|
1790
|
-
if(zerok) {
|
|
1791
|
-
// Use unscaled form of recurrence
|
|
1792
|
-
for(var i = 0; i < NM1; i++) {
|
|
1793
|
-
j = NM1 - i;
|
|
1794
|
-
K[j] = K[j - 1];
|
|
1795
|
-
} // End for i
|
|
1796
|
-
K[0] = 0;
|
|
1797
|
-
zerok = ((K[NM1] == 0) ? 1 : 0);
|
|
1798
|
-
}
|
|
1799
|
-
else {
|
|
1800
|
-
// Used scaled form of recurrence if value of K at 0 is nonzero
|
|
1801
|
-
t = -aa / cc;
|
|
1802
|
-
for(var i = 0; i < NM1; i++) {
|
|
1803
|
-
j = NM1 - i;
|
|
1804
|
-
K[j] = t * K[j - 1] + p[j];
|
|
1805
|
-
} // End for i
|
|
1806
|
-
K[0] = p[0];
|
|
1807
|
-
zerok = ((Math.abs(K[NM1]) <= Math.abs(bb) * DBL_EPSILON * 10.0) ? 1 : 0);
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
|
|
1811
|
-
// Save K for restarts with new shifts
|
|
1812
|
-
for(var i = 0; i < N; i++)
|
|
1813
|
-
temp[i] = K[i];
|
|
1814
|
-
|
|
1815
|
-
// Loop to select the quadratic corresponding to each new shift
|
|
1816
|
-
for(jj = 1; jj <= 20; jj++) {
|
|
1817
|
-
|
|
1818
|
-
// Quadratic corresponds to a double shift to a non-real point and its
|
|
1819
|
-
// complex conjugate. The point has modulus BND and amplitude rotated
|
|
1820
|
-
// by 94 degrees from the previous shift.
|
|
1821
|
-
|
|
1822
|
-
xxx = -(sinr * yy) + cosr * xx;
|
|
1823
|
-
yy = sinr * xx + cosr * yy;
|
|
1824
|
-
xx = xxx;
|
|
1825
|
-
sr = bnd * xx;
|
|
1826
|
-
u = -(2.0 * sr);
|
|
1827
|
-
|
|
1828
|
-
// Second stage calculation, fixed quadratic
|
|
1829
|
-
Fxshfr_ak1(DBL_EPSILON, MDP1, 20 * jj, sr, bnd, K, N, p, NN, qp, u, Fxshfr_Par);
|
|
1830
|
-
|
|
1831
|
-
if(Fxshfr_Par.NZ != 0) {
|
|
1832
|
-
// The second stage jumps directly to one of the third stage iterations and
|
|
1833
|
-
// returns here if successful. Deflate the polynomial, store the zero or
|
|
1834
|
-
// zeros, and return to the main algorithm.
|
|
1835
|
-
j = degPar.Degree - N;
|
|
1836
|
-
zeror[j] = Fxshfr_Par.szr;
|
|
1837
|
-
zeroi[j] = Fxshfr_Par.szi;
|
|
1838
|
-
NN = NN - Fxshfr_Par.NZ;
|
|
1839
|
-
N = NN - 1;
|
|
1840
|
-
for(var i = 0; i < NN; i++)
|
|
1841
|
-
p[i] = qp[i];
|
|
1842
|
-
if(Fxshfr_Par.NZ != 1) {
|
|
1843
|
-
zeror[j + 1] = Fxshfr_Par.lzr;
|
|
1844
|
-
zeroi[j + 1] = Fxshfr_Par.lzi;
|
|
1845
|
-
}
|
|
1846
|
-
break;
|
|
1847
|
-
}
|
|
1848
|
-
else {
|
|
1849
|
-
// If the iteration is unsuccessful, another quadratic is chosen after restoring K
|
|
1850
|
-
for(var i = 0; i < N; i++) {
|
|
1851
|
-
K[i] = temp[i];
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
}
|
|
1855
|
-
// Return with failure if no convergence with 20 shifts
|
|
1856
|
-
if(jj > 20) {
|
|
1857
|
-
degPar.Degree -= N;
|
|
1858
|
-
break;
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
// >>>>> End Main Loop <<<<<
|
|
1862
|
-
return;
|
|
1863
|
-
}
|
|
1864
|
-
//--> End Jenkins-Traub
|
|
1865
|
-
rpSolve(degreePar, p, zeror, zeroi);
|
|
1866
|
-
|
|
1867
|
-
var l = zeroi.length;
|
|
1868
|
-
//format the output
|
|
1869
|
-
for(i = 0; i < l; i++) {
|
|
1870
|
-
// We round the imaginary part to avoid having something crazy like 5.67e-16.
|
|
1871
|
-
var img = round(zeroi[i], decp + 8),
|
|
1872
|
-
real = round(zeror[i], decp + 8);
|
|
1873
|
-
// Did the rounding pay off? If the rounding did nothing more than chop off a few digits then no.
|
|
1874
|
-
// If the rounding results in a a number at least 3 digits shorter we'll keep it else we'll keep
|
|
1875
|
-
// the original otherwise the rounding was worth it.
|
|
1876
|
-
real = decp - String(real).length > 2 ? real : zeror[i];
|
|
1877
|
-
var sign = img < 0 ? '-' : '';
|
|
1878
|
-
|
|
1879
|
-
// Remove the zeroes
|
|
1880
|
-
if(real === 0) {
|
|
1881
|
-
real = '';
|
|
1882
|
-
}
|
|
1883
|
-
if(img === 0) {
|
|
1884
|
-
img = '';
|
|
1885
|
-
}
|
|
1886
|
-
|
|
1887
|
-
// Remove 1 as the multiplier and discard imaginary part if there isn't one.
|
|
1888
|
-
img = Math.abs(img) === 1 ? sign + 'i' : (img ? img + '*i' : '');
|
|
1889
|
-
|
|
1890
|
-
var num = (real && img) ? real + '+' + img : real + img;
|
|
1891
|
-
zeror[i] = num.replace(/\+\-/g, '-');
|
|
1892
|
-
}
|
|
1893
|
-
return zeror;
|
|
1894
|
-
}
|
|
1895
|
-
},
|
|
1896
|
-
roots: function (symbol) {
|
|
1897
|
-
|
|
1898
|
-
if(symbol.isConstant(true, true)) {
|
|
1899
|
-
return core.Utils.nroots(symbol);
|
|
1900
|
-
}
|
|
1901
|
-
var roots = __.proots(symbol).map(function (x) {
|
|
1902
|
-
return _.parse(x);
|
|
1903
|
-
});
|
|
1904
|
-
return core.Vector.fromArray(roots);
|
|
1905
|
-
},
|
|
1906
|
-
froot: function (f, guess, dx) {
|
|
1907
|
-
var newtonraph = function (xn) {
|
|
1908
|
-
var mesh = 1e-12,
|
|
1909
|
-
// If the derivative was already provided then don't recalculate.
|
|
1910
|
-
df = dx ? dx : core.Utils.build(core.Calculus.diff(f.clone())),
|
|
1911
|
-
// If the function was passed in as a function then don't recalculate.
|
|
1912
|
-
fn = f instanceof Function ? f : core.Utils.build(f),
|
|
1913
|
-
max = 10000,
|
|
1914
|
-
done = false,
|
|
1915
|
-
safety = 0;
|
|
1916
|
-
while(!done) {
|
|
1917
|
-
var x = xn - (fn(xn) / df(xn));
|
|
1918
|
-
//absolute values for both x & xn ensures that we indeed have the radius
|
|
1919
|
-
var r = Math.abs(x) - Math.abs(xn),
|
|
1920
|
-
delta = Math.abs(r);
|
|
1921
|
-
xn = x;
|
|
1922
|
-
|
|
1923
|
-
if(delta < mesh)
|
|
1924
|
-
done = true;
|
|
1925
|
-
else if(safety > max) {
|
|
1926
|
-
xn = null;
|
|
1927
|
-
done = true;
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
|
-
safety++;
|
|
1931
|
-
}
|
|
1932
|
-
return xn;
|
|
1933
|
-
};
|
|
1934
|
-
return newtonraph(Number(guess));
|
|
1935
|
-
},
|
|
1936
|
-
quad: function (a, b, c) {
|
|
1937
|
-
var q = function (a, b, c, sign) {
|
|
1938
|
-
return _.parse('-(' + b + '+' + sign + '*sqrt((' + b + ')^2-4*(' + a + ')*(' + c + ')))/(2*' + a + ')');
|
|
1939
|
-
};
|
|
1940
|
-
return [q(a, b, c, 1), q(a, b, c, -1)];
|
|
1941
|
-
},
|
|
1942
|
-
sumProd: function (a, b) {
|
|
1943
|
-
return __.quad(-b, a, -1).map(function (x) {
|
|
1944
|
-
return x.invert();
|
|
1945
|
-
});
|
|
1946
|
-
},
|
|
1947
|
-
coeffs: function (symbol, wrt, coeffs) {
|
|
1948
|
-
wrt = String(wrt);
|
|
1949
|
-
symbol = _.expand(symbol);
|
|
1950
|
-
coeffs = coeffs || [new Symbol(0)];
|
|
1951
|
-
//we cannot get coeffs for group EX
|
|
1952
|
-
if(symbol.group === EX && symbol.contains(wrt, true))
|
|
1953
|
-
_.error('Unable to get coefficients using expression ' + symbol.toString());
|
|
1954
|
-
var vars = variables(symbol);
|
|
1955
|
-
if(vars.length === 1 && vars[0] === wrt && !symbol.isImaginary()) {
|
|
1956
|
-
var a = new Polynomial(symbol).coeffs.map(function (x) {
|
|
1957
|
-
return new Symbol(x);
|
|
1958
|
-
});
|
|
1959
|
-
|
|
1960
|
-
for(var i = 0, l = a.length; i < l; i++) {
|
|
1961
|
-
var coeff = a[i],
|
|
1962
|
-
e = coeffs[i];
|
|
1963
|
-
if(e)
|
|
1964
|
-
coeff = _.add(e, coeff);
|
|
1965
|
-
coeffs[i] = coeff; //transfer it all over
|
|
1966
|
-
}
|
|
1967
|
-
}
|
|
1968
|
-
else {
|
|
1969
|
-
if(!wrt)
|
|
1970
|
-
_.error('Polynomial contains more than one variable. Please specify which variable is to be used!');
|
|
1971
|
-
//if the variable isn't part of this polynomial then we're looking at x^0
|
|
1972
|
-
|
|
1973
|
-
if(vars.indexOf(wrt) === -1) {
|
|
1974
|
-
coeffs[0] = _.add(symbol, coeffs[0]);
|
|
1975
|
-
}
|
|
1976
|
-
else {
|
|
1977
|
-
coeffs = coeffs || [new Symbol(0)];
|
|
1978
|
-
if(symbol.group === CB) {
|
|
1979
|
-
var s = symbol.symbols[wrt];
|
|
1980
|
-
if(!s)
|
|
1981
|
-
_.error('Expression is not a polynomial!');
|
|
1982
|
-
var p = Number(s.power);
|
|
1983
|
-
coeff = _.divide(symbol.clone(), s.clone());
|
|
1984
|
-
if(coeff.contains(wrt, true) || p < 0 || !isInt(p))
|
|
1985
|
-
_.error('Expression is not a polynomial!');
|
|
1986
|
-
var e = coeffs[p];
|
|
1987
|
-
if(e)
|
|
1988
|
-
coeff = _.add(e, coeff);
|
|
1989
|
-
coeffs[p] = coeff;
|
|
1990
|
-
}
|
|
1991
|
-
else if(symbol.group === CP) {
|
|
1992
|
-
symbol.each(function (x) {
|
|
1993
|
-
__.coeffs(x.clone(), wrt, coeffs);
|
|
1994
|
-
}, true);
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
//fill holes
|
|
1999
|
-
for(var i = 0, l = coeffs.length; i < l; i++)
|
|
2000
|
-
if(typeof coeffs[i] === 'undefined')
|
|
2001
|
-
coeffs[i] = new Symbol(0);
|
|
2002
|
-
|
|
2003
|
-
return coeffs;
|
|
2004
|
-
},
|
|
2005
|
-
/**
|
|
2006
|
-
* Get's all the powers of a particular polynomial including the denominators. The denominators powers
|
|
2007
|
-
* are returned as negative. All remaining polynomials are returned as zero order polynomials.
|
|
2008
|
-
* for example polyPowers(x^2+1/x+y+t) will return [ '-1', 0, '2' ]
|
|
2009
|
-
* @param {Symbol} e
|
|
2010
|
-
* @param {String} for_variable
|
|
2011
|
-
* @param {Array} powers
|
|
2012
|
-
* @returns {Array} An array of the powers
|
|
2013
|
-
*/
|
|
2014
|
-
//assumes you've already verified that it's a polynomial
|
|
2015
|
-
polyPowers: function (e, for_variable, powers) {
|
|
2016
|
-
powers = powers || [];
|
|
2017
|
-
var g = g = e.group;
|
|
2018
|
-
if(g === PL && for_variable === e.value) {
|
|
2019
|
-
powers = powers.concat(keys(e.symbols));
|
|
2020
|
-
}
|
|
2021
|
-
else if(g === CP) {
|
|
2022
|
-
for(var s in e.symbols) {
|
|
2023
|
-
var symbol = e.symbols[s];
|
|
2024
|
-
var g = symbol.group, v = symbol.value;
|
|
2025
|
-
if(g === S && for_variable === v)
|
|
2026
|
-
powers.push(symbol.power);
|
|
2027
|
-
else if(g === PL || g === CP)
|
|
2028
|
-
powers = __.polyPowers(symbol, for_variable, powers);
|
|
2029
|
-
else if(g === CB && symbol.contains(for_variable)) {
|
|
2030
|
-
var t = symbol.symbols[for_variable];
|
|
2031
|
-
if(t)
|
|
2032
|
-
powers.push((t.power));
|
|
2033
|
-
}
|
|
2034
|
-
else if(g === N || for_variable !== v)
|
|
2035
|
-
powers.push(0);
|
|
2036
|
-
}
|
|
2037
|
-
}
|
|
2038
|
-
else if(g === CB && e.contains(for_variable)) {
|
|
2039
|
-
powers.push(core.Utils.decompose_fn(e, for_variable, true).x.power);
|
|
2040
|
-
}
|
|
2041
|
-
return core.Utils.arrayUnique(powers).sort();
|
|
2042
|
-
},
|
|
2043
|
-
//The factor object
|
|
2044
|
-
Factor: {
|
|
2045
|
-
//splits the symbol in symbol and constant
|
|
2046
|
-
split: function (symbol) {
|
|
2047
|
-
var c = new Symbol(1); //the constants part
|
|
2048
|
-
var s = new Symbol(1); //the symbolic part
|
|
2049
|
-
__.Factor.factor(symbol, new Factors()).each(function (x) {
|
|
2050
|
-
var t = _.parse(x);
|
|
2051
|
-
if(x.isConstant(true)) {
|
|
2052
|
-
c = _.multiply(c, t);
|
|
2053
|
-
}
|
|
2054
|
-
else {
|
|
2055
|
-
s = _.multiply(s, t);
|
|
2056
|
-
}
|
|
2057
|
-
});
|
|
2058
|
-
return [c, s];
|
|
2059
|
-
},
|
|
2060
|
-
mix: function (o, include_negatives) {
|
|
2061
|
-
var factors = keys(o);
|
|
2062
|
-
var l = factors.length;
|
|
2063
|
-
var m = [];//create a row which we'r going to be mixing
|
|
2064
|
-
for(var i = 0; i < l; i++) {
|
|
2065
|
-
var factor = factors[i],
|
|
2066
|
-
p = o[factor];
|
|
2067
|
-
var ll = m.length;
|
|
2068
|
-
for(var j = 0; j < ll; j++) {
|
|
2069
|
-
var t = m[j] * factor;
|
|
2070
|
-
m.push(t);
|
|
2071
|
-
if(include_negatives)
|
|
2072
|
-
m.push(-t);
|
|
2073
|
-
}
|
|
2074
|
-
|
|
2075
|
-
for(var j = 1; j <= p; j++)
|
|
2076
|
-
m.push(Math.pow(factor, j));
|
|
2077
|
-
}
|
|
2078
|
-
return m;
|
|
2079
|
-
},
|
|
2080
|
-
//TODO: this method is to replace common factoring
|
|
2081
|
-
common: function (symbol, factors) {
|
|
2082
|
-
try {
|
|
2083
|
-
if(symbol.group === CP) {
|
|
2084
|
-
//this may have the unfortunate side effect of expanding and factoring again
|
|
2085
|
-
//to only end up with the same result.
|
|
2086
|
-
//TODO: try to avoid this
|
|
2087
|
-
//collect the symbols and sort to have the longest first. Thinking is that the longest terms
|
|
2088
|
-
//has to contain the variable in order for it to be factorable
|
|
2089
|
-
var symbols = _.expand(symbol.clone(), true).collectSymbols(null, null, function (a, b) {
|
|
2090
|
-
return (b.length || 1) - (a.length || 1);
|
|
2091
|
-
});
|
|
2092
|
-
|
|
2093
|
-
var map = {}; //create a map of common factors
|
|
2094
|
-
var coeffs = [];
|
|
2095
|
-
for(var i = 0; i < symbols.length; i++) {
|
|
2096
|
-
var sym = symbols[i];
|
|
2097
|
-
coeffs.push(sym.multiplier.clone());
|
|
2098
|
-
sym.each(function (x) {
|
|
2099
|
-
var p = Number(x.power);
|
|
2100
|
-
//This check exits since we have a symbolic power.
|
|
2101
|
-
//For the future... think about removing this check and modify for symbolic powers
|
|
2102
|
-
if(isNaN(p))
|
|
2103
|
-
throw new Error('exiting');
|
|
2104
|
-
//loop through the symbols and lump together common terms
|
|
2105
|
-
if(x.value in map) {
|
|
2106
|
-
if(p < map[x.value][0])
|
|
2107
|
-
map[x.value][0] = p;
|
|
2108
|
-
map[x.value][1].push(x);
|
|
2109
|
-
}
|
|
2110
|
-
else
|
|
2111
|
-
map[x.value] = [p, [x]];
|
|
2112
|
-
});
|
|
2113
|
-
}
|
|
2114
|
-
//the factor
|
|
2115
|
-
var factor = new Symbol(1);
|
|
2116
|
-
for(var x in map) {
|
|
2117
|
-
//if this factor is found in all terms since the length of
|
|
2118
|
-
//matching variable terms matches the number of original terms
|
|
2119
|
-
if(map[x][1].length === symbols.length) {
|
|
2120
|
-
//generate a symbol and multiply into the factor
|
|
2121
|
-
factor = _.multiply(factor, _.pow(new Symbol(x), new Symbol(map[x][0])));
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
//get coefficient factor
|
|
2125
|
-
var c = core.Math2.QGCD.apply(null, coeffs);
|
|
2126
|
-
|
|
2127
|
-
if(!c.equals(1)) {
|
|
2128
|
-
factors.add(new Symbol(c));
|
|
2129
|
-
for(var i = 0; i < symbols.length; i++) {
|
|
2130
|
-
symbols[i].multiplier = symbols[i].multiplier.divide(c);
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
|
|
2134
|
-
//if we actuall found any factors
|
|
2135
|
-
if(!factor.equals(1)) {
|
|
2136
|
-
factors.add(factor);
|
|
2137
|
-
symbol = new Symbol(0);
|
|
2138
|
-
for(var i = 0; i < symbols.length; i++) {
|
|
2139
|
-
symbol = _.add(symbol, _.divide(symbols[i], factor.clone()));
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
catch(e) {
|
|
2145
|
-
;
|
|
2146
|
-
}
|
|
2147
|
-
|
|
2148
|
-
return symbol;
|
|
2149
|
-
},
|
|
2150
|
-
zeroes: function (symbol, factors) {
|
|
2151
|
-
var exit = function () {
|
|
2152
|
-
throw new core.exceptions.ValueLimitExceededError('Exiting');
|
|
2153
|
-
};
|
|
2154
|
-
try {
|
|
2155
|
-
var vars, term, sum, p, e;
|
|
2156
|
-
symbol = _.expand(symbol.clone());
|
|
2157
|
-
e = symbol.toString();
|
|
2158
|
-
vars = variables(symbol);
|
|
2159
|
-
|
|
2160
|
-
sum = new Symbol(0);
|
|
2161
|
-
|
|
2162
|
-
var terms = [];
|
|
2163
|
-
var powers = [];
|
|
2164
|
-
|
|
2165
|
-
//start setting each variable to zero
|
|
2166
|
-
for(var i = 0, l = vars.length; i < vars.length; i++) {
|
|
2167
|
-
var subs = {};
|
|
2168
|
-
//we want to create a subs object with all but the current variable set to zero
|
|
2169
|
-
for(var j = 0; j < l; j++)
|
|
2170
|
-
if(i !== j) //make sure we're not looking at the same variable
|
|
2171
|
-
subs[vars[j]] = 0;
|
|
2172
|
-
term = _.parse(e, subs);
|
|
2173
|
-
var tp = term.power;
|
|
2174
|
-
//the temporary power has to be an integer as well
|
|
2175
|
-
if(!isInt(tp))
|
|
2176
|
-
exit();
|
|
2177
|
-
terms.push(term);
|
|
2178
|
-
powers.push(term.power);
|
|
2179
|
-
}
|
|
2180
|
-
|
|
2181
|
-
//get the gcd. This will be the p in (a^n+b^m)^p
|
|
2182
|
-
//if the gcd equals 1 meaning n = m then we need a tie breakder
|
|
2183
|
-
if(core.Utils.allSame(powers)) {
|
|
2184
|
-
//get p given x number of terms
|
|
2185
|
-
var n_terms = symbol.length;
|
|
2186
|
-
//the number of zeroes determines
|
|
2187
|
-
var n_zeroes = terms.length;
|
|
2188
|
-
if(n_zeroes === 2) {
|
|
2189
|
-
p = new Frac(powers[0] / (n_terms - 1));
|
|
2190
|
-
}
|
|
2191
|
-
if(n_zeroes === 3) {
|
|
2192
|
-
p = new Frac(powers[0] / Math.round((Math.sqrt(8 * n_terms - 1) - 3) / 2));
|
|
2193
|
-
}
|
|
2194
|
-
/*
|
|
2195
|
-
//get the lowest possible power
|
|
2196
|
-
//e.g. given b^4+2*a^2*b^2+a^4, the power we're looking for would be 2
|
|
2197
|
-
symbol.each(function(x) {
|
|
2198
|
-
if(x.group === CB)
|
|
2199
|
-
x.each(function(y) {
|
|
2200
|
-
if(!p || y.power.lessThan(p))
|
|
2201
|
-
//p = Number(y.power);
|
|
2202
|
-
p = y.power;
|
|
2203
|
-
});
|
|
2204
|
-
else if(!p || x.power.lessThan(p))
|
|
2205
|
-
//p = Number(x.power);
|
|
2206
|
-
p = x.power;
|
|
2207
|
-
});
|
|
2208
|
-
*/
|
|
2209
|
-
}
|
|
2210
|
-
else
|
|
2211
|
-
//p is just the gcd of the powers
|
|
2212
|
-
p = core.Math2.QGCD.apply(null, powers);
|
|
2213
|
-
|
|
2214
|
-
//if we don't have an integer then exit
|
|
2215
|
-
if(!isInt(p))
|
|
2216
|
-
exit();
|
|
2217
|
-
|
|
2218
|
-
//build the factor
|
|
2219
|
-
for(var i = 0; i < terms.length; i++) {
|
|
2220
|
-
var t = terms[i];
|
|
2221
|
-
var n = t.power.clone().divide(p);
|
|
2222
|
-
t.multiplier = new Frac(Math.pow(t.multiplier, 1 / n));
|
|
2223
|
-
t.power = p.clone();
|
|
2224
|
-
sum = _.add(sum, t);
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
//by now we have the factor of zeroes. We'll know if we got it right because
|
|
2228
|
-
//we'll get a remainder of zero each time we divide by it
|
|
2229
|
-
if(sum.group !== CP)
|
|
2230
|
-
return symbol; //nothing to do
|
|
2231
|
-
|
|
2232
|
-
while(true) {
|
|
2233
|
-
var d = __.div(symbol.clone(), sum.clone());
|
|
2234
|
-
if(d[1].equals(0)) {
|
|
2235
|
-
symbol = d[0];
|
|
2236
|
-
factors.add(sum.clone());
|
|
2237
|
-
if(symbol.equals(1)) //we've reached 1 so done.
|
|
2238
|
-
break;
|
|
2239
|
-
}
|
|
2240
|
-
else
|
|
2241
|
-
break;
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
catch(e) {
|
|
2245
|
-
}
|
|
2246
|
-
;
|
|
2247
|
-
|
|
2248
|
-
return symbol;
|
|
2249
|
-
},
|
|
2250
|
-
factor: function (symbol, factors) {
|
|
2251
|
-
// Don't try to factor constants
|
|
2252
|
-
if(symbol.isConstant()) {
|
|
2253
|
-
return core.Math2.factor(symbol);
|
|
2254
|
-
}
|
|
2255
|
-
|
|
2256
|
-
var _symbol = _.parse(symbol);
|
|
2257
|
-
var retval = __.Factor._factor(_symbol, factors);
|
|
2258
|
-
if(retval.equals(symbol)) {
|
|
2259
|
-
return retval;
|
|
2260
|
-
}
|
|
2261
|
-
|
|
2262
|
-
if(retval.group === CB) {
|
|
2263
|
-
var t = new Symbol(1);
|
|
2264
|
-
var p = _.parse(retval.power);
|
|
2265
|
-
//store the multiplier and strip it
|
|
2266
|
-
var m = _.parse(retval.multiplier);
|
|
2267
|
-
|
|
2268
|
-
retval.toUnitMultiplier();
|
|
2269
|
-
|
|
2270
|
-
/*
|
|
2271
|
-
* NOTE: for sign issues with factor START DEBUGGING HERE
|
|
2272
|
-
*/
|
|
2273
|
-
//move the sign to t
|
|
2274
|
-
if(retval.multiplier.lessThan(0)) {
|
|
2275
|
-
t.negate();
|
|
2276
|
-
retval.negate();
|
|
2277
|
-
}
|
|
2278
|
-
|
|
2279
|
-
retval.each(function (x) {
|
|
2280
|
-
// Related to #566. Since the symbol's group may not have been properly
|
|
2281
|
-
// updated, it's easier to just parse the symbol and have the parser
|
|
2282
|
-
// do the update for us.
|
|
2283
|
-
var factored = _.parse(__.Factor._factor(x));
|
|
2284
|
-
|
|
2285
|
-
if(factored.group === CB) {
|
|
2286
|
-
// Include the multiplier
|
|
2287
|
-
m = _.multiply(m, Symbol.create(factored.multiplier));
|
|
2288
|
-
factored.each(function (y) {
|
|
2289
|
-
var _factored = _.parse(__.Factor._factor(y));
|
|
2290
|
-
t = _.multiply(t, _factored);
|
|
2291
|
-
if(_factored.group === CB) {
|
|
2292
|
-
m = _.multiply(m, Symbol.create(_factored.multiplier));
|
|
2293
|
-
}
|
|
2294
|
-
});
|
|
2295
|
-
}
|
|
2296
|
-
else {
|
|
2297
|
-
t = _.multiply(t, factored);
|
|
2298
|
-
}
|
|
2299
|
-
});
|
|
2300
|
-
|
|
2301
|
-
//put back the multiplier and power
|
|
2302
|
-
retval = _.pow(_.multiply(m, t), p);
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
return retval;
|
|
2306
|
-
},
|
|
2307
|
-
quadFactor: function (symbol, factors) {
|
|
2308
|
-
if(symbol.isPoly() && __.degree(symbol.equals(2))) {
|
|
2309
|
-
//We've already checked that we're dealing with a polynomial
|
|
2310
|
-
var v = core.Utils.variables(symbol)[0]; //get the variable
|
|
2311
|
-
var coeffs = __.coeffs(symbol, v);
|
|
2312
|
-
//factor the lead coefficient
|
|
2313
|
-
var cf = __.Factor._factor(coeffs[2].clone());
|
|
2314
|
-
//check if we have factors
|
|
2315
|
-
if(cf.group === CB) {
|
|
2316
|
-
var symbols = cf.collectSymbols();
|
|
2317
|
-
//if the factors are greater than 2 we're done so exit
|
|
2318
|
-
if(symbols.length > 2)
|
|
2319
|
-
return symbol;
|
|
2320
|
-
//if we have two factors then attempt to factor the polynomial
|
|
2321
|
-
//let the factors be f1 and f1
|
|
2322
|
-
//let the factors be (ax+b)(cx+d)
|
|
2323
|
-
//let the coefficients be c1x^2+c2x+c3
|
|
2324
|
-
//then a(x1)+c(x2)=c2 and x1*x2=c3
|
|
2325
|
-
//we can solve for x1 and x2
|
|
2326
|
-
var c = _.multiply(_.parse(coeffs[0]), _.parse(symbols[0]));
|
|
2327
|
-
var b = _.parse(coeffs[1]).negate();
|
|
2328
|
-
var a = _.parse(symbols[1]);
|
|
2329
|
-
//solve the system
|
|
2330
|
-
var root = __.quad(a, b, c).filter(function (x) {
|
|
2331
|
-
if(core.Utils.isInt(x))
|
|
2332
|
-
return x;
|
|
2333
|
-
});
|
|
2334
|
-
//if we have one root then find the other one by dividing the constant
|
|
2335
|
-
if(root.length === 1) {
|
|
2336
|
-
var root1 = root[0];
|
|
2337
|
-
var root2 = _.divide(coeffs[0], _.parse(root1));
|
|
2338
|
-
if(core.Utils.isInt(root2)) {
|
|
2339
|
-
//we found them both
|
|
2340
|
-
factors.add(_.parse(format('({0})*({1})+({2})', symbols[1], v, root2)));
|
|
2341
|
-
factors.add(_.parse(format('({0})*({1})+({2})', symbols[0], v, root1)));
|
|
2342
|
-
symbol = new Symbol(1);
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
return symbol;
|
|
2348
|
-
},
|
|
2349
|
-
cubeFactor: function (symbol, factors) {
|
|
2350
|
-
if(symbol.isComposite()) {
|
|
2351
|
-
var symbols = symbol.collectSymbols();
|
|
2352
|
-
// The symbol should be in the form of a^3+-b^3. The length
|
|
2353
|
-
// should therefore only be two. If it's any different from this
|
|
2354
|
-
// then we're done
|
|
2355
|
-
if(symbols.length === 2) {
|
|
2356
|
-
// Store the signs and then strip them from the symbols
|
|
2357
|
-
var sign_a = symbols[0].sign();
|
|
2358
|
-
var a = symbols[0].clone().abs();
|
|
2359
|
-
var sign_b = symbols[1].sign();
|
|
2360
|
-
var b = symbols[1].clone().abs();
|
|
2361
|
-
// Check if they're cube
|
|
2362
|
-
if(a.isCube() && b.isCube()) {
|
|
2363
|
-
// Keep the negative sign on the right, meaning b is always negative.
|
|
2364
|
-
if(sign_a < sign_b) {
|
|
2365
|
-
// Swap the signs and then the values
|
|
2366
|
-
[sign_a, sign_b] = [sign_b, sign_a];
|
|
2367
|
-
[a, b] = [b, a];
|
|
2368
|
-
}
|
|
2369
|
-
|
|
2370
|
-
// Get teh roots
|
|
2371
|
-
var m_root_a = _.parse(a.getNth(3));
|
|
2372
|
-
var m_root_b = _.parse(b.getNth(3));
|
|
2373
|
-
|
|
2374
|
-
// Remove the cube for both
|
|
2375
|
-
var x = _.multiply(_.expand(_.pow(a.clone().toUnitMultiplier(), _.parse('1/3'))), m_root_a);
|
|
2376
|
-
var y = _.multiply(_.expand(_.pow(b.clone().toUnitMultiplier(), _.parse('1/3'))), m_root_b);
|
|
2377
|
-
|
|
2378
|
-
if(sign_a === 1 && sign_b === -1) {
|
|
2379
|
-
// Apply difference of cubes rule
|
|
2380
|
-
factors.add(_.parse(format('(({0})-({1}))', x, y)));
|
|
2381
|
-
factors.add(_.parse(format('(({0})^2+({0})*({1})+({1})^2)', x, y)));
|
|
2382
|
-
symbol = Symbol(1);
|
|
2383
|
-
}
|
|
2384
|
-
else if(sign_a === 1 && sign_b === 1) {
|
|
2385
|
-
// Apply sum of cubes rule
|
|
2386
|
-
factors.add(_.parse(format('(({0})+({1}))', x, y)));
|
|
2387
|
-
factors.add(_.parse(format('(({0})^2-({0})*({1})+({1})^2)', x, y)));
|
|
2388
|
-
symbol = Symbol(1);
|
|
2389
|
-
}
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
|
-
}
|
|
2393
|
-
|
|
2394
|
-
return symbol;
|
|
2395
|
-
},
|
|
2396
|
-
_factor: function (symbol, factors) {
|
|
2397
|
-
var g = symbol.group;
|
|
2398
|
-
//some items cannot be factored any further so return those right away
|
|
2399
|
-
if(symbol.group === FN) {
|
|
2400
|
-
var arg = symbol.args[0];
|
|
2401
|
-
if(arg.group === S && arg.isSimple()) {
|
|
2402
|
-
return symbol;
|
|
2403
|
-
}
|
|
2404
|
-
}
|
|
2405
|
-
else if(symbol.group === S && symbol.isSimple()) {
|
|
2406
|
-
return symbol;
|
|
2407
|
-
}
|
|
2408
|
-
|
|
2409
|
-
// Expand the symbol to get it in a predictable form. If this step
|
|
2410
|
-
// is skipped some factors are missed.
|
|
2411
|
-
//if(symbol.group === CP && !(even(symbol.power) && symbol.multiplier.lessThan(0))) {
|
|
2412
|
-
if(symbol.group === CP) {
|
|
2413
|
-
symbol.distributeMultiplier(true);
|
|
2414
|
-
var t = new Symbol(0);
|
|
2415
|
-
symbol.each(function (x) {
|
|
2416
|
-
if((x.group === CP && x.power.greaterThan(1) || x.group === CB))
|
|
2417
|
-
x = _.expand(x);
|
|
2418
|
-
t = _.add(t, x);
|
|
2419
|
-
});
|
|
2420
|
-
t.power = symbol.power;
|
|
2421
|
-
|
|
2422
|
-
symbol = t;
|
|
2423
|
-
}
|
|
2424
|
-
|
|
2425
|
-
if(symbol.group === FN && symbol.fname !== 'sqrt') {
|
|
2426
|
-
symbol = core.Utils.evaluate(symbol);
|
|
2427
|
-
}
|
|
2428
|
-
|
|
2429
|
-
//make a copy of the symbol to return if something goes wrong
|
|
2430
|
-
var untouched = symbol.clone();
|
|
2431
|
-
try {
|
|
2432
|
-
if(symbol.group === CB) {
|
|
2433
|
-
var p = _.parse(symbol.power);
|
|
2434
|
-
|
|
2435
|
-
var den_array, num_array, den, num, dfact, nfact;
|
|
2436
|
-
//grab the denominator and strip the multiplier and power. Store them in an array
|
|
2437
|
-
den_array = __.Simplify.strip(symbol.getDenom());
|
|
2438
|
-
num_array = __.Simplify.strip(symbol.getNum());
|
|
2439
|
-
|
|
2440
|
-
den = den_array.pop();
|
|
2441
|
-
num = num_array.pop();
|
|
2442
|
-
|
|
2443
|
-
//if the numerator equals the symbol then we've hit the simplest form and then we're done
|
|
2444
|
-
if(num.equals(symbol)) {
|
|
2445
|
-
return symbol;
|
|
2446
|
-
}
|
|
2447
|
-
nfact = __.Factor.factor(num);
|
|
2448
|
-
dfact = __.Factor.factor(den);
|
|
2449
|
-
|
|
2450
|
-
var n = __.Simplify.unstrip(num_array, nfact);
|
|
2451
|
-
var d = __.Simplify.unstrip(den_array, dfact);
|
|
2452
|
-
|
|
2453
|
-
var retval = _.divide(n, d);
|
|
2454
|
-
|
|
2455
|
-
return retval;
|
|
2456
|
-
}
|
|
2457
|
-
if(symbol.group === S) {
|
|
2458
|
-
return symbol; //absolutely nothing to do
|
|
2459
|
-
}
|
|
2460
|
-
|
|
2461
|
-
if(symbol.isConstant()) {
|
|
2462
|
-
if(symbol.equals(1))
|
|
2463
|
-
return symbol.clone();
|
|
2464
|
-
var ret = core.Math2.factor(symbol);
|
|
2465
|
-
return ret;
|
|
2466
|
-
}
|
|
2467
|
-
|
|
2468
|
-
var p = symbol.power.clone();
|
|
2469
|
-
|
|
2470
|
-
if(isInt(p) && !(p.lessThan(0) && symbol.group === FN)) {
|
|
2471
|
-
var sign = p.sign();
|
|
2472
|
-
symbol.toLinear();
|
|
2473
|
-
factors = factors || new Factors();
|
|
2474
|
-
var map = {};
|
|
2475
|
-
symbol = _.parse(core.Utils.subFunctions(symbol, map));
|
|
2476
|
-
if(keys(map).length > 0) { //it might have functions
|
|
2477
|
-
factors.preAdd = function (factor) {
|
|
2478
|
-
var ret = _.parse(factor, core.Utils.getFunctionsSubs(map));
|
|
2479
|
-
return ret;
|
|
2480
|
-
};
|
|
2481
|
-
}
|
|
2482
|
-
|
|
2483
|
-
//strip the power
|
|
2484
|
-
if(!symbol.isLinear()) {
|
|
2485
|
-
factors.pFactor = symbol.power.toString();
|
|
2486
|
-
symbol.toLinear();
|
|
2487
|
-
}
|
|
2488
|
-
|
|
2489
|
-
var vars = variables(symbol);
|
|
2490
|
-
//bypass for imaginary. TODO: find a better solution
|
|
2491
|
-
if(symbol.isImaginary()) {
|
|
2492
|
-
vars.push(core.Settings.IMAGINARY);
|
|
2493
|
-
}
|
|
2494
|
-
var multiVar = vars.length > 1;
|
|
2495
|
-
|
|
2496
|
-
//minor optimization. Seems to cut factor time by half in some cases.
|
|
2497
|
-
if(multiVar) {
|
|
2498
|
-
var all_S = true, all_unit = true;
|
|
2499
|
-
symbol.each(function (x) {
|
|
2500
|
-
if(x.group !== S)
|
|
2501
|
-
all_S = false;
|
|
2502
|
-
if(!x.multiplier.equals(1))
|
|
2503
|
-
all_unit = false;
|
|
2504
|
-
});
|
|
2505
|
-
|
|
2506
|
-
if(all_S && all_unit) {
|
|
2507
|
-
return _.pow(_.parse(symbol, core.Utils.getFunctionsSubs(map)), _.parse(p));
|
|
2508
|
-
}
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
//factor the coefficients
|
|
2512
|
-
var coeff_factors = new Factors();
|
|
2513
|
-
|
|
2514
|
-
symbol = __.Factor.coeffFactor(symbol, coeff_factors);
|
|
2515
|
-
|
|
2516
|
-
coeff_factors.each(function (x) {
|
|
2517
|
-
// If the factor was negative but was within a square then it becomes positive
|
|
2518
|
-
if(even(p) && x.lessThan(0)) {
|
|
2519
|
-
x.negate();
|
|
2520
|
-
}
|
|
2521
|
-
|
|
2522
|
-
if(sign < 0)
|
|
2523
|
-
x.invert();
|
|
2524
|
-
factors.add(x);
|
|
2525
|
-
});
|
|
2526
|
-
|
|
2527
|
-
//factor the power
|
|
2528
|
-
var power_factors = new Factors();
|
|
2529
|
-
symbol = __.Factor.powerFactor(symbol, power_factors);
|
|
2530
|
-
power_factors.each(function (x) {
|
|
2531
|
-
if(sign < 0)
|
|
2532
|
-
x.invert();
|
|
2533
|
-
factors.add(x);
|
|
2534
|
-
});
|
|
2535
|
-
|
|
2536
|
-
if(!multiVar) {
|
|
2537
|
-
//pass in vars[0] for safety
|
|
2538
|
-
var v = vars[0];
|
|
2539
|
-
|
|
2540
|
-
symbol = __.Factor.squareFree(symbol, factors, v);
|
|
2541
|
-
|
|
2542
|
-
var t_factors = new Factors();
|
|
2543
|
-
|
|
2544
|
-
symbol = __.Factor.trialAndError(symbol, t_factors, v);
|
|
2545
|
-
|
|
2546
|
-
//generate a symbol based off the last factors
|
|
2547
|
-
var tf_symbol = t_factors.toSymbol();
|
|
2548
|
-
//if nothing was factored then return the factors
|
|
2549
|
-
if(tf_symbol.equals(untouched)) {
|
|
2550
|
-
return tf_symbol;
|
|
2551
|
-
}
|
|
2552
|
-
|
|
2553
|
-
for(var x in t_factors.factors) {
|
|
2554
|
-
//store the current factor in t_factor
|
|
2555
|
-
var t_factor = t_factors.factors[x];
|
|
2556
|
-
factors.add(_.pow(t_factor, _.parse(p)));
|
|
2557
|
-
}
|
|
2558
|
-
//if we still don't have a factor and it's quadratic then let's just do a quad factor
|
|
2559
|
-
if(symbol.equals(untouched)) {
|
|
2560
|
-
symbol = __.Factor.quadFactor(symbol, factors);
|
|
2561
|
-
}
|
|
2562
|
-
|
|
2563
|
-
}
|
|
2564
|
-
else {
|
|
2565
|
-
// Try sum and difference of cubes
|
|
2566
|
-
symbol = __.Factor.cubeFactor(symbol, factors);
|
|
2567
|
-
|
|
2568
|
-
symbol = __.Factor.mfactor(symbol, factors);
|
|
2569
|
-
|
|
2570
|
-
//put back the sign of power
|
|
2571
|
-
factors.each(function (x) {
|
|
2572
|
-
if(sign < 0)
|
|
2573
|
-
x.power.negate();
|
|
2574
|
-
});
|
|
2575
|
-
}
|
|
2576
|
-
|
|
2577
|
-
//last minute clean up
|
|
2578
|
-
symbol = _.parse(symbol, core.Utils.getFunctionsSubs(map));
|
|
2579
|
-
|
|
2580
|
-
var addPower = factors.length === 1;
|
|
2581
|
-
|
|
2582
|
-
factors.add(_.pow(symbol, _.parse(p)));
|
|
2583
|
-
|
|
2584
|
-
var retval = factors.toSymbol();
|
|
2585
|
-
|
|
2586
|
-
// We may have only factored out the symbol itself so we end up with a factor of one
|
|
2587
|
-
// where the power needs to be placed back
|
|
2588
|
-
// e.g. factor((2*y+p)^2). Here we end up having a factor of 1 remaining and a p of 2.
|
|
2589
|
-
if(addPower && symbol.equals(1) && retval.isLinear()) {
|
|
2590
|
-
retval = _.pow(retval, _.parse(p));
|
|
2591
|
-
}
|
|
2592
|
-
|
|
2593
|
-
return retval;
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
|
-
return symbol;
|
|
2597
|
-
}
|
|
2598
|
-
catch(e) {
|
|
2599
|
-
//no need to stop the show because something went wrong :). Just return the unfactored.
|
|
2600
|
-
return untouched;
|
|
2601
|
-
}
|
|
2602
|
-
},
|
|
2603
|
-
reduce: function (symbol, factors) {
|
|
2604
|
-
if(symbol.group === CP && symbol.length === 2) {
|
|
2605
|
-
var symbols = symbol.collectSymbols().sort(function (a, b) {
|
|
2606
|
-
return b.multiplier - a.multiplier;
|
|
2607
|
-
});
|
|
2608
|
-
if(symbols[0].power.equals(symbols[1].power)) {
|
|
2609
|
-
//x^n-a^n
|
|
2610
|
-
var n = _.parse(symbols[0].power),
|
|
2611
|
-
a = symbols[0].clone().toLinear(),
|
|
2612
|
-
b = symbols[1].clone().toLinear();
|
|
2613
|
-
|
|
2614
|
-
//apply rule: (a-b)*sum(a^(n-i)*b^(i-1),1,n)
|
|
2615
|
-
factors.add(_.add(a.clone(), b.clone()));
|
|
2616
|
-
//flip the sign
|
|
2617
|
-
b.negate();
|
|
2618
|
-
//turn n into a number
|
|
2619
|
-
var nn = Number(n);
|
|
2620
|
-
//the remainder
|
|
2621
|
-
var result = new Symbol(0);
|
|
2622
|
-
for(var i = 1; i <= nn; i++) {
|
|
2623
|
-
var aa = _.pow(a.clone(), _.subtract(n.clone(), new Symbol(i))),
|
|
2624
|
-
bb = _.pow(b.clone(), _.subtract(new Symbol(i), new Symbol(1)));
|
|
2625
|
-
result = _.add(result, _.multiply(aa, bb));
|
|
2626
|
-
}
|
|
2627
|
-
return result;
|
|
2628
|
-
}
|
|
2629
|
-
}
|
|
2630
|
-
return symbol;
|
|
2631
|
-
},
|
|
2632
|
-
/**
|
|
2633
|
-
* Makes Symbol square free
|
|
2634
|
-
* @param {Symbol} symbol
|
|
2635
|
-
* @param {Factors} factors
|
|
2636
|
-
* @@param {String} variable The variable which is being factored
|
|
2637
|
-
* @returns {[Symbol, Factor]}
|
|
2638
|
-
*/
|
|
2639
|
-
squareFree: function (symbol, factors, variable) {
|
|
2640
|
-
if(symbol.isConstant() || symbol.group === S)
|
|
2641
|
-
return symbol;
|
|
2642
|
-
|
|
2643
|
-
var poly = new Polynomial(symbol, variable);
|
|
2644
|
-
var sqfr = poly.squareFree();
|
|
2645
|
-
var p = sqfr[2];
|
|
2646
|
-
//if we found a square then the p entry in the array will be non-unit
|
|
2647
|
-
if(p !== 1) {
|
|
2648
|
-
//make sure the remainder doesn't have factors
|
|
2649
|
-
var t = sqfr[1].toSymbol();
|
|
2650
|
-
t.power = t.power.multiply(new Frac(p));
|
|
2651
|
-
//send the factor to be fatored to be sure it's completely factored
|
|
2652
|
-
factors.add(__.Factor.factor(t));
|
|
2653
|
-
|
|
2654
|
-
var retval = __.Factor.squareFree(sqfr[0].toSymbol(), factors);
|
|
2655
|
-
|
|
2656
|
-
return retval;
|
|
2657
|
-
}
|
|
2658
|
-
|
|
2659
|
-
return symbol;
|
|
2660
|
-
},
|
|
2661
|
-
/**
|
|
2662
|
-
* Factors the powers such that the lowest power is a constant
|
|
2663
|
-
* @param {Symbol} symbol
|
|
2664
|
-
* @param {Factors} factors
|
|
2665
|
-
* @returns {[Symbol, Factor]}
|
|
2666
|
-
*/
|
|
2667
|
-
powerFactor: function (symbol, factors) {
|
|
2668
|
-
//only PL need apply
|
|
2669
|
-
if(symbol.group !== PL || symbol.previousGroup === EX)
|
|
2670
|
-
return symbol;
|
|
2671
|
-
var k = keys(symbol.symbols);
|
|
2672
|
-
//we expect only numeric powers so return all else
|
|
2673
|
-
if(!core.Utils.allNumeric(k))
|
|
2674
|
-
return symbol;
|
|
2675
|
-
|
|
2676
|
-
var d = core.Utils.arrayMin(k);
|
|
2677
|
-
var retval = new Symbol(0);
|
|
2678
|
-
var q = _.parse(symbol.value + '^' + d);
|
|
2679
|
-
symbol.each(function (x) {
|
|
2680
|
-
x = _.divide(x, q.clone());
|
|
2681
|
-
retval = _.add(retval, x);
|
|
2682
|
-
});
|
|
2683
|
-
|
|
2684
|
-
factors.add(q);
|
|
2685
|
-
return retval;
|
|
2686
|
-
},
|
|
2687
|
-
/**
|
|
2688
|
-
* Removes GCD from coefficients
|
|
2689
|
-
* @param {Symbol} symbol
|
|
2690
|
-
* @param {Factor} factors
|
|
2691
|
-
* @returns {Symbol}
|
|
2692
|
-
*/
|
|
2693
|
-
coeffFactor: function (symbol, factors) {
|
|
2694
|
-
if(symbol.isComposite()) {
|
|
2695
|
-
var gcd = core.Math2.QGCD.apply(null, symbol.coeffs());
|
|
2696
|
-
|
|
2697
|
-
if(!gcd.equals(1)) {
|
|
2698
|
-
symbol.each(function (x) {
|
|
2699
|
-
if(x.isComposite()) {
|
|
2700
|
-
x.each(function (y) {
|
|
2701
|
-
y.multiplier = y.multiplier.divide(gcd);
|
|
2702
|
-
});
|
|
2703
|
-
}
|
|
2704
|
-
else
|
|
2705
|
-
x.multiplier = x.multiplier.divide(gcd);
|
|
2706
|
-
});
|
|
2707
|
-
symbol.updateHash();
|
|
2708
|
-
}
|
|
2709
|
-
else {
|
|
2710
|
-
// TODO: This should probably go to the prototype
|
|
2711
|
-
var power = function (symbol) {
|
|
2712
|
-
var p;
|
|
2713
|
-
if(symbol.group === CB) {
|
|
2714
|
-
p = 0;
|
|
2715
|
-
symbol.each(function (x) {
|
|
2716
|
-
p += x.power;
|
|
2717
|
-
});
|
|
2718
|
-
}
|
|
2719
|
-
else {
|
|
2720
|
-
p = Number(symbol.power);
|
|
2721
|
-
}
|
|
2722
|
-
return p;
|
|
2723
|
-
};
|
|
2724
|
-
// Factor out negatives from the lead term
|
|
2725
|
-
var terms = symbol.collectSymbols(null, null, null, true).sort(function (a, b) {
|
|
2726
|
-
// Push constants to the back
|
|
2727
|
-
if(a.isConstant(true))
|
|
2728
|
-
return 1;
|
|
2729
|
-
return b.power - a.power;
|
|
2730
|
-
});
|
|
2731
|
-
|
|
2732
|
-
var LT = terms[0];
|
|
2733
|
-
|
|
2734
|
-
// Check if the LT is indeed the greatest
|
|
2735
|
-
if(power(LT) > power(terms[1]) || terms[1].isConstant(true)) {
|
|
2736
|
-
if(LT.multiplier.lessThan(0)) {
|
|
2737
|
-
// Although the symbol should always be linear at this point, remove the negative for squares
|
|
2738
|
-
// to be safe.
|
|
2739
|
-
factors.add(new Symbol(-1));
|
|
2740
|
-
|
|
2741
|
-
symbol.each(function (x) {
|
|
2742
|
-
x.negate();
|
|
2743
|
-
}, true);
|
|
2744
|
-
}
|
|
2745
|
-
}
|
|
2746
|
-
|
|
2747
|
-
}
|
|
2748
|
-
|
|
2749
|
-
if(factors) {
|
|
2750
|
-
factors.add(new Symbol(gcd));
|
|
2751
|
-
}
|
|
2752
|
-
}
|
|
2753
|
-
|
|
2754
|
-
return symbol;
|
|
2755
|
-
},
|
|
2756
|
-
/**
|
|
2757
|
-
* The name says it all :)
|
|
2758
|
-
* @param {Symbol} symbol
|
|
2759
|
-
* @param {Factor} factors
|
|
2760
|
-
* @@param {String} variable
|
|
2761
|
-
* @returns {Symbol}
|
|
2762
|
-
*/
|
|
2763
|
-
trialAndError: function (symbol, factors, variable) {
|
|
2764
|
-
var untouched = symbol.clone();
|
|
2765
|
-
try {
|
|
2766
|
-
// At temp holder for the factors. If all goes well then
|
|
2767
|
-
// they'll be moved to the actual factors.
|
|
2768
|
-
var factor_array = [];
|
|
2769
|
-
|
|
2770
|
-
if(symbol.isConstant() || symbol.group === S)
|
|
2771
|
-
return symbol;
|
|
2772
|
-
var poly = new Polynomial(symbol, variable),
|
|
2773
|
-
cnst = poly.coeffs[0],
|
|
2774
|
-
cfactors = core.Math2.ifactor(cnst),
|
|
2775
|
-
roots = __.proots(symbol);
|
|
2776
|
-
for(var i = 0; i < roots.length; i++) {
|
|
2777
|
-
var r = roots[i],
|
|
2778
|
-
p = 1;
|
|
2779
|
-
if(!isNaN(r)) { //if it's a number
|
|
2780
|
-
for(var x in cfactors) {
|
|
2781
|
-
//check it's raised to a power
|
|
2782
|
-
var n = core.Utils.round(Math.log(x) / Math.log(Math.abs(r)), 8);
|
|
2783
|
-
if(isInt(n)) {
|
|
2784
|
-
r = x; //x must be the root since n gave us a whole
|
|
2785
|
-
p = n;
|
|
2786
|
-
break;
|
|
2787
|
-
}
|
|
2788
|
-
}
|
|
2789
|
-
var root = new Frac(r),
|
|
2790
|
-
terms = [new Frac(root.num).negate()];
|
|
2791
|
-
terms[p] = new Frac(root.den);
|
|
2792
|
-
//convert to Frac. The den is coeff of LT and the num is coeff of constant
|
|
2793
|
-
var div = Polynomial.fromArray(terms, poly.variable).fill(),
|
|
2794
|
-
t = poly.divide(div);
|
|
2795
|
-
if(t[1].equalsNumber(0)) { //if it's zero we have a root and divide it out
|
|
2796
|
-
poly = t[0];
|
|
2797
|
-
// factors.add(div.toSymbol());
|
|
2798
|
-
factor_array.push(div.toSymbol());
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
}
|
|
2802
|
-
|
|
2803
|
-
if(!poly.equalsNumber(1)) {
|
|
2804
|
-
poly = __.Factor.search(poly, factors);
|
|
2805
|
-
}
|
|
2806
|
-
|
|
2807
|
-
// Move the factors over since all went well.
|
|
2808
|
-
factor_array.forEach(function (x) {
|
|
2809
|
-
factors.add(x);
|
|
2810
|
-
});
|
|
2811
|
-
|
|
2812
|
-
return poly.toSymbol();
|
|
2813
|
-
}
|
|
2814
|
-
catch(e) {
|
|
2815
|
-
return untouched;
|
|
2816
|
-
}
|
|
2817
|
-
},
|
|
2818
|
-
search: function (poly, factors, base) {
|
|
2819
|
-
base = base || 10; //I like 10 because numbers exhibit similar behaviours at 10
|
|
2820
|
-
var v = poly.variable; //the polynmial variable name
|
|
2821
|
-
/**
|
|
2822
|
-
* Attempt to remove a root by division given a number by first creating
|
|
2823
|
-
* a polynomial fromt he given information
|
|
2824
|
-
* @param {int} c1 - coeffient for the constant
|
|
2825
|
-
* @param {int} c2 - coefficient for the LT
|
|
2826
|
-
* @param {int} n - the number to be used to construct the polynomial
|
|
2827
|
-
* @param {int} p - the power at which to create the polynomial
|
|
2828
|
-
* @returns {null|Polynomial} - returns polynomial if successful otherwise null
|
|
2829
|
-
*/
|
|
2830
|
-
var check = function (c1, c2, n, p) {
|
|
2831
|
-
var candidate = Polynomial.fit(c1, c2, n, base, p, v);
|
|
2832
|
-
if(candidate && candidate.coeffs.length > 1) {
|
|
2833
|
-
var t = poly.divide(candidate);
|
|
2834
|
-
if(t[1].equalsNumber(0)) {
|
|
2835
|
-
factors.add(candidate.toSymbol());
|
|
2836
|
-
return [t[0], candidate];
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
return null;
|
|
2840
|
-
};
|
|
2841
|
-
var cnst = poly.coeffs[0];
|
|
2842
|
-
var cfactors = core.Math2.ifactor(cnst);
|
|
2843
|
-
var lc = poly.lc();
|
|
2844
|
-
var ltfactors = core.Math2.ifactor(lc);
|
|
2845
|
-
var subbed = poly.sub(base);
|
|
2846
|
-
var isubbed = core.Math2.ifactor(subbed);
|
|
2847
|
-
var nfactors = __.Factor.mix(isubbed, subbed < 0);
|
|
2848
|
-
var cp = Math.ceil(poly.coeffs.length / 2);
|
|
2849
|
-
var lc_is_neg = lc.lessThan(0);
|
|
2850
|
-
var cnst_is_neg = cnst.lessThan(0);
|
|
2851
|
-
ltfactors['1'] = 1;
|
|
2852
|
-
cfactors['1'] = 1;
|
|
2853
|
-
while(cp--) {
|
|
2854
|
-
for(var x in ltfactors) {
|
|
2855
|
-
for(var y in cfactors) {
|
|
2856
|
-
for(var i = 0; i < nfactors.length; i++) {
|
|
2857
|
-
var factor_found = check(x, y, nfactors[i], cp);
|
|
2858
|
-
if(factor_found) {
|
|
2859
|
-
poly = factor_found[0];
|
|
2860
|
-
if(!core.Utils.isPrime(poly.sub(base)))
|
|
2861
|
-
poly = __.Factor.search(poly, factors);
|
|
2862
|
-
return poly;
|
|
2863
|
-
}
|
|
2864
|
-
else if(!factor_found) {
|
|
2865
|
-
if(lc_is_neg && cnst_is_neg)
|
|
2866
|
-
factor_found = check(-x, -y, nfactors[i], cp);
|
|
2867
|
-
else if(lc_is_neg)
|
|
2868
|
-
factor_found = check(-x, y, nfactors[i], cp); //check a negative lc
|
|
2869
|
-
else if(cnst_is_neg)
|
|
2870
|
-
factor_found = check(x, -y, nfactors[i], cp); //check a negative constant
|
|
2871
|
-
}
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
}
|
|
2876
|
-
return poly;
|
|
2877
|
-
},
|
|
2878
|
-
/**
|
|
2879
|
-
* Equivalent of square free factor for multivariate polynomials
|
|
2880
|
-
* @param {type} symbol
|
|
2881
|
-
* @param {type} factors
|
|
2882
|
-
* @returns {AlgebraL#18.Factor.mSqfrFactor.symbol|Array|AlgebraL#18.__.Factor.mSqfrFactor.d}
|
|
2883
|
-
*/
|
|
2884
|
-
mSqfrFactor: function (symbol, factors) {
|
|
2885
|
-
if(symbol.group !== FN) {
|
|
2886
|
-
var vars = variables(symbol).reverse();
|
|
2887
|
-
|
|
2888
|
-
// Loop through all the variable and remove the partial derivatives
|
|
2889
|
-
for(var i = 0; i < vars.length; i++) {
|
|
2890
|
-
do {
|
|
2891
|
-
if(vars[i] === symbol.value) {
|
|
2892
|
-
//the derivative tells us nothing since this symbol is already the factor
|
|
2893
|
-
factors.add(symbol);
|
|
2894
|
-
symbol = new Symbol(1);
|
|
2895
|
-
continue;
|
|
2896
|
-
}
|
|
2897
|
-
|
|
2898
|
-
var diff = core.Calculus.diff(symbol, vars[i]);
|
|
2899
|
-
|
|
2900
|
-
var d = __.Factor.coeffFactor(diff);
|
|
2901
|
-
|
|
2902
|
-
if(d.equals(0))
|
|
2903
|
-
break;
|
|
2904
|
-
|
|
2905
|
-
//trial division to see if factors have whole numbers.
|
|
2906
|
-
//This can be optimized by stopping as soon as can_divide is false
|
|
2907
|
-
//this will also need utilize big number at some point
|
|
2908
|
-
var can_divide = true;
|
|
2909
|
-
if(d.isConstant() && symbol.isComposite()) {
|
|
2910
|
-
//check the coefficients
|
|
2911
|
-
|
|
2912
|
-
symbol.each(function (x) {
|
|
2913
|
-
if(x.multiplier % d !== 0)
|
|
2914
|
-
can_divide = false;
|
|
2915
|
-
}, true);
|
|
2916
|
-
}
|
|
2917
|
-
|
|
2918
|
-
//if we can divide then do so
|
|
2919
|
-
if(can_divide) {
|
|
2920
|
-
|
|
2921
|
-
var div = __.div(symbol, d.clone()),
|
|
2922
|
-
is_factor = div[1].equals(0);
|
|
2923
|
-
|
|
2924
|
-
// Break infinite loop for factoring e^t*x-1
|
|
2925
|
-
if((symbol.equals(div[0]) && div[1].equals(0))) {
|
|
2926
|
-
break;
|
|
2927
|
-
}
|
|
2928
|
-
|
|
2929
|
-
if(div[0].isConstant()) {
|
|
2930
|
-
factors.add(div[0]);
|
|
2931
|
-
break;
|
|
2932
|
-
}
|
|
2933
|
-
|
|
2934
|
-
}
|
|
2935
|
-
else
|
|
2936
|
-
is_factor = false;
|
|
2937
|
-
|
|
2938
|
-
if(is_factor) {
|
|
2939
|
-
factors.add(div[0]);
|
|
2940
|
-
symbol = d;
|
|
2941
|
-
}
|
|
2942
|
-
}
|
|
2943
|
-
while(is_factor)
|
|
2944
|
-
}
|
|
2945
|
-
}
|
|
2946
|
-
|
|
2947
|
-
return symbol;
|
|
2948
|
-
},
|
|
2949
|
-
//difference of squares factorization
|
|
2950
|
-
sqdiff: function (symbol, factors) {
|
|
2951
|
-
if(symbol.isConstant('all')) {
|
|
2952
|
-
// Nothing to do
|
|
2953
|
-
return symbol;
|
|
2954
|
-
}
|
|
2955
|
-
|
|
2956
|
-
try {
|
|
2957
|
-
var remove_square = function (x) {
|
|
2958
|
-
return core.Utils.block('POSITIVE_MULTIPLIERS', function () {
|
|
2959
|
-
return Symbol.unwrapPARENS(math.sqrt(math.abs(x)));
|
|
2960
|
-
}, true);
|
|
2961
|
-
};
|
|
2962
|
-
var separated = core.Utils.separate(symbol.clone());
|
|
2963
|
-
|
|
2964
|
-
var obj_array = [];
|
|
2965
|
-
|
|
2966
|
-
//get the unique variables
|
|
2967
|
-
for(var x in separated) {
|
|
2968
|
-
if(x !== 'constants') {
|
|
2969
|
-
obj_array.push(separated[x]);
|
|
2970
|
-
}
|
|
2971
|
-
}
|
|
2972
|
-
obj_array.sort(function (a, b) {
|
|
2973
|
-
return b.power - a.power;
|
|
2974
|
-
});
|
|
2975
|
-
|
|
2976
|
-
//if we have the same number of variables as unique variables then we can apply the difference of squares
|
|
2977
|
-
if(obj_array.length === 2) {
|
|
2978
|
-
var a, b;
|
|
2979
|
-
a = obj_array.pop();
|
|
2980
|
-
b = obj_array.pop();
|
|
2981
|
-
|
|
2982
|
-
if(even(a.power) && even(b.power)
|
|
2983
|
-
&& a.sign() === b.sign()
|
|
2984
|
-
&& a.group === S && b.group === S) {
|
|
2985
|
-
throw new Error('Unable to factor');
|
|
2986
|
-
}
|
|
2987
|
-
;
|
|
2988
|
-
|
|
2989
|
-
if(a.isComposite() && b.power.equals(2)) {
|
|
2990
|
-
//remove the square from b
|
|
2991
|
-
b = remove_square(b);
|
|
2992
|
-
var f = __.Factor.factor(_.add(a, separated.constants));
|
|
2993
|
-
if(f.power.equals(2)) {
|
|
2994
|
-
f.toLinear();
|
|
2995
|
-
factors.add(_.subtract(f.clone(), b.clone()));
|
|
2996
|
-
factors.add(_.add(f, b));
|
|
2997
|
-
symbol = new Symbol(1);
|
|
2998
|
-
}
|
|
2999
|
-
}
|
|
3000
|
-
else {
|
|
3001
|
-
a = a.powSimp();
|
|
3002
|
-
b = b.powSimp();
|
|
3003
|
-
|
|
3004
|
-
if((a.group === S || a.fname === '') && a.power.equals(2) && (b.group === S || b.fname === '') && b.power.equals(2) && !separated.constants) {
|
|
3005
|
-
if(a.multiplier.lessThan(0)) {
|
|
3006
|
-
var t = b;
|
|
3007
|
-
b = a;
|
|
3008
|
-
a = t;
|
|
3009
|
-
}
|
|
3010
|
-
if(a.multiplier.greaterThan(0)) {
|
|
3011
|
-
a = remove_square(a);
|
|
3012
|
-
b = remove_square(b);
|
|
3013
|
-
}
|
|
3014
|
-
|
|
3015
|
-
factors.add(_.subtract(a.clone(), b.clone()));
|
|
3016
|
-
factors.add(_.add(a, b));
|
|
3017
|
-
symbol = new Symbol(1);
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
|
-
}
|
|
3021
|
-
}
|
|
3022
|
-
catch(e) {
|
|
3023
|
-
;
|
|
3024
|
-
}
|
|
3025
|
-
|
|
3026
|
-
return symbol;
|
|
3027
|
-
},
|
|
3028
|
-
//factoring for multivariate
|
|
3029
|
-
mfactor: function (symbol, factors) {
|
|
3030
|
-
|
|
3031
|
-
if(symbol.group === FN) {
|
|
3032
|
-
if(symbol.fname === 'sqrt') {
|
|
3033
|
-
var factors2 = new Factors(),
|
|
3034
|
-
arg = __.Factor.common(symbol.args[0].clone(), factors2);
|
|
3035
|
-
arg = __.Factor.coeffFactor(arg, factors2);
|
|
3036
|
-
symbol = _.multiply(_.symfunction('sqrt', [arg]), _.parse(symbol.multiplier));
|
|
3037
|
-
factors2.each(function (x) {
|
|
3038
|
-
symbol = _.multiply(symbol, _.parse(core.Utils.format('sqrt({0})', x)));
|
|
3039
|
-
});
|
|
3040
|
-
}
|
|
3041
|
-
else
|
|
3042
|
-
factors.add(symbol);
|
|
3043
|
-
}
|
|
3044
|
-
else {
|
|
3045
|
-
|
|
3046
|
-
//square free factorization
|
|
3047
|
-
symbol = __.Factor.mSqfrFactor(symbol, factors);
|
|
3048
|
-
|
|
3049
|
-
//try factor out common factors
|
|
3050
|
-
//symbol = __.Factor.common(symbol, factors);
|
|
3051
|
-
|
|
3052
|
-
var vars = variables(symbol),
|
|
3053
|
-
symbols = symbol.collectSymbols().map(function (x) {
|
|
3054
|
-
return Symbol.unwrapSQRT(x);
|
|
3055
|
-
}),
|
|
3056
|
-
sorted = {},
|
|
3057
|
-
maxes = {},
|
|
3058
|
-
l = vars.length, n = symbols.length;
|
|
3059
|
-
//take all the variables in the symbol and organize by variable name
|
|
3060
|
-
//e.g. a^2+a^2+b*a -> {a: {a^3, a^2, b*a}, b: {b*a}}
|
|
3061
|
-
|
|
3062
|
-
for(var i = 0; i < l; i++) {
|
|
3063
|
-
var v = vars[i];
|
|
3064
|
-
sorted[v] = new Symbol(0);
|
|
3065
|
-
for(var j = 0; j < n; j++) {
|
|
3066
|
-
var s = symbols[j];
|
|
3067
|
-
if(s.contains(v)) {
|
|
3068
|
-
var p = s.value === v ? s.power.toDecimal() : s.symbols[v].power.toDecimal();
|
|
3069
|
-
if(!maxes[v] || p < maxes[v])
|
|
3070
|
-
maxes[v] = p;
|
|
3071
|
-
sorted[v] = _.add(sorted[v], s.clone());
|
|
3072
|
-
}
|
|
3073
|
-
}
|
|
3074
|
-
}
|
|
3075
|
-
|
|
3076
|
-
for(var x in sorted) {
|
|
3077
|
-
var r = _.parse(x + '^' + maxes[x]);
|
|
3078
|
-
var div = _.divide(sorted[x], r);
|
|
3079
|
-
var new_factor = _.expand(div);
|
|
3080
|
-
|
|
3081
|
-
if(new_factor.equals(1))
|
|
3082
|
-
break; //why divide by one. Just move
|
|
3083
|
-
var divided = __.div(symbol.clone(), new_factor);
|
|
3084
|
-
|
|
3085
|
-
if(divided[0].equals(0)) {
|
|
3086
|
-
//cant factor anymore
|
|
3087
|
-
break;
|
|
3088
|
-
}
|
|
3089
|
-
|
|
3090
|
-
// We potentially ended up with fractional coefficients when the
|
|
3091
|
-
// trial division was performed. We need to remove
|
|
3092
|
-
// This check will more then likely become superfluous with improvements
|
|
3093
|
-
// to polynomial division
|
|
3094
|
-
if(divided[1].equals(0)) {
|
|
3095
|
-
var has_fractions = false;
|
|
3096
|
-
|
|
3097
|
-
divided[0].each(function (x) {
|
|
3098
|
-
if(!isInt(x.multiplier)) {
|
|
3099
|
-
has_fractions = true;
|
|
3100
|
-
}
|
|
3101
|
-
});
|
|
3102
|
-
|
|
3103
|
-
// The factor isn't really a factor and needs to be put back
|
|
3104
|
-
if(has_fractions) {
|
|
3105
|
-
divided[1] = _.expand(_.multiply(divided[1], new_factor));
|
|
3106
|
-
// Since the new factor is not just one, we exit.
|
|
3107
|
-
break;
|
|
3108
|
-
}
|
|
3109
|
-
}
|
|
3110
|
-
|
|
3111
|
-
var neg_numeric_factor = isInt(new_factor) && new_factor.lessThan(0);
|
|
3112
|
-
|
|
3113
|
-
if(divided[1].equals(0) && !neg_numeric_factor) { //we found at least one factor
|
|
3114
|
-
|
|
3115
|
-
//factors.add(new_factor);
|
|
3116
|
-
var d = __.div(symbol.clone(), divided[0].clone());
|
|
3117
|
-
var r = d[0];
|
|
3118
|
-
|
|
3119
|
-
// Nothing left to do since we didn't get a reduction
|
|
3120
|
-
if(r.equals(0)) {
|
|
3121
|
-
return symbol;
|
|
3122
|
-
}
|
|
3123
|
-
|
|
3124
|
-
symbol = d[1];
|
|
3125
|
-
//we don't want to just flip the sign. If the remainder is -1 then we accomplished nothing
|
|
3126
|
-
//and we just return the symbol;
|
|
3127
|
-
//If r equals zero then there's nothing left to do so we're done
|
|
3128
|
-
|
|
3129
|
-
if(r.equals(-1) && !symbol.equals(0))
|
|
3130
|
-
return symbol;
|
|
3131
|
-
|
|
3132
|
-
var factor = divided[0];
|
|
3133
|
-
|
|
3134
|
-
if(symbol.equals(factor)) {
|
|
3135
|
-
var rem = __.Factor.reduce(factor, factors);
|
|
3136
|
-
|
|
3137
|
-
if(!symbol.equals(rem))
|
|
3138
|
-
return __.Factor.mfactor(rem, factors);
|
|
3139
|
-
|
|
3140
|
-
return rem;
|
|
3141
|
-
}
|
|
3142
|
-
else {
|
|
3143
|
-
factors.add(factor);
|
|
3144
|
-
//if the remainder of the symbol is zero then we're done. TODO: Rethink this logic a bit.
|
|
3145
|
-
if(symbol.equals(0))
|
|
3146
|
-
return r;
|
|
3147
|
-
}
|
|
3148
|
-
|
|
3149
|
-
if(r.isConstant('all')) {
|
|
3150
|
-
factors.add(r);
|
|
3151
|
-
return r;
|
|
3152
|
-
}
|
|
3153
|
-
|
|
3154
|
-
return __.Factor.mfactor(r, factors);
|
|
3155
|
-
}
|
|
3156
|
-
}
|
|
3157
|
-
|
|
3158
|
-
}
|
|
3159
|
-
|
|
3160
|
-
//difference of squares factorization
|
|
3161
|
-
symbol = __.Factor.sqdiff(symbol, factors);
|
|
3162
|
-
|
|
3163
|
-
//factors by fishing for zeroes
|
|
3164
|
-
symbol = __.Factor.zeroes(symbol, factors);
|
|
3165
|
-
|
|
3166
|
-
return symbol;
|
|
3167
|
-
}
|
|
3168
|
-
},
|
|
3169
|
-
/**
|
|
3170
|
-
* Checks to see if a set of "equations" is linear.
|
|
3171
|
-
* @param {type} set
|
|
3172
|
-
* @returns {Boolean}
|
|
3173
|
-
*/
|
|
3174
|
-
allLinear: function (set) {
|
|
3175
|
-
var l = set.length;
|
|
3176
|
-
for(var i = 0; i < l; i++) {
|
|
3177
|
-
if(!__.isLinear(set[i]))
|
|
3178
|
-
return false;
|
|
3179
|
-
}
|
|
3180
|
-
return true;
|
|
3181
|
-
},
|
|
3182
|
-
/*
|
|
3183
|
-
* Checks to see if the "equation" is linear
|
|
3184
|
-
* @param {Symbol} e
|
|
3185
|
-
* @returns {boolean}
|
|
3186
|
-
*/
|
|
3187
|
-
isLinear: function (e) {
|
|
3188
|
-
var status = false, g = e.group;
|
|
3189
|
-
if(g === PL || g === CP) {
|
|
3190
|
-
status = true;
|
|
3191
|
-
for(var s in e.symbols) {
|
|
3192
|
-
var symbol = e.symbols[s], sg = symbol.group;
|
|
3193
|
-
if(sg === FN || sg === EX) {
|
|
3194
|
-
status = false;
|
|
3195
|
-
}
|
|
3196
|
-
if(sg === CB) {
|
|
3197
|
-
//needs further checking since it might be imaginary
|
|
3198
|
-
status = variables(symbol).length === 1;
|
|
3199
|
-
}
|
|
3200
|
-
else {
|
|
3201
|
-
if(sg === PL || sg === CP)
|
|
3202
|
-
status = __.isLinear(symbol);
|
|
3203
|
-
else {
|
|
3204
|
-
if(symbol.group !== N && symbol.power.toString() !== '1') {
|
|
3205
|
-
status = false;
|
|
3206
|
-
break;
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
}
|
|
3210
|
-
}
|
|
3211
|
-
}
|
|
3212
|
-
else if(g === S && e.power === 1)
|
|
3213
|
-
status = true;
|
|
3214
|
-
return status;
|
|
3215
|
-
},
|
|
3216
|
-
gcd: function () {
|
|
3217
|
-
var args;
|
|
3218
|
-
if(arguments.length === 1 && arguments[0] instanceof core.Vector)
|
|
3219
|
-
args = arguments[0].elements;
|
|
3220
|
-
else
|
|
3221
|
-
args = core.Utils.arguments2Array(arguments);
|
|
3222
|
-
|
|
3223
|
-
//short-circuit early
|
|
3224
|
-
if(args.length === 0)
|
|
3225
|
-
return new Symbol(1);
|
|
3226
|
-
else if(args.length === 1)
|
|
3227
|
-
return args[0];
|
|
3228
|
-
|
|
3229
|
-
var appeared = [], evaluate = false;
|
|
3230
|
-
for(var i = 0; i < args.length; i++) {
|
|
3231
|
-
if(args[i].group === FN && args[i].fname === 'gcd')
|
|
3232
|
-
{
|
|
3233
|
-
//compress gcd(a,gcd(b,c)) into gcd(a,b,c)
|
|
3234
|
-
args = args.concat(arguments[i].args);
|
|
3235
|
-
//do not keep gcd in args
|
|
3236
|
-
args.splice(i, 1);
|
|
3237
|
-
}
|
|
3238
|
-
else
|
|
3239
|
-
{
|
|
3240
|
-
//Look if there are any common variables such that
|
|
3241
|
-
//gcd(a,b) => gcd(a,b); gcd(a,a) => a
|
|
3242
|
-
var vars = variables(args[i]);
|
|
3243
|
-
if(core.Utils.haveIntersection(vars, appeared))
|
|
3244
|
-
{
|
|
3245
|
-
//Ok, there are common variables
|
|
3246
|
-
evaluate = true;
|
|
3247
|
-
break;
|
|
3248
|
-
}
|
|
3249
|
-
else
|
|
3250
|
-
appeared = appeared.concat(vars);
|
|
3251
|
-
}
|
|
3252
|
-
}
|
|
3253
|
-
|
|
3254
|
-
//appeared.length is 0 when all arguments are group N
|
|
3255
|
-
if(evaluate || appeared.length === 0) {
|
|
3256
|
-
//TODO: distribute exponent so that (a^-1*b^-1)^-1 => a*b
|
|
3257
|
-
if(args.every(function (symbol) {
|
|
3258
|
-
return symbol.getDenom().equals(1)
|
|
3259
|
-
})) {
|
|
3260
|
-
var aggregate = args[0];
|
|
3261
|
-
|
|
3262
|
-
for(var i = 1; i < args.length; i++) {
|
|
3263
|
-
aggregate = __.gcd_(args[i], aggregate);
|
|
3264
|
-
}
|
|
3265
|
-
return aggregate;
|
|
3266
|
-
}
|
|
3267
|
-
else {
|
|
3268
|
-
//gcd_ cannot handle denominators correctly
|
|
3269
|
-
return _.divide(__.gcd.apply(null, args.map(function (symbol) {
|
|
3270
|
-
return symbol.getNum();
|
|
3271
|
-
})),
|
|
3272
|
-
__.lcm.apply(null, args.map(function (symbol) {
|
|
3273
|
-
return symbol.getDenom();
|
|
3274
|
-
})));
|
|
3275
|
-
}
|
|
3276
|
-
}
|
|
3277
|
-
else
|
|
3278
|
-
return _.symfunction('gcd', args);
|
|
3279
|
-
},
|
|
3280
|
-
gcd_: function (a, b) {
|
|
3281
|
-
if(a.group === FN || a.group === P)
|
|
3282
|
-
a = core.Utils.block('PARSE2NUMBER', function () {
|
|
3283
|
-
return _.parse(a);
|
|
3284
|
-
});
|
|
3285
|
-
|
|
3286
|
-
if(b.group === FN)
|
|
3287
|
-
b = core.Utils.block('PARSE2NUMBER', function () {
|
|
3288
|
-
return _.parse(b);
|
|
3289
|
-
});
|
|
3290
|
-
|
|
3291
|
-
if(a.isConstant() && b.isConstant()) {
|
|
3292
|
-
// return core.Math2.QGCD(new Frac(+a), new Frac(+b));
|
|
3293
|
-
return new Symbol(core.Math2.QGCD(new Frac(+a), new Frac(+b)));
|
|
3294
|
-
}
|
|
3295
|
-
|
|
3296
|
-
var den = _.multiply(a.getDenom() || new Symbol(1), b.getDenom() || new Symbol(1)).invert();
|
|
3297
|
-
a = _.multiply(a.clone(), den.clone());
|
|
3298
|
-
b = _.multiply(b.clone(), den.clone());
|
|
3299
|
-
|
|
3300
|
-
//feels counter intuitive but it works. Issue #123 (nerdamer("gcd(x+y,(x+y)^2)"))
|
|
3301
|
-
a = _.expand(a);
|
|
3302
|
-
b = _.expand(b);
|
|
3303
|
-
|
|
3304
|
-
if(a.group === CB || b.group === CB) {
|
|
3305
|
-
var q = _.divide(a.clone(), b.clone()); //get the quotient
|
|
3306
|
-
var t = _.multiply(b.clone(), q.getDenom().invert());//multiply by the denominator
|
|
3307
|
-
//if they have a common factor then the result will not equal one
|
|
3308
|
-
if(!t.equals(1))
|
|
3309
|
-
return t;
|
|
3310
|
-
}
|
|
3311
|
-
|
|
3312
|
-
//just take the gcd of each component when either of them is in group EX
|
|
3313
|
-
if(a.group === EX || b.group === EX)
|
|
3314
|
-
{
|
|
3315
|
-
var gcd_m = new Symbol(core.Math2.GCD(a.multiplier, b.multiplier));
|
|
3316
|
-
var gcd_v = __.gcd_(a.value === CONST_HASH ? new Symbol(1) : _.parse(a.value), b.value === CONST_HASH ? new Symbol(1) : _.parse(b.value));
|
|
3317
|
-
var gcd_p = __.gcd_(_.parse(a.power), _.parse(b.power));
|
|
3318
|
-
return _.multiply(gcd_m, _.pow(gcd_v, gcd_p));
|
|
3319
|
-
}
|
|
3320
|
-
|
|
3321
|
-
if(a.length < b.length) { //swap'm
|
|
3322
|
-
var t = a;
|
|
3323
|
-
a = b;
|
|
3324
|
-
b = t;
|
|
3325
|
-
}
|
|
3326
|
-
var vars_a = variables(a), vars_b = variables(b);
|
|
3327
|
-
if((vars_a.length === vars_b.length && vars_a.length === 1 && vars_a[0] === vars_b[0])
|
|
3328
|
-
|| vars_a.length === 1 && vars_b.length === 0
|
|
3329
|
-
|| vars_a.length === 0 && vars_b.length === 1) {
|
|
3330
|
-
a = new Polynomial(a);
|
|
3331
|
-
b = new Polynomial(b);
|
|
3332
|
-
return _.divide(a.gcd(b).toSymbol(), den);
|
|
3333
|
-
}
|
|
3334
|
-
else {
|
|
3335
|
-
//get the gcd of the multipiers
|
|
3336
|
-
//get rid of gcd in coeffs
|
|
3337
|
-
var multipliers = [];
|
|
3338
|
-
a.each(function (x) {
|
|
3339
|
-
multipliers.push(x.multiplier);
|
|
3340
|
-
});
|
|
3341
|
-
b.each(function (x) {
|
|
3342
|
-
multipliers.push(x.multiplier);
|
|
3343
|
-
});
|
|
3344
|
-
|
|
3345
|
-
var T;
|
|
3346
|
-
while(!b.equals(0)) {
|
|
3347
|
-
var t = b.clone();
|
|
3348
|
-
a = a.clone();
|
|
3349
|
-
T = __.div(a, t);
|
|
3350
|
-
|
|
3351
|
-
b = T[1];
|
|
3352
|
-
if(T[0].equals(0)) {
|
|
3353
|
-
//return _.multiply(new Symbol(core.Math2.QGCD(a.multiplier, b.multiplier)), b);
|
|
3354
|
-
return _.divide(new Symbol(core.Math2.QGCD(a.multiplier, b.multiplier)), den);
|
|
3355
|
-
}
|
|
3356
|
-
a = t;
|
|
3357
|
-
}
|
|
3358
|
-
|
|
3359
|
-
var gcd = core.Math2.QGCD.apply(undefined, multipliers);
|
|
3360
|
-
|
|
3361
|
-
if(!gcd.equals(1)) {
|
|
3362
|
-
a.each(function (x) {
|
|
3363
|
-
x.multiplier = x.multiplier.divide(gcd);
|
|
3364
|
-
});
|
|
3365
|
-
}
|
|
3366
|
-
|
|
3367
|
-
//return symbolic function for gcd in indeterminate form
|
|
3368
|
-
if(a.equals(1) && !a.isConstant() && !b.isConstant())
|
|
3369
|
-
return _.divide(_.symfunction('gcd', arguments), den);
|
|
3370
|
-
|
|
3371
|
-
return _.divide(a, den);
|
|
3372
|
-
}
|
|
3373
|
-
},
|
|
3374
|
-
lcm: function () {
|
|
3375
|
-
//https://math.stackexchange.com/a/319310
|
|
3376
|
-
//generalization of the 2-variable formula of lcm
|
|
3377
|
-
|
|
3378
|
-
var args;
|
|
3379
|
-
if(arguments.length === 1)
|
|
3380
|
-
if(arguments[0] instanceof core.Vector)
|
|
3381
|
-
args = arguments[0].elements;
|
|
3382
|
-
else
|
|
3383
|
-
_.error('lcm expects either 1 vector or 2 or more arguments');
|
|
3384
|
-
else
|
|
3385
|
-
args = core.Utils.arguments2Array(arguments);
|
|
3386
|
-
|
|
3387
|
-
//product of all arguments
|
|
3388
|
-
//start with new Symbol(1) so that prev.clone() which makes unnessesary clones can be avoided
|
|
3389
|
-
var numer = args.reduce(function (prev, curr) {
|
|
3390
|
-
return _.multiply(prev, curr.clone())
|
|
3391
|
-
}, new Symbol(1));
|
|
3392
|
-
|
|
3393
|
-
//gcd of complementary terms
|
|
3394
|
-
var denom_args =
|
|
3395
|
-
//https://stackoverflow.com/a/18223072
|
|
3396
|
-
//take all complementary terms, e.g.
|
|
3397
|
-
//[a,b,c] => [a*b, b*c, a*c]
|
|
3398
|
-
//[a,b,c,d] => [a*b*c, a*b*d, a*c*d, b*c*d]
|
|
3399
|
-
(function (input, size) {
|
|
3400
|
-
size = Number(size);
|
|
3401
|
-
var results = [], result, mask, i, total = Math.pow(2, input.length);
|
|
3402
|
-
for(mask = size; mask < total; mask++) {
|
|
3403
|
-
result = [];
|
|
3404
|
-
i = input.length - 1;
|
|
3405
|
-
|
|
3406
|
-
do {
|
|
3407
|
-
if((mask & (1 << i)) !== 0) {
|
|
3408
|
-
result.push(input[i]);
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3411
|
-
while(i--);
|
|
3412
|
-
|
|
3413
|
-
if(result.length === size) {
|
|
3414
|
-
results.push(result);
|
|
3415
|
-
}
|
|
3416
|
-
}
|
|
3417
|
-
return results;
|
|
3418
|
-
//start with new Symbol(1) so that prev.clone() which makes unnessesary clones can be avoided
|
|
3419
|
-
})(arguments, arguments.length - 1).map(function (x) {
|
|
3420
|
-
return x.reduce(function (prev, curr) {
|
|
3421
|
-
return _.multiply(prev, curr.clone())
|
|
3422
|
-
}, new Symbol(1))
|
|
3423
|
-
});
|
|
3424
|
-
|
|
3425
|
-
var denom;
|
|
3426
|
-
//don't eat the gcd term if all arguments are symbols
|
|
3427
|
-
if(args.every(function (x) {
|
|
3428
|
-
return core.Utils.isVariableSymbol(x)
|
|
3429
|
-
}))
|
|
3430
|
-
denom = _.symfunction('gcd', core.Utils.arrayUnique(denom_args));
|
|
3431
|
-
else
|
|
3432
|
-
denom = __.gcd.apply(null, denom_args);
|
|
3433
|
-
//divide product of all arguments by gcd of complementary terms
|
|
3434
|
-
var div = _.divide(numer, denom);
|
|
3435
|
-
return div;
|
|
3436
|
-
},
|
|
3437
|
-
/**
|
|
3438
|
-
* Divides one expression by another
|
|
3439
|
-
* @param {Symbol} symbol1
|
|
3440
|
-
* @param {Symbol} symbol2
|
|
3441
|
-
* @returns {Array}
|
|
3442
|
-
*/
|
|
3443
|
-
divide: function (symbol1, symbol2) {
|
|
3444
|
-
var result, remainder, factored, den;
|
|
3445
|
-
factored = core.Algebra.Factor.factor(symbol1.clone());
|
|
3446
|
-
den = factored.getDenom();
|
|
3447
|
-
if(!den.isConstant('all')) {
|
|
3448
|
-
symbol1 = _.expand(Symbol.unwrapPARENS(_.multiply(factored, den.clone())));
|
|
3449
|
-
}
|
|
3450
|
-
else
|
|
3451
|
-
//reset the denominator since we're not dividing by it anymore
|
|
3452
|
-
den = new Symbol(1);
|
|
3453
|
-
result = __.div(symbol1, symbol2);
|
|
3454
|
-
remainder = _.divide(result[1], symbol2);
|
|
3455
|
-
return _.divide(_.add(result[0], remainder), den);
|
|
3456
|
-
},
|
|
3457
|
-
div: function (symbol1, symbol2) {
|
|
3458
|
-
// If all else fails then assume that division failed with
|
|
3459
|
-
// a remainder of zero and the original quotient
|
|
3460
|
-
var fail = [new Symbol(0), symbol1.clone()];
|
|
3461
|
-
|
|
3462
|
-
try {
|
|
3463
|
-
|
|
3464
|
-
// Division by constants
|
|
3465
|
-
if(symbol2.isConstant('all')) {
|
|
3466
|
-
symbol1.each(function (x) {
|
|
3467
|
-
x.multiplier = x.multiplier.divide(symbol2.multiplier);
|
|
3468
|
-
});
|
|
3469
|
-
return [symbol1, new Symbol(0)];
|
|
3470
|
-
}
|
|
3471
|
-
// So that factorized symbols don't affect the result
|
|
3472
|
-
symbol1 = _.expand(symbol1);
|
|
3473
|
-
symbol2 = _.expand(symbol2);
|
|
3474
|
-
// Special case. May need revisiting
|
|
3475
|
-
if(symbol1.group === S && symbol2.group === CP) {
|
|
3476
|
-
var x = symbol1.value;
|
|
3477
|
-
var f = core.Utils.decompose_fn(symbol2.clone(), x, true);
|
|
3478
|
-
if(symbol1.isLinear() && f.x && f.x.isLinear() && symbol2.isLinear()) {
|
|
3479
|
-
var k = Symbol.create(symbol1.multiplier);
|
|
3480
|
-
return [_.divide(k.clone(), f.a.clone()), _.divide(_.multiply(k, f.b), f.a).negate()];
|
|
3481
|
-
}
|
|
3482
|
-
}
|
|
3483
|
-
if(symbol1.group === S && symbol2.group === S) {
|
|
3484
|
-
var r = _.divide(symbol1.clone(), symbol2.clone());
|
|
3485
|
-
if(r.isConstant()) //we have a whole
|
|
3486
|
-
return [r, new Symbol(0)];
|
|
3487
|
-
return [new Symbol(0), symbol1.clone()];
|
|
3488
|
-
}
|
|
3489
|
-
var symbol1_has_func = symbol1.hasFunc(),
|
|
3490
|
-
symbol2_has_func = symbol2.hasFunc(),
|
|
3491
|
-
parse_funcs = false;
|
|
3492
|
-
|
|
3493
|
-
//substitute out functions so we can treat them as regular variables
|
|
3494
|
-
if(symbol1_has_func || symbol2_has_func) {
|
|
3495
|
-
parse_funcs = true;
|
|
3496
|
-
var map = {},
|
|
3497
|
-
symbol1 = _.parse(core.Utils.subFunctions(symbol1, map)),
|
|
3498
|
-
symbol2 = _.parse(core.Utils.subFunctions(symbol2, map)),
|
|
3499
|
-
subs = core.Utils.getFunctionsSubs(map);
|
|
3500
|
-
}
|
|
3501
|
-
//get a list of the variables
|
|
3502
|
-
var vars = core.Utils.arrayUnique(variables(symbol1).concat(variables(symbol2))),
|
|
3503
|
-
quot, rem;
|
|
3504
|
-
|
|
3505
|
-
//treat imaginary numbers as variables
|
|
3506
|
-
if(symbol1.isImaginary() || symbol2.isImaginary()) {
|
|
3507
|
-
vars.push(core.Settings.IMAGINARY);
|
|
3508
|
-
}
|
|
3509
|
-
|
|
3510
|
-
if(vars.length === 1) {
|
|
3511
|
-
var q = new Polynomial(symbol1).divide(new Polynomial(symbol2));
|
|
3512
|
-
quot = q[0].toSymbol();
|
|
3513
|
-
rem = q[1].toSymbol();
|
|
3514
|
-
}
|
|
3515
|
-
else {
|
|
3516
|
-
vars.push(CONST_HASH); //this is for the numbers
|
|
3517
|
-
var reconvert = function (arr) {
|
|
3518
|
-
var symbol = new Symbol(0);
|
|
3519
|
-
for(var i = 0; i < arr.length; i++) {
|
|
3520
|
-
var x = arr[i].toSymbol();
|
|
3521
|
-
symbol = _.add(symbol, x);
|
|
3522
|
-
}
|
|
3523
|
-
return symbol;
|
|
3524
|
-
};
|
|
3525
|
-
|
|
3526
|
-
// Silly Martin. This is why you document. I don't remember now
|
|
3527
|
-
var get_unique_max = function (term, any) {
|
|
3528
|
-
var max = Math.max.apply(null, term.terms),
|
|
3529
|
-
count = 0, idx;
|
|
3530
|
-
|
|
3531
|
-
if(!any) {
|
|
3532
|
-
for(var i = 0; i < term.terms.length; i++) {
|
|
3533
|
-
if(term.terms[i].equals(max)) {
|
|
3534
|
-
idx = i;
|
|
3535
|
-
count++;
|
|
3536
|
-
}
|
|
3537
|
-
if(count > 1)
|
|
3538
|
-
return;
|
|
3539
|
-
}
|
|
3540
|
-
}
|
|
3541
|
-
if(any) {
|
|
3542
|
-
for(i = 0; i < term.terms.length; i++)
|
|
3543
|
-
if(term.terms[i].equals(max)) {
|
|
3544
|
-
idx = i;
|
|
3545
|
-
break;
|
|
3546
|
-
}
|
|
3547
|
-
}
|
|
3548
|
-
return [max, idx, term];
|
|
3549
|
-
};
|
|
3550
|
-
|
|
3551
|
-
// Tries to find an LT in the dividend that will satisfy division
|
|
3552
|
-
var get_det = function (s, lookat) {
|
|
3553
|
-
lookat = lookat || 0;
|
|
3554
|
-
var det = s[lookat], l = s.length;
|
|
3555
|
-
if(!det)
|
|
3556
|
-
return;
|
|
3557
|
-
//eliminate the first term if it doesn't apply
|
|
3558
|
-
var umax = get_unique_max(det);
|
|
3559
|
-
for(var i = lookat + 1; i < l; i++) {
|
|
3560
|
-
var term = s[i],
|
|
3561
|
-
is_equal = det.sum.equals(term.sum);
|
|
3562
|
-
if(!is_equal && umax) {
|
|
3563
|
-
break;
|
|
3564
|
-
}
|
|
3565
|
-
if(is_equal) {
|
|
3566
|
-
// Check the differences of their maxes. The one with the biggest difference governs
|
|
3567
|
-
// e.g. x^2*y^3 vs x^2*y^3 is unclear but this isn't the case in x*y and x^2
|
|
3568
|
-
var max1, max2, idx1, idx2, l2 = det.terms.length;
|
|
3569
|
-
for(var j = 0; j < l2; j++) {
|
|
3570
|
-
var item1 = det.terms[j], item2 = term.terms[j];
|
|
3571
|
-
if(typeof max1 === 'undefined' || item1.greaterThan(max1)) {
|
|
3572
|
-
max1 = item1;
|
|
3573
|
-
idx1 = j;
|
|
3574
|
-
}
|
|
3575
|
-
if(typeof max2 === 'undefined' || item2.greaterThan(max2)) {
|
|
3576
|
-
max2 = item2;
|
|
3577
|
-
idx2 = j;
|
|
3578
|
-
}
|
|
3579
|
-
}
|
|
3580
|
-
//check their differences
|
|
3581
|
-
var d1 = max1.subtract(term.terms[idx1]),
|
|
3582
|
-
d2 = max2.subtract(det.terms[idx2]);
|
|
3583
|
-
if(d2 > d1) {
|
|
3584
|
-
umax = [max2, idx2, term];
|
|
3585
|
-
break;
|
|
3586
|
-
}
|
|
3587
|
-
if(d1 > d2) {
|
|
3588
|
-
umax = [max1, idx1, det];
|
|
3589
|
-
break;
|
|
3590
|
-
}
|
|
3591
|
-
}
|
|
3592
|
-
else {
|
|
3593
|
-
//check if it's a suitable pick to determine the order
|
|
3594
|
-
umax = get_unique_max(term);
|
|
3595
|
-
//if(umax) return umax;
|
|
3596
|
-
if(umax)
|
|
3597
|
-
break;
|
|
3598
|
-
}
|
|
3599
|
-
umax = get_unique_max(term); //calculate a new unique max
|
|
3600
|
-
}
|
|
3601
|
-
|
|
3602
|
-
//if still no umax then any will do since we have a tie
|
|
3603
|
-
if(!umax)
|
|
3604
|
-
return get_unique_max(s[0], true);
|
|
3605
|
-
var e, idx;
|
|
3606
|
-
for(var i = 0; i < s2.length; i++) {
|
|
3607
|
-
var cterm = s2[i].terms;
|
|
3608
|
-
//confirm that this is a good match for the denominator
|
|
3609
|
-
idx = umax[1];
|
|
3610
|
-
if(idx === cterm.length - 1)
|
|
3611
|
-
return;
|
|
3612
|
-
e = cterm[idx];
|
|
3613
|
-
if(!e.equals(0))
|
|
3614
|
-
break;
|
|
3615
|
-
}
|
|
3616
|
-
if(e.equals(0))
|
|
3617
|
-
return get_det(s, ++lookat); //look at the next term
|
|
3618
|
-
|
|
3619
|
-
return umax;
|
|
3620
|
-
};
|
|
3621
|
-
|
|
3622
|
-
var t_map = core.Utils.toMapObj(vars);
|
|
3623
|
-
var init_sort = function (a, b) {
|
|
3624
|
-
return b.sum.subtract(a.sum);
|
|
3625
|
-
};
|
|
3626
|
-
var is_larger = function (a, b) {
|
|
3627
|
-
if(!a || !b)
|
|
3628
|
-
return false; //it's empty so...
|
|
3629
|
-
for(var i = 0; i < a.terms.length; i++) {
|
|
3630
|
-
if(a.terms[i].lessThan(b.terms[i]))
|
|
3631
|
-
return false;
|
|
3632
|
-
}
|
|
3633
|
-
return true;
|
|
3634
|
-
};
|
|
3635
|
-
|
|
3636
|
-
var s1 = symbol1.tBase(t_map).sort(init_sort),
|
|
3637
|
-
s2 = symbol2.tBase(t_map).sort(init_sort);
|
|
3638
|
-
var target = is_larger(s1[0], s2[0]) && s1[0].count > s2[0].count ? s2 : s1; //since the num is already larger than we can get the det from denom
|
|
3639
|
-
var det = get_det(target);//we'll begin by assuming that this will let us know which term
|
|
3640
|
-
var quotient = [];
|
|
3641
|
-
if(det) {
|
|
3642
|
-
var lead_var = det[1];
|
|
3643
|
-
var can_divide = function (a, b) {
|
|
3644
|
-
if(a[0].sum.equals(b[0].sum))
|
|
3645
|
-
return a.length >= b.length;
|
|
3646
|
-
return true;
|
|
3647
|
-
};
|
|
3648
|
-
|
|
3649
|
-
var try_better_lead_var = function (s1, s2, lead_var) {
|
|
3650
|
-
var checked = [];
|
|
3651
|
-
for(var i = 0; i < s1.length; i++) {
|
|
3652
|
-
var t = s1[i];
|
|
3653
|
-
for(var j = 0; j < t.terms.length; j++) {
|
|
3654
|
-
var cf = checked[j], tt = t.terms[j];
|
|
3655
|
-
if(i === 0)
|
|
3656
|
-
checked[j] = tt; //add the terms for the first one
|
|
3657
|
-
else if(cf && !cf.equals(tt))
|
|
3658
|
-
checked[j] = undefined;
|
|
3659
|
-
}
|
|
3660
|
-
}
|
|
3661
|
-
for(var i = 0; i < checked.length; i++) {
|
|
3662
|
-
var t = checked[i];
|
|
3663
|
-
if(t && !t.equals(0))
|
|
3664
|
-
return i;
|
|
3665
|
-
}
|
|
3666
|
-
return lead_var;
|
|
3667
|
-
};
|
|
3668
|
-
var sf = function (a, b) {
|
|
3669
|
-
var l1 = a.len(), l2 = b.len();
|
|
3670
|
-
var blv = b.terms[lead_var], alv = a.terms[lead_var];
|
|
3671
|
-
if(l2 > l1 && blv.greaterThan(alv))
|
|
3672
|
-
return l2 - l1;
|
|
3673
|
-
return blv.subtract(alv);
|
|
3674
|
-
};
|
|
3675
|
-
|
|
3676
|
-
//check to see if there's a better lead_var
|
|
3677
|
-
lead_var = try_better_lead_var(s1, s2, lead_var);
|
|
3678
|
-
//reorder both according to the max power
|
|
3679
|
-
s1.sort(sf); //sort them both according to the leading variable power
|
|
3680
|
-
s2.sort(sf);
|
|
3681
|
-
|
|
3682
|
-
//try to adjust if den is larger
|
|
3683
|
-
var fdt = s2[0], fnt = s1[0];
|
|
3684
|
-
|
|
3685
|
-
var den = new MVTerm(new Frac(1), [], fnt.map);
|
|
3686
|
-
if(fdt.sum.greaterThan(fnt.sum) && fnt.len() > 1) {
|
|
3687
|
-
for(var i = 0; i < fnt.terms.length; i++) {
|
|
3688
|
-
var d = fdt.terms[i].subtract(fnt.terms[i]);
|
|
3689
|
-
if(!d.equals(0)) {
|
|
3690
|
-
var nd = d.add(new Frac(1));
|
|
3691
|
-
den.terms[i] = d;
|
|
3692
|
-
for(var j = 0; j < s1.length; j++) {
|
|
3693
|
-
s1[j].terms[i] = s1[j].terms[i].add(nd);
|
|
3694
|
-
}
|
|
3695
|
-
}
|
|
3696
|
-
else
|
|
3697
|
-
den.terms[i] = new Frac(0);
|
|
3698
|
-
}
|
|
3699
|
-
}
|
|
3700
|
-
|
|
3701
|
-
var dividend_larger = is_larger(s1[0], s2[0]);
|
|
3702
|
-
|
|
3703
|
-
var safety = 0;
|
|
3704
|
-
var max = 200;
|
|
3705
|
-
|
|
3706
|
-
while(dividend_larger && can_divide(s1, s2)) {
|
|
3707
|
-
if(safety++ > max) {
|
|
3708
|
-
throw new core.exceptions.InfiniteLoopError('Unable to compute!');
|
|
3709
|
-
}
|
|
3710
|
-
|
|
3711
|
-
var q = s1[0].divide(s2[0]);
|
|
3712
|
-
|
|
3713
|
-
quotient.push(q); //add what's divided to the quotient
|
|
3714
|
-
s1.shift();//the first one is guaranteed to be gone so remove from dividend
|
|
3715
|
-
for(var i = 1; i < s2.length; i++) { //loop through the denominator
|
|
3716
|
-
var t = s2[i].multiply(q).generateImage(),
|
|
3717
|
-
l2 = s1.length;
|
|
3718
|
-
//if we're subtracting from 0
|
|
3719
|
-
if(l2 === 0) {
|
|
3720
|
-
t.coeff = t.coeff.neg();
|
|
3721
|
-
s1.push(t);
|
|
3722
|
-
s1.sort(sf);
|
|
3723
|
-
}
|
|
3724
|
-
|
|
3725
|
-
for(var j = 0; j < l2; j++) {
|
|
3726
|
-
var cur = s1[j];
|
|
3727
|
-
if(cur.getImg() === t.getImg()) {
|
|
3728
|
-
cur.coeff = cur.coeff.subtract(t.coeff);
|
|
3729
|
-
if(cur.coeff.equals(0)) {
|
|
3730
|
-
core.Utils.remove(s1, j);
|
|
3731
|
-
j--; //adjust the iterator
|
|
3732
|
-
}
|
|
3733
|
-
break;
|
|
3734
|
-
}
|
|
3735
|
-
if(j === l2 - 1) {
|
|
3736
|
-
t.coeff = t.coeff.neg();
|
|
3737
|
-
s1.push(t);
|
|
3738
|
-
s1.sort(sf);
|
|
3739
|
-
}
|
|
3740
|
-
}
|
|
3741
|
-
}
|
|
3742
|
-
dividend_larger = is_larger(s1[0], s2[0]);
|
|
3743
|
-
|
|
3744
|
-
if(!dividend_larger && s1.length >= s2.length) {
|
|
3745
|
-
//One more try since there might be a terms that is larger than the LT of the divisor
|
|
3746
|
-
for(var i = 1; i < s1.length; i++) {
|
|
3747
|
-
dividend_larger = is_larger(s1[i], s2[0]);
|
|
3748
|
-
if(dividend_larger) {
|
|
3749
|
-
//take it from its current position and move it to the front
|
|
3750
|
-
s1.unshift(core.Utils.remove(s1, i));
|
|
3751
|
-
break;
|
|
3752
|
-
}
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
}
|
|
3756
|
-
}
|
|
3757
|
-
|
|
3758
|
-
quot = reconvert(quotient);
|
|
3759
|
-
rem = reconvert(s1);
|
|
3760
|
-
|
|
3761
|
-
if(typeof den !== 'undefined') {
|
|
3762
|
-
den = den.toSymbol();
|
|
3763
|
-
quot = _.divide(quot, den.clone());
|
|
3764
|
-
rem = _.divide(rem, den);
|
|
3765
|
-
}
|
|
3766
|
-
}
|
|
3767
|
-
|
|
3768
|
-
//put back the functions
|
|
3769
|
-
if(parse_funcs) {
|
|
3770
|
-
quot = _.parse(quot.text(), subs);
|
|
3771
|
-
rem = _.parse(rem.text(), subs);
|
|
3772
|
-
}
|
|
3773
|
-
|
|
3774
|
-
return [quot, rem];
|
|
3775
|
-
}
|
|
3776
|
-
catch(e) {
|
|
3777
|
-
return fail;
|
|
3778
|
-
}
|
|
3779
|
-
|
|
3780
|
-
},
|
|
3781
|
-
line: function (v1, v2, x) {
|
|
3782
|
-
if(core.Utils.isArray(v1))
|
|
3783
|
-
v1 = core.Utils.convertToVector(v1);
|
|
3784
|
-
if(core.Utils.isArray(v2))
|
|
3785
|
-
v2 = core.Utils.convertToVector(v2);
|
|
3786
|
-
x = _.parse(x || 'x');
|
|
3787
|
-
if(!core.Utils.isVector(v1) || !core.Utils.isVector(v2))
|
|
3788
|
-
_.error('Line expects a vector! Received "' + v1 + '" & "' + v2 + '"');
|
|
3789
|
-
var dx = _.subtract(v2.e(1).clone(), v1.e(1).clone()),
|
|
3790
|
-
dy = _.subtract(v2.e(2).clone(), v1.e(2).clone()),
|
|
3791
|
-
m = _.divide(dy, dx),
|
|
3792
|
-
a = _.multiply(x, m.clone()),
|
|
3793
|
-
b = _.multiply(v1.e(1).clone(), m);
|
|
3794
|
-
return _.add(_.subtract(a, b), v1.e(2).clone());
|
|
3795
|
-
},
|
|
3796
|
-
PartFrac: {
|
|
3797
|
-
createTemplate: function (den, denom_factors, f_array, v) {
|
|
3798
|
-
//clean up the denominator function by factors so it reduces nicely
|
|
3799
|
-
den = __.Factor.factor(den);
|
|
3800
|
-
|
|
3801
|
-
//clean up factors. This is so inefficient but factors are wrapped in parens for safety
|
|
3802
|
-
den.each(function (x, key) {
|
|
3803
|
-
if(x.group === FN && x.fname === '' && x.args[0].group === S) {
|
|
3804
|
-
var y = x.args[0];
|
|
3805
|
-
if(this.symbols) {
|
|
3806
|
-
delete this.symbols[key];
|
|
3807
|
-
this.symbols[y.value] = y;
|
|
3808
|
-
}
|
|
3809
|
-
else {
|
|
3810
|
-
den = x.args[0];
|
|
3811
|
-
}
|
|
3812
|
-
}
|
|
3813
|
-
});
|
|
3814
|
-
|
|
3815
|
-
var factors, factors_vec, f, p, deg, degrees, m;
|
|
3816
|
-
factors = denom_factors.collectFactors();
|
|
3817
|
-
factors_vec = []; //a vector for the template
|
|
3818
|
-
degrees = [];
|
|
3819
|
-
m = new Symbol(1);
|
|
3820
|
-
|
|
3821
|
-
for(var i = 0; i < factors.length; i++) { //loop through the factors
|
|
3822
|
-
var factor = Symbol.unwrapPARENS(factors[i]);
|
|
3823
|
-
//if in he for P^n where P is polynomial and n = integer
|
|
3824
|
-
if(factor.power.greaterThan(1)) {
|
|
3825
|
-
p = Number(factor.power);
|
|
3826
|
-
f = factor.clone().toLinear(); //remove the power so we have only the function
|
|
3827
|
-
deg = Number(__.degree(f, v)); //get the degree of f
|
|
3828
|
-
//expand the factor
|
|
3829
|
-
for(var j = 0; j < p; j++) {
|
|
3830
|
-
var efactor = _.pow(f.clone(), new Symbol(j + 1));
|
|
3831
|
-
f_array.push(efactor.clone());
|
|
3832
|
-
var d = _.divide(den.clone(), efactor.clone());
|
|
3833
|
-
degrees.push(deg);
|
|
3834
|
-
factors_vec.push(d);
|
|
3835
|
-
}
|
|
3836
|
-
}
|
|
3837
|
-
/*
|
|
3838
|
-
Possible bug.
|
|
3839
|
-
Removed: causes 1/(20+24*x+4*x^2) to result in (-1/64)*(5+x)^(-1)+(1/64)*(1+x)^(-1)
|
|
3840
|
-
else if(factor.isConstant('all')) {
|
|
3841
|
-
m = _.multiply(m, factor);
|
|
3842
|
-
}
|
|
3843
|
-
*/
|
|
3844
|
-
else {
|
|
3845
|
-
//get the degree of the factor so we tack it on tot he factor. This should probably be an array
|
|
3846
|
-
//but for now we note it on the symbol
|
|
3847
|
-
deg = Number(__.degree(factor, v));
|
|
3848
|
-
f_array.push(factor);
|
|
3849
|
-
var d = _.divide(den.clone(), factor.clone());
|
|
3850
|
-
d = _.expand(Symbol.unwrapPARENS(d));
|
|
3851
|
-
degrees.push(deg);
|
|
3852
|
-
factors_vec.push(d);
|
|
3853
|
-
}
|
|
3854
|
-
}
|
|
3855
|
-
//put back the constant
|
|
3856
|
-
f_array = f_array.map(function (x) {
|
|
3857
|
-
return _.multiply(x, m.clone());
|
|
3858
|
-
});
|
|
3859
|
-
return [f_array, factors_vec, degrees];
|
|
3860
|
-
},
|
|
3861
|
-
partfrac: function (symbol, v, as_array) {
|
|
3862
|
-
|
|
3863
|
-
var vars = variables(symbol);
|
|
3864
|
-
|
|
3865
|
-
v = v || _.parse(vars[0]); //make wrt optional and assume first variable
|
|
3866
|
-
try {
|
|
3867
|
-
var num, den, factors, tfactors, ofactors, nterms, degrees,
|
|
3868
|
-
dterms, max, M, c, powers, div, r, factors_vec, ks,
|
|
3869
|
-
template, tfactors;
|
|
3870
|
-
num = _.expand(symbol.getNum());
|
|
3871
|
-
den = _.expand(symbol.getDenom().toUnitMultiplier());
|
|
3872
|
-
//move the entire multipier to the numerator
|
|
3873
|
-
num.multiplier = symbol.multiplier;
|
|
3874
|
-
//we only have a meaningful change if n factors > 1. This means that
|
|
3875
|
-
//the returned group will be a CB
|
|
3876
|
-
//collect the terms wrt the x
|
|
3877
|
-
nterms = num.groupTerms(v);
|
|
3878
|
-
//divide out wholes if top is larger
|
|
3879
|
-
if(Number(__.degree(num, v)) >= Number(__.degree(den, v))) {
|
|
3880
|
-
div = __.div(num.clone(), _.expand(den.clone()));
|
|
3881
|
-
r = div[0]; //remove the wholes
|
|
3882
|
-
num = div[1]; //work with the remainder
|
|
3883
|
-
nterms = num.groupTerms(v); //recalculate the nterms
|
|
3884
|
-
}
|
|
3885
|
-
else
|
|
3886
|
-
r = new Symbol(0);
|
|
3887
|
-
|
|
3888
|
-
if(Number(__.degree(den, v)) === 1) {
|
|
3889
|
-
var q = _.divide(num, den);
|
|
3890
|
-
if(as_array)
|
|
3891
|
-
return [r, q];
|
|
3892
|
-
return _.add(r, q);
|
|
3893
|
-
}
|
|
3894
|
-
//first factor the denominator. This means that the strength of this
|
|
3895
|
-
//algorithm depends on how well we can factor the denominator.
|
|
3896
|
-
ofactors = __.Factor.factor(den);
|
|
3897
|
-
//create the template. This method will create the template for solving
|
|
3898
|
-
//the partial fractions. So given x/(x-1)^2 the template creates A/(x-1)+B/(x-1)^2
|
|
3899
|
-
template = __.PartFrac.createTemplate(den.clone(), ofactors, [], v);
|
|
3900
|
-
tfactors = template[0]; //grab the factors
|
|
3901
|
-
factors_vec = template[1]; //grab the factor vectors
|
|
3902
|
-
degrees = template[2]; //grab the degrees
|
|
3903
|
-
//make note of the powers of each term
|
|
3904
|
-
powers = [nterms.length];
|
|
3905
|
-
//create the dterms vector
|
|
3906
|
-
dterms = [];
|
|
3907
|
-
factors = [];
|
|
3908
|
-
ks = [];
|
|
3909
|
-
var factor, deg;
|
|
3910
|
-
factors_vec.map(function (x, idx) {
|
|
3911
|
-
factor = tfactors[idx];
|
|
3912
|
-
deg = degrees[idx];
|
|
3913
|
-
for(var i = 0; i < deg; i++) {
|
|
3914
|
-
factors.push(factor.clone());
|
|
3915
|
-
var k = Symbol.create(v, i);
|
|
3916
|
-
var t = _.expand(_.multiply(x, k.clone())).groupTerms(v);
|
|
3917
|
-
//make a note of the power which corresponds to the length of the array
|
|
3918
|
-
var p = t.length;
|
|
3919
|
-
powers.push(p);
|
|
3920
|
-
dterms.push(t);
|
|
3921
|
-
ks.push(k.clone());
|
|
3922
|
-
}
|
|
3923
|
-
});
|
|
3924
|
-
//get the max power
|
|
3925
|
-
max = core.Utils.arrayMax(powers);
|
|
3926
|
-
|
|
3927
|
-
//fill the holes and create a matrix
|
|
3928
|
-
c = new core.Matrix(core.Utils.fillHoles(nterms, max)).transpose();
|
|
3929
|
-
//for each of the factors we do the same
|
|
3930
|
-
M = new core.Matrix();
|
|
3931
|
-
for(var i = 0; i < dterms.length; i++) {
|
|
3932
|
-
M.elements.push(core.Utils.fillHoles(dterms[i], max));
|
|
3933
|
-
}
|
|
3934
|
-
|
|
3935
|
-
//solve the system of equations
|
|
3936
|
-
var partials = _.multiply(M.transpose().invert(), c);
|
|
3937
|
-
//the results are backwards to reverse it
|
|
3938
|
-
//partials.elements.reverse();
|
|
3939
|
-
//convert it all back
|
|
3940
|
-
var retval = as_array ? [r] : r;
|
|
3941
|
-
partials.each(function (e, i) {
|
|
3942
|
-
var term = _.multiply(ks[i], _.divide(e, factors[i]));
|
|
3943
|
-
if(as_array)
|
|
3944
|
-
retval.push(term);
|
|
3945
|
-
else
|
|
3946
|
-
retval = _.add(retval, term);
|
|
3947
|
-
});
|
|
3948
|
-
|
|
3949
|
-
//done
|
|
3950
|
-
return retval;
|
|
3951
|
-
}
|
|
3952
|
-
catch(e) {
|
|
3953
|
-
//try to group symbols
|
|
3954
|
-
try {
|
|
3955
|
-
if(symbol.isComposite()) {
|
|
3956
|
-
//group denominators
|
|
3957
|
-
var denominators = {};
|
|
3958
|
-
|
|
3959
|
-
symbol.each(function (x) {
|
|
3960
|
-
var d = x.getDenom();
|
|
3961
|
-
var n = x.getNum();
|
|
3962
|
-
var e = denominators[d];
|
|
3963
|
-
denominators[d] = e ? _.add(e, n) : n;
|
|
3964
|
-
});
|
|
3965
|
-
|
|
3966
|
-
var t = new Symbol(0);
|
|
3967
|
-
|
|
3968
|
-
for(var x in denominators) {
|
|
3969
|
-
t = _.add(t, _.divide(denominators[x], _.parse(x)));
|
|
3970
|
-
}
|
|
3971
|
-
|
|
3972
|
-
symbol = t;
|
|
3973
|
-
}
|
|
3974
|
-
}
|
|
3975
|
-
catch(e2) {
|
|
3976
|
-
}
|
|
3977
|
-
;
|
|
3978
|
-
}
|
|
3979
|
-
;
|
|
3980
|
-
|
|
3981
|
-
return symbol;
|
|
3982
|
-
}
|
|
3983
|
-
},
|
|
3984
|
-
degree: function (symbol, v, o) {
|
|
3985
|
-
o = o || {
|
|
3986
|
-
nd: [], //numeric
|
|
3987
|
-
sd: [], //symbolic
|
|
3988
|
-
depth: 0 //call depth
|
|
3989
|
-
};
|
|
3990
|
-
|
|
3991
|
-
if(!v) {
|
|
3992
|
-
var vars = variables(symbol);
|
|
3993
|
-
//The user must specify the variable for multivariate
|
|
3994
|
-
if(vars.length > 1)
|
|
3995
|
-
throw new Error('You must specify the variable for multivariate polynomials!');
|
|
3996
|
-
//if it's empty then we're dealing with a constant
|
|
3997
|
-
if(vars.length === 0)
|
|
3998
|
-
return new Symbol(0);
|
|
3999
|
-
//assume the variable for univariate
|
|
4000
|
-
v = _.parse(vars[0]);
|
|
4001
|
-
}
|
|
4002
|
-
|
|
4003
|
-
//store the group
|
|
4004
|
-
var g = symbol.group;
|
|
4005
|
-
//we're going to trust the user and assume no EX. Calling isPoly
|
|
4006
|
-
//would eliminate this but no sense in checking twice.
|
|
4007
|
-
if(symbol.isComposite()) {
|
|
4008
|
-
symbol = symbol.clone();
|
|
4009
|
-
symbol.distributeExponent();
|
|
4010
|
-
symbol.each(function (x) {
|
|
4011
|
-
o.depth++; //mark a depth increase
|
|
4012
|
-
__.degree(x, v, o);
|
|
4013
|
-
o.depth--; //we're back
|
|
4014
|
-
});
|
|
4015
|
-
}
|
|
4016
|
-
else if(symbol.group === CB) {
|
|
4017
|
-
symbol.each(function (x) {
|
|
4018
|
-
o.depth++;
|
|
4019
|
-
__.degree(x, v, o);
|
|
4020
|
-
o.depth++;
|
|
4021
|
-
});
|
|
4022
|
-
}
|
|
4023
|
-
else if(g === EX && symbol.value === v.value) {
|
|
4024
|
-
o.sd.push(symbol.power.clone());
|
|
4025
|
-
}
|
|
4026
|
-
else if(g === S && symbol.value === v.value) {
|
|
4027
|
-
o.nd.push(_.parse(symbol.power));
|
|
4028
|
-
}
|
|
4029
|
-
else
|
|
4030
|
-
o.nd.push(new Symbol(0));
|
|
4031
|
-
|
|
4032
|
-
//get the max out of the array
|
|
4033
|
-
var deg = o.nd.length > 0 ? core.Utils.arrayMax(o.nd) : undefined;
|
|
4034
|
-
|
|
4035
|
-
if(o.depth === 0 && o.sd.length > 0) {
|
|
4036
|
-
if(deg !== undefined)
|
|
4037
|
-
o.sd.unshift(deg);
|
|
4038
|
-
return _.symfunction('max', o.sd);
|
|
4039
|
-
}
|
|
4040
|
-
if(!core.Utils.isSymbol(deg))
|
|
4041
|
-
deg = _.parse(deg);
|
|
4042
|
-
//return the degree
|
|
4043
|
-
return deg;
|
|
4044
|
-
},
|
|
4045
|
-
/**
|
|
4046
|
-
* Attempts to complete the square of a polynomial
|
|
4047
|
-
* @param {type} symbol
|
|
4048
|
-
* @param {type} v
|
|
4049
|
-
* @param {type} raw
|
|
4050
|
-
* @throws {Error}
|
|
4051
|
-
* @returns {Object|Symbol[]}
|
|
4052
|
-
*/
|
|
4053
|
-
sqComplete: function (symbol, v, raw) {
|
|
4054
|
-
if(!core.Utils.isSymbol(v))
|
|
4055
|
-
v = _.parse(v);
|
|
4056
|
-
var stop = function (msg) {
|
|
4057
|
-
msg = msg || 'Stopping';
|
|
4058
|
-
throw new core.exceptions.ValueLimitExceededError(msg);
|
|
4059
|
-
};
|
|
4060
|
-
//if not CP then nothing to do
|
|
4061
|
-
if(!symbol.isPoly(true))
|
|
4062
|
-
stop('Must be a polynomial!');
|
|
4063
|
-
|
|
4064
|
-
//declare vars
|
|
4065
|
-
var deg, a, b, c, d, e, coeffs, sign, br, sym, sqrt_a;
|
|
4066
|
-
|
|
4067
|
-
br = core.Utils.inBrackets;
|
|
4068
|
-
//make a copy
|
|
4069
|
-
symbol = symbol.clone();
|
|
4070
|
-
deg = core.Algebra.degree(symbol, v); //get the degree of polynomial
|
|
4071
|
-
//must be in form ax^2 +/- bx +/- c
|
|
4072
|
-
if(!deg.equals(2))
|
|
4073
|
-
stop('Cannot complete square for degree ' + deg);
|
|
4074
|
-
//get the coeffs
|
|
4075
|
-
coeffs = core.Algebra.coeffs(symbol, v);
|
|
4076
|
-
a = coeffs[2];
|
|
4077
|
-
//store the sign
|
|
4078
|
-
sign = coeffs[1].sign();
|
|
4079
|
-
//divide the linear term by two and square it
|
|
4080
|
-
b = _.divide(coeffs[1], new Symbol(2));
|
|
4081
|
-
//add the difference to the constant
|
|
4082
|
-
c = _.pow(b.clone(), new Symbol(2));
|
|
4083
|
-
if(raw)
|
|
4084
|
-
return [a, b, d];
|
|
4085
|
-
sqrt_a = math.sqrt(a);
|
|
4086
|
-
e = _.divide(math.sqrt(c), sqrt_a.clone());
|
|
4087
|
-
//calculate d which is the constant
|
|
4088
|
-
d = _.subtract(coeffs[0], _.pow(e.clone(), new Symbol(2)));
|
|
4089
|
-
//compute the square part
|
|
4090
|
-
sym = _.parse(br(sqrt_a.clone() + '*' + v + (sign < 0 ? '-' : '+') + e));
|
|
4091
|
-
return {
|
|
4092
|
-
a: sym,
|
|
4093
|
-
c: d,
|
|
4094
|
-
f: _.add(_.pow(sym.clone(), new Symbol(2)), d.clone())
|
|
4095
|
-
};
|
|
4096
|
-
},
|
|
4097
|
-
Simplify: {
|
|
4098
|
-
strip: function (symbol) {
|
|
4099
|
-
var c = _.parse(symbol.multiplier);
|
|
4100
|
-
symbol.toUnitMultiplier();
|
|
4101
|
-
var p = _.parse(symbol.power);
|
|
4102
|
-
symbol.toLinear();
|
|
4103
|
-
return [c, p, symbol];
|
|
4104
|
-
},
|
|
4105
|
-
unstrip: function (cp, symbol) {
|
|
4106
|
-
var c = cp[0];
|
|
4107
|
-
var p = cp[1];
|
|
4108
|
-
return _.multiply(c, _.pow(symbol, p));
|
|
4109
|
-
},
|
|
4110
|
-
complexSimp: function (num, den) {
|
|
4111
|
-
var ac, bd, bc, ad, cd, r1, r2, i1, i2;
|
|
4112
|
-
r1 = num.realpart();
|
|
4113
|
-
i1 = num.imagpart();
|
|
4114
|
-
r2 = den.realpart();
|
|
4115
|
-
i2 = den.imagpart();
|
|
4116
|
-
//apply complex arithmatic rule
|
|
4117
|
-
ac = _.multiply(r1.clone(), r2.clone());
|
|
4118
|
-
bd = _.multiply(i1.clone(), i2.clone());
|
|
4119
|
-
bc = _.multiply(r2.clone(), i1);
|
|
4120
|
-
ad = _.multiply(r1, i2.clone());
|
|
4121
|
-
cd = _.add(_.pow(r2, new Symbol(2)), _.pow(i2, new Symbol(2)));
|
|
4122
|
-
|
|
4123
|
-
return _.divide(_.add(_.add(ac, bd), _.multiply(_.subtract(bc, ad), Symbol.imaginary())), cd);
|
|
4124
|
-
},
|
|
4125
|
-
trigSimp: function (symbol) {
|
|
4126
|
-
if(symbol.containsFunction(['cos', 'sin', 'tan'])) {
|
|
4127
|
-
symbol = symbol.clone();
|
|
4128
|
-
//remove power and multiplier
|
|
4129
|
-
var sym_array = __.Simplify.strip(symbol);
|
|
4130
|
-
symbol = sym_array.pop();
|
|
4131
|
-
//the default return value is the symbol
|
|
4132
|
-
var retval = symbol.clone();
|
|
4133
|
-
|
|
4134
|
-
//rewrite the symbol
|
|
4135
|
-
if(symbol.group === CP) {
|
|
4136
|
-
var sym = new Symbol(0);
|
|
4137
|
-
symbol.each(function (x) {
|
|
4138
|
-
//rewrite the function
|
|
4139
|
-
var tr = __.Simplify.trigSimp(x.fnTransform());
|
|
4140
|
-
sym = _.add(sym, tr);
|
|
4141
|
-
}, true);
|
|
4142
|
-
|
|
4143
|
-
//put back the power and multiplier and return
|
|
4144
|
-
retval = _.pow(_.multiply(new Symbol(symbol.multiplier), sym), new Symbol(symbol.power));
|
|
4145
|
-
}
|
|
4146
|
-
else if(symbol.group === CB) {
|
|
4147
|
-
|
|
4148
|
-
var n = symbol.getNum();
|
|
4149
|
-
var d = symbol.getDenom();
|
|
4150
|
-
|
|
4151
|
-
//try for tangent
|
|
4152
|
-
if(n.fname === 'sin' && d.fname === 'cos' && n.args[0].equals(d.args[0]) && n.power.equals(d.power)) {
|
|
4153
|
-
retval = _.parse(core.Utils.format('({0})*({1})*tan({2})^({3})', d.multiplier, n.multiplier, n.args[0], n.power));
|
|
4154
|
-
}
|
|
4155
|
-
if(retval.group === CB) {
|
|
4156
|
-
var t = new Symbol(1);
|
|
4157
|
-
retval.each(function (x) {
|
|
4158
|
-
if(x.fname === 'tan') {
|
|
4159
|
-
x = _.parse(core.Utils.format('({0})*sin({1})^({2})/cos({1})^({2})', x.multiplier, __.Simplify.simplify(x.args[0]), x.power));
|
|
4160
|
-
}
|
|
4161
|
-
t = _.multiply(t, x);
|
|
4162
|
-
});
|
|
4163
|
-
retval = t;
|
|
4164
|
-
}
|
|
4165
|
-
}
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
retval = __.Simplify.unstrip(sym_array, retval).distributeMultiplier();
|
|
4169
|
-
|
|
4170
|
-
symbol = retval;
|
|
4171
|
-
}
|
|
4172
|
-
|
|
4173
|
-
return symbol;
|
|
4174
|
-
},
|
|
4175
|
-
fracSimp: function (symbol) {
|
|
4176
|
-
//try a quick simplify of imaginary numbers
|
|
4177
|
-
var den = symbol.getDenom();
|
|
4178
|
-
var num = symbol.getNum();
|
|
4179
|
-
|
|
4180
|
-
if(num.isImaginary() && den.isImaginary())
|
|
4181
|
-
symbol = __.Simplify.complexSimp(num, den);
|
|
4182
|
-
|
|
4183
|
-
if(symbol.isComposite()) {
|
|
4184
|
-
if(symbol.power > 1) {
|
|
4185
|
-
symbol = _.expand(symbol);
|
|
4186
|
-
}
|
|
4187
|
-
|
|
4188
|
-
var symbols = symbol.collectSymbols();
|
|
4189
|
-
//assumption 1.
|
|
4190
|
-
//since it's a composite, it has a length of at least 1
|
|
4191
|
-
var retval, a, b, d1, d2, n1, n2, s, x, y, c, den, num;
|
|
4192
|
-
a = symbols.pop(); //grab the first symbol
|
|
4193
|
-
//loop through each term and make denominator common
|
|
4194
|
-
while(symbols.length) {
|
|
4195
|
-
b = symbols.pop(); //grab the second symbol
|
|
4196
|
-
d1 = _.parse(a.getDenom());
|
|
4197
|
-
d2 = _.parse(b.getDenom());
|
|
4198
|
-
n1 = a.getNum();
|
|
4199
|
-
n2 = b.getNum();
|
|
4200
|
-
c = _.multiply(d1.clone(), d2.clone());
|
|
4201
|
-
x = _.multiply(n1, d2);
|
|
4202
|
-
y = _.multiply(n2, d1);
|
|
4203
|
-
s = _.add(x, y);
|
|
4204
|
-
a = _.divide(s, c);
|
|
4205
|
-
}
|
|
4206
|
-
den = _.expand(a.getDenom());
|
|
4207
|
-
num = _.expand(a.getNum());
|
|
4208
|
-
//simplify imaginary
|
|
4209
|
-
if(num.isImaginary() && den.isImaginary()) {
|
|
4210
|
-
retval = __.Simplify.complexSimp(num, den);
|
|
4211
|
-
}
|
|
4212
|
-
else {
|
|
4213
|
-
retval = _.divide(num, den);
|
|
4214
|
-
}
|
|
4215
|
-
|
|
4216
|
-
//we've already hit the simplest form so return that
|
|
4217
|
-
if(retval.equals(symbol)) {
|
|
4218
|
-
return symbol;
|
|
4219
|
-
}
|
|
4220
|
-
|
|
4221
|
-
//otherwise simplify it some more
|
|
4222
|
-
return __.Simplify.simplify(retval);
|
|
4223
|
-
}
|
|
4224
|
-
return symbol;
|
|
4225
|
-
},
|
|
4226
|
-
ratSimp: function (symbol) {
|
|
4227
|
-
if(symbol.group === CB) {
|
|
4228
|
-
var den = symbol.getDenom();
|
|
4229
|
-
var num = symbol.getNum().distributeMultiplier();
|
|
4230
|
-
var d = __.Simplify.fracSimp(den);
|
|
4231
|
-
var n = __.Simplify.fracSimp(num);
|
|
4232
|
-
symbol = _.divide(n, d);
|
|
4233
|
-
}
|
|
4234
|
-
return symbol;
|
|
4235
|
-
},
|
|
4236
|
-
sqrtSimp: function (symbol, sym_array) {
|
|
4237
|
-
var retval;
|
|
4238
|
-
if(symbol.isSQRT()) {
|
|
4239
|
-
var factored = __.Factor.factor(symbol.args[0].clone());
|
|
4240
|
-
var m = _.parse(factored.multiplier);
|
|
4241
|
-
var sign = m.sign();
|
|
4242
|
-
|
|
4243
|
-
var retval = _.sqrt(m.abs());
|
|
4244
|
-
var arg;
|
|
4245
|
-
|
|
4246
|
-
if(isInt(retval)) {
|
|
4247
|
-
|
|
4248
|
-
if(factored.group === CB) {
|
|
4249
|
-
var rem = new Symbol(1);
|
|
4250
|
-
|
|
4251
|
-
factored.each(function (x) {
|
|
4252
|
-
if(x.group === N) {
|
|
4253
|
-
var trial = _.sqrt(x.clone());
|
|
4254
|
-
|
|
4255
|
-
// Multiply back sqrt if it's an integer otherwise just put back the number
|
|
4256
|
-
if(isInt(trial)) {
|
|
4257
|
-
retval = _.multiply(retval, trial);
|
|
4258
|
-
}
|
|
4259
|
-
else {
|
|
4260
|
-
rem = _.multiply(rem, x);
|
|
4261
|
-
}
|
|
4262
|
-
}
|
|
4263
|
-
else {
|
|
4264
|
-
rem = _.multiply(rem, x);
|
|
4265
|
-
}
|
|
4266
|
-
|
|
4267
|
-
});
|
|
4268
|
-
var t = _.multiply(rem, _.parse(sign));
|
|
4269
|
-
arg = _.sqrt(t.clone());
|
|
4270
|
-
|
|
4271
|
-
// Expand if it's imaginary
|
|
4272
|
-
if(arg.isImaginary) {
|
|
4273
|
-
arg = _.sqrt(_.expand(t.clone()));
|
|
4274
|
-
}
|
|
4275
|
-
}
|
|
4276
|
-
else {
|
|
4277
|
-
// Strip the multiplier
|
|
4278
|
-
arg = _.sqrt(factored.clone().toUnitMultiplier());
|
|
4279
|
-
}
|
|
4280
|
-
return _.multiply(retval, arg);
|
|
4281
|
-
|
|
4282
|
-
}
|
|
4283
|
-
|
|
4284
|
-
}
|
|
4285
|
-
else if(symbol.isComposite() && symbol.isLinear()) {
|
|
4286
|
-
retval = new Symbol(0);
|
|
4287
|
-
symbol.each(function (x) {
|
|
4288
|
-
retval = _.add(retval, __.Simplify.sqrtSimp(x));
|
|
4289
|
-
}, true);
|
|
4290
|
-
// Put back the multiplier
|
|
4291
|
-
retval = _.multiply(retval, _.parse(symbol.multiplier));
|
|
4292
|
-
}
|
|
4293
|
-
else if(symbol.group === CB) {
|
|
4294
|
-
retval = _.parse(symbol.multiplier);
|
|
4295
|
-
symbol.each(function (x) {
|
|
4296
|
-
var simp = __.Simplify.sqrtSimp(x);
|
|
4297
|
-
retval = _.multiply(retval, simp);
|
|
4298
|
-
|
|
4299
|
-
}, true);
|
|
4300
|
-
// Put back the power
|
|
4301
|
-
retval = _.pow(retval, _.parse(symbol.power));
|
|
4302
|
-
}
|
|
4303
|
-
|
|
4304
|
-
return retval ? retval : _.parse(symbol);
|
|
4305
|
-
},
|
|
4306
|
-
/**
|
|
4307
|
-
* Unused. The goal is to substitute out patterns but it currently doesn't work.
|
|
4308
|
-
* @param {Symbol} symbol
|
|
4309
|
-
* @return {Array} The symbol and the matched patterns
|
|
4310
|
-
*/
|
|
4311
|
-
patternSub: function (symbol) {
|
|
4312
|
-
var patterns = {};
|
|
4313
|
-
|
|
4314
|
-
var has_CP = function (symbol) {
|
|
4315
|
-
var found = false;
|
|
4316
|
-
symbol.each(function (x) {
|
|
4317
|
-
if(x.group === CP) {
|
|
4318
|
-
found = true;
|
|
4319
|
-
}
|
|
4320
|
-
else if(x.symbols) {
|
|
4321
|
-
found = has_CP(x);
|
|
4322
|
-
}
|
|
4323
|
-
});
|
|
4324
|
-
|
|
4325
|
-
return found;
|
|
4326
|
-
};
|
|
4327
|
-
|
|
4328
|
-
var collect = function (sym) {
|
|
4329
|
-
// We loop through each symbol looking for anything in the simplest
|
|
4330
|
-
// form of ax+byz+...
|
|
4331
|
-
sym.each(function (x) {
|
|
4332
|
-
// Items of group N,P,S, need to apply
|
|
4333
|
-
if(!x.symbols && x.group !== FN) {
|
|
4334
|
-
return;
|
|
4335
|
-
}
|
|
4336
|
-
|
|
4337
|
-
// Check to see if it has any symbols of group CP
|
|
4338
|
-
// Get the patterns in that symbol instead if it has anything of group CP
|
|
4339
|
-
if(has_CP(x)) {
|
|
4340
|
-
collect(x);
|
|
4341
|
-
}
|
|
4342
|
-
else {
|
|
4343
|
-
if(!patterns[x.value]) {
|
|
4344
|
-
var u = core.Utils.getU(symbol);
|
|
4345
|
-
// Get a u value and mark it for subsitution
|
|
4346
|
-
patterns[x.value] = u;
|
|
4347
|
-
symbol = symbol.sub(x.value, u);
|
|
4348
|
-
}
|
|
4349
|
-
}
|
|
4350
|
-
}, true);
|
|
4351
|
-
};
|
|
4352
|
-
|
|
4353
|
-
// Collect a list of patterns
|
|
4354
|
-
collect(symbol);
|
|
4355
|
-
|
|
4356
|
-
return [symbol, patterns];
|
|
4357
|
-
},
|
|
4358
|
-
simplify: function (symbol) {
|
|
4359
|
-
//remove the multiplier to make calculation easier;
|
|
4360
|
-
var sym_array = __.Simplify.strip(symbol);
|
|
4361
|
-
symbol = sym_array.pop();
|
|
4362
|
-
//remove gcd from denominator
|
|
4363
|
-
symbol = __.Simplify.fracSimp(symbol);
|
|
4364
|
-
//nothing more to do
|
|
4365
|
-
if(symbol.isConstant() || symbol.group === core.groups.S) {
|
|
4366
|
-
sym_array.push(symbol);
|
|
4367
|
-
var ret = __.Simplify.unstrip(sym_array, symbol);
|
|
4368
|
-
return ret;
|
|
4369
|
-
}
|
|
4370
|
-
|
|
4371
|
-
//var patterns;
|
|
4372
|
-
|
|
4373
|
-
var simplified = symbol.clone(); //make a copy
|
|
4374
|
-
|
|
4375
|
-
//[simplified, patterns] = __.Simplify.patternSub(symbol);
|
|
4376
|
-
|
|
4377
|
-
// Simplify sqrt within the symbol
|
|
4378
|
-
// simplified = __.Simplify.sqrtSimp(simplified, sym_array);
|
|
4379
|
-
|
|
4380
|
-
// Try trig simplificatons e.g. cos(x)^2+sin(x)^2
|
|
4381
|
-
simplified = __.Simplify.trigSimp(simplified);
|
|
4382
|
-
|
|
4383
|
-
// Simplify common denominators
|
|
4384
|
-
simplified = __.Simplify.ratSimp(simplified);
|
|
4385
|
-
|
|
4386
|
-
// First go for the "cheapest" simplification which may eliminate
|
|
4387
|
-
// your problems right away. factor -> evaluate. Remember
|
|
4388
|
-
// that there's no need to expand since factor already does that
|
|
4389
|
-
|
|
4390
|
-
simplified = __.Factor.factor(simplified);
|
|
4391
|
-
|
|
4392
|
-
//If the simplfied is a sum then we can make a few more simplifications
|
|
4393
|
-
//e.g. simplify(1/(x-1)+1/(1-x)) as per issue #431
|
|
4394
|
-
if(simplified.group === core.groups.CP && simplified.isLinear()) {
|
|
4395
|
-
var m = simplified.multiplier.clone();
|
|
4396
|
-
simplified.toUnitMultiplier(); //strip the multiplier
|
|
4397
|
-
var r = new Symbol(0);
|
|
4398
|
-
//return the sum of simplifications
|
|
4399
|
-
simplified.each(function (x) {
|
|
4400
|
-
var s = __.Simplify.simplify(x);
|
|
4401
|
-
r = _.add(r, s);
|
|
4402
|
-
});
|
|
4403
|
-
simplified = r;
|
|
4404
|
-
//put back the multiplier
|
|
4405
|
-
r.multiplier = r.multiplier.multiply(m);
|
|
4406
|
-
}
|
|
4407
|
-
|
|
4408
|
-
//place back multiplier and return
|
|
4409
|
-
var retval = __.Simplify.unstrip(sym_array, simplified);
|
|
4410
|
-
|
|
4411
|
-
// Back substitute
|
|
4412
|
-
/*
|
|
4413
|
-
for(var x in patterns) {
|
|
4414
|
-
retval = retval.sub(patterns[x], x);
|
|
4415
|
-
}
|
|
4416
|
-
*/
|
|
4417
|
-
|
|
4418
|
-
return retval;
|
|
4419
|
-
}
|
|
4420
|
-
},
|
|
4421
|
-
|
|
4422
|
-
Classes: {
|
|
4423
|
-
Polynomial: Polynomial,
|
|
4424
|
-
Factors: Factors,
|
|
4425
|
-
MVTerm: MVTerm
|
|
4426
|
-
}
|
|
4427
|
-
};
|
|
4428
|
-
|
|
4429
|
-
// Add a link to simplify
|
|
4430
|
-
core.Expression.prototype.simplify = function () {
|
|
4431
|
-
return __.Simplify.simplify(this.symbol);
|
|
4432
|
-
};
|
|
4433
|
-
|
|
4434
|
-
nerdamer.useAlgebraDiv = function () {
|
|
4435
|
-
var divide = __.divideFn = _.divide;
|
|
4436
|
-
var calls = 0; //keep track of how many calls were made
|
|
4437
|
-
_.divide = function (a, b) {
|
|
4438
|
-
calls++;
|
|
4439
|
-
var ans;
|
|
4440
|
-
if(calls === 1) //check if this is the first call. If it is use algebra divide
|
|
4441
|
-
ans = core.Algebra.divide(a, b);
|
|
4442
|
-
else //otherwise use parser divide
|
|
4443
|
-
ans = divide(a, b);
|
|
4444
|
-
calls = 0; //reset the number of calls back to none
|
|
4445
|
-
return ans;
|
|
4446
|
-
};
|
|
4447
|
-
};
|
|
4448
|
-
|
|
4449
|
-
nerdamer.useParserDiv = function () {
|
|
4450
|
-
if(__.divideFn)
|
|
4451
|
-
_.divide = __.divideFn;
|
|
4452
|
-
delete __.divideFn;
|
|
4453
|
-
};
|
|
4454
|
-
|
|
4455
|
-
nerdamer.register([
|
|
4456
|
-
{
|
|
4457
|
-
name: 'factor',
|
|
4458
|
-
visible: true,
|
|
4459
|
-
numargs: 1,
|
|
4460
|
-
build: function () {
|
|
4461
|
-
return __.Factor.factor;
|
|
4462
|
-
}
|
|
4463
|
-
},
|
|
4464
|
-
{
|
|
4465
|
-
name: 'simplify',
|
|
4466
|
-
visible: true,
|
|
4467
|
-
numargs: 1,
|
|
4468
|
-
build: function () {
|
|
4469
|
-
return __.Simplify.simplify;
|
|
4470
|
-
}
|
|
4471
|
-
},
|
|
4472
|
-
{
|
|
4473
|
-
name: 'gcd',
|
|
4474
|
-
visible: true,
|
|
4475
|
-
numargs: [1, ],
|
|
4476
|
-
build: function () {
|
|
4477
|
-
return __.gcd;
|
|
4478
|
-
}
|
|
4479
|
-
},
|
|
4480
|
-
{
|
|
4481
|
-
name: 'lcm',
|
|
4482
|
-
visible: true,
|
|
4483
|
-
numargs: [1, ],
|
|
4484
|
-
build: function () {
|
|
4485
|
-
return __.lcm;
|
|
4486
|
-
}
|
|
4487
|
-
},
|
|
4488
|
-
{
|
|
4489
|
-
name: 'roots',
|
|
4490
|
-
visible: true,
|
|
4491
|
-
numargs: -1,
|
|
4492
|
-
build: function () {
|
|
4493
|
-
return __.roots;
|
|
4494
|
-
}
|
|
4495
|
-
},
|
|
4496
|
-
{
|
|
4497
|
-
name: 'divide',
|
|
4498
|
-
visible: true,
|
|
4499
|
-
numargs: 2,
|
|
4500
|
-
build: function () {
|
|
4501
|
-
return __.divide;
|
|
4502
|
-
}
|
|
4503
|
-
},
|
|
4504
|
-
{
|
|
4505
|
-
name: 'div',
|
|
4506
|
-
visible: true,
|
|
4507
|
-
numargs: 2,
|
|
4508
|
-
build: function () {
|
|
4509
|
-
return __.div;
|
|
4510
|
-
}
|
|
4511
|
-
},
|
|
4512
|
-
{
|
|
4513
|
-
name: 'partfrac',
|
|
4514
|
-
visible: true,
|
|
4515
|
-
numargs: [1, 2],
|
|
4516
|
-
build: function () {
|
|
4517
|
-
return __.PartFrac.partfrac;
|
|
4518
|
-
}
|
|
4519
|
-
},
|
|
4520
|
-
{
|
|
4521
|
-
name: 'deg',
|
|
4522
|
-
visible: true,
|
|
4523
|
-
numargs: [1, 2],
|
|
4524
|
-
build: function () {
|
|
4525
|
-
return __.degree;
|
|
4526
|
-
}
|
|
4527
|
-
},
|
|
4528
|
-
{
|
|
4529
|
-
name: 'coeffs',
|
|
4530
|
-
visible: true,
|
|
4531
|
-
numargs: [1, 2],
|
|
4532
|
-
build: function () {
|
|
4533
|
-
var f = function () {
|
|
4534
|
-
var coeffs = __.coeffs.apply(__, arguments);
|
|
4535
|
-
return new core.Vector(coeffs);
|
|
4536
|
-
};
|
|
4537
|
-
return f;
|
|
4538
|
-
}
|
|
4539
|
-
},
|
|
4540
|
-
{
|
|
4541
|
-
name: 'line',
|
|
4542
|
-
visible: true,
|
|
4543
|
-
numargs: [2, 3],
|
|
4544
|
-
build: function () {
|
|
4545
|
-
return __.line;
|
|
4546
|
-
}
|
|
4547
|
-
},
|
|
4548
|
-
{
|
|
4549
|
-
name: 'sqcomp',
|
|
4550
|
-
visible: true,
|
|
4551
|
-
numargs: [1, 2],
|
|
4552
|
-
build: function () {
|
|
4553
|
-
var f = function (x, v) {
|
|
4554
|
-
try {
|
|
4555
|
-
v = v || variables(x)[0];
|
|
4556
|
-
var sq = __.sqComplete(x.clone(), v);
|
|
4557
|
-
return sq.f;
|
|
4558
|
-
}
|
|
4559
|
-
catch(e) {
|
|
4560
|
-
return x;
|
|
4561
|
-
}
|
|
4562
|
-
};
|
|
4563
|
-
return f;
|
|
4564
|
-
}
|
|
4565
|
-
}
|
|
4566
|
-
]);
|
|
4567
|
-
nerdamer.updateAPI();
|
|
4568
|
-
})();
|