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