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/Solve.js
DELETED
|
@@ -1,1783 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Author : Martin Donk
|
|
3
|
-
* Website : http://www.nerdamer.com
|
|
4
|
-
* Email : martin.r.donk@gmail.com
|
|
5
|
-
* Source : https://github.com/jiggzson/nerdamer
|
|
6
|
-
*/
|
|
7
|
-
/* global module */
|
|
8
|
-
|
|
9
|
-
if((typeof module) !== 'undefined') {
|
|
10
|
-
var nerdamer = require('./nerdamer.core.js');
|
|
11
|
-
require('./Calculus.js');
|
|
12
|
-
require('./Algebra.js');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
(function () {
|
|
16
|
-
//handle imports
|
|
17
|
-
var core = nerdamer.getCore(),
|
|
18
|
-
_ = core.PARSER,
|
|
19
|
-
_A = core.Algebra,
|
|
20
|
-
_C = core.Calculus,
|
|
21
|
-
explode = _C.integration.decompose_arg,
|
|
22
|
-
evaluate = core.Utils.evaluate,
|
|
23
|
-
remove = core.Utils.remove,
|
|
24
|
-
format = core.Utils.format,
|
|
25
|
-
build = core.Utils.build,
|
|
26
|
-
knownVariable = core.Utils.knownVariable,
|
|
27
|
-
Symbol = core.Symbol,
|
|
28
|
-
isSymbol = core.Utils.isSymbol,
|
|
29
|
-
variables = core.Utils.variables,
|
|
30
|
-
S = core.groups.S,
|
|
31
|
-
PL = core.groups.PL,
|
|
32
|
-
CB = core.groups.CB,
|
|
33
|
-
CP = core.groups.CP,
|
|
34
|
-
FN = core.groups.FN,
|
|
35
|
-
Settings = core.Settings,
|
|
36
|
-
range = core.Utils.range,
|
|
37
|
-
isArray = core.Utils.isArray;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// The search radius for the roots
|
|
41
|
-
core.Settings.SOLVE_RADIUS = 1000;
|
|
42
|
-
// The maximum number to fish for on each side of the zero
|
|
43
|
-
core.Settings.ROOTS_PER_SIDE = 10;
|
|
44
|
-
// Covert the number to multiples of pi if possible
|
|
45
|
-
core.Settings.make_pi_conversions = false;
|
|
46
|
-
// The step size
|
|
47
|
-
core.Settings.STEP_SIZE = 0.1;
|
|
48
|
-
// The epsilon size
|
|
49
|
-
core.Settings.EPSILON = 1e-13;
|
|
50
|
-
//the maximum iterations for Newton's method
|
|
51
|
-
core.Settings.MAX_NEWTON_ITERATIONS = 200;
|
|
52
|
-
//the maximum number of time non-linear solve tries another jump point
|
|
53
|
-
core.Settings.MAX_NON_LINEAR_TRIES = 12;
|
|
54
|
-
//the amount of iterations the function will start to jump at
|
|
55
|
-
core.Settings.NON_LINEAR_JUMP_AT = 50;
|
|
56
|
-
//the size of the jump
|
|
57
|
-
core.Settings.NON_LINEAR_JUMP_SIZE = 100;
|
|
58
|
-
//the original starting point for nonlinear solving
|
|
59
|
-
core.Settings.NON_LINEAR_START = 0.01;
|
|
60
|
-
//When points are generated as starting points for Newton's method, they are sliced into small
|
|
61
|
-
//slices to make sure that we have convergence on the right point. This defines the
|
|
62
|
-
//size of the slice
|
|
63
|
-
core.Settings.NEWTON_SLICES = 200;
|
|
64
|
-
//The epsilon used in Newton's iteration
|
|
65
|
-
core.Settings.NEWTON_EPSILON = Number.EPSILON * 2;
|
|
66
|
-
//The distance in which two solutions are deemed the same
|
|
67
|
-
core.Settings.SOLUTION_PROXIMITY = 1e-14;
|
|
68
|
-
//Indicate wheter to filter the solutions are not
|
|
69
|
-
core.Settings.FILTER_SOLUTIONS = true;
|
|
70
|
-
//the maximum number of recursive calls
|
|
71
|
-
core.Settings.MAX_SOLVE_DEPTH = 10;
|
|
72
|
-
// The tolerance that's considered close enough to zero
|
|
73
|
-
core.Settings.ZERO_EPSILON = 1e-9;
|
|
74
|
-
// The maximum iteration for the bisection method incase of some JS strangeness
|
|
75
|
-
core.Settings.MAX_BISECTION_ITER = 2000;
|
|
76
|
-
// The tolerance for the bisection method
|
|
77
|
-
core.Settings.BI_SECTION_EPSILON = 1e-12;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
core.Symbol.prototype.hasTrig = function () {
|
|
81
|
-
return this.containsFunction(['cos', 'sin', 'tan', 'cot', 'csc', 'sec']);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
core.Symbol.prototype.hasNegativeTerms = function () {
|
|
85
|
-
if(this.isComposite()) {
|
|
86
|
-
for(var x in this.symbols) {
|
|
87
|
-
var sym = this.symbols[x];
|
|
88
|
-
if(sym.group === PL && sym.hasNegativeTerms() || this.symbols[x].power.lessThan(0))
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/* nerdamer version 0.7.x and up allows us to make better use of operator overloading
|
|
96
|
-
* As such we can have this data type be supported completely outside of the core.
|
|
97
|
-
* This is an equation that has a left hand side and a right hand side
|
|
98
|
-
*/
|
|
99
|
-
function Equation(lhs, rhs) {
|
|
100
|
-
if(rhs.isConstant() && lhs.isConstant() && !lhs.equals(rhs) || lhs.equals(core.Settings.IMAGINARY) && rhs.isConstant(true) || rhs.equals(core.Settings.IMAGINARY) && lhs.isConstant(true))
|
|
101
|
-
throw new core.exceptions.NerdamerValueError(lhs.toString() + ' does not equal ' + rhs.toString());
|
|
102
|
-
this.LHS = lhs; //left hand side
|
|
103
|
-
this.RHS = rhs; //right and side
|
|
104
|
-
}
|
|
105
|
-
;
|
|
106
|
-
|
|
107
|
-
//UTILS ##!!
|
|
108
|
-
|
|
109
|
-
Equation.prototype = {
|
|
110
|
-
toString: function () {
|
|
111
|
-
return this.LHS.toString() + '=' + this.RHS.toString();
|
|
112
|
-
},
|
|
113
|
-
text: function (option) {
|
|
114
|
-
return this.LHS.text(option) + '=' + this.RHS.text(option);
|
|
115
|
-
},
|
|
116
|
-
toLHS: function (expand) {
|
|
117
|
-
expand = typeof expand === 'undefined' ? true : false;
|
|
118
|
-
var eqn;
|
|
119
|
-
if(!expand) {
|
|
120
|
-
eqn = this.clone();
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
eqn = this.removeDenom();
|
|
124
|
-
}
|
|
125
|
-
var a = eqn.LHS;
|
|
126
|
-
var b = eqn.RHS;
|
|
127
|
-
|
|
128
|
-
if(a.isConstant(true) && !b.isConstant(true)) {
|
|
129
|
-
// Swap them to avoid confusing parser and cause an infinite loop
|
|
130
|
-
[a, b] = [b, a];
|
|
131
|
-
}
|
|
132
|
-
var _t = _.subtract(a, b);
|
|
133
|
-
var retval = expand ? _.expand(_t) : _t;
|
|
134
|
-
|
|
135
|
-
// Quick workaround for issue #636
|
|
136
|
-
// This basically borrows the removeDenom method from the Equation class.
|
|
137
|
-
// TODO: Make this function a stand-alone function
|
|
138
|
-
retval = new Equation(retval, new Symbol(0)).removeDenom().LHS;
|
|
139
|
-
|
|
140
|
-
return retval;
|
|
141
|
-
},
|
|
142
|
-
removeDenom: function () {
|
|
143
|
-
var a = this.LHS.clone();
|
|
144
|
-
var b = this.RHS.clone();
|
|
145
|
-
//remove the denominator on both sides
|
|
146
|
-
var den = _.multiply(a.getDenom(), b.getDenom());
|
|
147
|
-
a = _.expand(_.multiply(a, den.clone()));
|
|
148
|
-
b = _.expand(_.multiply(b, den));
|
|
149
|
-
//swap the groups
|
|
150
|
-
if(b.group === CP && b.group !== CP) {
|
|
151
|
-
var t = a;
|
|
152
|
-
a = b;
|
|
153
|
-
b = t; //swap
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
//scan to eliminate denominators
|
|
157
|
-
if(a.group === CB) {
|
|
158
|
-
var t = new Symbol(a.multiplier),
|
|
159
|
-
newRHS = b.clone();
|
|
160
|
-
a.each(function (y) {
|
|
161
|
-
if(y.power.lessThan(0))
|
|
162
|
-
newRHS = _.divide(newRHS, y);
|
|
163
|
-
else
|
|
164
|
-
t = _.multiply(t, y);
|
|
165
|
-
});
|
|
166
|
-
a = t;
|
|
167
|
-
b = newRHS;
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
else if(a.group === CP) {
|
|
171
|
-
//the logic: loop through each and if it has a denominator then multiply it out on both ends
|
|
172
|
-
//and then start over
|
|
173
|
-
for(var x in a.symbols) {
|
|
174
|
-
var sym = a.symbols[x];
|
|
175
|
-
if(sym.group === CB) {
|
|
176
|
-
for(var y in sym.symbols) {
|
|
177
|
-
var sym2 = sym.symbols[y];
|
|
178
|
-
if(sym2.power.lessThan(0)) {
|
|
179
|
-
return new Equation(
|
|
180
|
-
_.expand(_.multiply(sym2.clone().toLinear(), a)),
|
|
181
|
-
_.expand(_.multiply(sym2.clone().toLinear(), b))
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return new Equation(a, b);
|
|
190
|
-
},
|
|
191
|
-
clone: function () {
|
|
192
|
-
return new Equation(this.LHS.clone(), this.RHS.clone());
|
|
193
|
-
},
|
|
194
|
-
sub: function (x, y) {
|
|
195
|
-
var clone = this.clone();
|
|
196
|
-
clone.LHS = clone.LHS.sub(x.clone(), y.clone());
|
|
197
|
-
clone.RHS = clone.RHS.sub(x.clone(), y.clone());
|
|
198
|
-
return clone;
|
|
199
|
-
},
|
|
200
|
-
isZero: function () {
|
|
201
|
-
return core.Utils.evaluate(this.toLHS()).equals(0);
|
|
202
|
-
},
|
|
203
|
-
latex: function (option) {
|
|
204
|
-
return [this.LHS.latex(option), this.RHS.latex(option)].join('=');
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
//overwrite the equals function
|
|
208
|
-
_.equals = function (a, b) {
|
|
209
|
-
return new Equation(a, b);
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
// Extend simplify
|
|
213
|
-
(function () {
|
|
214
|
-
var simplify = _.functions.simplify[0];
|
|
215
|
-
_.functions.simplify[0] = function (symbol) {
|
|
216
|
-
if(symbol instanceof Equation) {
|
|
217
|
-
symbol.LHS = simplify(symbol.LHS);
|
|
218
|
-
symbol.RHS = simplify(symbol.RHS);
|
|
219
|
-
return symbol;
|
|
220
|
-
}
|
|
221
|
-
// Just call the original simplify
|
|
222
|
-
return simplify(symbol);
|
|
223
|
-
};
|
|
224
|
-
})();
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Sets two expressions equal
|
|
228
|
-
* @param {Symbol} symbol
|
|
229
|
-
* @returns {Expression}
|
|
230
|
-
*/
|
|
231
|
-
core.Expression.prototype.equals = function (symbol) {
|
|
232
|
-
if(symbol instanceof core.Expression)
|
|
233
|
-
symbol = symbol.symbol; //grab the symbol if it's an expression
|
|
234
|
-
var eq = new Equation(this.symbol, symbol);
|
|
235
|
-
return eq;
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
core.Expression.prototype.solveFor = function (x) {
|
|
239
|
-
var symbol;
|
|
240
|
-
if(this.symbol instanceof Equation) {
|
|
241
|
-
//exit right away if we already have the answer
|
|
242
|
-
//check the LHS
|
|
243
|
-
if(this.symbol.LHS.isConstant() && this.symbol.RHS.equals(x))
|
|
244
|
-
return new core.Expression(this.symbol.LHS);
|
|
245
|
-
|
|
246
|
-
//check the RHS
|
|
247
|
-
if(this.symbol.RHS.isConstant() && this.symbol.LHS.equals(x))
|
|
248
|
-
return new core.Expression(this.symbol.RHS);
|
|
249
|
-
|
|
250
|
-
//otherwise just bring it to LHS
|
|
251
|
-
symbol = this.symbol.toLHS();
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
symbol = this.symbol;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return solve(symbol, x).map(function (x) {
|
|
258
|
-
return new core.Expression(x);
|
|
259
|
-
});
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
core.Expression.prototype.expand = function () {
|
|
263
|
-
if(this.symbol instanceof Equation) {
|
|
264
|
-
var clone = this.symbol.clone();
|
|
265
|
-
clone.RHS = _.expand(clone.RHS);
|
|
266
|
-
clone.LHS = _.expand(clone.LHS);
|
|
267
|
-
return new core.Expression(clone);
|
|
268
|
-
}
|
|
269
|
-
return new core.Expression(_.expand(this.symbol));
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
core.Expression.prototype.variables = function () {
|
|
273
|
-
if(this.symbol instanceof Equation)
|
|
274
|
-
return core.Utils.arrayUnique(variables(this.symbol.LHS).concat(variables(this.symbol.RHS)));
|
|
275
|
-
return variables(this.symbol);
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
var setEq = function (a, b) {
|
|
281
|
-
return _.equals(a, b);
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
//link the Equation class back to the core
|
|
285
|
-
core.Equation = Equation;
|
|
286
|
-
|
|
287
|
-
//Loops through an array and attempts to fails a test. Stops if manages to fail.
|
|
288
|
-
var checkAll = core.Utils.checkAll = function (args, test) {
|
|
289
|
-
for(var i = 0; i < args.length; i++)
|
|
290
|
-
if(test(args[i]))
|
|
291
|
-
return false;
|
|
292
|
-
return true;
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
//version solve
|
|
296
|
-
var __ = core.Solve = {
|
|
297
|
-
version: '2.0.3',
|
|
298
|
-
solutions: [],
|
|
299
|
-
solve: function (eq, variable) {
|
|
300
|
-
var solution = solve(eq, String(variable));
|
|
301
|
-
return new core.Vector(solution);
|
|
302
|
-
//return new core.Vector(solve(eq.toString(), variable ? variable.toString() : variable));
|
|
303
|
-
},
|
|
304
|
-
/**
|
|
305
|
-
* Brings the equation to LHS. A string can be supplied which will be converted to an Equation
|
|
306
|
-
* @param {Equation|String} eqn
|
|
307
|
-
* @returns {Symbol}
|
|
308
|
-
*/
|
|
309
|
-
toLHS: function (eqn, expand) {
|
|
310
|
-
if(isSymbol(eqn))
|
|
311
|
-
return eqn;
|
|
312
|
-
//If it's an equation then call its toLHS function instead
|
|
313
|
-
if(!(eqn instanceof Equation)) {
|
|
314
|
-
var es = eqn.split('=');
|
|
315
|
-
//convert falsey values to zero
|
|
316
|
-
es[1] = es[1] || '0';
|
|
317
|
-
eqn = new Equation(_.parse(es[0]), _.parse(es[1]));
|
|
318
|
-
}
|
|
319
|
-
return eqn.toLHS(expand);
|
|
320
|
-
},
|
|
321
|
-
// getSystemVariables: function(eqns) {
|
|
322
|
-
// vars = variables(eqns[0], null, null, true);
|
|
323
|
-
//
|
|
324
|
-
// //get all variables
|
|
325
|
-
// for (var i = 1, l=eqns.length; i < l; i++)
|
|
326
|
-
// vars = vars.concat(variables(eqns[i]));
|
|
327
|
-
// //remove duplicates
|
|
328
|
-
// vars = core.Utils.arrayUnique(vars).sort();
|
|
329
|
-
//
|
|
330
|
-
// //done
|
|
331
|
-
// return vars;
|
|
332
|
-
// },
|
|
333
|
-
/**
|
|
334
|
-
* Solve a set of circle equations.
|
|
335
|
-
* @param {Symbol[]} eqns
|
|
336
|
-
* @returns {Array}
|
|
337
|
-
*/
|
|
338
|
-
solveCircle: function (eqns, vars) {
|
|
339
|
-
// Convert the variables to symbols
|
|
340
|
-
var svars = vars.map(function (x) {
|
|
341
|
-
return _.parse(x)
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
var deg = [];
|
|
345
|
-
|
|
346
|
-
var solutions = [];
|
|
347
|
-
|
|
348
|
-
// Get the degree for the equations
|
|
349
|
-
for(var i = 0; i < eqns.length; i++) {
|
|
350
|
-
var d = [];
|
|
351
|
-
for(var j = 0; j < svars.length; j++) {
|
|
352
|
-
d.push(Number(core.Algebra.degree(eqns[i], svars[j])));
|
|
353
|
-
}
|
|
354
|
-
// Store the total degree
|
|
355
|
-
d.push(core.Utils.arraySum(d, true));
|
|
356
|
-
deg.push(d);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
var a = eqns[0];
|
|
360
|
-
var b = eqns[1];
|
|
361
|
-
|
|
362
|
-
if(deg[0][2] > deg[1][2]) {
|
|
363
|
-
[b, a] = [a, b];
|
|
364
|
-
[deg[1], deg[0]] = [deg[0], deg[1]];
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Only solve it's truly a circle
|
|
368
|
-
if(deg[0][0] === 1 && deg[0][2] === 2 && deg[1][0] === 2 && deg[1][2] === 4) {
|
|
369
|
-
// For clarity we'll refer to the variables as x and y
|
|
370
|
-
var x = vars[0];
|
|
371
|
-
var y = vars[1];
|
|
372
|
-
|
|
373
|
-
// We can now get the two points for y
|
|
374
|
-
var y_points = solve(_.parse(b, knownVariable(x, solve(_.parse(a), x)[0])), y).map(function (x) {
|
|
375
|
-
return x.toString();
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
// Since we now know y we can get the two x points from the first equation
|
|
379
|
-
var x_points = [
|
|
380
|
-
solve(_.parse(a, knownVariable(y, y_points[0])))[0].toString()
|
|
381
|
-
];
|
|
382
|
-
|
|
383
|
-
if(y_points[1]) {
|
|
384
|
-
x_points.push(solve(_.parse(a, knownVariable(y, y_points[1])))[0].toString());
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if(Settings.SOLUTIONS_AS_OBJECT) {
|
|
388
|
-
var solutions = {};
|
|
389
|
-
solutions[x] = x_points;
|
|
390
|
-
solutions[y] = y_points;
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
y_points.unshift(y);
|
|
394
|
-
x_points.unshift(x);
|
|
395
|
-
solutions = [x_points, y_points];
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return solutions;
|
|
400
|
-
},
|
|
401
|
-
/**
|
|
402
|
-
* Solve a system of nonlinear equations
|
|
403
|
-
* @param {Symbol[]} eqns The array of equations
|
|
404
|
-
* @param {number} tries The maximum number of tries
|
|
405
|
-
* @param {number} start The starting point where to start looking for solutions
|
|
406
|
-
* @returns {Array}
|
|
407
|
-
*/
|
|
408
|
-
solveNonLinearSystem: function (eqns, tries, start) {
|
|
409
|
-
if(tries < 0) {
|
|
410
|
-
return [];//can't find a solution
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
start = typeof start === 'undefined' ? core.Settings.NON_LINEAR_START : start;
|
|
414
|
-
|
|
415
|
-
//the maximum number of times to jump
|
|
416
|
-
var max_tries = core.Settings.MAX_NON_LINEAR_TRIES;
|
|
417
|
-
|
|
418
|
-
//halfway through the tries
|
|
419
|
-
var halfway = Math.floor(max_tries / 2);
|
|
420
|
-
|
|
421
|
-
//initialize the number of tries to 10 if not specified
|
|
422
|
-
tries = typeof tries === 'undefined' ? max_tries : tries;
|
|
423
|
-
|
|
424
|
-
//a point at which we check to see if we're converging. By inspection it seems that we can
|
|
425
|
-
//use around 20 iterations to see if we're converging. If not then we retry a jump of x
|
|
426
|
-
var jump_at = core.Settings.NON_LINEAR_JUMP_AT;
|
|
427
|
-
|
|
428
|
-
//we jump by this many points at each pivot point
|
|
429
|
-
var jump = core.Settings.NON_LINEAR_JUMP_SIZE;
|
|
430
|
-
|
|
431
|
-
//used to check if we actually found a solution or if we gave up. Assume we will find a solution.
|
|
432
|
-
var found = true;
|
|
433
|
-
|
|
434
|
-
var create_subs = function (vars, matrix) {
|
|
435
|
-
return vars.map(function (x, i) {
|
|
436
|
-
return Number(matrix.get(i, 0));
|
|
437
|
-
});
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
var vars = core.Utils.arrayGetVariables(eqns);
|
|
441
|
-
var jacobian = core.Matrix.jacobian(eqns, vars, function (x) {
|
|
442
|
-
return build(x, vars);
|
|
443
|
-
}, true);
|
|
444
|
-
|
|
445
|
-
var max_iter = core.Settings.MAX_NEWTON_ITERATIONS;
|
|
446
|
-
var o, y, iters, xn1, norm, lnorm, xn, d;
|
|
447
|
-
|
|
448
|
-
var f_eqns = eqns.map(function (eq) {
|
|
449
|
-
return build(eq, vars);
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
var J = jacobian.map(function (e) {
|
|
453
|
-
return build(e, vars);
|
|
454
|
-
}, true);
|
|
455
|
-
//initial values
|
|
456
|
-
xn1 = core.Matrix.cMatrix(0, vars);
|
|
457
|
-
|
|
458
|
-
//initialize the c matrix with something close to 0.
|
|
459
|
-
var c = core.Matrix.cMatrix(start, vars);
|
|
460
|
-
|
|
461
|
-
iters = 0;
|
|
462
|
-
|
|
463
|
-
//start of algorithm
|
|
464
|
-
do {
|
|
465
|
-
//if we've reached the max iterations then exit
|
|
466
|
-
if(iters > max_iter) {
|
|
467
|
-
break;
|
|
468
|
-
found = false;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
//set the substitution object
|
|
472
|
-
o = create_subs(vars, c);
|
|
473
|
-
|
|
474
|
-
//set xn
|
|
475
|
-
xn = c.clone();
|
|
476
|
-
|
|
477
|
-
//make all the substitutions for each of the equations
|
|
478
|
-
f_eqns.forEach(function (f, i) {
|
|
479
|
-
c.set(i, 0, f.apply(null, o));
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
var m = new core.Matrix();
|
|
483
|
-
J.each(function (fn, i, j) {
|
|
484
|
-
var ans = fn.apply(null, o);
|
|
485
|
-
m.set(i, j, ans);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
m = m.invert();
|
|
489
|
-
|
|
490
|
-
//preform the elimination
|
|
491
|
-
y = _.multiply(m, c).negate();
|
|
492
|
-
|
|
493
|
-
//the callback is to avoid overflow in the coeffient denonimator
|
|
494
|
-
//it converts it to a decimal and then back to a fraction. Some precision
|
|
495
|
-
//is lost be it's better than overflow.
|
|
496
|
-
d = y.subtract(xn1, function (x) {
|
|
497
|
-
return _.parse(Number(x));
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
xn1 = xn.add(y, function (x) {
|
|
501
|
-
return _.parse(Number(x));
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
//move c is now xn1
|
|
505
|
-
c = xn1;
|
|
506
|
-
|
|
507
|
-
//get the norm
|
|
508
|
-
|
|
509
|
-
//the expectation is that we're converging to some answer as this point regardless of where we start
|
|
510
|
-
//this may have to be adjusted at some point because of erroneous assumptions
|
|
511
|
-
if(iters >= jump_at) {
|
|
512
|
-
//check the norm. If the norm is greater than one then it's time to try another point
|
|
513
|
-
if(norm > 1) {
|
|
514
|
-
//reset the start point at halway
|
|
515
|
-
if(tries === halfway)
|
|
516
|
-
start = 0;
|
|
517
|
-
var sign = tries > halfway ? 1 : -1; //which side are we incrementing
|
|
518
|
-
//we increment +n at one side and -n at the other.
|
|
519
|
-
n = (tries % Math.floor(halfway)) + 1;
|
|
520
|
-
//adjust the start point
|
|
521
|
-
start += (sign * n * jump);
|
|
522
|
-
//call restart
|
|
523
|
-
return __.solveNonLinearSystem(eqns, --tries, start);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
lnorm = norm;
|
|
527
|
-
iters++;
|
|
528
|
-
norm = d.max();
|
|
529
|
-
|
|
530
|
-
//exit early. Revisit if we get bugs
|
|
531
|
-
if(Number(norm) === Number(lnorm)) {
|
|
532
|
-
break;
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
while(Number(norm) >= Number.EPSILON)
|
|
536
|
-
|
|
537
|
-
//return a blank set if nothing was found;
|
|
538
|
-
if(!found)
|
|
539
|
-
return [];
|
|
540
|
-
|
|
541
|
-
//return c since that's the answer
|
|
542
|
-
return __.systemSolutions(c, vars, true, function (x) {
|
|
543
|
-
return core.Utils.round(Number(x), 14);
|
|
544
|
-
});
|
|
545
|
-
},
|
|
546
|
-
systemSolutions: function (result, vars, expand_result, callback) {
|
|
547
|
-
var solutions = core.Settings.SOLUTIONS_AS_OBJECT ? {} : [];
|
|
548
|
-
|
|
549
|
-
result.each(function (e, idx) {
|
|
550
|
-
var solution = (expand_result ? _.expand(e) : e).valueOf();
|
|
551
|
-
if(callback)
|
|
552
|
-
solution = callback.call(e, solution);
|
|
553
|
-
var variable = vars[idx];
|
|
554
|
-
if(core.Settings.SOLUTIONS_AS_OBJECT) {
|
|
555
|
-
solutions[variable] = solution;
|
|
556
|
-
}
|
|
557
|
-
else
|
|
558
|
-
solutions.push([variable, solution]); /*NO*/
|
|
559
|
-
});
|
|
560
|
-
//done
|
|
561
|
-
return solutions;
|
|
562
|
-
},
|
|
563
|
-
/**
|
|
564
|
-
* Solves a system of equations by substitution. This is useful when
|
|
565
|
-
* no distinct solution exists. e.g. a line, plane, etc.
|
|
566
|
-
* @param {Array} eqns
|
|
567
|
-
* @returns {Array}
|
|
568
|
-
*/
|
|
569
|
-
solveSystemBySubstitution: function (eqns) {
|
|
570
|
-
// Assume at least 2 equations. The function variables will just return an empty array if undefined is provided
|
|
571
|
-
var vars_a = variables(eqns[0]);
|
|
572
|
-
var vars_b = variables(eqns[1]);
|
|
573
|
-
// Check if it's a circle equation
|
|
574
|
-
if(eqns.length === 2 && vars_a.length === 2 && core.Utils.arrayEqual(vars_a, vars_b)) {
|
|
575
|
-
return __.solveCircle(eqns, vars_a);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
return []; // return an empty set
|
|
579
|
-
},
|
|
580
|
-
|
|
581
|
-
//https://www.lakeheadu.ca/sites/default/files/uploads/77/docs/RemaniFinal.pdf
|
|
582
|
-
/**
|
|
583
|
-
* Solves a systems of equations
|
|
584
|
-
* @param {Array} eqns An array of equations
|
|
585
|
-
* @param {Array} var_array An array of variables
|
|
586
|
-
* @returns {Array|object}
|
|
587
|
-
*/
|
|
588
|
-
solveSystem: function (eqns, var_array) {
|
|
589
|
-
//check if a var_array was specified
|
|
590
|
-
//nerdamer.clearVars();// this deleted ALL variables: not what we want
|
|
591
|
-
//parse all the equations to LHS. Remember that they come in as strings
|
|
592
|
-
for(var i = 0; i < eqns.length; i++)
|
|
593
|
-
eqns[i] = __.toLHS(eqns[i]);
|
|
594
|
-
|
|
595
|
-
var l = eqns.length,
|
|
596
|
-
m = new core.Matrix(),
|
|
597
|
-
c = new core.Matrix(),
|
|
598
|
-
expand_result = false,
|
|
599
|
-
vars;
|
|
600
|
-
|
|
601
|
-
if(typeof var_array === 'undefined') {
|
|
602
|
-
//check to make sure that all the equations are linear
|
|
603
|
-
if(!_A.allLinear(eqns)) {
|
|
604
|
-
try {
|
|
605
|
-
return __.solveNonLinearSystem(eqns);
|
|
606
|
-
}
|
|
607
|
-
catch(e) {
|
|
608
|
-
if(e instanceof core.exceptions.DivisionByZero) {
|
|
609
|
-
return __.solveSystemBySubstitution(eqns);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
vars = core.Utils.arrayGetVariables(eqns);
|
|
615
|
-
|
|
616
|
-
// If the system only has one variable then we solve for the first one and
|
|
617
|
-
// then test the remaining equations with that solution. If any of the remaining
|
|
618
|
-
// equation fails then the system has no solution
|
|
619
|
-
if(vars.length === 1) {
|
|
620
|
-
var n = 0,
|
|
621
|
-
sol, e;
|
|
622
|
-
do {
|
|
623
|
-
var e = eqns[n].clone();
|
|
624
|
-
|
|
625
|
-
if(n > 0) {
|
|
626
|
-
e = e.sub(vars[0], sol[0]);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
sol = solve(e, vars[0]);
|
|
630
|
-
// Skip the first one
|
|
631
|
-
if(n === 0)
|
|
632
|
-
continue;
|
|
633
|
-
}
|
|
634
|
-
while(++n < eqns.length)
|
|
635
|
-
|
|
636
|
-
// Format the output
|
|
637
|
-
var solutions;
|
|
638
|
-
if(Settings.SOLUTIONS_AS_OBJECT) {
|
|
639
|
-
solutions = {};
|
|
640
|
-
solutions[vars[0]] = sol;
|
|
641
|
-
}
|
|
642
|
-
else if(sol.length === 0) {
|
|
643
|
-
solutions = sol; // No solutions
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
solutions = [vars[0], sol];
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
return solutions;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// Deal with redundant equations as expressed in #562
|
|
653
|
-
// The fix is to remove all but the number of equations equal to the number
|
|
654
|
-
// of variables. We then solve those and then evaluate the remaining equations
|
|
655
|
-
// with those solutions. If the all equal true then those are just redundant
|
|
656
|
-
// equations and we can return the solution set.
|
|
657
|
-
if(vars.length < eqns.length) {
|
|
658
|
-
var reduced = [];
|
|
659
|
-
var n = eqns.length;
|
|
660
|
-
for(var i = 0; i < n - 1; i++) {
|
|
661
|
-
reduced.push(_.parse(eqns[i]));
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
var knowns = {};
|
|
665
|
-
var solutions = __.solveSystem(reduced, vars);
|
|
666
|
-
// The solutions may have come back as an array
|
|
667
|
-
if(Array.isArray(solutions)) {
|
|
668
|
-
solutions.forEach(function (sol) {
|
|
669
|
-
knowns[sol[0]] = sol[1];
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
else {
|
|
673
|
-
knowns = solutions;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
// Start by assuming they will all evaluate to zero. If even one fails
|
|
677
|
-
// then all zero will be false
|
|
678
|
-
var all_zero = true;
|
|
679
|
-
// Check if the last solution evalutes to zero given these solutions
|
|
680
|
-
for(var i = n - 1; i < n; i++) {
|
|
681
|
-
if(!_.parse(eqns[i], knowns).equals(0)) {
|
|
682
|
-
all_zero = false;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
if(all_zero) {
|
|
687
|
-
return solutions;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// deletes only the variables of the linear equations in the nerdamer namespace
|
|
692
|
-
for(var i = 0; i < vars.length; i++) {
|
|
693
|
-
nerdamer.setVar(vars[i], "delete");
|
|
694
|
-
}
|
|
695
|
-
// TODO: move this to cMatrix or something similar
|
|
696
|
-
// populate the matrix
|
|
697
|
-
for(var i = 0; i < l; i++) {
|
|
698
|
-
var e = eqns[i]; //store the expression
|
|
699
|
-
// Iterate over the columns
|
|
700
|
-
for(var j = 0; j < vars.length; j++) {
|
|
701
|
-
var v = vars[j];
|
|
702
|
-
var coeffs = [];
|
|
703
|
-
e.each(function (x) {
|
|
704
|
-
if(x.contains(v)) {
|
|
705
|
-
coeffs = coeffs.concat(x.coeffs());
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
|
|
709
|
-
var cf = core.Utils.arraySum(coeffs);
|
|
710
|
-
m.set(i, j, cf);
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
//strip the variables from the symbol so we're left with only the zeroth coefficient
|
|
714
|
-
//start with the symbol and remove each variable and its coefficient
|
|
715
|
-
var num = e.clone();
|
|
716
|
-
vars.map(function (e) {
|
|
717
|
-
num = num.stripVar(e, true);
|
|
718
|
-
});
|
|
719
|
-
c.set(i, 0, num.negate());
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
else {
|
|
723
|
-
/**
|
|
724
|
-
* The idea is that we loop through each equation and then expand it. Afterwards we loop
|
|
725
|
-
* through each term and see if and check to see if it matches one of the variables.
|
|
726
|
-
* When a match is found we mark it. No other match should be found for that term. If it
|
|
727
|
-
* is we stop since it's not linear.
|
|
728
|
-
*/
|
|
729
|
-
vars = var_array;
|
|
730
|
-
expand_result = true;
|
|
731
|
-
for(i = 0; i < l; i++) {
|
|
732
|
-
//prefill
|
|
733
|
-
c.set(i, 0, new Symbol(0));
|
|
734
|
-
var e = _.expand(eqns[i]).collectSymbols(); //expand and store
|
|
735
|
-
//go trough each of the variables
|
|
736
|
-
for(var j = 0; j < var_array.length; j++) {
|
|
737
|
-
m.set(i, j, new Symbol(0));
|
|
738
|
-
var v = var_array[j];
|
|
739
|
-
//go through the terms and sort the variables
|
|
740
|
-
for(var k = 0; k < e.length; k++) {
|
|
741
|
-
var term = e[k],
|
|
742
|
-
check = false;
|
|
743
|
-
for(var z = 0; z < var_array.length; z++) {
|
|
744
|
-
//check to see if terms contain multiple variables
|
|
745
|
-
if(term.contains(var_array[z])) {
|
|
746
|
-
if(check)
|
|
747
|
-
core.err('Multiple variables found for term ' + term);
|
|
748
|
-
check = true;
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
//we made sure that every term contains one variable so it's safe to assume that if the
|
|
752
|
-
//variable is found then the remainder is the coefficient.
|
|
753
|
-
if(term.contains(v)) {
|
|
754
|
-
var tparts = explode(remove(e, k), v);
|
|
755
|
-
m.set(i, j, _.add(m.get(i, j), tparts[0]));
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
//all the remaining terms go to the c matrix
|
|
760
|
-
for(k = 0; k < e.length; k++) {
|
|
761
|
-
c.set(i, 0, _.add(c.get(i, 0), e[k]));
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
//consider case (a+b)*I+u
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
//check if the system has a distinct solution
|
|
768
|
-
if(vars.length !== eqns.length || m.determinant().equals(0)) {
|
|
769
|
-
// solve the system by hand
|
|
770
|
-
//return __.solveSystemBySubstitution(eqns, vars, m, c);
|
|
771
|
-
throw new core.exceptions.SolveError('System does not have a distinct solution');
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// Use M^-1*c to solve system
|
|
775
|
-
m = m.invert();
|
|
776
|
-
var result = m.multiply(c);
|
|
777
|
-
//correct the sign as per issue #410
|
|
778
|
-
if(core.Utils.isArray(var_array))
|
|
779
|
-
result.each(function (x) {
|
|
780
|
-
return x.negate();
|
|
781
|
-
});
|
|
782
|
-
|
|
783
|
-
return __.systemSolutions(result, vars, expand_result);
|
|
784
|
-
},
|
|
785
|
-
/**
|
|
786
|
-
* The quadratic function but only one side.
|
|
787
|
-
* @param {Symbol} c
|
|
788
|
-
* @param {Symbol} b
|
|
789
|
-
* @param {Symbol} a
|
|
790
|
-
* @returns {Symbol}
|
|
791
|
-
*/
|
|
792
|
-
quad: function (c, b, a) {
|
|
793
|
-
var discriminant = _.subtract(_.pow(b.clone(), Symbol(2)), _.multiply(_.multiply(a.clone(), c.clone()), Symbol(4)))/*b^2 - 4ac*/;
|
|
794
|
-
// Fix for #608
|
|
795
|
-
discriminant = _.expand(discriminant);
|
|
796
|
-
var det = _.pow(discriminant, Symbol(0.5));
|
|
797
|
-
var den = _.parse(_.multiply(new Symbol(2), a.clone()));
|
|
798
|
-
var retval = [
|
|
799
|
-
_.parse(format('(-({0})+({1}))/({2})', b, det, den)),
|
|
800
|
-
_.parse(format('(-({0})-({1}))/({2})', b, det, den))
|
|
801
|
-
];
|
|
802
|
-
|
|
803
|
-
return retval;
|
|
804
|
-
},
|
|
805
|
-
/**
|
|
806
|
-
* The cubic equation
|
|
807
|
-
* http://math.stackexchange.com/questions/61725/is-there-a-systematic-way-of-solving-cubic-equations
|
|
808
|
-
* @param {Symbol} d_o
|
|
809
|
-
* @param {Symbol} c_o
|
|
810
|
-
* @param {Symbol} b_o
|
|
811
|
-
* @param {Symbol} a_o
|
|
812
|
-
* @returns {Array}
|
|
813
|
-
*/
|
|
814
|
-
cubic: function (d_o, c_o, b_o, a_o) {
|
|
815
|
-
//convert everything to text
|
|
816
|
-
var a = a_o.text(), b = b_o.text(), c = c_o.text(), d = d_o.text();
|
|
817
|
-
|
|
818
|
-
var t = `(-(${b})^3/(27*(${a})^3)+(${b})*(${c})/(6*(${a})^2)-(${d})/(2*(${a})))`;
|
|
819
|
-
var u = `((${c})/(3*(${a}))-(${b})^2/(9*(${a})^2))`;
|
|
820
|
-
var v = `(${b})/(3*(${a}))`;
|
|
821
|
-
var x = `((${t})+sqrt((${t})^2+(${u})^3))^(1/3)+((${t})-sqrt((${t})^2+(${u})^3))^(1/3)-(${v})`;
|
|
822
|
-
|
|
823
|
-
// Convert a to one
|
|
824
|
-
var w = '1/2+sqrt(3)/2*i'; // Cube root of unity
|
|
825
|
-
|
|
826
|
-
return [
|
|
827
|
-
_.parse(x),
|
|
828
|
-
_.parse(`(${x})(${w})`),
|
|
829
|
-
_.parse(`(${x})(${w})^2`)
|
|
830
|
-
];
|
|
831
|
-
},
|
|
832
|
-
/**
|
|
833
|
-
* The quartic equation
|
|
834
|
-
* @param {Symbol} e
|
|
835
|
-
* @param {Symbol} d
|
|
836
|
-
* @param {Symbol} c
|
|
837
|
-
* @param {Symbol} b
|
|
838
|
-
* @param {Symbol} a
|
|
839
|
-
* @returns {Array}
|
|
840
|
-
*/
|
|
841
|
-
quartic: function (e, d, c, b, a) {
|
|
842
|
-
var scope = {};
|
|
843
|
-
core.Utils.arrayUnique(variables(a).concat(variables(b))
|
|
844
|
-
.concat(variables(c)).concat(variables(d)).concat(variables(e)))
|
|
845
|
-
.map(function (x) {
|
|
846
|
-
scope[x] = 1;
|
|
847
|
-
});
|
|
848
|
-
a = a.toString();
|
|
849
|
-
b = b.toString();
|
|
850
|
-
c = c.toString();
|
|
851
|
-
d = d.toString();
|
|
852
|
-
e = e.toString();
|
|
853
|
-
var p, q, D, D0, D1, Q, x1, x2, x3, x4;
|
|
854
|
-
/*var D = core.Utils.block('PARSE2NUMBER', function() {
|
|
855
|
-
return _.parse(format("256*({0})^3*({4})^3-192*({0})^2*({1})*({3})*({4})^2-128*({0})^2*({2})^2*({4})^2+144*({0})^2*({2})*({3})^2*({4})"+
|
|
856
|
-
"-27*({0})^2*({3})^4+144*({0})*({1})^2*({2})*({4})^2-6*({0})*({1})^2*({3})^2*({4})-80*({0})*({1})*({2})^2*({3})*({4})+18*({0})*({1})*({2})*({3})^3"+
|
|
857
|
-
"+16*({0})*({2})^4*({4})-4*({0})*({2})^3*({3})^2-27*({1})^4*({4})^2+18*({1})^3*({2})*({3})*({4})-4*({1})^3*({3})^3-4*({1})^2*({2})^3*({4})+({1})^2*({2})^2*({3})^2",
|
|
858
|
-
a, b, c, d, e), scope);
|
|
859
|
-
});*/
|
|
860
|
-
|
|
861
|
-
p = _.parse(format("(8*({0})*({2})-3*({1})^2)/(8*({0})^2)", a, b, c)).toString(); //a, b, c
|
|
862
|
-
q = _.parse(format("(({1})^3-4*({0})*({1})*({2})+8*({0})^2*({3}))/(8*({0})^3)", a, b, c, d)).toString();//a, b, c, d, e
|
|
863
|
-
D0 = _.parse(format("12*({0})*({4})-3*({1})*({3})+({2})^2", a, b, c, d, e)).toString(); //a, b, c, d, e
|
|
864
|
-
D1 = _.parse(format("2*({2})^3-9*({1})*({2})*({3})+27*({1})^2*({4})+27*({0})*({3})^2-72*({0})*({2})*({4})", a, b, c, d, e)).toString(); //a, b, c, d, e
|
|
865
|
-
Q = _.parse(format("((({1})+(({1})^2-4*({0})^3)^(1/2))/2)^(1/3)", D0, D1)).toString(); //D0, D1
|
|
866
|
-
S = _.parse(format("(1/2)*(-(2/3)*({1})+(1/(3*({0}))*(({2})+(({3})/({2})))))^(1/2)", a, p, Q, D0)).toString(); //a, p, Q, D0
|
|
867
|
-
x1 = _.parse(format("-(({1})/(4*({0})))-({4})+(1/2)*sqrt(-4*({4})^2-2*({2})+(({3})/({4})))", a, b, p, q, S)); //a, b, p, q, S
|
|
868
|
-
x2 = _.parse(format("-(({1})/(4*({0})))-({4})-(1/2)*sqrt(-4*({4})^2-2*({2})+(({3})/({4})))", a, b, p, q, S)); //a, b, p, q, S
|
|
869
|
-
x3 = _.parse(format("-(({1})/(4*({0})))+({4})+(1/2)*sqrt(-4*({4})^2-2*({2})-(({3})/({4})))", a, b, p, q, S)); //a, b, p, q, S
|
|
870
|
-
x4 = _.parse(format("-(({1})/(4*({0})))+({4})-(1/2)*sqrt(-4*({4})^2-2*({2})-(({3})/({4})))", a, b, p, q, S)); //a, b, p, q, S
|
|
871
|
-
return [x1, x2, x3, x4];
|
|
872
|
-
},
|
|
873
|
-
/**
|
|
874
|
-
* Breaks the equation up in its factors and tries to solve the smaller parts
|
|
875
|
-
* @param {Symbol} symbol
|
|
876
|
-
* @param {String} solve_for
|
|
877
|
-
* @returns {Array}
|
|
878
|
-
*/
|
|
879
|
-
divideAndConquer: function (symbol, solve_for) {
|
|
880
|
-
var sols = [];
|
|
881
|
-
//see if we can solve the factors
|
|
882
|
-
var factors = core.Algebra.Factor.factor(symbol);
|
|
883
|
-
if(factors.group === CB) {
|
|
884
|
-
factors.each(function (x) {
|
|
885
|
-
x = Symbol.unwrapPARENS(x);
|
|
886
|
-
sols = sols.concat(solve(x, solve_for));
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
return sols;
|
|
890
|
-
},
|
|
891
|
-
/**
|
|
892
|
-
* Attempts to solve the equation assuming it's a polynomial with numeric coefficients
|
|
893
|
-
* @param {Symbol} eq
|
|
894
|
-
* @param {String} solve_for
|
|
895
|
-
* @returns {Array}
|
|
896
|
-
*/
|
|
897
|
-
csolve: function (eq, solve_for) {
|
|
898
|
-
return core.Utils.block('IGNORE_E', function () {
|
|
899
|
-
var f, p, pn, n, pf, r, theta, sr, sp, roots;
|
|
900
|
-
roots = [];
|
|
901
|
-
f = core.Utils.decompose_fn(eq, solve_for, true);
|
|
902
|
-
if(f.x.group === S) {
|
|
903
|
-
p = _.parse(f.x.power);
|
|
904
|
-
pn = Number(p);
|
|
905
|
-
n = _.pow(_.divide(f.b.negate(), f.a), p.invert());
|
|
906
|
-
pf = Symbol.toPolarFormArray(n);
|
|
907
|
-
r = pf[0];
|
|
908
|
-
theta = pf[1];
|
|
909
|
-
sr = r.toString();
|
|
910
|
-
sp = p.toString();
|
|
911
|
-
var k, root, str;
|
|
912
|
-
for(var i = 0; i < pn; i++) {
|
|
913
|
-
k = i;
|
|
914
|
-
str = format('({0})*e^(2*{1}*pi*{2}*{3})', sr, k, p, core.Settings.IMAGINARY);
|
|
915
|
-
root = _.parse(str);
|
|
916
|
-
roots.push(root);
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
return roots;
|
|
920
|
-
}, true);
|
|
921
|
-
},
|
|
922
|
-
/**
|
|
923
|
-
* Generates starting points for the Newton solver given an expression at zero.
|
|
924
|
-
* It beings by check if zero is a good point and starts expanding by a provided step size.
|
|
925
|
-
* Builds on the fact that if the sign changes over an interval then a zero
|
|
926
|
-
* must exist on that interval
|
|
927
|
-
* @param {Symbol} symbol
|
|
928
|
-
* @param {Number} step
|
|
929
|
-
* @param {Array} points
|
|
930
|
-
* @returns {Array}
|
|
931
|
-
*/
|
|
932
|
-
getPoints: function (symbol, step, points) {
|
|
933
|
-
step = step || 0.01;
|
|
934
|
-
points = points || [];
|
|
935
|
-
var f = build(symbol);
|
|
936
|
-
var x0 = 0;
|
|
937
|
-
|
|
938
|
-
var start = Math.round(x0),
|
|
939
|
-
last = f(start),
|
|
940
|
-
last_sign = last / Math.abs(last),
|
|
941
|
-
rside = core.Settings.ROOTS_PER_SIDE, // the max number of roots on right side
|
|
942
|
-
lside = rside; // the max number of roots on left side
|
|
943
|
-
// check around the starting point
|
|
944
|
-
points.push(Math.floor(start / 2)); //half way from zero might be a good start
|
|
945
|
-
points.push(Math.abs(start)); //|f(0)| could be a good start
|
|
946
|
-
points.push(start);//|f(0)| could be a good start
|
|
947
|
-
//adjust for log. A good starting point to include for log is 0.1
|
|
948
|
-
symbol.each(function (x) {
|
|
949
|
-
if(x.containsFunction(core.Settings.LOG))
|
|
950
|
-
points.push(0.1);
|
|
951
|
-
});
|
|
952
|
-
|
|
953
|
-
var left = range(-core.Settings.SOLVE_RADIUS, start, step),
|
|
954
|
-
right = range(start, core.Settings.SOLVE_RADIUS, step);
|
|
955
|
-
|
|
956
|
-
var test_side = function (side, num_roots) {
|
|
957
|
-
var xi, val, sign;
|
|
958
|
-
var hits = [];
|
|
959
|
-
for(var i = 0, l = side.length; i < l; i++) {
|
|
960
|
-
xi = side[i]; //the point being evaluated
|
|
961
|
-
val = f(xi);
|
|
962
|
-
sign = val / Math.abs(val);
|
|
963
|
-
//Don't add non-numeric values
|
|
964
|
-
if(isNaN(val) || !isFinite(val) || hits.length > num_roots) {
|
|
965
|
-
continue;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
//compare the signs. The have to be different if they cross a zero
|
|
969
|
-
if(sign !== last_sign) {
|
|
970
|
-
hits.push(xi); //take note of the possible zero location
|
|
971
|
-
}
|
|
972
|
-
last_sign = sign;
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
points = points.concat(hits);
|
|
976
|
-
};
|
|
977
|
-
|
|
978
|
-
test_side(left, lside);
|
|
979
|
-
test_side(right, rside);
|
|
980
|
-
|
|
981
|
-
return points;
|
|
982
|
-
},
|
|
983
|
-
/**
|
|
984
|
-
* Implements the bisection method. Returns undefined in no solution is found
|
|
985
|
-
* @param {number} point
|
|
986
|
-
* @param {function} f
|
|
987
|
-
* @returns {undefined | number}
|
|
988
|
-
*/
|
|
989
|
-
bisection: function (point, f) {
|
|
990
|
-
var left = point - 1;
|
|
991
|
-
var right = point + 1;
|
|
992
|
-
// First test if this point is even worth evaluating. It should
|
|
993
|
-
// be crossing the x axis so the signs should be different
|
|
994
|
-
if(Math.sign(f(left)) !== Math.sign(f(right))) {
|
|
995
|
-
var safety = 0;
|
|
996
|
-
|
|
997
|
-
var epsilon, middle;
|
|
998
|
-
|
|
999
|
-
do {
|
|
1000
|
-
epsilon = Math.abs(right - left);
|
|
1001
|
-
// Safety against an infinite loop
|
|
1002
|
-
if(safety++ > core.Settings.MAX_BISECTION_ITER || isNaN(epsilon)) {
|
|
1003
|
-
return;
|
|
1004
|
-
}
|
|
1005
|
-
// Calculate the middle point
|
|
1006
|
-
middle = (left + right) / 2;
|
|
1007
|
-
|
|
1008
|
-
if(f(left) * f(middle) > 0) {
|
|
1009
|
-
left = middle;
|
|
1010
|
-
}
|
|
1011
|
-
else {
|
|
1012
|
-
right = middle;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
while(epsilon >= Settings.EPSILON);
|
|
1016
|
-
|
|
1017
|
-
var solution = (left + right) / 2;
|
|
1018
|
-
|
|
1019
|
-
// Test the solution to make sure that it's within tolerance
|
|
1020
|
-
var x_point = f(solution);
|
|
1021
|
-
|
|
1022
|
-
if(!isNaN(x_point) && Math.abs(x_point) <= core.Settings.BI_SECTION_EPSILON) {
|
|
1023
|
-
// Returns too many junk solutions if not rounded at 13th place.
|
|
1024
|
-
return core.Utils.round(solution, 13);
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
},
|
|
1028
|
-
/**
|
|
1029
|
-
* Implements Newton's iterations. Returns undefined if no solutions if found
|
|
1030
|
-
* @param {number} point
|
|
1031
|
-
* @param {function} f
|
|
1032
|
-
* @param {function} fp
|
|
1033
|
-
* @returns {undefined|number}
|
|
1034
|
-
*/
|
|
1035
|
-
Newton: function (point, f, fp) {
|
|
1036
|
-
var maxiter = core.Settings.MAX_NEWTON_ITERATIONS,
|
|
1037
|
-
iter = 0;
|
|
1038
|
-
//first try the point itself. If it's zero viola. We're done
|
|
1039
|
-
var x0 = point, x;
|
|
1040
|
-
do {
|
|
1041
|
-
var fx0 = f(x0); //store the result of the function
|
|
1042
|
-
//if the value is zero then we're done because 0 - (0/d f(x0)) = 0
|
|
1043
|
-
if(x0 === 0 && fx0 === 0) {
|
|
1044
|
-
x = 0;
|
|
1045
|
-
break;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
iter++;
|
|
1049
|
-
if(iter > maxiter)
|
|
1050
|
-
return; //naximum iterations reached
|
|
1051
|
-
|
|
1052
|
-
x = x0 - fx0 / fp(x0);
|
|
1053
|
-
var e = Math.abs(x - x0);
|
|
1054
|
-
x0 = x;
|
|
1055
|
-
}
|
|
1056
|
-
while(e > Settings.NEWTON_EPSILON)
|
|
1057
|
-
|
|
1058
|
-
//check if the number is indeed zero. 1e-13 seems to give the most accurate results
|
|
1059
|
-
if(Math.abs(f(x)) <= Settings.EPSILON)
|
|
1060
|
-
return x;
|
|
1061
|
-
},
|
|
1062
|
-
rewrite: function (rhs, lhs, for_variable) {
|
|
1063
|
-
lhs = lhs || new Symbol(0);
|
|
1064
|
-
if(rhs.isComposite() && rhs.isLinear()) {
|
|
1065
|
-
//try to isolate the square root
|
|
1066
|
-
//container for the square roots
|
|
1067
|
-
var sqrts = [];
|
|
1068
|
-
//all else
|
|
1069
|
-
var rem = [];
|
|
1070
|
-
rhs.each(function (x) {
|
|
1071
|
-
x = x.clone();
|
|
1072
|
-
if(x.fname === 'sqrt' && x.contains(for_variable)) {
|
|
1073
|
-
sqrts.push(x);
|
|
1074
|
-
}
|
|
1075
|
-
else {
|
|
1076
|
-
rem.push(x);
|
|
1077
|
-
}
|
|
1078
|
-
}, true);
|
|
1079
|
-
|
|
1080
|
-
if(sqrts.length === 1) {
|
|
1081
|
-
//move the remainder to the RHS
|
|
1082
|
-
lhs = _.expand(_.pow(_.subtract(lhs, core.Utils.arraySum(rem)), new Symbol(2)));
|
|
1083
|
-
//square both sides
|
|
1084
|
-
rhs = _.expand(_.pow(Symbol.unwrapSQRT(sqrts[0]), new Symbol(2)));
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
else {
|
|
1088
|
-
rhs = Symbol.unwrapSQRT(_.expand(rhs)); //expand the term expression go get rid of quotients when possible
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
var c = 0, //a counter to see if we have all terms with the variable
|
|
1092
|
-
l = rhs.length;
|
|
1093
|
-
//try to rewrite the whole thing
|
|
1094
|
-
if(rhs.group === CP && rhs.contains(for_variable) && rhs.isLinear()) {
|
|
1095
|
-
rhs.distributeMultiplier();
|
|
1096
|
-
var t = new Symbol(0);
|
|
1097
|
-
//first bring all the terms containing the variable to the lhs
|
|
1098
|
-
rhs.each(function (x) {
|
|
1099
|
-
if(x.contains(for_variable)) {
|
|
1100
|
-
c++;
|
|
1101
|
-
t = _.add(t, x.clone());
|
|
1102
|
-
}
|
|
1103
|
-
else
|
|
1104
|
-
lhs = _.subtract(lhs, x.clone());
|
|
1105
|
-
});
|
|
1106
|
-
rhs = t;
|
|
1107
|
-
|
|
1108
|
-
//if not all the terms contain the variable so it's in the form
|
|
1109
|
-
//a*x^2+x
|
|
1110
|
-
if(c !== l) {
|
|
1111
|
-
return __.rewrite(rhs, lhs, for_variable);
|
|
1112
|
-
}
|
|
1113
|
-
else {
|
|
1114
|
-
return [rhs, lhs];
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
else if(rhs.group === CB && rhs.contains(for_variable) && rhs.isLinear()) {
|
|
1118
|
-
if(rhs.multiplier.lessThan(0)) {
|
|
1119
|
-
rhs.multiplier = rhs.multiplier.multiply(new core.Frac(-1));
|
|
1120
|
-
lhs.multiplier = lhs.multiplier.multiply(new core.Frac(-1));
|
|
1121
|
-
}
|
|
1122
|
-
if(lhs.equals(0))
|
|
1123
|
-
return new Symbol(0);
|
|
1124
|
-
else {
|
|
1125
|
-
var t = new Symbol(1);
|
|
1126
|
-
rhs.each(function (x) {
|
|
1127
|
-
if(x.contains(for_variable))
|
|
1128
|
-
t = _.multiply(t, x.clone());
|
|
1129
|
-
else
|
|
1130
|
-
lhs = _.divide(lhs, x.clone());
|
|
1131
|
-
});
|
|
1132
|
-
rhs = t;
|
|
1133
|
-
return __.rewrite(rhs, lhs, for_variable);
|
|
1134
|
-
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
else if(!rhs.isLinear() && rhs.contains(for_variable)) {
|
|
1138
|
-
var p = _.parse(rhs.power.clone().invert());
|
|
1139
|
-
rhs = _.pow(rhs, p.clone());
|
|
1140
|
-
lhs = _.pow(_.expand(lhs), p.clone());
|
|
1141
|
-
return __.rewrite(rhs, lhs, for_variable);
|
|
1142
|
-
}
|
|
1143
|
-
else if(rhs.group === FN || rhs.group === S || rhs.group === PL) {
|
|
1144
|
-
return [rhs, lhs];
|
|
1145
|
-
}
|
|
1146
|
-
},
|
|
1147
|
-
sqrtSolve: function (symbol, v) {
|
|
1148
|
-
var sqrts = new Symbol(0);
|
|
1149
|
-
var rem = new Symbol(0);
|
|
1150
|
-
if(symbol.isComposite()) {
|
|
1151
|
-
symbol.each(function (x) {
|
|
1152
|
-
if(x.fname === 'sqrt' && x.contains(v)) {
|
|
1153
|
-
sqrts = _.add(sqrts, x.clone());
|
|
1154
|
-
}
|
|
1155
|
-
else {
|
|
1156
|
-
rem = _.add(rem, x.clone());
|
|
1157
|
-
}
|
|
1158
|
-
});
|
|
1159
|
-
//quick and dirty ATM
|
|
1160
|
-
if(!sqrts.equals(0)) {
|
|
1161
|
-
var t = _.expand(_.multiply(_.parse(symbol.multiplier), _.subtract(_.pow(rem, new Symbol(2)), _.pow(sqrts, new Symbol(2)))));
|
|
1162
|
-
//square both sides
|
|
1163
|
-
var solutions = solve(t, v);
|
|
1164
|
-
//test the points. The dumb way of getting the answers
|
|
1165
|
-
solutions = solutions.filter(function (e) {
|
|
1166
|
-
if(e.isImaginary())
|
|
1167
|
-
return e;
|
|
1168
|
-
var subs = {};
|
|
1169
|
-
subs[v] = e;
|
|
1170
|
-
var point = evaluate(symbol, subs);
|
|
1171
|
-
if(point.equals(0))
|
|
1172
|
-
return e;
|
|
1173
|
-
});
|
|
1174
|
-
return solutions;
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
};
|
|
1179
|
-
|
|
1180
|
-
/*
|
|
1181
|
-
*
|
|
1182
|
-
* @param {String[]|String|Equation} eqns
|
|
1183
|
-
* @param {String} solve_for
|
|
1184
|
-
* @param {Array} solutions
|
|
1185
|
-
* @param {Number} depth
|
|
1186
|
-
* @param {String|Equation} fn
|
|
1187
|
-
* @returns {Array}
|
|
1188
|
-
*/
|
|
1189
|
-
var solve = function (eqns, solve_for, solutions, depth, fn) {
|
|
1190
|
-
depth = depth || 0;
|
|
1191
|
-
|
|
1192
|
-
if(depth++ > Settings.MAX_SOLVE_DEPTH) {
|
|
1193
|
-
return solutions;
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
//make preparations if it's an Equation
|
|
1197
|
-
if(eqns instanceof Equation) {
|
|
1198
|
-
//if it's zero then we're done
|
|
1199
|
-
if(eqns.isZero()) {
|
|
1200
|
-
return [new Symbol(0)];
|
|
1201
|
-
}
|
|
1202
|
-
//if the lhs = x then we're done
|
|
1203
|
-
if(eqns.LHS.equals(solve_for) && !eqns.RHS.contains(solve_for)) {
|
|
1204
|
-
return [eqns.RHS];
|
|
1205
|
-
}
|
|
1206
|
-
//if the rhs = x then we're done
|
|
1207
|
-
if(eqns.RHS.equals(solve_for) && !eqns.LHS.contains(solve_for)) {
|
|
1208
|
-
return [eqns.LHS];
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
//unwrap the vector since what we want are the elements
|
|
1213
|
-
if(eqns instanceof core.Vector)
|
|
1214
|
-
eqns = eqns.elements;
|
|
1215
|
-
solve_for = solve_for || 'x'; //assumes x by default
|
|
1216
|
-
//If it's an array then solve it as a system of equations
|
|
1217
|
-
if(isArray(eqns)) {
|
|
1218
|
-
return __.solveSystem.apply(undefined, arguments);
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
// Parse out functions. Fix for issue #300
|
|
1222
|
-
// eqns = core.Utils.evaluate(eqns);
|
|
1223
|
-
solutions = solutions || [];
|
|
1224
|
-
//mark existing solutions as not to have duplicates
|
|
1225
|
-
var existing = {};
|
|
1226
|
-
|
|
1227
|
-
// Easy fail. If it's a rational function and the denominator is zero
|
|
1228
|
-
// the we're done. Issue #555
|
|
1229
|
-
var known = {};
|
|
1230
|
-
known[solve_for] = 0;
|
|
1231
|
-
if(isSymbol(eqns) && evaluate(eqns.getDenom(), known).equals(0) === true) {
|
|
1232
|
-
return solutions;
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
// Is usued to add solutions to set.
|
|
1236
|
-
// TODO: Set is now implemented and should be utilized
|
|
1237
|
-
var add_to_result = function (r, has_trig) {
|
|
1238
|
-
var r_is_symbol = isSymbol(r);
|
|
1239
|
-
if(r === undefined || typeof r === 'number' && isNaN(r))
|
|
1240
|
-
return;
|
|
1241
|
-
if(isArray(r)) {
|
|
1242
|
-
r.forEach(function (sol) {
|
|
1243
|
-
add_to_result(sol);
|
|
1244
|
-
});
|
|
1245
|
-
}
|
|
1246
|
-
else {
|
|
1247
|
-
if(r.valueOf() !== 'null') {
|
|
1248
|
-
// Call the pre-add function if defined. This could be useful for rounding
|
|
1249
|
-
if(typeof core.Settings.PRE_ADD_SOLUTION === 'function') {
|
|
1250
|
-
r = core.Settings.PRE_ADD_SOLUTION(r);
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
if(!r_is_symbol) {
|
|
1254
|
-
r = _.parse(r);
|
|
1255
|
-
}
|
|
1256
|
-
// try to convert the number to multiples of pi
|
|
1257
|
-
if(core.Settings.make_pi_conversions && has_trig) {
|
|
1258
|
-
var temp = _.divide(r.clone(), new Symbol(Math.PI)),
|
|
1259
|
-
m = temp.multiplier,
|
|
1260
|
-
a = Math.abs(m.num),
|
|
1261
|
-
b = Math.abs(m.den);
|
|
1262
|
-
if(a < 10 && b < 10)
|
|
1263
|
-
r = _.multiply(temp, new Symbol('pi'));
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
// And check if we get a number otherwise we might be throwing out symbolic solutions.
|
|
1267
|
-
var r_str = r.toString();
|
|
1268
|
-
|
|
1269
|
-
if(!existing[r_str]) {
|
|
1270
|
-
solutions.push(r);
|
|
1271
|
-
}
|
|
1272
|
-
// Mark the answer as seen
|
|
1273
|
-
existing[r_str] = true;
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
};
|
|
1277
|
-
|
|
1278
|
-
// Maybe we get lucky. Try the point at the function. If it works we have a point
|
|
1279
|
-
// If not it failed
|
|
1280
|
-
if(eqns.group === S && eqns.contains(solve_for)) {
|
|
1281
|
-
try {
|
|
1282
|
-
var o = {};
|
|
1283
|
-
o[solve_for] = 0;
|
|
1284
|
-
evaluate(fn, o, 'numer');
|
|
1285
|
-
add_to_result(new Symbol(0));
|
|
1286
|
-
}
|
|
1287
|
-
catch(e) {
|
|
1288
|
-
// Do nothing;
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
return solutions;
|
|
1292
|
-
}
|
|
1293
|
-
if(eqns.group === CB) {
|
|
1294
|
-
// It suffices to solve for the numerator
|
|
1295
|
-
var num = eqns.getNum();
|
|
1296
|
-
|
|
1297
|
-
if(num.group === CB) {
|
|
1298
|
-
var sf = String(solve_for); //everything else belongs to the coeff
|
|
1299
|
-
//get the denominator and make sure it doesn't have x since we don't know how to solve for those
|
|
1300
|
-
num.each(function (x) {
|
|
1301
|
-
if(x.contains(sf))
|
|
1302
|
-
solve(x, solve_for, solutions, depth, eqns);
|
|
1303
|
-
});
|
|
1304
|
-
|
|
1305
|
-
return solutions;
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
return solve(num, solve_for, solutions, depth, fn);
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
if(eqns.group === FN && eqns.fname === 'sqrt') {
|
|
1312
|
-
eqns = _.pow(Symbol.unwrapSQRT(eqns), new Symbol(2));
|
|
1313
|
-
}
|
|
1314
|
-
//pass in false to not expand equations such as (x+y)^5.
|
|
1315
|
-
//It suffices to solve for the numerator since there's no value in the denominator which yields a zero for the function
|
|
1316
|
-
var eq = (core.Utils.isSymbol(eqns) ? eqns : __.toLHS(eqns, false)).getNum(),
|
|
1317
|
-
vars = core.Utils.variables(eq), //get a list of all the variables
|
|
1318
|
-
numvars = vars.length;//how many variables are we dealing with
|
|
1319
|
-
|
|
1320
|
-
//it sufficient to solve (x+y) if eq is (x+y)^n since 0^n
|
|
1321
|
-
if(core.Utils.isInt(eq.power) && eq.power > 0) {
|
|
1322
|
-
eq = _.parse(eq).toLinear();
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
//if we're dealing with a single variable then we first check if it's a
|
|
1326
|
-
//polynomial (including rationals).If it is then we use the Jenkins-Traubb algorithm.
|
|
1327
|
-
//Don't waste time
|
|
1328
|
-
if(eq.group === S || eq.group === CB && eq.contains(solve_for)) {
|
|
1329
|
-
return [new Symbol(0)];
|
|
1330
|
-
}
|
|
1331
|
-
//force to polynomial. We go through each and then we look at what it would
|
|
1332
|
-
//take for its power to be an integer
|
|
1333
|
-
//if the power is a fractional we divide by the fractional power
|
|
1334
|
-
var fractionals = {},
|
|
1335
|
-
cfact;
|
|
1336
|
-
|
|
1337
|
-
var correct_denom = function (symbol) {
|
|
1338
|
-
symbol = _.expand(symbol, {
|
|
1339
|
-
expand_denominator: true,
|
|
1340
|
-
expand_functions: true
|
|
1341
|
-
});
|
|
1342
|
-
var original = symbol.clone(); //preserve the original
|
|
1343
|
-
|
|
1344
|
-
if(symbol.symbols) {
|
|
1345
|
-
for(var x in symbol.symbols) {
|
|
1346
|
-
var sym = symbol.symbols[x];
|
|
1347
|
-
|
|
1348
|
-
//get the denominator of the sub-symbol
|
|
1349
|
-
var den = sym.getDenom();
|
|
1350
|
-
|
|
1351
|
-
if(!den.isConstant(true) && symbol.isComposite()) {
|
|
1352
|
-
var t = new Symbol(0);
|
|
1353
|
-
symbol.each(function (e) {
|
|
1354
|
-
t = _.add(t, _.multiply(e, den.clone()));
|
|
1355
|
-
});
|
|
1356
|
-
|
|
1357
|
-
return correct_denom(_.multiply(_.parse(symbol.multiplier), t));
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
var parts = explode(sym, solve_for);
|
|
1361
|
-
var is_sqrt = parts[1].fname === core.Settings.SQRT;
|
|
1362
|
-
var v = Symbol.unwrapSQRT(parts[1]);
|
|
1363
|
-
var p = v.power.clone();
|
|
1364
|
-
//circular logic with sqrt. Since sqrt(x) becomes x^(1/2) which then becomes sqrt(x), this continues forever
|
|
1365
|
-
//this needs to be terminated if p = 1/2
|
|
1366
|
-
if(!isSymbol(p) && !p.equals(1 / 2)) {
|
|
1367
|
-
if(p.den.gt(1)) {
|
|
1368
|
-
if(is_sqrt) {
|
|
1369
|
-
symbol = _.subtract(symbol, sym.clone());
|
|
1370
|
-
symbol = _.add(symbol, _.multiply(parts[0].clone(), v));
|
|
1371
|
-
return correct_denom(symbol);
|
|
1372
|
-
}
|
|
1373
|
-
var c = fractionals[p.den];
|
|
1374
|
-
fractionals[p.den] = c ? c++ : 1;
|
|
1375
|
-
}
|
|
1376
|
-
else if(p.sign() === -1) {
|
|
1377
|
-
var factor = _.parse(solve_for + '^' + Math.abs(p)); //this
|
|
1378
|
-
//unwrap the symbol's denoniator
|
|
1379
|
-
symbol.each(function (y, index) {
|
|
1380
|
-
if(y.contains(solve_for)) {
|
|
1381
|
-
symbol.symbols[index] = _.multiply(y, factor.clone());
|
|
1382
|
-
}
|
|
1383
|
-
});
|
|
1384
|
-
fractionals = {};
|
|
1385
|
-
return correct_denom(_.parse(symbol));
|
|
1386
|
-
}
|
|
1387
|
-
else if(sym.group === PL) {
|
|
1388
|
-
var min_p = core.Utils.arrayMin(core.Utils.keys(sym.symbols));
|
|
1389
|
-
if(min_p < 0) {
|
|
1390
|
-
var factor = _.parse(solve_for + '^' + Math.abs(min_p));
|
|
1391
|
-
var corrected = new Symbol(0);
|
|
1392
|
-
original.each(function (x) {
|
|
1393
|
-
corrected = _.add(corrected, _.multiply(x.clone(), factor.clone()));
|
|
1394
|
-
}, true);
|
|
1395
|
-
return corrected;
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
return symbol;
|
|
1403
|
-
};
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
//separate the equation
|
|
1407
|
-
var separate = function (eq) {
|
|
1408
|
-
var lhs = new Symbol(0),
|
|
1409
|
-
rhs = new Symbol(0);
|
|
1410
|
-
eq.each(function (x) {
|
|
1411
|
-
if(x.contains(solve_for, true))
|
|
1412
|
-
lhs = _.add(lhs, x.clone());
|
|
1413
|
-
else
|
|
1414
|
-
rhs = _.subtract(rhs, x.clone());
|
|
1415
|
-
});
|
|
1416
|
-
return [lhs, rhs];
|
|
1417
|
-
};
|
|
1418
|
-
|
|
1419
|
-
__.inverseFunctionSolve = function (name, lhs, rhs) {
|
|
1420
|
-
//ax+b comes back as [a, x, ax, b];
|
|
1421
|
-
var parts = explode(lhs.args[0], solve_for);
|
|
1422
|
-
//check if x is by itself
|
|
1423
|
-
var x = parts[1];
|
|
1424
|
-
if(x.group === S) {
|
|
1425
|
-
return _.divide(_.symfunction(name, [_.divide(rhs, _.parse(lhs.multiplier))]), parts[0]);
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
};
|
|
1429
|
-
|
|
1430
|
-
//first remove any denominators
|
|
1431
|
-
eq = correct_denom(eq);
|
|
1432
|
-
|
|
1433
|
-
if(eq.equals(0))
|
|
1434
|
-
return [eq];
|
|
1435
|
-
//correct fractionals. I can only handle one type right now
|
|
1436
|
-
var fkeys = core.Utils.keys(fractionals);
|
|
1437
|
-
if(fkeys.length === 1) {
|
|
1438
|
-
//make a note of the factor
|
|
1439
|
-
cfact = fkeys[0];
|
|
1440
|
-
eq.each(function (x, index) {
|
|
1441
|
-
if(x.contains(solve_for)) {
|
|
1442
|
-
var parts = explode(x, solve_for);
|
|
1443
|
-
var v = parts[1];
|
|
1444
|
-
var p = v.power;
|
|
1445
|
-
if(p.den.gt(1)) {
|
|
1446
|
-
v.power = p.multiply(new core.Frac(cfact));
|
|
1447
|
-
eq.symbols[index] = _.multiply(v, parts[0]);
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
});
|
|
1451
|
-
eq = _.parse(eq);
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
//try for nested sqrts as per issue #486
|
|
1455
|
-
add_to_result(__.sqrtSolve(eq, solve_for));
|
|
1456
|
-
|
|
1457
|
-
//polynomial single variable
|
|
1458
|
-
if(numvars === 1) {
|
|
1459
|
-
if(eq.isPoly(true)) {
|
|
1460
|
-
//try to factor and solve
|
|
1461
|
-
var factors = new core.Algebra.Classes.Factors();
|
|
1462
|
-
|
|
1463
|
-
core.Algebra.Factor.factor(eq, factors);
|
|
1464
|
-
//if the equation has more than one symbolic factor then solve those individually
|
|
1465
|
-
if(factors.getNumberSymbolics() > 1) {
|
|
1466
|
-
for(var x in factors.factors) {
|
|
1467
|
-
add_to_result(solve(factors.factors[x], solve_for));
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
else {
|
|
1471
|
-
var coeffs = core.Utils.getCoeffs(eq, solve_for),
|
|
1472
|
-
deg = coeffs.length - 1,
|
|
1473
|
-
was_calculated = false;
|
|
1474
|
-
if(vars[0] === solve_for) {
|
|
1475
|
-
//check to see if all the coefficients are constant
|
|
1476
|
-
if(checkAll(coeffs, function (x) {
|
|
1477
|
-
return x.group !== core.groups.N;
|
|
1478
|
-
})) {
|
|
1479
|
-
var roots = core.Algebra.proots(eq);
|
|
1480
|
-
//if all the roots are integers then return those
|
|
1481
|
-
if(checkAll(roots, function (x) {
|
|
1482
|
-
return !core.Utils.isInt(x);
|
|
1483
|
-
})) {
|
|
1484
|
-
//roots have been calculates
|
|
1485
|
-
was_calculated = true;
|
|
1486
|
-
roots.map(function (x) {
|
|
1487
|
-
add_to_result(new Symbol(x));
|
|
1488
|
-
});
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
if(!was_calculated) {
|
|
1493
|
-
eqns = _.parse(eqns);
|
|
1494
|
-
if(eqns instanceof core.Equation)
|
|
1495
|
-
eqns = eqns.toLHS();
|
|
1496
|
-
|
|
1497
|
-
//we can solve algebraically for degrees 1, 2, 3. The remainder we switch to Jenkins-
|
|
1498
|
-
if(deg === 1)
|
|
1499
|
-
add_to_result(_.divide(coeffs[0], coeffs[1].negate()));
|
|
1500
|
-
else if(deg === 2) {
|
|
1501
|
-
add_to_result(_.expand(__.quad.apply(undefined, coeffs)));
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
else if(deg === 3) {
|
|
1505
|
-
var solutions = []; //set to blank
|
|
1506
|
-
//first try to factor and solve
|
|
1507
|
-
var factored = core.Algebra.Factor.factor(eqns);
|
|
1508
|
-
|
|
1509
|
-
//if it was successfully factored
|
|
1510
|
-
var solutions = [];
|
|
1511
|
-
if(solutions.length > 0)
|
|
1512
|
-
add_to_result(solutions);
|
|
1513
|
-
else
|
|
1514
|
-
add_to_result(__.cubic.apply(undefined, coeffs));
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
else {
|
|
1518
|
-
/*
|
|
1519
|
-
var sym_roots = csolve(eq, solve_for);
|
|
1520
|
-
if(sym_roots.length === 0)
|
|
1521
|
-
sym_roots = divnconsolve(eq, solve_for);
|
|
1522
|
-
if(sym_roots.length > 0)
|
|
1523
|
-
add_to_result(sym_roots);
|
|
1524
|
-
else
|
|
1525
|
-
*/
|
|
1526
|
-
_A.proots(eq).map(add_to_result);
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
else {
|
|
1533
|
-
try {
|
|
1534
|
-
// Attempt Newton
|
|
1535
|
-
// Since it's not a polynomial then we'll try to look for a solution using Newton's method
|
|
1536
|
-
var has_trig = eq.hasTrig();
|
|
1537
|
-
// we get all the points where a possible zero might exist.
|
|
1538
|
-
var points1 = __.getPoints(eq, 0.1);
|
|
1539
|
-
var points2 = __.getPoints(eq, 0.05);
|
|
1540
|
-
var points3 = __.getPoints(eq, 0.01);
|
|
1541
|
-
var points = core.Utils.arrayUnique(points1.concat(points2).concat(points3)).sort(function (a, b) {
|
|
1542
|
-
return a - b;
|
|
1543
|
-
});
|
|
1544
|
-
var i, point, solution;
|
|
1545
|
-
|
|
1546
|
-
// Compile the function
|
|
1547
|
-
var f = build(eq.clone());
|
|
1548
|
-
|
|
1549
|
-
// First try to eliminate some points using bisection
|
|
1550
|
-
var t_points = [];
|
|
1551
|
-
for(i = 0; i < points.length; i++) {
|
|
1552
|
-
point = points[i];
|
|
1553
|
-
|
|
1554
|
-
// See if there's a solution at this point
|
|
1555
|
-
solution = __.bisection(point, f);
|
|
1556
|
-
|
|
1557
|
-
// If there's no solution then add it to the array for further investigation
|
|
1558
|
-
if(typeof solution === 'undefined') {
|
|
1559
|
-
t_points.push(point);
|
|
1560
|
-
continue;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
// Add the solution to the solution set
|
|
1564
|
-
add_to_result(solution, has_trig);
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
// Reset the points to the remaining points
|
|
1568
|
-
points = t_points;
|
|
1569
|
-
|
|
1570
|
-
// Build the derivative and compile a function
|
|
1571
|
-
var d = _C.diff(eq.clone());
|
|
1572
|
-
var fp = build(d);
|
|
1573
|
-
for(i = 0; i < points.length; i++) {
|
|
1574
|
-
point = points[i];
|
|
1575
|
-
|
|
1576
|
-
add_to_result(__.Newton(point, f, fp), has_trig);
|
|
1577
|
-
}
|
|
1578
|
-
solutions.sort();
|
|
1579
|
-
}
|
|
1580
|
-
catch(e) {
|
|
1581
|
-
console.log(e);
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
else {
|
|
1586
|
-
//The idea here is to go through the equation and collect the coefficients
|
|
1587
|
-
//place them in an array and call the quad or cubic function to get the results
|
|
1588
|
-
if(!eq.hasFunc(solve_for) && eq.isComposite()) {
|
|
1589
|
-
try {
|
|
1590
|
-
var factored = core.Algebra.Factor.factor(eq.clone());
|
|
1591
|
-
|
|
1592
|
-
if(factored.group === CB) {
|
|
1593
|
-
factored.each(function (x) {
|
|
1594
|
-
add_to_result(solve(x, solve_for));
|
|
1595
|
-
});
|
|
1596
|
-
}
|
|
1597
|
-
else {
|
|
1598
|
-
var coeffs = core.Utils.getCoeffs(eq, solve_for);
|
|
1599
|
-
|
|
1600
|
-
var l = coeffs.length,
|
|
1601
|
-
deg = l - 1; //the degree of the polynomial
|
|
1602
|
-
//get the denominator and make sure it doesn't have x
|
|
1603
|
-
|
|
1604
|
-
//handle the problem based on the degree
|
|
1605
|
-
switch(deg) {
|
|
1606
|
-
case 0:
|
|
1607
|
-
var separated = separate(eq);
|
|
1608
|
-
var lhs = separated[0],
|
|
1609
|
-
rhs = separated[1];
|
|
1610
|
-
|
|
1611
|
-
if(lhs.group === core.groups.EX) {
|
|
1612
|
-
var log = core.Settings.LOG;
|
|
1613
|
-
var expr_str = `${log}((${rhs})/(${lhs.multiplier}))/${log}(${lhs.value})/${lhs.power.multiplier}`;
|
|
1614
|
-
add_to_result(_.parse(expr_str));
|
|
1615
|
-
}
|
|
1616
|
-
break;
|
|
1617
|
-
case 1:
|
|
1618
|
-
//nothing to do but to return the quotient of the constant and the LT
|
|
1619
|
-
//e.g. 2*x-1
|
|
1620
|
-
add_to_result(_.divide(coeffs[0], coeffs[1].negate()));
|
|
1621
|
-
break;
|
|
1622
|
-
case 2:
|
|
1623
|
-
add_to_result(__.quad.apply(undefined, coeffs));
|
|
1624
|
-
break;
|
|
1625
|
-
case 3:
|
|
1626
|
-
add_to_result(__.cubic.apply(undefined, coeffs));
|
|
1627
|
-
break;
|
|
1628
|
-
case 4:
|
|
1629
|
-
add_to_result(__.quartic.apply(undefined, coeffs));
|
|
1630
|
-
break;
|
|
1631
|
-
default:
|
|
1632
|
-
add_to_result(__.csolve(eq, solve_for));
|
|
1633
|
-
if(solutions.length === 0)
|
|
1634
|
-
add_to_result(__.divideAndConquer(eq, solve_for));
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
if(solutions.length === 0) {
|
|
1638
|
-
//try factoring
|
|
1639
|
-
add_to_result(solve(factored, solve_for, solutions, depth));
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
}
|
|
1644
|
-
catch(e) { /*something went wrong. EXITING*/
|
|
1645
|
-
;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
else {
|
|
1649
|
-
try {
|
|
1650
|
-
var rw = __.rewrite(eq, null, solve_for);
|
|
1651
|
-
var lhs = rw[0];
|
|
1652
|
-
var rhs = rw[1];
|
|
1653
|
-
if(lhs.group === FN) {
|
|
1654
|
-
if(lhs.fname === 'abs') {
|
|
1655
|
-
add_to_result([rhs.clone(), rhs.negate()]);
|
|
1656
|
-
}
|
|
1657
|
-
else if(lhs.fname === 'sin') {
|
|
1658
|
-
//asin
|
|
1659
|
-
add_to_result(__.inverseFunctionSolve('asin', lhs, rhs));
|
|
1660
|
-
}
|
|
1661
|
-
else if(lhs.fname === 'cos') {
|
|
1662
|
-
//asin
|
|
1663
|
-
add_to_result(__.inverseFunctionSolve('acos', lhs, rhs));
|
|
1664
|
-
}
|
|
1665
|
-
else if(lhs.fname === 'tan') {
|
|
1666
|
-
//asin
|
|
1667
|
-
add_to_result(__.inverseFunctionSolve('atan', lhs, rhs));
|
|
1668
|
-
}
|
|
1669
|
-
else if(lhs.fname === core.Settings.LOG) {
|
|
1670
|
-
//ax+b comes back as [a, x, ax, b];
|
|
1671
|
-
var parts = explode(lhs.args[0], solve_for);
|
|
1672
|
-
//check if x is by itself
|
|
1673
|
-
var x = parts[1];
|
|
1674
|
-
if(x.group === S) {
|
|
1675
|
-
rhs = _.divide(_.subtract(_.pow(lhs.args.length > 1 ? lhs.args[1] : new Symbol('e'), _.divide(rhs, _.parse(lhs.multiplier))), parts[3]), parts[0]);
|
|
1676
|
-
var eq = new Equation(x, rhs).toLHS();
|
|
1677
|
-
add_to_result(solve(eq, solve_for));
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
else
|
|
1681
|
-
add_to_result(_.subtract(lhs, rhs));
|
|
1682
|
-
}
|
|
1683
|
-
else {
|
|
1684
|
-
var neq = new Equation(lhs, rhs).toLHS(); //create a new equation
|
|
1685
|
-
|
|
1686
|
-
if(neq.equals(eq))
|
|
1687
|
-
throw new Error('Stopping. No stop condition exists');
|
|
1688
|
-
add_to_result(solve(neq, solve_for));
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
catch(error) {
|
|
1692
|
-
//Let's try this another way
|
|
1693
|
-
try {
|
|
1694
|
-
//1. if the symbol is in the form a*b*c*... then the solution is zero if
|
|
1695
|
-
//either a or b or c is zero.
|
|
1696
|
-
if(eq.group === CB)
|
|
1697
|
-
add_to_result(0);
|
|
1698
|
-
else if(eq.group === CP) {
|
|
1699
|
-
var separated = separate(eq);
|
|
1700
|
-
var lhs = separated[0],
|
|
1701
|
-
rhs = separated[1];
|
|
1702
|
-
|
|
1703
|
-
//reduce the equation
|
|
1704
|
-
if(lhs.group === core.groups.EX && lhs.value === solve_for) {
|
|
1705
|
-
//change the base of both sides
|
|
1706
|
-
var p = lhs.power.clone().invert();
|
|
1707
|
-
add_to_result(_.pow(rhs, p));
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
catch(error) {
|
|
1712
|
-
;
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
if(cfact) {
|
|
1719
|
-
solutions = solutions.map(function (x) {
|
|
1720
|
-
return _.pow(x, new Symbol(cfact));
|
|
1721
|
-
});
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
// Perform some cleanup but don't do it agains arrays, etc
|
|
1725
|
-
// Check it actually evaluates to zero
|
|
1726
|
-
if(isSymbol(eqns)) {
|
|
1727
|
-
var knowns = {};
|
|
1728
|
-
solutions = solutions.filter(function (x) {
|
|
1729
|
-
try {
|
|
1730
|
-
knowns[solve_for] = x;
|
|
1731
|
-
var zero = Number(evaluate(eqns, knowns));
|
|
1732
|
-
|
|
1733
|
-
// Allow symbolic answers
|
|
1734
|
-
if(isNaN(zero)) {
|
|
1735
|
-
return true;
|
|
1736
|
-
}
|
|
1737
|
-
return true;
|
|
1738
|
-
}
|
|
1739
|
-
catch(e) {
|
|
1740
|
-
return false;
|
|
1741
|
-
}
|
|
1742
|
-
});
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
return solutions;
|
|
1746
|
-
};
|
|
1747
|
-
|
|
1748
|
-
//Register the functions for external use
|
|
1749
|
-
nerdamer.register([
|
|
1750
|
-
{
|
|
1751
|
-
name: 'solveEquations',
|
|
1752
|
-
parent: 'nerdamer',
|
|
1753
|
-
numargs: -1,
|
|
1754
|
-
visible: true,
|
|
1755
|
-
build: function () {
|
|
1756
|
-
return solve; //comment out to return a vector
|
|
1757
|
-
/*
|
|
1758
|
-
return function() {
|
|
1759
|
-
return core.Utils.convertToVector(solve.apply(null, arguments));
|
|
1760
|
-
};
|
|
1761
|
-
*/
|
|
1762
|
-
}
|
|
1763
|
-
},
|
|
1764
|
-
{
|
|
1765
|
-
name: 'solve',
|
|
1766
|
-
parent: 'Solve',
|
|
1767
|
-
numargs: 2,
|
|
1768
|
-
visible: true,
|
|
1769
|
-
build: function () {
|
|
1770
|
-
return core.Solve.solve;
|
|
1771
|
-
}
|
|
1772
|
-
},
|
|
1773
|
-
{
|
|
1774
|
-
name: 'setEquation',
|
|
1775
|
-
parent: 'Solve',
|
|
1776
|
-
visible: true,
|
|
1777
|
-
build: function () {
|
|
1778
|
-
return setEq;
|
|
1779
|
-
}
|
|
1780
|
-
}
|
|
1781
|
-
]);
|
|
1782
|
-
nerdamer.updateAPI();
|
|
1783
|
-
})();
|