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/Solve.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  /* global module */
8
8
 
9
- if ((typeof module) !== 'undefined') {
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 (this.isComposite()) {
85
- for (var x in this.symbols) {
85
+ if(this.isComposite()) {
86
+ for(var x in this.symbols) {
86
87
  var sym = this.symbols[x];
87
- if (sym.group === PL && sym.hasNegativeTerms() || this.symbols[x].power.lessThan(0))
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 (rhs.isConstant() && lhs.isConstant() && !lhs.equals(rhs) || lhs.equals(core.Settings.IMAGINARY) || rhs.equals(core.Settings.IMAGINARY))
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 (b.group === CP && b.group !== CP) {
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 (a.group === CB) {
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 (y.power.lessThan(0))
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 (a.group === CP) {
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 (var x in a.symbols) {
173
+ for(var x in a.symbols) {
165
174
  var sym = a.symbols[x];
166
- if (sym.group === CB) {
167
- for (var y in sym.symbols) {
175
+ if(sym.group === CB) {
176
+ for(var y in sym.symbols) {
168
177
  var sym2 = sym.symbols[y];
169
- if (sym2.power.lessThan(0)) {
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 (this.symbol instanceof Equation) {
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 (this.symbol instanceof Equation)
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
- core.Matrix.jacobian = function(eqns, vars) {
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 (var i = 0; i < args.length; i++)
301
- if (test(args[i]))
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 (!(eqn instanceof Equation)) {
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
- solveNonLinearSystem: function(eqns, tries, start) {
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 = __.getSystemVariables(eqns);
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) { return _.parse(Number(x)); });
496
+ d = y.subtract(xn1, function (x) {
497
+ return _.parse(Number(x));
498
+ });
433
499
 
434
- xn1 = xn.add(y, function(x) { return _.parse(Number(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 (core.Settings.SOLUTIONS_AS_OBJECT) {
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
- * @param {Array} var_array
500
- * @returns {Array|object}
567
+ * @returns {Array}
501
568
  */
502
- solveSystemBySubstitution: function(eqns, var_array, m, c) {
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 (var i = 0; i < eqns.length; i++)
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
- m = new core.Matrix(),
521
- c = new core.Matrix(),
522
- expand_result = false,
523
- vars;
596
+ m = new core.Matrix(),
597
+ c = new core.Matrix(),
598
+ expand_result = false,
599
+ vars;
524
600
 
525
- if (typeof var_array === 'undefined') {
601
+ if(typeof var_array === 'undefined') {
526
602
  //check to make sure that all the equations are linear
527
- if (!_A.allLinear(eqns))
528
- return __.solveNonLinearSystem(eqns);
529
- //core.err('System must contain all linear equations!');
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
- vars = __.getSystemVariables(eqns);
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 (var i = 0; i < vars.length; i++) {
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 (var i = 0; i < l; i++) {
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 (var j = 0; j < vars.length; j++) {
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 (i = 0; i < l; i++) {
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 (var j = 0; j < var_array.length; j++) {
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 (var k = 0; k < e.length; k++) {
740
+ for(var k = 0; k < e.length; k++) {
622
741
  var term = e[k],
623
742
  check = false;
624
- for (var z = 0; z < var_array.length; z++) {
743
+ for(var z = 0; z < var_array.length; z++) {
625
744
  //check to see if terms contain multiple variables
626
- if (term.contains(var_array[z])) {
627
- if (check)
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 (term.contains(v)) {
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 (k = 0; k < e.length; k++) {
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 (core.Utils.isArray(var_array))
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)+(${u})^3)^(1/3)+((${t})-sqrt((${t})^2)+(${u})^3)^(1/3)-(${v})`;
701
- var x = `(((-((${b}))^3/(27*((${a}))^3)+((${b}))*((${c}))/(6*((${a}))^2)-((${d}))/(2*((${a})))))+sqrt(((-((${b}))^3/(27*((${a}))^3)+((${b}))*((${c}))/(6*((${a}))^2)-((${d}))/(2*((${a})))))^2)+((((${c}))/(3*((${a})))-((${b}))^2/(9*((${a}))^2)))^(3/2))^(1/3)+(((-((${b}))^3/(27*((${a}))^3)+((${b}))*((${c}))/(6*((${a}))^2)-((${d}))/(2*((${a})))))-sqrt(((-((${b}))^3/(27*((${a}))^3)+((${b}))*((${c}))/(6*((${a}))^2)-((${d}))/(2*((${a})))))^2)+((((${c}))/(3*((${a})))-((${b}))^2/(9*((${a}))^2)))^(3/2))^(1/3)-(((${b}))/(3*((${a}))))`
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 (factors.group === CB) {
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 (f.x.group === S) {
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 (var i = 0; i < pn; i++) {
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 (x.containsFunction(core.Settings.LOG))
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
- right = range(start, core.Settings.SOLVE_RADIUS, step);
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 (isNaN(val) || !isFinite(val) || hits.length > num_roots) {
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 (sign !== last_sign) {
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 (x0 === 0 && fx0 === 0) {
1043
+ if(x0 === 0 && fx0 === 0) {
924
1044
  x = 0;
925
1045
  break;
926
1046
  }
927
-
1047
+
928
1048
  iter++;
929
- if (iter > maxiter)
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 (e > Settings.NEWTON_EPSILON)
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 (rhs.group === CP && rhs.contains(for_variable) && rhs.isLinear()) {
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 (x.contains(for_variable)) {
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 (c !== l) {
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 (rhs.group === CB && rhs.contains(for_variable) && rhs.isLinear()) {
998
- if (rhs.multiplier.lessThan(0)) {
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 (lhs.equals(0))
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 (x.contains(for_variable))
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 (!rhs.isLinear() && rhs.contains(for_variable)) {
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 (rhs.group === FN || rhs.group === S || rhs.group === PL) {
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 {type} solve_for
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 (eqns instanceof Equation) {
1197
+ if(eqns instanceof Equation) {
1075
1198
  //if it's zero then we're done
1076
- if (eqns.isZero())
1199
+ if(eqns.isZero()) {
1077
1200
  return [new Symbol(0)];
1201
+ }
1078
1202
  //if the lhs = x then we're done
1079
- if (eqns.LHS.equals(solve_for) && !eqns.RHS.contains(solve_for)) {
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 (eqns.RHS.equals(solve_for) && !eqns.LHS.contains(solve_for)) {
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 (eqns instanceof core.Vector)
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 (isArray(eqns)) {
1217
+ if(isArray(eqns)) {
1094
1218
  return __.solveSystem.apply(undefined, arguments);
1095
1219
  }
1096
-
1097
- //parse out functions. Fix for issue #300
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 (r === undefined || typeof r === 'number' && isNaN(r))
1239
+ if(r === undefined || typeof r === 'number' && isNaN(r))
1116
1240
  return;
1117
- if (isArray(r)) {
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 (r.valueOf() !== 'null') {
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 (!r_is_symbol) {
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 (core.Settings.make_pi_conversions && has_trig) {
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 (a < 10 && b < 10)
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 (!existing[r_str]) {
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
- if (eqns.group === S && eqns.contains(solve_for)) {
1156
- add_to_result(new Symbol(0));
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 (eqns.group === CB) {
1160
- var sf = String(solve_for); //everything else belongs to the coeff
1161
- //get the denominator and make sure it doesn't have x since we don't know how to solve for those
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
- return solutions;
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 (eq.group === S || eq.group === CB && eq.contains(solve_for))
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 (symbol.symbols) {
1203
- for (var x in symbol.symbols) {
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 (!isSymbol(p) && !p.equals(1 / 2)) {
1225
- if (p.den.gt(1)) {
1226
- if (is_sqrt) {
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 (p.sign() === -1) {
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 (y.contains(solve_for)) {
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 (sym.group === PL) {
1387
+ else if(sym.group === PL) {
1246
1388
  var min_p = core.Utils.arrayMin(core.Utils.keys(sym.symbols));
1247
- if (min_p < 0) {
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 (x.contains(solve_for, true))
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 (eq.equals(0))
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 (fkeys.length === 1) {
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 (x.contains(solve_for)) {
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 (p.den.gt(1)) {
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 (numvars === 1) {
1316
- if (eq.isPoly(true)) {
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 (vars[0] === solve_for) {
1474
+ if(vars[0] === solve_for) {
1332
1475
  //check to see if all the coefficients are constant
1333
- if (checkAll(coeffs, function (x) {
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 (checkAll(roots, function (x) {
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 (!was_calculated) {
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 (deg === 1)
1498
+ if(deg === 1)
1356
1499
  add_to_result(_.divide(coeffs[0], coeffs[1].negate()));
1357
- else if (deg === 2) {
1500
+ else if(deg === 2) {
1358
1501
  add_to_result(_.expand(__.quad.apply(undefined, coeffs)));
1359
1502
  }
1360
- /*
1361
- else if (deg === 3) {
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 = !factored.equals(eqns) ? solve(factored, solve_for) : [];
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) { return 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 (i = 0; i < points.length; i++) {
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 (!eq.hasFunc(solve_for) && eq.isComposite()) {
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 (deg) {
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
- if (lhs.group === core.groups.EX) {
1465
- add_to_result(_.parse(core.Utils.format(core.Settings.LOG+'(({0})/({2}))/'+core.Settings.LOG+'({1})', rhs, lhs.value, lhs.multiplier)));
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 (solutions.length === 0)
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 (e) { /*something went wrong. EXITING*/
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 (lhs.group === FN) {
1505
- if (lhs.fname === 'abs') {
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 (error) {
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 (eq.group === CB)
1696
+ if(eq.group === CB)
1548
1697
  add_to_result(0);
1549
- else if (eq.group === CP) {
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 (lhs.group === core.groups.EX && lhs.value === solve_for) {
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 (error) {
1711
+ catch(error) {
1563
1712
  ;
1564
1713
  }
1565
1714
  }
1566
1715
  }
1567
1716
  }
1568
-
1569
- if (cfact) {
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.api();
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
+ })();