@khanacademy/kas 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/es/index.js +302 -304
- package/dist/es/index.js.map +1 -1
- package/package.json +2 -2
package/dist/es/index.js
CHANGED
|
@@ -77,8 +77,7 @@ import _ from 'underscore';
|
|
|
77
77
|
*/
|
|
78
78
|
var parser$1 = function () {
|
|
79
79
|
var o = function o(k, v, _o, l) {
|
|
80
|
-
for (_o = _o || {}, l = k.length; l--; _o[k[l]] = v)
|
|
81
|
-
}
|
|
80
|
+
for (_o = _o || {}, l = k.length; l--; _o[k[l]] = v);
|
|
82
81
|
return _o;
|
|
83
82
|
},
|
|
84
83
|
$V0 = [1, 11],
|
|
@@ -424,7 +423,7 @@ var parser$1 = function () {
|
|
|
424
423
|
}
|
|
425
424
|
},
|
|
426
425
|
// resets the lexer, sets new input
|
|
427
|
-
setInput: function
|
|
426
|
+
setInput: function (input, yy) {
|
|
428
427
|
this.yy = yy || this.yy || {};
|
|
429
428
|
this._input = input;
|
|
430
429
|
this._more = this._backtrack = this.done = false;
|
|
@@ -444,7 +443,7 @@ var parser$1 = function () {
|
|
|
444
443
|
return this;
|
|
445
444
|
},
|
|
446
445
|
// consumes and returns one char from the input
|
|
447
|
-
input: function
|
|
446
|
+
input: function () {
|
|
448
447
|
var ch = this._input[0];
|
|
449
448
|
this.yytext += ch;
|
|
450
449
|
this.yyleng++;
|
|
@@ -465,7 +464,7 @@ var parser$1 = function () {
|
|
|
465
464
|
return ch;
|
|
466
465
|
},
|
|
467
466
|
// unshifts one char (or a string) into the input
|
|
468
|
-
unput: function
|
|
467
|
+
unput: function (ch) {
|
|
469
468
|
var len = ch.length;
|
|
470
469
|
var lines = ch.split(/(?:\r\n?|\n)/g);
|
|
471
470
|
this._input = ch + this._input;
|
|
@@ -492,12 +491,12 @@ var parser$1 = function () {
|
|
|
492
491
|
return this;
|
|
493
492
|
},
|
|
494
493
|
// When called from action, caches matched text and appends it on next action
|
|
495
|
-
more: function
|
|
494
|
+
more: function () {
|
|
496
495
|
this._more = true;
|
|
497
496
|
return this;
|
|
498
497
|
},
|
|
499
498
|
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
|
|
500
|
-
reject: function
|
|
499
|
+
reject: function () {
|
|
501
500
|
if (this.options.backtrack_lexer) {
|
|
502
501
|
this._backtrack = true;
|
|
503
502
|
} else {
|
|
@@ -510,16 +509,16 @@ var parser$1 = function () {
|
|
|
510
509
|
return this;
|
|
511
510
|
},
|
|
512
511
|
// retain first n characters of the match
|
|
513
|
-
less: function
|
|
512
|
+
less: function (n) {
|
|
514
513
|
this.unput(this.match.slice(n));
|
|
515
514
|
},
|
|
516
515
|
// displays already matched input, i.e. for error messages
|
|
517
|
-
pastInput: function
|
|
516
|
+
pastInput: function () {
|
|
518
517
|
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
|
519
518
|
return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, "");
|
|
520
519
|
},
|
|
521
520
|
// displays upcoming input, i.e. for error messages
|
|
522
|
-
upcomingInput: function
|
|
521
|
+
upcomingInput: function () {
|
|
523
522
|
var next = this.match;
|
|
524
523
|
if (next.length < 20) {
|
|
525
524
|
next += this._input.substr(0, 20 - next.length);
|
|
@@ -527,13 +526,13 @@ var parser$1 = function () {
|
|
|
527
526
|
return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
|
|
528
527
|
},
|
|
529
528
|
// displays the character position where the lexing error occurred, i.e. for error messages
|
|
530
|
-
showPosition: function
|
|
529
|
+
showPosition: function () {
|
|
531
530
|
var pre = this.pastInput();
|
|
532
531
|
var c = new Array(pre.length + 1).join("-");
|
|
533
532
|
return pre + this.upcomingInput() + "\n" + c + "^";
|
|
534
533
|
},
|
|
535
534
|
// test the lexed token: return FALSE when not a match, otherwise return token
|
|
536
|
-
test_match: function
|
|
535
|
+
test_match: function (match, indexed_rule) {
|
|
537
536
|
var token, lines, backup;
|
|
538
537
|
if (this.options.backtrack_lexer) {
|
|
539
538
|
// save context
|
|
@@ -599,7 +598,7 @@ var parser$1 = function () {
|
|
|
599
598
|
return false;
|
|
600
599
|
},
|
|
601
600
|
// return next match in input
|
|
602
|
-
next: function
|
|
601
|
+
next: function () {
|
|
603
602
|
if (this.done) {
|
|
604
603
|
return this.EOF;
|
|
605
604
|
}
|
|
@@ -750,7 +749,7 @@ var parser$1 = function () {
|
|
|
750
749
|
parser.Parser = Parser;
|
|
751
750
|
return new Parser();
|
|
752
751
|
}();
|
|
753
|
-
|
|
752
|
+
const unitParser = parser$1;
|
|
754
753
|
|
|
755
754
|
// This is a @generated file
|
|
756
755
|
|
|
@@ -829,8 +828,7 @@ var unitParser = parser$1;
|
|
|
829
828
|
*/
|
|
830
829
|
var parser = function () {
|
|
831
830
|
var o = function o(k, v, _o, l) {
|
|
832
|
-
for (_o = _o || {}, l = k.length; l--; _o[k[l]] = v)
|
|
833
|
-
}
|
|
831
|
+
for (_o = _o || {}, l = k.length; l--; _o[k[l]] = v);
|
|
834
832
|
return _o;
|
|
835
833
|
},
|
|
836
834
|
$V0 = [1, 7],
|
|
@@ -2103,7 +2101,7 @@ var parser = function () {
|
|
|
2103
2101
|
}
|
|
2104
2102
|
},
|
|
2105
2103
|
// resets the lexer, sets new input
|
|
2106
|
-
setInput: function
|
|
2104
|
+
setInput: function (input, yy) {
|
|
2107
2105
|
this.yy = yy || this.yy || {};
|
|
2108
2106
|
this._input = input;
|
|
2109
2107
|
this._more = this._backtrack = this.done = false;
|
|
@@ -2123,7 +2121,7 @@ var parser = function () {
|
|
|
2123
2121
|
return this;
|
|
2124
2122
|
},
|
|
2125
2123
|
// consumes and returns one char from the input
|
|
2126
|
-
input: function
|
|
2124
|
+
input: function () {
|
|
2127
2125
|
var ch = this._input[0];
|
|
2128
2126
|
this.yytext += ch;
|
|
2129
2127
|
this.yyleng++;
|
|
@@ -2144,7 +2142,7 @@ var parser = function () {
|
|
|
2144
2142
|
return ch;
|
|
2145
2143
|
},
|
|
2146
2144
|
// unshifts one char (or a string) into the input
|
|
2147
|
-
unput: function
|
|
2145
|
+
unput: function (ch) {
|
|
2148
2146
|
var len = ch.length;
|
|
2149
2147
|
var lines = ch.split(/(?:\r\n?|\n)/g);
|
|
2150
2148
|
this._input = ch + this._input;
|
|
@@ -2171,12 +2169,12 @@ var parser = function () {
|
|
|
2171
2169
|
return this;
|
|
2172
2170
|
},
|
|
2173
2171
|
// When called from action, caches matched text and appends it on next action
|
|
2174
|
-
more: function
|
|
2172
|
+
more: function () {
|
|
2175
2173
|
this._more = true;
|
|
2176
2174
|
return this;
|
|
2177
2175
|
},
|
|
2178
2176
|
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
|
|
2179
|
-
reject: function
|
|
2177
|
+
reject: function () {
|
|
2180
2178
|
if (this.options.backtrack_lexer) {
|
|
2181
2179
|
this._backtrack = true;
|
|
2182
2180
|
} else {
|
|
@@ -2189,16 +2187,16 @@ var parser = function () {
|
|
|
2189
2187
|
return this;
|
|
2190
2188
|
},
|
|
2191
2189
|
// retain first n characters of the match
|
|
2192
|
-
less: function
|
|
2190
|
+
less: function (n) {
|
|
2193
2191
|
this.unput(this.match.slice(n));
|
|
2194
2192
|
},
|
|
2195
2193
|
// displays already matched input, i.e. for error messages
|
|
2196
|
-
pastInput: function
|
|
2194
|
+
pastInput: function () {
|
|
2197
2195
|
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
|
2198
2196
|
return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, "");
|
|
2199
2197
|
},
|
|
2200
2198
|
// displays upcoming input, i.e. for error messages
|
|
2201
|
-
upcomingInput: function
|
|
2199
|
+
upcomingInput: function () {
|
|
2202
2200
|
var next = this.match;
|
|
2203
2201
|
if (next.length < 20) {
|
|
2204
2202
|
next += this._input.substr(0, 20 - next.length);
|
|
@@ -2206,13 +2204,13 @@ var parser = function () {
|
|
|
2206
2204
|
return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
|
|
2207
2205
|
},
|
|
2208
2206
|
// displays the character position where the lexing error occurred, i.e. for error messages
|
|
2209
|
-
showPosition: function
|
|
2207
|
+
showPosition: function () {
|
|
2210
2208
|
var pre = this.pastInput();
|
|
2211
2209
|
var c = new Array(pre.length + 1).join("-");
|
|
2212
2210
|
return pre + this.upcomingInput() + "\n" + c + "^";
|
|
2213
2211
|
},
|
|
2214
2212
|
// test the lexed token: return FALSE when not a match, otherwise return token
|
|
2215
|
-
test_match: function
|
|
2213
|
+
test_match: function (match, indexed_rule) {
|
|
2216
2214
|
var token, lines, backup;
|
|
2217
2215
|
if (this.options.backtrack_lexer) {
|
|
2218
2216
|
// save context
|
|
@@ -2278,7 +2276,7 @@ var parser = function () {
|
|
|
2278
2276
|
return false;
|
|
2279
2277
|
},
|
|
2280
2278
|
// return next match in input
|
|
2281
|
-
next: function
|
|
2279
|
+
next: function () {
|
|
2282
2280
|
if (this.done) {
|
|
2283
2281
|
return this.EOF;
|
|
2284
2282
|
}
|
|
@@ -2681,13 +2679,13 @@ _.extend(Expr.prototype, {
|
|
|
2681
2679
|
// an array of the arguments to this node's immediate constructor
|
|
2682
2680
|
args: abstract,
|
|
2683
2681
|
// make a new node with the given arguments
|
|
2684
|
-
construct: function
|
|
2682
|
+
construct: function (args) {
|
|
2685
2683
|
var instance = new this.func();
|
|
2686
2684
|
this.func.apply(instance, args);
|
|
2687
2685
|
return instance;
|
|
2688
2686
|
},
|
|
2689
2687
|
// an abstraction for chainable, bottom-up recursion
|
|
2690
|
-
recurse: function
|
|
2688
|
+
recurse: function (method) {
|
|
2691
2689
|
var passed = Array.prototype.slice.call(arguments, 1);
|
|
2692
2690
|
var args = _.map(this.args(), function (arg) {
|
|
2693
2691
|
return _.isString(arg) ? arg : arg[method].apply(arg, passed);
|
|
@@ -2697,7 +2695,7 @@ _.extend(Expr.prototype, {
|
|
|
2697
2695
|
// evaluate numerically with given variable mapping
|
|
2698
2696
|
eval: abstract,
|
|
2699
2697
|
codegen: abstract,
|
|
2700
|
-
compile: function
|
|
2698
|
+
compile: function () {
|
|
2701
2699
|
var code = this.codegen();
|
|
2702
2700
|
try {
|
|
2703
2701
|
return new Function("vars", "return " + code + ";");
|
|
@@ -2712,7 +2710,7 @@ _.extend(Expr.prototype, {
|
|
|
2712
2710
|
// returns a TeX string representing the expression
|
|
2713
2711
|
tex: abstract,
|
|
2714
2712
|
// returns a TeX string, modified by the given options
|
|
2715
|
-
asTex: function
|
|
2713
|
+
asTex: function (options) {
|
|
2716
2714
|
options = options || {};
|
|
2717
2715
|
_.defaults(options, {
|
|
2718
2716
|
display: true,
|
|
@@ -2734,7 +2732,7 @@ _.extend(Expr.prototype, {
|
|
|
2734
2732
|
},
|
|
2735
2733
|
// returns the name of this expression's constructor as a string
|
|
2736
2734
|
// only used for testing and debugging (the ugly regex is for IE8)
|
|
2737
|
-
name: function
|
|
2735
|
+
name: function () {
|
|
2738
2736
|
if (this.func.name) {
|
|
2739
2737
|
return this.func.name;
|
|
2740
2738
|
} else {
|
|
@@ -2742,37 +2740,37 @@ _.extend(Expr.prototype, {
|
|
|
2742
2740
|
}
|
|
2743
2741
|
},
|
|
2744
2742
|
// returns a string representing current node structure
|
|
2745
|
-
repr: function
|
|
2743
|
+
repr: function () {
|
|
2746
2744
|
return this.name() + "(" + _.map(this.args(), function (arg) {
|
|
2747
2745
|
return _.isString(arg) ? arg : arg.repr();
|
|
2748
2746
|
}).join(",") + ")";
|
|
2749
2747
|
},
|
|
2750
2748
|
// removes all negative signs
|
|
2751
|
-
strip: function
|
|
2749
|
+
strip: function () {
|
|
2752
2750
|
return this.recurse("strip");
|
|
2753
2751
|
},
|
|
2754
2752
|
// canonically reorders all commutative elements
|
|
2755
|
-
normalize: function
|
|
2753
|
+
normalize: function () {
|
|
2756
2754
|
return this.recurse("normalize");
|
|
2757
2755
|
},
|
|
2758
2756
|
// expands the expression
|
|
2759
|
-
expand: function
|
|
2757
|
+
expand: function () {
|
|
2760
2758
|
return this.recurse("expand");
|
|
2761
2759
|
},
|
|
2762
2760
|
// naively factors out like terms
|
|
2763
|
-
factor: function
|
|
2761
|
+
factor: function (options) {
|
|
2764
2762
|
return this.recurse("factor", options);
|
|
2765
2763
|
},
|
|
2766
2764
|
// collect all like terms
|
|
2767
|
-
collect: function
|
|
2765
|
+
collect: function (options) {
|
|
2768
2766
|
return this.recurse("collect", options);
|
|
2769
2767
|
},
|
|
2770
2768
|
// strict syntactic equality check
|
|
2771
|
-
equals: function
|
|
2769
|
+
equals: function (other) {
|
|
2772
2770
|
return this.normalize().print() === other.normalize().print();
|
|
2773
2771
|
},
|
|
2774
2772
|
// expand and collect until the expression no longer changes
|
|
2775
|
-
simplify: function
|
|
2773
|
+
simplify: function (options) {
|
|
2776
2774
|
options = _.extend({
|
|
2777
2775
|
once: false
|
|
2778
2776
|
}, options);
|
|
@@ -2804,31 +2802,31 @@ _.extend(Expr.prototype, {
|
|
|
2804
2802
|
}
|
|
2805
2803
|
},
|
|
2806
2804
|
// check whether this expression is simplified
|
|
2807
|
-
isSimplified: function
|
|
2805
|
+
isSimplified: function () {
|
|
2808
2806
|
return this.equals(this.simplify());
|
|
2809
2807
|
},
|
|
2810
2808
|
// return the child nodes of this node
|
|
2811
|
-
exprArgs: function
|
|
2809
|
+
exprArgs: function () {
|
|
2812
2810
|
return _.filter(this.args(), function (arg) {
|
|
2813
2811
|
return arg instanceof Expr;
|
|
2814
2812
|
});
|
|
2815
2813
|
},
|
|
2816
2814
|
// return the variables (function and non) within the expression
|
|
2817
|
-
getVars: function
|
|
2815
|
+
getVars: function (excludeFunc) {
|
|
2818
2816
|
return _.uniq(_.flatten(_.invoke(this.exprArgs(), "getVars", excludeFunc))).sort();
|
|
2819
2817
|
},
|
|
2820
|
-
getConsts: function
|
|
2818
|
+
getConsts: function () {
|
|
2821
2819
|
return _.uniq(_.flatten(_.invoke(this.exprArgs(), "getConsts"))).sort();
|
|
2822
2820
|
},
|
|
2823
|
-
getUnits: function
|
|
2821
|
+
getUnits: function () {
|
|
2824
2822
|
return _.flatten(_.invoke(this.exprArgs(), "getUnits"));
|
|
2825
2823
|
},
|
|
2826
2824
|
// check whether this expression node is of a particular type
|
|
2827
|
-
is: function
|
|
2825
|
+
is: function (func) {
|
|
2828
2826
|
return this instanceof func;
|
|
2829
2827
|
},
|
|
2830
2828
|
// check whether this expression has a particular node type
|
|
2831
|
-
has: function
|
|
2829
|
+
has: function (func) {
|
|
2832
2830
|
if (this instanceof func) {
|
|
2833
2831
|
return true;
|
|
2834
2832
|
}
|
|
@@ -2838,26 +2836,26 @@ _.extend(Expr.prototype, {
|
|
|
2838
2836
|
},
|
|
2839
2837
|
// raise this expression to a given exponent
|
|
2840
2838
|
// most useful for eventually implementing i^3 = -i, etc.
|
|
2841
|
-
raiseToThe: function
|
|
2839
|
+
raiseToThe: function (exp) {
|
|
2842
2840
|
return new Pow(this, exp);
|
|
2843
2841
|
},
|
|
2844
2842
|
// does this expression have a specific rendering hint?
|
|
2845
2843
|
// rendering hints are picked up while parsing, but are lost during transformations
|
|
2846
|
-
isSubtract: function
|
|
2844
|
+
isSubtract: function () {
|
|
2847
2845
|
return false;
|
|
2848
2846
|
},
|
|
2849
|
-
isDivide: function
|
|
2847
|
+
isDivide: function () {
|
|
2850
2848
|
return false;
|
|
2851
2849
|
},
|
|
2852
|
-
isRoot: function
|
|
2850
|
+
isRoot: function () {
|
|
2853
2851
|
return false;
|
|
2854
2852
|
},
|
|
2855
2853
|
// whether this node needs an explicit multiplication sign if following a Num
|
|
2856
|
-
needsExplicitMul: function
|
|
2854
|
+
needsExplicitMul: function () {
|
|
2857
2855
|
return this.args()[0].needsExplicitMul();
|
|
2858
2856
|
},
|
|
2859
2857
|
// check that the variables in both expressions are the same
|
|
2860
|
-
sameVars: function
|
|
2858
|
+
sameVars: function (other) {
|
|
2861
2859
|
var vars1 = this.getVars();
|
|
2862
2860
|
var vars2 = other.getVars();
|
|
2863
2861
|
|
|
@@ -2879,7 +2877,7 @@ _.extend(Expr.prototype, {
|
|
|
2879
2877
|
// semantic equality check, call after sameVars() to avoid potential false positives
|
|
2880
2878
|
// plug in random numbers for the variables in both expressions
|
|
2881
2879
|
// if they both consistently evaluate the same, then they're the same
|
|
2882
|
-
compare: function
|
|
2880
|
+
compare: function (other) {
|
|
2883
2881
|
// equation comparisons are handled by Eq.compare()
|
|
2884
2882
|
if (other instanceof Eq) {
|
|
2885
2883
|
return false;
|
|
@@ -2967,7 +2965,7 @@ _.extend(Expr.prototype, {
|
|
|
2967
2965
|
return true;
|
|
2968
2966
|
},
|
|
2969
2967
|
// evaluate as much of the expression as possible
|
|
2970
|
-
partialEval: function
|
|
2968
|
+
partialEval: function (vars) {
|
|
2971
2969
|
if (this instanceof Unit) {
|
|
2972
2970
|
return this;
|
|
2973
2971
|
} else if (!this.has(Func)) {
|
|
@@ -2982,19 +2980,19 @@ _.extend(Expr.prototype, {
|
|
|
2982
2980
|
// all negative signs are stripped and the expressions are converted to
|
|
2983
2981
|
// a canonical commutative form
|
|
2984
2982
|
// should only be done after compare() returns true to avoid false positives
|
|
2985
|
-
sameForm: function
|
|
2983
|
+
sameForm: function (other) {
|
|
2986
2984
|
return this.strip().equals(other.strip());
|
|
2987
2985
|
},
|
|
2988
2986
|
// returns the GCD of this expression and the given factor
|
|
2989
|
-
findGCD: function
|
|
2987
|
+
findGCD: function (factor) {
|
|
2990
2988
|
return this.equals(factor) ? factor : Num.One;
|
|
2991
2989
|
},
|
|
2992
2990
|
// return this expression's denominator
|
|
2993
|
-
getDenominator: function
|
|
2991
|
+
getDenominator: function () {
|
|
2994
2992
|
return Num.One;
|
|
2995
2993
|
},
|
|
2996
2994
|
// return this expression as a Mul
|
|
2997
|
-
asMul: function
|
|
2995
|
+
asMul: function () {
|
|
2998
2996
|
return new Mul(Num.One, this);
|
|
2999
2997
|
},
|
|
3000
2998
|
// TODO(alex): rename to isDefinitePositive or similar?
|
|
@@ -3002,15 +3000,15 @@ _.extend(Expr.prototype, {
|
|
|
3002
3000
|
isPositive: abstract,
|
|
3003
3001
|
// TODO(alex): rename to hasNegativeSign or similar?
|
|
3004
3002
|
// return whether this expression has a negative sign
|
|
3005
|
-
isNegative: function
|
|
3003
|
+
isNegative: function () {
|
|
3006
3004
|
return false;
|
|
3007
3005
|
},
|
|
3008
3006
|
// return a factor of this expression that is 100% positive
|
|
3009
|
-
asPositiveFactor: function
|
|
3007
|
+
asPositiveFactor: function () {
|
|
3010
3008
|
return this.isPositive() ? this : Num.One;
|
|
3011
3009
|
},
|
|
3012
3010
|
// return a copy of the expression with a new hint set (preserves hints)
|
|
3013
|
-
addHint: function
|
|
3011
|
+
addHint: function (hint) {
|
|
3014
3012
|
if (!hint) {
|
|
3015
3013
|
return this;
|
|
3016
3014
|
}
|
|
@@ -3023,15 +3021,15 @@ _.extend(Expr.prototype, {
|
|
|
3023
3021
|
parens: false
|
|
3024
3022
|
},
|
|
3025
3023
|
// currently unused!
|
|
3026
|
-
asExpr: function
|
|
3024
|
+
asExpr: function () {
|
|
3027
3025
|
return this;
|
|
3028
3026
|
},
|
|
3029
3027
|
// complete parse by performing a few necessary transformations
|
|
3030
|
-
completeParse: function
|
|
3028
|
+
completeParse: function () {
|
|
3031
3029
|
return this.recurse("completeParse");
|
|
3032
3030
|
},
|
|
3033
3031
|
abs: abstract,
|
|
3034
|
-
negate: function
|
|
3032
|
+
negate: function () {
|
|
3035
3033
|
return new Mul(Num.Neg, this);
|
|
3036
3034
|
}
|
|
3037
3035
|
});
|
|
@@ -3040,21 +3038,21 @@ _.extend(Expr.prototype, {
|
|
|
3040
3038
|
function Seq() {}
|
|
3041
3039
|
Seq.prototype = new Expr();
|
|
3042
3040
|
_.extend(Seq.prototype, {
|
|
3043
|
-
args: function
|
|
3041
|
+
args: function () {
|
|
3044
3042
|
return this.terms;
|
|
3045
3043
|
},
|
|
3046
|
-
normalize: function
|
|
3044
|
+
normalize: function () {
|
|
3047
3045
|
var terms = _.sortBy(_.invoke(this.terms, "normalize"), function (term) {
|
|
3048
3046
|
return term.print();
|
|
3049
3047
|
});
|
|
3050
3048
|
return new this.func(terms);
|
|
3051
3049
|
},
|
|
3052
|
-
expand: function
|
|
3050
|
+
expand: function () {
|
|
3053
3051
|
return this.recurse("expand").flatten();
|
|
3054
3052
|
},
|
|
3055
3053
|
// partition the sequence into its numeric and non-numeric parts
|
|
3056
3054
|
// makes no guarantees about the validity of either part!
|
|
3057
|
-
partition: function
|
|
3055
|
+
partition: function () {
|
|
3058
3056
|
var terms = _.groupBy(this.terms, function (term) {
|
|
3059
3057
|
return term instanceof Num;
|
|
3060
3058
|
});
|
|
@@ -3068,7 +3066,7 @@ _.extend(Seq.prototype, {
|
|
|
3068
3066
|
},
|
|
3069
3067
|
// ensure that sequences have 2+ terms and no nested sequences of the same type
|
|
3070
3068
|
// this is a shallow flattening and will return a non-Seq if terms.length <= 1
|
|
3071
|
-
flatten: function
|
|
3069
|
+
flatten: function () {
|
|
3072
3070
|
var type = this;
|
|
3073
3071
|
var terms = _.reject(this.terms, function (term) {
|
|
3074
3072
|
return term.equals(type.identity);
|
|
@@ -3093,14 +3091,14 @@ _.extend(Seq.prototype, {
|
|
|
3093
3091
|
identity: undefined,
|
|
3094
3092
|
// reduce a numeric sequence to a Num
|
|
3095
3093
|
reduce: abstract,
|
|
3096
|
-
isPositive: function
|
|
3094
|
+
isPositive: function () {
|
|
3097
3095
|
var terms = _.invoke(this.terms, "collect");
|
|
3098
3096
|
return _.all(_.invoke(terms, "isPositive"));
|
|
3099
3097
|
},
|
|
3100
3098
|
// return a new Seq with a given term replaced by a different term
|
|
3101
3099
|
// (or array of terms). given term can be passed directly, or by index
|
|
3102
3100
|
// if no new term is provided, the old one is simply removed
|
|
3103
|
-
replace: function
|
|
3101
|
+
replace: function (oldTerm, newTerm) {
|
|
3104
3102
|
var index;
|
|
3105
3103
|
if (oldTerm instanceof Expr) {
|
|
3106
3104
|
index = _.indexOf(this.terms, oldTerm);
|
|
@@ -3117,10 +3115,10 @@ _.extend(Seq.prototype, {
|
|
|
3117
3115
|
return new this.func(terms);
|
|
3118
3116
|
},
|
|
3119
3117
|
// syntactic sugar for replace()
|
|
3120
|
-
remove: function
|
|
3118
|
+
remove: function (term) {
|
|
3121
3119
|
return this.replace(term);
|
|
3122
3120
|
},
|
|
3123
|
-
getDenominator: function
|
|
3121
|
+
getDenominator: function () {
|
|
3124
3122
|
// TODO(alex): find and return LCM
|
|
3125
3123
|
return new Mul(_.invoke(this.terms, "getDenominator")).flatten();
|
|
3126
3124
|
}
|
|
@@ -3137,20 +3135,20 @@ function Add() {
|
|
|
3137
3135
|
Add.prototype = new Seq();
|
|
3138
3136
|
_.extend(Add.prototype, {
|
|
3139
3137
|
func: Add,
|
|
3140
|
-
eval: function
|
|
3138
|
+
eval: function (vars, options) {
|
|
3141
3139
|
return _.reduce(this.terms, function (memo, term) {
|
|
3142
3140
|
return memo + term.eval(vars, options);
|
|
3143
3141
|
}, 0);
|
|
3144
3142
|
},
|
|
3145
|
-
codegen: function
|
|
3143
|
+
codegen: function () {
|
|
3146
3144
|
return _.map(this.terms, function (term) {
|
|
3147
3145
|
return "(" + term.codegen() + ")";
|
|
3148
3146
|
}).join(" + ") || "0";
|
|
3149
3147
|
},
|
|
3150
|
-
print: function
|
|
3148
|
+
print: function () {
|
|
3151
3149
|
return _.invoke(this.terms, "print").join("+");
|
|
3152
3150
|
},
|
|
3153
|
-
tex: function
|
|
3151
|
+
tex: function () {
|
|
3154
3152
|
var tex = "";
|
|
3155
3153
|
_.each(this.terms, function (term) {
|
|
3156
3154
|
if (!tex || term.isSubtract()) {
|
|
@@ -3161,7 +3159,7 @@ _.extend(Add.prototype, {
|
|
|
3161
3159
|
});
|
|
3162
3160
|
return tex;
|
|
3163
3161
|
},
|
|
3164
|
-
collect: function
|
|
3162
|
+
collect: function (options) {
|
|
3165
3163
|
var terms = _.invoke(this.terms, "collect", options);
|
|
3166
3164
|
|
|
3167
3165
|
// [Expr expr, Num coefficient]
|
|
@@ -3195,7 +3193,7 @@ _.extend(Add.prototype, {
|
|
|
3195
3193
|
},
|
|
3196
3194
|
// naively factor out anything that is common to all terms
|
|
3197
3195
|
// if options.keepNegative is specified, won't factor out a common -1
|
|
3198
|
-
factor: function
|
|
3196
|
+
factor: function (options) {
|
|
3199
3197
|
options = _.extend({
|
|
3200
3198
|
keepNegative: false
|
|
3201
3199
|
}, options);
|
|
@@ -3221,19 +3219,19 @@ _.extend(Add.prototype, {
|
|
|
3221
3219
|
remainder = new Add(remainder).flatten();
|
|
3222
3220
|
return Mul.createOrAppend(factors, remainder).flatten();
|
|
3223
3221
|
},
|
|
3224
|
-
reduce: function
|
|
3222
|
+
reduce: function (options) {
|
|
3225
3223
|
return _.reduce(this.terms, function (memo, term) {
|
|
3226
3224
|
return memo.add(term, options);
|
|
3227
3225
|
}, this.identity);
|
|
3228
3226
|
},
|
|
3229
|
-
needsExplicitMul: function
|
|
3227
|
+
needsExplicitMul: function () {
|
|
3230
3228
|
return false;
|
|
3231
3229
|
},
|
|
3232
|
-
isNegative: function
|
|
3230
|
+
isNegative: function () {
|
|
3233
3231
|
var terms = _.invoke(this.terms, "collect");
|
|
3234
3232
|
return _.all(_.invoke(terms, "isNegative"));
|
|
3235
3233
|
},
|
|
3236
|
-
negate: function
|
|
3234
|
+
negate: function () {
|
|
3237
3235
|
return new Add(_.invoke(this.terms, "negate"));
|
|
3238
3236
|
}
|
|
3239
3237
|
});
|
|
@@ -3249,22 +3247,22 @@ function Mul() {
|
|
|
3249
3247
|
Mul.prototype = new Seq();
|
|
3250
3248
|
_.extend(Mul.prototype, {
|
|
3251
3249
|
func: Mul,
|
|
3252
|
-
eval: function
|
|
3250
|
+
eval: function (vars, options) {
|
|
3253
3251
|
return _.reduce(this.terms, function (memo, term) {
|
|
3254
3252
|
return memo * term.eval(vars, options);
|
|
3255
3253
|
}, 1);
|
|
3256
3254
|
},
|
|
3257
|
-
codegen: function
|
|
3255
|
+
codegen: function () {
|
|
3258
3256
|
return _.map(this.terms, function (term) {
|
|
3259
3257
|
return "(" + term.codegen() + ")";
|
|
3260
3258
|
}).join(" * ") || "0";
|
|
3261
3259
|
},
|
|
3262
|
-
print: function
|
|
3260
|
+
print: function () {
|
|
3263
3261
|
return _.map(this.terms, function (term) {
|
|
3264
3262
|
return term instanceof Add ? "(" + term.print() + ")" : term.print();
|
|
3265
3263
|
}).join("*");
|
|
3266
3264
|
},
|
|
3267
|
-
getUnits: function
|
|
3265
|
+
getUnits: function () {
|
|
3268
3266
|
var tmUnits = _(this.terms).chain().map(function (term) {
|
|
3269
3267
|
return term.getUnits();
|
|
3270
3268
|
}).flatten().value();
|
|
@@ -3273,7 +3271,7 @@ _.extend(Mul.prototype, {
|
|
|
3273
3271
|
},
|
|
3274
3272
|
// since we don't care about commutativity, we can render a Mul any way we choose
|
|
3275
3273
|
// so we follow convention: first any negatives, then any numbers, then everything else
|
|
3276
|
-
tex: function
|
|
3274
|
+
tex: function () {
|
|
3277
3275
|
var cdot = " \\cdot ";
|
|
3278
3276
|
var terms = _.groupBy(this.terms, function (term) {
|
|
3279
3277
|
if (term.isDivide()) {
|
|
@@ -3354,14 +3352,14 @@ _.extend(Mul.prototype, {
|
|
|
3354
3352
|
return negatives + "\\frac{" + numerator + "}{" + denominator + "}";
|
|
3355
3353
|
}
|
|
3356
3354
|
},
|
|
3357
|
-
strip: function
|
|
3355
|
+
strip: function () {
|
|
3358
3356
|
var terms = _.map(this.terms, function (term) {
|
|
3359
3357
|
return term instanceof Num ? term.abs() : term.strip();
|
|
3360
3358
|
});
|
|
3361
3359
|
return new Mul(terms).flatten();
|
|
3362
3360
|
},
|
|
3363
3361
|
// expand numerator and denominator separately
|
|
3364
|
-
expand: function
|
|
3362
|
+
expand: function () {
|
|
3365
3363
|
var isAdd = function isAdd(term) {
|
|
3366
3364
|
return term instanceof Add;
|
|
3367
3365
|
};
|
|
@@ -3408,7 +3406,7 @@ _.extend(Mul.prototype, {
|
|
|
3408
3406
|
}
|
|
3409
3407
|
return new Mul(normals.concat(inverses)).flatten();
|
|
3410
3408
|
},
|
|
3411
|
-
factor: function
|
|
3409
|
+
factor: function (options) {
|
|
3412
3410
|
var factored = this.recurse("factor", options).flatten();
|
|
3413
3411
|
if (!(factored instanceof Mul)) {
|
|
3414
3412
|
return factored;
|
|
@@ -3438,7 +3436,7 @@ _.extend(Mul.prototype, {
|
|
|
3438
3436
|
}
|
|
3439
3437
|
return new Mul((grouped[false] || []).concat(rational)).flatten();
|
|
3440
3438
|
},
|
|
3441
|
-
collect: function
|
|
3439
|
+
collect: function (options) {
|
|
3442
3440
|
var partitioned = this.recurse("collect", options).partition();
|
|
3443
3441
|
var number = partitioned[0].reduce(options);
|
|
3444
3442
|
|
|
@@ -3569,14 +3567,14 @@ _.extend(Mul.prototype, {
|
|
|
3569
3567
|
});
|
|
3570
3568
|
return new Mul([number].concat(collected)).flatten();
|
|
3571
3569
|
},
|
|
3572
|
-
isSubtract: function
|
|
3570
|
+
isSubtract: function () {
|
|
3573
3571
|
return _.any(this.terms, function (term) {
|
|
3574
3572
|
return term instanceof Num && term.hints.subtract;
|
|
3575
3573
|
});
|
|
3576
3574
|
},
|
|
3577
3575
|
// factor a single -1 in to the Mul
|
|
3578
3576
|
// combine with a Num if all Nums are positive, else add as a term
|
|
3579
|
-
factorIn: function
|
|
3577
|
+
factorIn: function (hint) {
|
|
3580
3578
|
var partitioned = this.partition();
|
|
3581
3579
|
var numbers = partitioned[0].terms;
|
|
3582
3580
|
var fold = numbers.length && _.all(numbers, function (num) {
|
|
@@ -3595,7 +3593,7 @@ _.extend(Mul.prototype, {
|
|
|
3595
3593
|
},
|
|
3596
3594
|
// factor out a single hinted -1 (assume it is the division hint)
|
|
3597
3595
|
// TODO(alex): make more general or rename to be more specific
|
|
3598
|
-
factorOut: function
|
|
3596
|
+
factorOut: function () {
|
|
3599
3597
|
var factored = false;
|
|
3600
3598
|
var terms = _.compact(_.map(this.terms, function (term, i, list) {
|
|
3601
3599
|
if (!factored && term instanceof Num && term.hints.divide) {
|
|
@@ -3611,18 +3609,18 @@ _.extend(Mul.prototype, {
|
|
|
3611
3609
|
return new Mul(terms);
|
|
3612
3610
|
}
|
|
3613
3611
|
},
|
|
3614
|
-
reduce: function
|
|
3612
|
+
reduce: function (options) {
|
|
3615
3613
|
return _.reduce(this.terms, function (memo, term) {
|
|
3616
3614
|
return memo.mul(term, options);
|
|
3617
3615
|
}, this.identity);
|
|
3618
3616
|
},
|
|
3619
|
-
findGCD: function
|
|
3617
|
+
findGCD: function (factor) {
|
|
3620
3618
|
return new Mul(_.invoke(this.terms, "findGCD", factor)).flatten();
|
|
3621
3619
|
},
|
|
3622
|
-
asMul: function
|
|
3620
|
+
asMul: function () {
|
|
3623
3621
|
return this;
|
|
3624
3622
|
},
|
|
3625
|
-
asPositiveFactor: function
|
|
3623
|
+
asPositiveFactor: function () {
|
|
3626
3624
|
if (this.isPositive()) {
|
|
3627
3625
|
return this;
|
|
3628
3626
|
} else {
|
|
@@ -3630,13 +3628,13 @@ _.extend(Mul.prototype, {
|
|
|
3630
3628
|
return new Mul(terms).flatten();
|
|
3631
3629
|
}
|
|
3632
3630
|
},
|
|
3633
|
-
isNegative: function
|
|
3631
|
+
isNegative: function () {
|
|
3634
3632
|
return _.any(_.invoke(this.collect().terms, "isNegative"));
|
|
3635
3633
|
},
|
|
3636
|
-
fold: function
|
|
3634
|
+
fold: function () {
|
|
3637
3635
|
return Mul.fold(this);
|
|
3638
3636
|
},
|
|
3639
|
-
negate: function
|
|
3637
|
+
negate: function () {
|
|
3640
3638
|
var isNum = function isNum(expr) {
|
|
3641
3639
|
return expr instanceof Num;
|
|
3642
3640
|
};
|
|
@@ -3653,7 +3651,7 @@ _.extend(Mul.prototype, {
|
|
|
3653
3651
|
_.each([Add, Mul], function (type) {
|
|
3654
3652
|
_.extend(type, {
|
|
3655
3653
|
// create a new sequence unless left is already one (returns a copy)
|
|
3656
|
-
createOrAppend: function
|
|
3654
|
+
createOrAppend: function (left, right) {
|
|
3657
3655
|
if (left instanceof type) {
|
|
3658
3656
|
return new type(left.terms.concat(right));
|
|
3659
3657
|
} else {
|
|
@@ -3667,7 +3665,7 @@ _.extend(Mul, {
|
|
|
3667
3665
|
// never fold into a Num that's already negative or a Mul that has a negative Num
|
|
3668
3666
|
// an optional hint is kept track of to properly render user input
|
|
3669
3667
|
// an empty hint means negation
|
|
3670
|
-
handleNegative: function
|
|
3668
|
+
handleNegative: function (expr, hint) {
|
|
3671
3669
|
if (expr instanceof Num && expr.n > 0) {
|
|
3672
3670
|
// e.g. - 2 -> -2
|
|
3673
3671
|
var negated = expr.negate();
|
|
@@ -3685,7 +3683,7 @@ _.extend(Mul, {
|
|
|
3685
3683
|
}
|
|
3686
3684
|
},
|
|
3687
3685
|
// division can create either a Rational or a Mul
|
|
3688
|
-
handleDivide: function
|
|
3686
|
+
handleDivide: function (left, right) {
|
|
3689
3687
|
// dividing by a Mul is the same as repeated division by its terms
|
|
3690
3688
|
if (right instanceof Mul) {
|
|
3691
3689
|
var first = Mul.handleDivide(left, right.terms[0]);
|
|
@@ -3791,7 +3789,7 @@ _.extend(Mul, {
|
|
|
3791
3789
|
// e.g. sin(x)*x -> sin(x)*x
|
|
3792
3790
|
// e.g. sin(x)*(x) -> sin(x)*x
|
|
3793
3791
|
// e.g. sin(x)*sin(y) -> sin(x)*sin(y)
|
|
3794
|
-
fold: function
|
|
3792
|
+
fold: function (expr) {
|
|
3795
3793
|
if (expr instanceof Mul) {
|
|
3796
3794
|
// assuming that this will be second to last
|
|
3797
3795
|
var trigLog = _.find(_.initial(expr.terms), function (term) {
|
|
@@ -3851,10 +3849,10 @@ function Pow(base, exp) {
|
|
|
3851
3849
|
Pow.prototype = new Expr();
|
|
3852
3850
|
_.extend(Pow.prototype, {
|
|
3853
3851
|
func: Pow,
|
|
3854
|
-
args: function
|
|
3852
|
+
args: function () {
|
|
3855
3853
|
return [this.base, this.exp];
|
|
3856
3854
|
},
|
|
3857
|
-
eval: function
|
|
3855
|
+
eval: function (vars, options) {
|
|
3858
3856
|
var evaledBase = this.base.eval(vars, options);
|
|
3859
3857
|
var evaledExp = this.exp.eval(vars, options);
|
|
3860
3858
|
|
|
@@ -3889,7 +3887,7 @@ _.extend(Pow.prototype, {
|
|
|
3889
3887
|
}
|
|
3890
3888
|
return Math.pow(evaledBase, evaledExp);
|
|
3891
3889
|
},
|
|
3892
|
-
getUnits: function
|
|
3890
|
+
getUnits: function () {
|
|
3893
3891
|
return this.base.getUnits().map(function (unit) {
|
|
3894
3892
|
return {
|
|
3895
3893
|
unit: unit.unit,
|
|
@@ -3897,17 +3895,17 @@ _.extend(Pow.prototype, {
|
|
|
3897
3895
|
};
|
|
3898
3896
|
}.bind(this));
|
|
3899
3897
|
},
|
|
3900
|
-
codegen: function
|
|
3898
|
+
codegen: function () {
|
|
3901
3899
|
return "Math.pow(" + this.base.codegen() + ", " + this.exp.codegen() + ")";
|
|
3902
3900
|
},
|
|
3903
|
-
print: function
|
|
3901
|
+
print: function () {
|
|
3904
3902
|
var base = this.base.print();
|
|
3905
3903
|
if (this.base instanceof Seq || this.base instanceof Pow) {
|
|
3906
3904
|
base = "(" + base + ")";
|
|
3907
3905
|
}
|
|
3908
3906
|
return base + "^(" + this.exp.print() + ")";
|
|
3909
3907
|
},
|
|
3910
|
-
tex: function
|
|
3908
|
+
tex: function () {
|
|
3911
3909
|
if (this.isDivide()) {
|
|
3912
3910
|
// e.g. x ^ -1 w/hint -> 1/x
|
|
3913
3911
|
return "\\frac{1}{" + this.asDivide().tex() + "}";
|
|
@@ -3941,10 +3939,10 @@ _.extend(Pow.prototype, {
|
|
|
3941
3939
|
return base + "^{" + this.exp.tex() + "}";
|
|
3942
3940
|
}
|
|
3943
3941
|
},
|
|
3944
|
-
needsExplicitMul: function
|
|
3942
|
+
needsExplicitMul: function () {
|
|
3945
3943
|
return this.isRoot() ? false : this.base.needsExplicitMul();
|
|
3946
3944
|
},
|
|
3947
|
-
expand: function
|
|
3945
|
+
expand: function () {
|
|
3948
3946
|
var pow = this.recurse("expand");
|
|
3949
3947
|
if (pow.base instanceof Mul) {
|
|
3950
3948
|
// e.g. (ab)^c -> a^c*b^c
|
|
@@ -3998,7 +3996,7 @@ _.extend(Pow.prototype, {
|
|
|
3998
3996
|
return pow;
|
|
3999
3997
|
}
|
|
4000
3998
|
},
|
|
4001
|
-
factor: function
|
|
3999
|
+
factor: function () {
|
|
4002
4000
|
var pow = this.recurse("factor");
|
|
4003
4001
|
if (pow.base instanceof Mul) {
|
|
4004
4002
|
var terms = _.map(pow.base.terms, function (term) {
|
|
@@ -4015,7 +4013,7 @@ _.extend(Pow.prototype, {
|
|
|
4015
4013
|
return pow;
|
|
4016
4014
|
}
|
|
4017
4015
|
},
|
|
4018
|
-
collect: function
|
|
4016
|
+
collect: function (options) {
|
|
4019
4017
|
if (this.base instanceof Pow) {
|
|
4020
4018
|
// collect this first to avoid having to deal with float precision
|
|
4021
4019
|
// e.g. sqrt(2)^2 -> 2, not 2.0000000000000004
|
|
@@ -4075,14 +4073,14 @@ _.extend(Pow.prototype, {
|
|
|
4075
4073
|
}
|
|
4076
4074
|
},
|
|
4077
4075
|
// checks whether this Pow represents user-entered division
|
|
4078
|
-
isDivide: function
|
|
4076
|
+
isDivide: function () {
|
|
4079
4077
|
var isDiv = function isDiv(arg) {
|
|
4080
4078
|
return arg instanceof Num && arg.hints.divide;
|
|
4081
4079
|
};
|
|
4082
4080
|
return isDiv(this.exp) || this.exp instanceof Mul && _.any(this.exp.terms, isDiv);
|
|
4083
4081
|
},
|
|
4084
4082
|
// assuming this Pow represents user-entered division, returns the denominator
|
|
4085
|
-
asDivide: function
|
|
4083
|
+
asDivide: function () {
|
|
4086
4084
|
if (this.exp instanceof Num) {
|
|
4087
4085
|
if (this.exp.eval() === -1) {
|
|
4088
4086
|
return this.base;
|
|
@@ -4098,15 +4096,15 @@ _.extend(Pow.prototype, {
|
|
|
4098
4096
|
error("called asDivide() on an Expr that wasn't a Num or Mul");
|
|
4099
4097
|
}
|
|
4100
4098
|
},
|
|
4101
|
-
isRoot: function
|
|
4099
|
+
isRoot: function () {
|
|
4102
4100
|
return this.exp instanceof Rational && this.exp.hints.root;
|
|
4103
4101
|
},
|
|
4104
|
-
isSquaredTrig: function
|
|
4102
|
+
isSquaredTrig: function () {
|
|
4105
4103
|
return this.base instanceof Trig && !this.base.isInverse() && this.exp instanceof Num && this.exp.eval() === 2;
|
|
4106
4104
|
},
|
|
4107
4105
|
// extract whatever denominator makes sense, ignoring hints
|
|
4108
4106
|
// if negative exponent, will recursively include the base's denominator as well
|
|
4109
|
-
getDenominator: function
|
|
4107
|
+
getDenominator: function () {
|
|
4110
4108
|
if (this.exp instanceof Num && this.exp.eval() === -1) {
|
|
4111
4109
|
return Mul.createOrAppend(this.base, this.base.getDenominator()).flatten();
|
|
4112
4110
|
} else if (this.exp.isNegative()) {
|
|
@@ -4118,7 +4116,7 @@ _.extend(Pow.prototype, {
|
|
|
4118
4116
|
return Num.One;
|
|
4119
4117
|
}
|
|
4120
4118
|
},
|
|
4121
|
-
findGCD: function
|
|
4119
|
+
findGCD: function (factor) {
|
|
4122
4120
|
var base, exp;
|
|
4123
4121
|
if (factor instanceof Pow) {
|
|
4124
4122
|
base = factor.base;
|
|
@@ -4155,14 +4153,14 @@ _.extend(Pow.prototype, {
|
|
|
4155
4153
|
}
|
|
4156
4154
|
return Num.One;
|
|
4157
4155
|
},
|
|
4158
|
-
isPositive: function
|
|
4156
|
+
isPositive: function () {
|
|
4159
4157
|
if (this.base.isPositive()) {
|
|
4160
4158
|
return true;
|
|
4161
4159
|
}
|
|
4162
4160
|
var exp = this.exp.simplify();
|
|
4163
4161
|
return exp instanceof Int && exp.eval() % 2 === 0;
|
|
4164
4162
|
},
|
|
4165
|
-
asPositiveFactor: function
|
|
4163
|
+
asPositiveFactor: function () {
|
|
4166
4164
|
if (this.isPositive()) {
|
|
4167
4165
|
return this;
|
|
4168
4166
|
} else {
|
|
@@ -4182,10 +4180,10 @@ _.extend(Pow.prototype, {
|
|
|
4182
4180
|
}
|
|
4183
4181
|
});
|
|
4184
4182
|
_.extend(Pow, {
|
|
4185
|
-
sqrt: function
|
|
4183
|
+
sqrt: function (arg) {
|
|
4186
4184
|
return new Pow(arg, Num.Sqrt);
|
|
4187
4185
|
},
|
|
4188
|
-
nthroot: function
|
|
4186
|
+
nthroot: function (radicand, degree) {
|
|
4189
4187
|
var exp = Mul.fold(Mul.handleDivide(new Int(1), degree));
|
|
4190
4188
|
|
|
4191
4189
|
// FIXME(johnsullivan): If oneOverDegree ends up being a pow object,
|
|
@@ -4202,16 +4200,16 @@ function Log(base, power) {
|
|
|
4202
4200
|
Log.prototype = new Expr();
|
|
4203
4201
|
_.extend(Log.prototype, {
|
|
4204
4202
|
func: Log,
|
|
4205
|
-
args: function
|
|
4203
|
+
args: function () {
|
|
4206
4204
|
return [this.base, this.power];
|
|
4207
4205
|
},
|
|
4208
|
-
eval: function
|
|
4206
|
+
eval: function (vars, options) {
|
|
4209
4207
|
return Math.log(this.power.eval(vars, options)) / Math.log(this.base.eval(vars, options));
|
|
4210
4208
|
},
|
|
4211
|
-
codegen: function
|
|
4209
|
+
codegen: function () {
|
|
4212
4210
|
return "(Math.log(" + this.power.codegen() + ") / Math.log(" + this.base.codegen() + "))";
|
|
4213
4211
|
},
|
|
4214
|
-
print: function
|
|
4212
|
+
print: function () {
|
|
4215
4213
|
var power = "(" + this.power.print() + ")";
|
|
4216
4214
|
if (this.isNatural()) {
|
|
4217
4215
|
return "ln" + power;
|
|
@@ -4219,7 +4217,7 @@ _.extend(Log.prototype, {
|
|
|
4219
4217
|
return "log_(" + this.base.print() + ") " + power;
|
|
4220
4218
|
}
|
|
4221
4219
|
},
|
|
4222
|
-
tex: function
|
|
4220
|
+
tex: function () {
|
|
4223
4221
|
var power = "(" + this.power.tex() + ")";
|
|
4224
4222
|
if (this.isNatural()) {
|
|
4225
4223
|
return "\\ln" + power;
|
|
@@ -4227,7 +4225,7 @@ _.extend(Log.prototype, {
|
|
|
4227
4225
|
return "\\log_{" + this.base.tex() + "}" + power;
|
|
4228
4226
|
}
|
|
4229
4227
|
},
|
|
4230
|
-
collect: function
|
|
4228
|
+
collect: function (options) {
|
|
4231
4229
|
var log = this.recurse("collect", options);
|
|
4232
4230
|
if (log.power instanceof Num && log.power.eval() === 1) {
|
|
4233
4231
|
// e.g. ln(1) -> 0
|
|
@@ -4242,7 +4240,7 @@ _.extend(Log.prototype, {
|
|
|
4242
4240
|
return log;
|
|
4243
4241
|
}
|
|
4244
4242
|
},
|
|
4245
|
-
expand: function
|
|
4243
|
+
expand: function () {
|
|
4246
4244
|
var log = this.recurse("expand");
|
|
4247
4245
|
if (log.power instanceof Mul) {
|
|
4248
4246
|
// might want behind super-simplify() flag
|
|
@@ -4268,7 +4266,7 @@ _.extend(Log.prototype, {
|
|
|
4268
4266
|
hints: _.extend(Log.prototype.hints, {
|
|
4269
4267
|
open: false
|
|
4270
4268
|
}),
|
|
4271
|
-
isPositive: function
|
|
4269
|
+
isPositive: function () {
|
|
4272
4270
|
var log = this.collect();
|
|
4273
4271
|
if (log.base instanceof Num && log.power instanceof Num) {
|
|
4274
4272
|
return this.eval() > 0;
|
|
@@ -4276,21 +4274,21 @@ _.extend(Log.prototype, {
|
|
|
4276
4274
|
return false;
|
|
4277
4275
|
}
|
|
4278
4276
|
},
|
|
4279
|
-
needsExplicitMul: function
|
|
4277
|
+
needsExplicitMul: function () {
|
|
4280
4278
|
return false;
|
|
4281
4279
|
},
|
|
4282
|
-
isNatural: function
|
|
4280
|
+
isNatural: function () {
|
|
4283
4281
|
return this.base.equals(Const.e);
|
|
4284
4282
|
}
|
|
4285
4283
|
});
|
|
4286
4284
|
_.extend(Log, {
|
|
4287
|
-
natural: function
|
|
4285
|
+
natural: function () {
|
|
4288
4286
|
return Const.e;
|
|
4289
4287
|
},
|
|
4290
|
-
common: function
|
|
4288
|
+
common: function () {
|
|
4291
4289
|
return Num.Ten;
|
|
4292
4290
|
},
|
|
4293
|
-
create: function
|
|
4291
|
+
create: function (base, power) {
|
|
4294
4292
|
var log = new Log(base, power);
|
|
4295
4293
|
if (!power.hints.parens) {
|
|
4296
4294
|
log = log.addHint("open");
|
|
@@ -4307,7 +4305,7 @@ function Trig(type, arg) {
|
|
|
4307
4305
|
Trig.prototype = new Expr();
|
|
4308
4306
|
_.extend(Trig.prototype, {
|
|
4309
4307
|
func: Trig,
|
|
4310
|
-
args: function
|
|
4308
|
+
args: function () {
|
|
4311
4309
|
return [this.type, this.arg];
|
|
4312
4310
|
},
|
|
4313
4311
|
functions: {
|
|
@@ -4315,7 +4313,7 @@ _.extend(Trig.prototype, {
|
|
|
4315
4313
|
eval: Math.sin,
|
|
4316
4314
|
codegen: "Math.sin((",
|
|
4317
4315
|
tex: "\\sin",
|
|
4318
|
-
expand: function
|
|
4316
|
+
expand: function () {
|
|
4319
4317
|
return this;
|
|
4320
4318
|
}
|
|
4321
4319
|
},
|
|
@@ -4323,7 +4321,7 @@ _.extend(Trig.prototype, {
|
|
|
4323
4321
|
eval: Math.cos,
|
|
4324
4322
|
codegen: "Math.cos((",
|
|
4325
4323
|
tex: "\\cos",
|
|
4326
|
-
expand: function
|
|
4324
|
+
expand: function () {
|
|
4327
4325
|
return this;
|
|
4328
4326
|
}
|
|
4329
4327
|
},
|
|
@@ -4331,37 +4329,37 @@ _.extend(Trig.prototype, {
|
|
|
4331
4329
|
eval: Math.tan,
|
|
4332
4330
|
codegen: "Math.tan((",
|
|
4333
4331
|
tex: "\\tan",
|
|
4334
|
-
expand: function
|
|
4332
|
+
expand: function () {
|
|
4335
4333
|
return Mul.handleDivide(Trig.sin(this.arg), Trig.cos(this.arg));
|
|
4336
4334
|
}
|
|
4337
4335
|
},
|
|
4338
4336
|
csc: {
|
|
4339
|
-
eval: function
|
|
4337
|
+
eval: function (arg) {
|
|
4340
4338
|
return 1 / Math.sin(arg);
|
|
4341
4339
|
},
|
|
4342
4340
|
codegen: "(1/Math.sin(",
|
|
4343
4341
|
tex: "\\csc",
|
|
4344
|
-
expand: function
|
|
4342
|
+
expand: function () {
|
|
4345
4343
|
return Mul.handleDivide(Num.One, Trig.sin(this.arg));
|
|
4346
4344
|
}
|
|
4347
4345
|
},
|
|
4348
4346
|
sec: {
|
|
4349
|
-
eval: function
|
|
4347
|
+
eval: function (arg) {
|
|
4350
4348
|
return 1 / Math.cos(arg);
|
|
4351
4349
|
},
|
|
4352
4350
|
codegen: "(1/Math.cos(",
|
|
4353
4351
|
tex: "\\sec",
|
|
4354
|
-
expand: function
|
|
4352
|
+
expand: function () {
|
|
4355
4353
|
return Mul.handleDivide(Num.One, Trig.cos(this.arg));
|
|
4356
4354
|
}
|
|
4357
4355
|
},
|
|
4358
4356
|
cot: {
|
|
4359
|
-
eval: function
|
|
4357
|
+
eval: function (arg) {
|
|
4360
4358
|
return 1 / Math.tan(arg);
|
|
4361
4359
|
},
|
|
4362
4360
|
codegen: "(1/Math.tan(",
|
|
4363
4361
|
tex: "\\cot",
|
|
4364
|
-
expand: function
|
|
4362
|
+
expand: function () {
|
|
4365
4363
|
return Mul.handleDivide(Trig.cos(this.arg), Trig.sin(this.arg));
|
|
4366
4364
|
}
|
|
4367
4365
|
},
|
|
@@ -4381,114 +4379,114 @@ _.extend(Trig.prototype, {
|
|
|
4381
4379
|
tex: "\\arctan"
|
|
4382
4380
|
},
|
|
4383
4381
|
arccsc: {
|
|
4384
|
-
eval: function
|
|
4382
|
+
eval: function (arg) {
|
|
4385
4383
|
return Math.asin(1 / arg);
|
|
4386
4384
|
},
|
|
4387
4385
|
codegen: "Math.asin(1/(",
|
|
4388
4386
|
tex: "\\operatorname{arccsc}"
|
|
4389
4387
|
},
|
|
4390
4388
|
arcsec: {
|
|
4391
|
-
eval: function
|
|
4389
|
+
eval: function (arg) {
|
|
4392
4390
|
return Math.acos(1 / arg);
|
|
4393
4391
|
},
|
|
4394
4392
|
codegen: "Math.acos(1/(",
|
|
4395
4393
|
tex: "\\operatorname{arcsec}"
|
|
4396
4394
|
},
|
|
4397
4395
|
arccot: {
|
|
4398
|
-
eval: function
|
|
4396
|
+
eval: function (arg) {
|
|
4399
4397
|
return Math.atan(1 / arg);
|
|
4400
4398
|
},
|
|
4401
4399
|
codegen: "Math.atan(1/(",
|
|
4402
4400
|
tex: "\\operatorname{arccot}"
|
|
4403
4401
|
},
|
|
4404
4402
|
sinh: {
|
|
4405
|
-
eval: function
|
|
4403
|
+
eval: function (arg) {
|
|
4406
4404
|
return (Math.exp(arg) - Math.exp(-arg)) / 2;
|
|
4407
4405
|
},
|
|
4408
|
-
codegen: function
|
|
4406
|
+
codegen: function (argStr) {
|
|
4409
4407
|
return "((Math.exp(" + argStr + ") - Math.exp(-(" + argStr + "))) / 2)";
|
|
4410
4408
|
},
|
|
4411
4409
|
tex: "\\sinh",
|
|
4412
|
-
expand: function
|
|
4410
|
+
expand: function () {
|
|
4413
4411
|
return this;
|
|
4414
4412
|
}
|
|
4415
4413
|
},
|
|
4416
4414
|
cosh: {
|
|
4417
|
-
eval: function
|
|
4415
|
+
eval: function (arg) {
|
|
4418
4416
|
return (Math.exp(arg) + Math.exp(-arg)) / 2;
|
|
4419
4417
|
},
|
|
4420
|
-
codegen: function
|
|
4418
|
+
codegen: function (argStr) {
|
|
4421
4419
|
return "((Math.exp(" + argStr + ") + Math.exp(-(" + argStr + "))) / 2)";
|
|
4422
4420
|
},
|
|
4423
4421
|
tex: "\\cosh",
|
|
4424
|
-
expand: function
|
|
4422
|
+
expand: function () {
|
|
4425
4423
|
return this;
|
|
4426
4424
|
}
|
|
4427
4425
|
},
|
|
4428
4426
|
tanh: {
|
|
4429
|
-
eval: function
|
|
4427
|
+
eval: function (arg) {
|
|
4430
4428
|
return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
|
|
4431
4429
|
},
|
|
4432
|
-
codegen: function
|
|
4430
|
+
codegen: function (argStr) {
|
|
4433
4431
|
return "(" + "(Math.exp(" + argStr + ") - Math.exp(-(" + argStr + ")))" + " / " + "(Math.exp(" + argStr + ") + Math.exp(-(" + argStr + ")))" + ")";
|
|
4434
4432
|
},
|
|
4435
4433
|
tex: "\\tanh",
|
|
4436
|
-
expand: function
|
|
4434
|
+
expand: function () {
|
|
4437
4435
|
return Mul.handleDivide(Trig.sinh(this.arg), Trig.cosh(this.arg));
|
|
4438
4436
|
}
|
|
4439
4437
|
},
|
|
4440
4438
|
csch: {
|
|
4441
|
-
eval: function
|
|
4439
|
+
eval: function (arg) {
|
|
4442
4440
|
return 2 / (Math.exp(arg) - Math.exp(-arg));
|
|
4443
4441
|
},
|
|
4444
|
-
codegen: function
|
|
4442
|
+
codegen: function (argStr) {
|
|
4445
4443
|
return "(2 / (Math.exp(" + argStr + ") - Math.exp(-(" + argStr + "))))";
|
|
4446
4444
|
},
|
|
4447
4445
|
tex: "\\csch",
|
|
4448
|
-
expand: function
|
|
4446
|
+
expand: function () {
|
|
4449
4447
|
return Mul.handleDivide(Num.One, Trig.sinh(this.arg));
|
|
4450
4448
|
}
|
|
4451
4449
|
},
|
|
4452
4450
|
sech: {
|
|
4453
|
-
eval: function
|
|
4451
|
+
eval: function (arg) {
|
|
4454
4452
|
return 2 / (Math.exp(arg) + Math.exp(-arg));
|
|
4455
4453
|
},
|
|
4456
|
-
codegen: function
|
|
4454
|
+
codegen: function (argStr) {
|
|
4457
4455
|
return "(2 / (Math.exp(" + argStr + ") + Math.exp(-(" + argStr + "))))";
|
|
4458
4456
|
},
|
|
4459
4457
|
tex: "\\sech",
|
|
4460
|
-
expand: function
|
|
4458
|
+
expand: function () {
|
|
4461
4459
|
return Mul.handleDivide(Num.One, Trig.cosh(this.arg));
|
|
4462
4460
|
}
|
|
4463
4461
|
},
|
|
4464
4462
|
coth: {
|
|
4465
|
-
eval: function
|
|
4463
|
+
eval: function (arg) {
|
|
4466
4464
|
return (Math.exp(arg) + Math.exp(-arg)) / (Math.exp(arg) - Math.exp(-arg));
|
|
4467
4465
|
},
|
|
4468
|
-
codegen: function
|
|
4466
|
+
codegen: function (argStr) {
|
|
4469
4467
|
return "(" + "(Math.exp(" + argStr + ") + Math.exp(-(" + argStr + ")))" + " / " + "(Math.exp(" + argStr + ") - Math.exp(-(" + argStr + ")))" + ")";
|
|
4470
4468
|
},
|
|
4471
4469
|
tex: "\\coth",
|
|
4472
|
-
expand: function
|
|
4470
|
+
expand: function () {
|
|
4473
4471
|
return Mul.handleDivide(Trig.cosh(this.arg), Trig.sinh(this.arg));
|
|
4474
4472
|
}
|
|
4475
4473
|
}
|
|
4476
4474
|
},
|
|
4477
|
-
isEven: function
|
|
4475
|
+
isEven: function () {
|
|
4478
4476
|
return _.contains(["cos", "sec"], this.type);
|
|
4479
4477
|
},
|
|
4480
|
-
isInverse: function
|
|
4478
|
+
isInverse: function () {
|
|
4481
4479
|
return this.type.indexOf("arc") === 0;
|
|
4482
4480
|
},
|
|
4483
|
-
isBasic: function
|
|
4481
|
+
isBasic: function () {
|
|
4484
4482
|
return _.contains(["sin", "cos"], this.type);
|
|
4485
4483
|
},
|
|
4486
|
-
eval: function
|
|
4484
|
+
eval: function (vars, options) {
|
|
4487
4485
|
var func = this.functions[this.type].eval;
|
|
4488
4486
|
var arg = this.arg.eval(vars, options);
|
|
4489
4487
|
return func(arg);
|
|
4490
4488
|
},
|
|
4491
|
-
codegen: function
|
|
4489
|
+
codegen: function () {
|
|
4492
4490
|
var func = this.functions[this.type].codegen;
|
|
4493
4491
|
if (typeof func === "function") {
|
|
4494
4492
|
return func(this.arg.codegen());
|
|
@@ -4498,10 +4496,10 @@ _.extend(Trig.prototype, {
|
|
|
4498
4496
|
throw new Error("codegen not implemented for " + this.type);
|
|
4499
4497
|
}
|
|
4500
4498
|
},
|
|
4501
|
-
print: function
|
|
4499
|
+
print: function () {
|
|
4502
4500
|
return this.type + "(" + this.arg.print() + ")";
|
|
4503
4501
|
},
|
|
4504
|
-
tex: function
|
|
4502
|
+
tex: function (options) {
|
|
4505
4503
|
var func = this.functions[this.type].tex;
|
|
4506
4504
|
var arg = "(" + this.arg.tex() + ")";
|
|
4507
4505
|
return options && options.split ? [func, arg] : func + arg;
|
|
@@ -4509,7 +4507,7 @@ _.extend(Trig.prototype, {
|
|
|
4509
4507
|
hints: _.extend(Trig.prototype.hints, {
|
|
4510
4508
|
open: false
|
|
4511
4509
|
}),
|
|
4512
|
-
isPositive: function
|
|
4510
|
+
isPositive: function () {
|
|
4513
4511
|
var trig = this.collect();
|
|
4514
4512
|
if (trig.arg instanceof Num) {
|
|
4515
4513
|
return this.eval() > 0;
|
|
@@ -4517,7 +4515,7 @@ _.extend(Trig.prototype, {
|
|
|
4517
4515
|
return false;
|
|
4518
4516
|
}
|
|
4519
4517
|
},
|
|
4520
|
-
completeParse: function
|
|
4518
|
+
completeParse: function () {
|
|
4521
4519
|
if (this.exp) {
|
|
4522
4520
|
var pow = new Pow(this, this.exp);
|
|
4523
4521
|
this.exp = undefined;
|
|
@@ -4527,10 +4525,10 @@ _.extend(Trig.prototype, {
|
|
|
4527
4525
|
}
|
|
4528
4526
|
},
|
|
4529
4527
|
// TODO(alex): does every new node type need to redefine these?
|
|
4530
|
-
needsExplicitMul: function
|
|
4528
|
+
needsExplicitMul: function () {
|
|
4531
4529
|
return false;
|
|
4532
4530
|
},
|
|
4533
|
-
expand: function
|
|
4531
|
+
expand: function () {
|
|
4534
4532
|
var trig = this.recurse("expand");
|
|
4535
4533
|
if (!trig.isInverse()) {
|
|
4536
4534
|
// e.g. tan(x) -> sin(x)/cos(x)
|
|
@@ -4540,7 +4538,7 @@ _.extend(Trig.prototype, {
|
|
|
4540
4538
|
return trig;
|
|
4541
4539
|
}
|
|
4542
4540
|
},
|
|
4543
|
-
collect: function
|
|
4541
|
+
collect: function (options) {
|
|
4544
4542
|
var trig = this.recurse("collect", options);
|
|
4545
4543
|
if (!trig.isInverse() && trig.arg.isNegative()) {
|
|
4546
4544
|
var arg;
|
|
@@ -4562,7 +4560,7 @@ _.extend(Trig.prototype, {
|
|
|
4562
4560
|
}
|
|
4563
4561
|
});
|
|
4564
4562
|
_.extend(Trig, {
|
|
4565
|
-
create: function
|
|
4563
|
+
create: function (pair, arg) {
|
|
4566
4564
|
var type = pair[0];
|
|
4567
4565
|
var exp = pair[1];
|
|
4568
4566
|
if (exp && exp.equals(Num.Neg)) {
|
|
@@ -4579,16 +4577,16 @@ _.extend(Trig, {
|
|
|
4579
4577
|
}
|
|
4580
4578
|
return trig;
|
|
4581
4579
|
},
|
|
4582
|
-
sin: function
|
|
4580
|
+
sin: function (arg) {
|
|
4583
4581
|
return new Trig("sin", arg);
|
|
4584
4582
|
},
|
|
4585
|
-
cos: function
|
|
4583
|
+
cos: function (arg) {
|
|
4586
4584
|
return new Trig("cos", arg);
|
|
4587
4585
|
},
|
|
4588
|
-
sinh: function
|
|
4586
|
+
sinh: function (arg) {
|
|
4589
4587
|
return new Trig("sinh", arg);
|
|
4590
4588
|
},
|
|
4591
|
-
cosh: function
|
|
4589
|
+
cosh: function (arg) {
|
|
4592
4590
|
return new Trig("cosh", arg);
|
|
4593
4591
|
}
|
|
4594
4592
|
});
|
|
@@ -4598,22 +4596,22 @@ function Abs(arg) {
|
|
|
4598
4596
|
Abs.prototype = new Expr();
|
|
4599
4597
|
_.extend(Abs.prototype, {
|
|
4600
4598
|
func: Abs,
|
|
4601
|
-
args: function
|
|
4599
|
+
args: function () {
|
|
4602
4600
|
return [this.arg];
|
|
4603
4601
|
},
|
|
4604
|
-
eval: function
|
|
4602
|
+
eval: function (vars, options) {
|
|
4605
4603
|
return Math.abs(this.arg.eval(vars, options));
|
|
4606
4604
|
},
|
|
4607
|
-
codegen: function
|
|
4605
|
+
codegen: function () {
|
|
4608
4606
|
return "Math.abs(" + this.arg.codegen() + ")";
|
|
4609
4607
|
},
|
|
4610
|
-
print: function
|
|
4608
|
+
print: function () {
|
|
4611
4609
|
return "abs(" + this.arg.print() + ")";
|
|
4612
4610
|
},
|
|
4613
|
-
tex: function
|
|
4611
|
+
tex: function () {
|
|
4614
4612
|
return "\\left|" + this.arg.tex() + "\\right|";
|
|
4615
4613
|
},
|
|
4616
|
-
collect: function
|
|
4614
|
+
collect: function (options) {
|
|
4617
4615
|
var abs = this.recurse("collect", options);
|
|
4618
4616
|
if (abs.arg.isPositive()) {
|
|
4619
4617
|
// e.g. |2^x| -> 2^x
|
|
@@ -4642,7 +4640,7 @@ _.extend(Abs.prototype, {
|
|
|
4642
4640
|
}
|
|
4643
4641
|
},
|
|
4644
4642
|
// this should definitely be behind a super-simplify flag
|
|
4645
|
-
expand: function
|
|
4643
|
+
expand: function () {
|
|
4646
4644
|
var abs = this.recurse("expand");
|
|
4647
4645
|
if (abs.arg instanceof Mul) {
|
|
4648
4646
|
// e.g. |xyz| -> |x|*|y|*|z|
|
|
@@ -4654,7 +4652,7 @@ _.extend(Abs.prototype, {
|
|
|
4654
4652
|
return abs;
|
|
4655
4653
|
}
|
|
4656
4654
|
},
|
|
4657
|
-
isPositive: function
|
|
4655
|
+
isPositive: function () {
|
|
4658
4656
|
return true;
|
|
4659
4657
|
}
|
|
4660
4658
|
});
|
|
@@ -4668,13 +4666,13 @@ function Eq(left, type, right) {
|
|
|
4668
4666
|
Eq.prototype = new Expr();
|
|
4669
4667
|
_.extend(Eq.prototype, {
|
|
4670
4668
|
func: Eq,
|
|
4671
|
-
args: function
|
|
4669
|
+
args: function () {
|
|
4672
4670
|
return [this.left, this.type, this.right];
|
|
4673
4671
|
},
|
|
4674
|
-
needsExplicitMul: function
|
|
4672
|
+
needsExplicitMul: function () {
|
|
4675
4673
|
return false;
|
|
4676
4674
|
},
|
|
4677
|
-
print: function
|
|
4675
|
+
print: function () {
|
|
4678
4676
|
return this.left.print() + this.type + this.right.print();
|
|
4679
4677
|
},
|
|
4680
4678
|
signs: {
|
|
@@ -4685,10 +4683,10 @@ _.extend(Eq.prototype, {
|
|
|
4685
4683
|
"<=": " \\le ",
|
|
4686
4684
|
">=": " \\ge "
|
|
4687
4685
|
},
|
|
4688
|
-
tex: function
|
|
4686
|
+
tex: function () {
|
|
4689
4687
|
return this.left.tex() + this.signs[this.type] + this.right.tex();
|
|
4690
4688
|
},
|
|
4691
|
-
normalize: function
|
|
4689
|
+
normalize: function () {
|
|
4692
4690
|
var eq = this.recurse("normalize");
|
|
4693
4691
|
if (_.contains([">", ">="], eq.type)) {
|
|
4694
4692
|
// inequalities should have the smaller side on the left
|
|
@@ -4701,7 +4699,7 @@ _.extend(Eq.prototype, {
|
|
|
4701
4699
|
// the expression is normalized to a canonical form
|
|
4702
4700
|
// e.g. y/2=x/4 -> y/2-x/4(=0) -> 2y-x(=0)
|
|
4703
4701
|
// unless unfactored is specified, will then divide through
|
|
4704
|
-
asExpr: function
|
|
4702
|
+
asExpr: function (unfactored) {
|
|
4705
4703
|
var isZero = function isZero(expr) {
|
|
4706
4704
|
return expr instanceof Num && expr.isSimple() && expr.eval() === 0;
|
|
4707
4705
|
};
|
|
@@ -4753,7 +4751,7 @@ _.extend(Eq.prototype, {
|
|
|
4753
4751
|
// e.g. 2y-4x(=0) -> y-2x(=0)
|
|
4754
4752
|
// TODO(alex): Make it an option to only divide by variables/expressions
|
|
4755
4753
|
// guaranteed to be nonzero
|
|
4756
|
-
divideThrough: function
|
|
4754
|
+
divideThrough: function (expr) {
|
|
4757
4755
|
var isInequality = !this.isEquality();
|
|
4758
4756
|
var simplified = expr.simplify({
|
|
4759
4757
|
once: true
|
|
@@ -4809,10 +4807,10 @@ _.extend(Eq.prototype, {
|
|
|
4809
4807
|
return dividedResult;
|
|
4810
4808
|
}
|
|
4811
4809
|
},
|
|
4812
|
-
isEquality: function
|
|
4810
|
+
isEquality: function () {
|
|
4813
4811
|
return _.contains(["=", "<>"], this.type);
|
|
4814
4812
|
},
|
|
4815
|
-
compare: function
|
|
4813
|
+
compare: function (other) {
|
|
4816
4814
|
// expression comparisons are handled by Expr.compare()
|
|
4817
4815
|
if (!(other instanceof Eq)) {
|
|
4818
4816
|
return false;
|
|
@@ -4835,7 +4833,7 @@ _.extend(Eq.prototype, {
|
|
|
4835
4833
|
}
|
|
4836
4834
|
},
|
|
4837
4835
|
// should only be done after compare() returns true to avoid false positives
|
|
4838
|
-
sameForm: function
|
|
4836
|
+
sameForm: function (other) {
|
|
4839
4837
|
var eq1 = this.normalize();
|
|
4840
4838
|
var eq2 = other.normalize();
|
|
4841
4839
|
var same = eq1.left.sameForm(eq2.left) && eq1.right.sameForm(eq2.right);
|
|
@@ -4848,7 +4846,7 @@ _.extend(Eq.prototype, {
|
|
|
4848
4846
|
},
|
|
4849
4847
|
// we don't want to override collect because it would turn y=x into y-x(=0)
|
|
4850
4848
|
// instead, we ask if the equation was in that form, would it be simplified?
|
|
4851
|
-
isSimplified: function
|
|
4849
|
+
isSimplified: function () {
|
|
4852
4850
|
var expr = this.asExpr( /* unfactored */true);
|
|
4853
4851
|
var simplified = this.divideThrough(expr).simplify();
|
|
4854
4852
|
return expr.equals(simplified) && this.left.isSimplified() && this.right.isSimplified();
|
|
@@ -4856,7 +4854,7 @@ _.extend(Eq.prototype, {
|
|
|
4856
4854
|
});
|
|
4857
4855
|
_.extend(Eq.prototype, {
|
|
4858
4856
|
// Assumptions: Expression is of the form a+bx, and we solve for x
|
|
4859
|
-
solveLinearEquationForVariable: function
|
|
4857
|
+
solveLinearEquationForVariable: function (variable) {
|
|
4860
4858
|
var expr = this.asExpr();
|
|
4861
4859
|
if (!expr.is(Add) || expr.terms.length !== 2) {
|
|
4862
4860
|
throw new Error("Can only handle linear equations of the form " + "a + bx (= 0)");
|
|
@@ -4880,10 +4878,10 @@ _.extend(Eq.prototype, {
|
|
|
4880
4878
|
function Symbol() {}
|
|
4881
4879
|
Symbol.prototype = new Expr();
|
|
4882
4880
|
_.extend(Symbol.prototype, {
|
|
4883
|
-
needsExplicitMul: function
|
|
4881
|
+
needsExplicitMul: function () {
|
|
4884
4882
|
return false;
|
|
4885
4883
|
},
|
|
4886
|
-
findGCD: function
|
|
4884
|
+
findGCD: function (factor) {
|
|
4887
4885
|
if (factor instanceof Symbol || factor instanceof Num) {
|
|
4888
4886
|
return this.equals(factor) ? this : Num.One;
|
|
4889
4887
|
} else {
|
|
@@ -4900,16 +4898,16 @@ function Func(symbol, arg) {
|
|
|
4900
4898
|
Func.prototype = new Symbol();
|
|
4901
4899
|
_.extend(Func.prototype, {
|
|
4902
4900
|
func: Func,
|
|
4903
|
-
args: function
|
|
4901
|
+
args: function () {
|
|
4904
4902
|
return [this.symbol, this.arg];
|
|
4905
4903
|
},
|
|
4906
|
-
print: function
|
|
4904
|
+
print: function () {
|
|
4907
4905
|
return this.symbol + "(" + this.arg.print() + ")";
|
|
4908
4906
|
},
|
|
4909
|
-
tex: function
|
|
4907
|
+
tex: function () {
|
|
4910
4908
|
return this.symbol + "(" + this.arg.tex() + ")";
|
|
4911
4909
|
},
|
|
4912
|
-
eval: function
|
|
4910
|
+
eval: function (vars, options) {
|
|
4913
4911
|
var arg = this.arg;
|
|
4914
4912
|
var func = vars[this.symbol];
|
|
4915
4913
|
var newVars = _.extend(_.clone(vars), {
|
|
@@ -4922,20 +4920,20 @@ _.extend(Func.prototype, {
|
|
|
4922
4920
|
// If parsedFunc isn't actually parsed, return its error
|
|
4923
4921
|
return parsedFunc;
|
|
4924
4922
|
},
|
|
4925
|
-
codegen: function
|
|
4923
|
+
codegen: function () {
|
|
4926
4924
|
return 'vars["' + this.symbol + '"](' + this.arg.codegen() + ")";
|
|
4927
4925
|
},
|
|
4928
|
-
getUnits: function
|
|
4926
|
+
getUnits: function () {
|
|
4929
4927
|
return this.arg.getUnits();
|
|
4930
4928
|
},
|
|
4931
|
-
getVars: function
|
|
4929
|
+
getVars: function (excludeFunc) {
|
|
4932
4930
|
if (excludeFunc) {
|
|
4933
4931
|
return this.arg.getVars();
|
|
4934
4932
|
} else {
|
|
4935
4933
|
return _.union(this.arg.getVars(), [this.symbol]).sort();
|
|
4936
4934
|
}
|
|
4937
4935
|
},
|
|
4938
|
-
getConsts: function
|
|
4936
|
+
getConsts: function () {
|
|
4939
4937
|
return this.arg.getConsts();
|
|
4940
4938
|
}
|
|
4941
4939
|
});
|
|
@@ -4948,16 +4946,16 @@ function Var(symbol, subscript) {
|
|
|
4948
4946
|
Var.prototype = new Symbol();
|
|
4949
4947
|
_.extend(Var.prototype, {
|
|
4950
4948
|
func: Var,
|
|
4951
|
-
args: function
|
|
4949
|
+
args: function () {
|
|
4952
4950
|
return [this.symbol, this.subscript];
|
|
4953
4951
|
},
|
|
4954
|
-
exprArgs: function
|
|
4952
|
+
exprArgs: function () {
|
|
4955
4953
|
return [];
|
|
4956
4954
|
},
|
|
4957
|
-
recurse: function
|
|
4955
|
+
recurse: function () {
|
|
4958
4956
|
return this;
|
|
4959
4957
|
},
|
|
4960
|
-
print: function
|
|
4958
|
+
print: function () {
|
|
4961
4959
|
var sub = "";
|
|
4962
4960
|
if (this.subscript) {
|
|
4963
4961
|
sub = "_(" + this.subscript.print() + ")";
|
|
@@ -4966,7 +4964,7 @@ _.extend(Var.prototype, {
|
|
|
4966
4964
|
},
|
|
4967
4965
|
// Provide a way to easily evalate expressions with the common case,
|
|
4968
4966
|
// subscripts that consist of a single number or symbol e.g. x_a or x_42
|
|
4969
|
-
prettyPrint: function
|
|
4967
|
+
prettyPrint: function () {
|
|
4970
4968
|
var sub = this.subscript;
|
|
4971
4969
|
if (sub && (sub instanceof Num || sub instanceof Symbol)) {
|
|
4972
4970
|
return this.symbol + "_" + sub.print();
|
|
@@ -4974,7 +4972,7 @@ _.extend(Var.prototype, {
|
|
|
4974
4972
|
return this.print();
|
|
4975
4973
|
}
|
|
4976
4974
|
},
|
|
4977
|
-
tex: function
|
|
4975
|
+
tex: function () {
|
|
4978
4976
|
var sub = "";
|
|
4979
4977
|
if (this.subscript) {
|
|
4980
4978
|
sub = "_{" + this.subscript.tex() + "}";
|
|
@@ -4982,19 +4980,19 @@ _.extend(Var.prototype, {
|
|
|
4982
4980
|
var prefix = this.symbol.length > 1 ? "\\" : "";
|
|
4983
4981
|
return prefix + this.symbol + sub;
|
|
4984
4982
|
},
|
|
4985
|
-
repr: function
|
|
4983
|
+
repr: function () {
|
|
4986
4984
|
return "Var(" + this.print() + ")";
|
|
4987
4985
|
},
|
|
4988
|
-
eval: function
|
|
4986
|
+
eval: function (vars, options) {
|
|
4989
4987
|
return vars[this.prettyPrint()];
|
|
4990
4988
|
},
|
|
4991
|
-
codegen: function
|
|
4989
|
+
codegen: function () {
|
|
4992
4990
|
return 'vars["' + this.prettyPrint() + '"]';
|
|
4993
4991
|
},
|
|
4994
|
-
getVars: function
|
|
4992
|
+
getVars: function () {
|
|
4995
4993
|
return [this.prettyPrint()];
|
|
4996
4994
|
},
|
|
4997
|
-
isPositive: function
|
|
4995
|
+
isPositive: function () {
|
|
4998
4996
|
return false;
|
|
4999
4997
|
}
|
|
5000
4998
|
});
|
|
@@ -5006,47 +5004,47 @@ function Const(symbol) {
|
|
|
5006
5004
|
Const.prototype = new Symbol();
|
|
5007
5005
|
_.extend(Const.prototype, {
|
|
5008
5006
|
func: Const,
|
|
5009
|
-
args: function
|
|
5007
|
+
args: function () {
|
|
5010
5008
|
return [this.symbol];
|
|
5011
5009
|
},
|
|
5012
|
-
recurse: function
|
|
5010
|
+
recurse: function () {
|
|
5013
5011
|
return this;
|
|
5014
5012
|
},
|
|
5015
|
-
eval: function
|
|
5013
|
+
eval: function (vars, options) {
|
|
5016
5014
|
if (this.symbol === "pi") {
|
|
5017
5015
|
return Math.PI;
|
|
5018
5016
|
} else if (this.symbol === "e") {
|
|
5019
5017
|
return Math.E;
|
|
5020
5018
|
}
|
|
5021
5019
|
},
|
|
5022
|
-
codegen: function
|
|
5020
|
+
codegen: function () {
|
|
5023
5021
|
if (this.symbol === "pi") {
|
|
5024
5022
|
return "Math.PI";
|
|
5025
5023
|
} else if (this.symbol === "e") {
|
|
5026
5024
|
return "Math.E";
|
|
5027
5025
|
}
|
|
5028
5026
|
},
|
|
5029
|
-
print: function
|
|
5027
|
+
print: function () {
|
|
5030
5028
|
return this.symbol;
|
|
5031
5029
|
},
|
|
5032
|
-
tex: function
|
|
5030
|
+
tex: function () {
|
|
5033
5031
|
if (this.symbol === "pi") {
|
|
5034
5032
|
return "\\pi ";
|
|
5035
5033
|
} else if (this.symbol === "e") {
|
|
5036
5034
|
return "e";
|
|
5037
5035
|
}
|
|
5038
5036
|
},
|
|
5039
|
-
isPositive: function
|
|
5037
|
+
isPositive: function () {
|
|
5040
5038
|
return this.eval() > 0;
|
|
5041
5039
|
},
|
|
5042
|
-
abs: function
|
|
5040
|
+
abs: function () {
|
|
5043
5041
|
if (this.eval() > 0) {
|
|
5044
5042
|
return this;
|
|
5045
5043
|
} else {
|
|
5046
5044
|
return Mul.handleNegative(this);
|
|
5047
5045
|
}
|
|
5048
5046
|
},
|
|
5049
|
-
getConsts: function
|
|
5047
|
+
getConsts: function () {
|
|
5050
5048
|
return [this.print()];
|
|
5051
5049
|
}
|
|
5052
5050
|
});
|
|
@@ -5057,16 +5055,16 @@ Const.pi = new Const("pi");
|
|
|
5057
5055
|
function Num() {}
|
|
5058
5056
|
Num.prototype = new Expr();
|
|
5059
5057
|
_.extend(Num.prototype, {
|
|
5060
|
-
repr: function
|
|
5058
|
+
repr: function () {
|
|
5061
5059
|
return this.print();
|
|
5062
5060
|
},
|
|
5063
|
-
strip: function
|
|
5061
|
+
strip: function () {
|
|
5064
5062
|
return this.abs();
|
|
5065
5063
|
},
|
|
5066
|
-
recurse: function
|
|
5064
|
+
recurse: function () {
|
|
5067
5065
|
return this;
|
|
5068
5066
|
},
|
|
5069
|
-
codegen: function
|
|
5067
|
+
codegen: function () {
|
|
5070
5068
|
return this.print();
|
|
5071
5069
|
},
|
|
5072
5070
|
// takes another Num and returns a new Num
|
|
@@ -5074,22 +5072,22 @@ _.extend(Num.prototype, {
|
|
|
5074
5072
|
mul: abstract,
|
|
5075
5073
|
// returns this Num's additive inverse
|
|
5076
5074
|
negate: abstract,
|
|
5077
|
-
isSubtract: function
|
|
5075
|
+
isSubtract: function () {
|
|
5078
5076
|
return this.hints.subtract;
|
|
5079
5077
|
},
|
|
5080
5078
|
// return the absolute value of the number
|
|
5081
5079
|
abs: abstract,
|
|
5082
|
-
needsExplicitMul: function
|
|
5080
|
+
needsExplicitMul: function () {
|
|
5083
5081
|
return true;
|
|
5084
5082
|
},
|
|
5085
5083
|
findGCD: abstract,
|
|
5086
|
-
isPositive: function
|
|
5084
|
+
isPositive: function () {
|
|
5087
5085
|
return this.eval() > 0;
|
|
5088
5086
|
},
|
|
5089
|
-
isNegative: function
|
|
5087
|
+
isNegative: function () {
|
|
5090
5088
|
return this.eval() < 0;
|
|
5091
5089
|
},
|
|
5092
|
-
asPositiveFactor: function
|
|
5090
|
+
asPositiveFactor: function () {
|
|
5093
5091
|
return this.isPositive() ? this : this.abs();
|
|
5094
5092
|
},
|
|
5095
5093
|
// hints for interpreting and rendering user input
|
|
@@ -5105,7 +5103,7 @@ _.extend(Num.prototype, {
|
|
|
5105
5103
|
// e.g. for reals, ints and floats are simple
|
|
5106
5104
|
isSimple: abstract,
|
|
5107
5105
|
// Based on http://stackoverflow.com/a/10454560/2571482
|
|
5108
|
-
getDecimalPlaces: function
|
|
5106
|
+
getDecimalPlaces: function () {
|
|
5109
5107
|
var match = ("" + this.n).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
|
|
5110
5108
|
if (match) {
|
|
5111
5109
|
return Math.max(0,
|
|
@@ -5134,34 +5132,34 @@ function Rational(numerator, denominator) {
|
|
|
5134
5132
|
Rational.prototype = new Num();
|
|
5135
5133
|
_.extend(Rational.prototype, {
|
|
5136
5134
|
func: Rational,
|
|
5137
|
-
args: function
|
|
5135
|
+
args: function () {
|
|
5138
5136
|
return [this.n, this.d];
|
|
5139
5137
|
},
|
|
5140
|
-
eval: function
|
|
5138
|
+
eval: function () {
|
|
5141
5139
|
return this.n / this.d;
|
|
5142
5140
|
},
|
|
5143
|
-
print: function
|
|
5141
|
+
print: function () {
|
|
5144
5142
|
return this.n.toString() + "/" + this.d.toString();
|
|
5145
5143
|
},
|
|
5146
|
-
tex: function
|
|
5144
|
+
tex: function () {
|
|
5147
5145
|
var tex = "\\frac{" + Math.abs(this.n).toString() + "}{" + this.d.toString() + "}";
|
|
5148
5146
|
return this.n < 0 ? "-" + tex : tex;
|
|
5149
5147
|
},
|
|
5150
|
-
add: function
|
|
5148
|
+
add: function (num, options) {
|
|
5151
5149
|
if (num instanceof Rational) {
|
|
5152
5150
|
return new Rational(this.n * num.d + this.d * num.n, this.d * num.d).collect();
|
|
5153
5151
|
} else {
|
|
5154
5152
|
return num.add(this, options);
|
|
5155
5153
|
}
|
|
5156
5154
|
},
|
|
5157
|
-
mul: function
|
|
5155
|
+
mul: function (num, options) {
|
|
5158
5156
|
if (num instanceof Rational) {
|
|
5159
5157
|
return new Rational(this.n * num.n, this.d * num.d).collect();
|
|
5160
5158
|
} else {
|
|
5161
5159
|
return num.mul(this, options);
|
|
5162
5160
|
}
|
|
5163
5161
|
},
|
|
5164
|
-
collect: function
|
|
5162
|
+
collect: function () {
|
|
5165
5163
|
var gcd = Num.findGCD(this.n, this.d);
|
|
5166
5164
|
var n = this.n / gcd;
|
|
5167
5165
|
var d = this.d / gcd;
|
|
@@ -5171,13 +5169,13 @@ _.extend(Rational.prototype, {
|
|
|
5171
5169
|
return new Rational(n, d);
|
|
5172
5170
|
}
|
|
5173
5171
|
},
|
|
5174
|
-
negate: function
|
|
5172
|
+
negate: function () {
|
|
5175
5173
|
return new Rational(-this.n, this.d);
|
|
5176
5174
|
},
|
|
5177
|
-
abs: function
|
|
5175
|
+
abs: function () {
|
|
5178
5176
|
return new Rational(Math.abs(this.n), this.d);
|
|
5179
5177
|
},
|
|
5180
|
-
findGCD: function
|
|
5178
|
+
findGCD: function (factor) {
|
|
5181
5179
|
// Attempt to factor out common numerators and denominators to return
|
|
5182
5180
|
// a Rational instead of a Float
|
|
5183
5181
|
if (factor instanceof Rational) {
|
|
@@ -5194,7 +5192,7 @@ _.extend(Rational.prototype, {
|
|
|
5194
5192
|
}
|
|
5195
5193
|
},
|
|
5196
5194
|
// for now, assuming that exp is a Num
|
|
5197
|
-
raiseToThe: function
|
|
5195
|
+
raiseToThe: function (exp) {
|
|
5198
5196
|
if (exp instanceof Int) {
|
|
5199
5197
|
var positive = exp.eval() > 0;
|
|
5200
5198
|
var abs = exp.abs().eval();
|
|
@@ -5209,13 +5207,13 @@ _.extend(Rational.prototype, {
|
|
|
5209
5207
|
return new Float(this.eval()).raiseToThe(exp);
|
|
5210
5208
|
}
|
|
5211
5209
|
},
|
|
5212
|
-
getDenominator: function
|
|
5210
|
+
getDenominator: function () {
|
|
5213
5211
|
return new Int(this.d);
|
|
5214
5212
|
},
|
|
5215
|
-
isSimple: function
|
|
5213
|
+
isSimple: function () {
|
|
5216
5214
|
return false;
|
|
5217
5215
|
},
|
|
5218
|
-
asRational: function
|
|
5216
|
+
asRational: function () {
|
|
5219
5217
|
return this;
|
|
5220
5218
|
}
|
|
5221
5219
|
});
|
|
@@ -5227,25 +5225,25 @@ function Int(number) {
|
|
|
5227
5225
|
Int.prototype = new Rational(0, 1);
|
|
5228
5226
|
_.extend(Int.prototype, {
|
|
5229
5227
|
func: Int,
|
|
5230
|
-
args: function
|
|
5228
|
+
args: function () {
|
|
5231
5229
|
return [this.n];
|
|
5232
5230
|
},
|
|
5233
|
-
print: function
|
|
5231
|
+
print: function () {
|
|
5234
5232
|
return this.n.toString();
|
|
5235
5233
|
},
|
|
5236
|
-
tex: function
|
|
5234
|
+
tex: function () {
|
|
5237
5235
|
return this.n.toString();
|
|
5238
5236
|
},
|
|
5239
|
-
negate: function
|
|
5237
|
+
negate: function () {
|
|
5240
5238
|
return new Int(-this.n);
|
|
5241
5239
|
},
|
|
5242
|
-
abs: function
|
|
5240
|
+
abs: function () {
|
|
5243
5241
|
return new Int(Math.abs(this.n));
|
|
5244
5242
|
},
|
|
5245
|
-
isSimple: function
|
|
5243
|
+
isSimple: function () {
|
|
5246
5244
|
return true;
|
|
5247
5245
|
},
|
|
5248
|
-
findGCD: function
|
|
5246
|
+
findGCD: function (factor) {
|
|
5249
5247
|
if (factor instanceof Int) {
|
|
5250
5248
|
return new Int(Num.findGCD(this.n, factor.n));
|
|
5251
5249
|
} else {
|
|
@@ -5254,7 +5252,7 @@ _.extend(Int.prototype, {
|
|
|
5254
5252
|
}
|
|
5255
5253
|
});
|
|
5256
5254
|
_.extend(Int, {
|
|
5257
|
-
create: function
|
|
5255
|
+
create: function (n) {
|
|
5258
5256
|
return new Int(n).addHint("entered");
|
|
5259
5257
|
}
|
|
5260
5258
|
});
|
|
@@ -5266,46 +5264,46 @@ function Float(number) {
|
|
|
5266
5264
|
Float.prototype = new Num();
|
|
5267
5265
|
_.extend(Float.prototype, {
|
|
5268
5266
|
func: Float,
|
|
5269
|
-
args: function
|
|
5267
|
+
args: function () {
|
|
5270
5268
|
return [this.n];
|
|
5271
5269
|
},
|
|
5272
|
-
eval: function
|
|
5270
|
+
eval: function () {
|
|
5273
5271
|
return this.n;
|
|
5274
5272
|
},
|
|
5275
5273
|
// TODO(alex): when we internationalize number parsing/display
|
|
5276
5274
|
// we should make sure to use the appropriate decimal mark here
|
|
5277
|
-
print: function
|
|
5275
|
+
print: function () {
|
|
5278
5276
|
return this.n.toString();
|
|
5279
5277
|
},
|
|
5280
|
-
tex: function
|
|
5278
|
+
tex: function () {
|
|
5281
5279
|
return this.n.toString();
|
|
5282
5280
|
},
|
|
5283
|
-
add: function
|
|
5281
|
+
add: function (num, options) {
|
|
5284
5282
|
if (options && options.preciseFloats) {
|
|
5285
5283
|
return Float.toDecimalPlaces(this.n + num.eval(), Math.max(this.getDecimalPlaces(), num.getDecimalPlaces()));
|
|
5286
5284
|
} else {
|
|
5287
5285
|
return new Float(this.n + num.eval()).collect();
|
|
5288
5286
|
}
|
|
5289
5287
|
},
|
|
5290
|
-
mul: function
|
|
5288
|
+
mul: function (num, options) {
|
|
5291
5289
|
if (options && options.preciseFloats) {
|
|
5292
5290
|
return Float.toDecimalPlaces(this.n * num.eval(), this.getDecimalPlaces() + num.getDecimalPlaces());
|
|
5293
5291
|
} else {
|
|
5294
5292
|
return new Float(this.n * num.eval()).collect();
|
|
5295
5293
|
}
|
|
5296
5294
|
},
|
|
5297
|
-
collect: function
|
|
5295
|
+
collect: function () {
|
|
5298
5296
|
// We used to simplify Floats to Ints here whenever possible, but no
|
|
5299
5297
|
// longer do so in order to preserve significant figures.
|
|
5300
5298
|
return this;
|
|
5301
5299
|
},
|
|
5302
|
-
negate: function
|
|
5300
|
+
negate: function () {
|
|
5303
5301
|
return new Float(-this.n);
|
|
5304
5302
|
},
|
|
5305
|
-
abs: function
|
|
5303
|
+
abs: function () {
|
|
5306
5304
|
return new Float(Math.abs(this.n));
|
|
5307
5305
|
},
|
|
5308
|
-
findGCD: function
|
|
5306
|
+
findGCD: function (factor) {
|
|
5309
5307
|
if (factor instanceof Num) {
|
|
5310
5308
|
return new Float(Num.findGCD(this.eval(), factor.eval())).collect();
|
|
5311
5309
|
} else {
|
|
@@ -5313,7 +5311,7 @@ _.extend(Float.prototype, {
|
|
|
5313
5311
|
}
|
|
5314
5312
|
},
|
|
5315
5313
|
// for now, assuming that exp is a Num
|
|
5316
|
-
raiseToThe: function
|
|
5314
|
+
raiseToThe: function (exp, options) {
|
|
5317
5315
|
if (options && options.preciseFloats && exp instanceof Int && exp.n > 1) {
|
|
5318
5316
|
return Float.toDecimalPlaces(new Pow(this, exp).eval(), this.getDecimalPlaces() * exp.n);
|
|
5319
5317
|
} else {
|
|
@@ -5321,7 +5319,7 @@ _.extend(Float.prototype, {
|
|
|
5321
5319
|
}
|
|
5322
5320
|
},
|
|
5323
5321
|
// only to be used on non-repeating decimals (e.g. user-provided)
|
|
5324
|
-
asRational: function
|
|
5322
|
+
asRational: function () {
|
|
5325
5323
|
var parts = this.n.toString().split(".");
|
|
5326
5324
|
if (parts.length === 1) {
|
|
5327
5325
|
return new Rational(this.n, 1);
|
|
@@ -5331,27 +5329,27 @@ _.extend(Float.prototype, {
|
|
|
5331
5329
|
return new Rational(numerator, denominator).collect();
|
|
5332
5330
|
}
|
|
5333
5331
|
},
|
|
5334
|
-
getDenominator: function
|
|
5332
|
+
getDenominator: function () {
|
|
5335
5333
|
return this.asRational().getDenominator();
|
|
5336
5334
|
},
|
|
5337
|
-
isSimple: function
|
|
5335
|
+
isSimple: function () {
|
|
5338
5336
|
return true;
|
|
5339
5337
|
}
|
|
5340
5338
|
});
|
|
5341
5339
|
_.extend(Float, {
|
|
5342
|
-
create: function
|
|
5340
|
+
create: function (n) {
|
|
5343
5341
|
return new Float(n).addHint("entered");
|
|
5344
5342
|
},
|
|
5345
5343
|
// Account for floating point imprecision by explicitly controlling the
|
|
5346
5344
|
// number of decimal places in common operations (e.g. +, *, ^)
|
|
5347
|
-
toDecimalPlaces: function
|
|
5345
|
+
toDecimalPlaces: function (n, places) {
|
|
5348
5346
|
return new Float(+n.toFixed(Math.min(places, 20))).collect();
|
|
5349
5347
|
}
|
|
5350
5348
|
});
|
|
5351
5349
|
|
|
5352
5350
|
// static methods and fields that are best defined on Num
|
|
5353
5351
|
_.extend(Num, {
|
|
5354
|
-
negativeOne: function
|
|
5352
|
+
negativeOne: function (hint) {
|
|
5355
5353
|
if (hint === "subtract") {
|
|
5356
5354
|
return Num.Sub;
|
|
5357
5355
|
} else if (hint === "divide") {
|
|
@@ -5361,7 +5359,7 @@ _.extend(Num, {
|
|
|
5361
5359
|
}
|
|
5362
5360
|
},
|
|
5363
5361
|
// find the greatest common denominator
|
|
5364
|
-
findGCD: function
|
|
5362
|
+
findGCD: function (a, b) {
|
|
5365
5363
|
var mod;
|
|
5366
5364
|
a = Math.abs(a);
|
|
5367
5365
|
b = Math.abs(b);
|
|
@@ -5379,12 +5377,12 @@ _.extend(Num, {
|
|
|
5379
5377
|
}
|
|
5380
5378
|
return a;
|
|
5381
5379
|
},
|
|
5382
|
-
min: function
|
|
5380
|
+
min: function () {
|
|
5383
5381
|
return _.min(_.toArray(arguments), function (num) {
|
|
5384
5382
|
return num.eval();
|
|
5385
5383
|
});
|
|
5386
5384
|
},
|
|
5387
|
-
max: function
|
|
5385
|
+
max: function () {
|
|
5388
5386
|
return _.max(_.toArray(arguments), function (num) {
|
|
5389
5387
|
return num.eval();
|
|
5390
5388
|
});
|
|
@@ -5423,7 +5421,7 @@ parser.yy = {
|
|
|
5423
5421
|
Float: Float,
|
|
5424
5422
|
parseError: parseError,
|
|
5425
5423
|
constants: ["e"],
|
|
5426
|
-
symbolLexer: function
|
|
5424
|
+
symbolLexer: function (symbol) {
|
|
5427
5425
|
if (_.contains(parser.yy.constants, symbol)) {
|
|
5428
5426
|
return "CONST";
|
|
5429
5427
|
} else if (_.contains(parser.yy.functions, symbol)) {
|
|
@@ -5433,7 +5431,7 @@ parser.yy = {
|
|
|
5433
5431
|
}
|
|
5434
5432
|
}
|
|
5435
5433
|
};
|
|
5436
|
-
|
|
5434
|
+
const parse = function parse(input, options) {
|
|
5437
5435
|
try {
|
|
5438
5436
|
if (options && options.functions) {
|
|
5439
5437
|
// reserve the symbol "i" for complex numbers
|
|
@@ -5499,7 +5497,7 @@ var unprefixify = function unprefixify(symbol) {
|
|
|
5499
5497
|
return new Unit(symbol);
|
|
5500
5498
|
}
|
|
5501
5499
|
};
|
|
5502
|
-
|
|
5500
|
+
const unitParse = function unitParse(input) {
|
|
5503
5501
|
try {
|
|
5504
5502
|
var parseResult = unitParser.parse(input);
|
|
5505
5503
|
|
|
@@ -5555,13 +5553,13 @@ var unitParse = function unitParse(input) {
|
|
|
5555
5553
|
};
|
|
5556
5554
|
_.extend(Unit.prototype, {
|
|
5557
5555
|
func: Unit,
|
|
5558
|
-
args: function
|
|
5556
|
+
args: function () {
|
|
5559
5557
|
return [this.symbol];
|
|
5560
5558
|
},
|
|
5561
|
-
recurse: function
|
|
5559
|
+
recurse: function () {
|
|
5562
5560
|
return this;
|
|
5563
5561
|
},
|
|
5564
|
-
eval: function
|
|
5562
|
+
eval: function (vars, options) {
|
|
5565
5563
|
// This is called when comparing units. A unit doesn't affect the
|
|
5566
5564
|
// numerical value of its coefficient, so this needs to be 1.
|
|
5567
5565
|
//
|
|
@@ -5571,23 +5569,23 @@ _.extend(Unit.prototype, {
|
|
|
5571
5569
|
// However, there are a couple tests checking this.
|
|
5572
5570
|
return 1;
|
|
5573
5571
|
},
|
|
5574
|
-
getUnits: function
|
|
5572
|
+
getUnits: function () {
|
|
5575
5573
|
return [{
|
|
5576
5574
|
unit: this.symbol,
|
|
5577
5575
|
pow: 1
|
|
5578
5576
|
}];
|
|
5579
5577
|
},
|
|
5580
|
-
codegen: function
|
|
5578
|
+
codegen: function () {
|
|
5581
5579
|
return "1";
|
|
5582
5580
|
},
|
|
5583
|
-
print: function
|
|
5581
|
+
print: function () {
|
|
5584
5582
|
return this.symbol;
|
|
5585
5583
|
},
|
|
5586
|
-
tex: function
|
|
5584
|
+
tex: function () {
|
|
5587
5585
|
return this.symbol;
|
|
5588
5586
|
},
|
|
5589
5587
|
// Simplify units by replacing prefixes with multiplication
|
|
5590
|
-
collect: function
|
|
5588
|
+
collect: function (options) {
|
|
5591
5589
|
if (_(baseUnits).has(this.symbol)) {
|
|
5592
5590
|
return this;
|
|
5593
5591
|
} else if (_(derivedUnits).has(this.symbol)) {
|
|
@@ -5810,14 +5808,14 @@ var derivedUnits = {
|
|
|
5810
5808
|
// other
|
|
5811
5809
|
Hz: makeAlias("| / s", hasPrefixes)
|
|
5812
5810
|
};
|
|
5813
|
-
|
|
5814
|
-
|
|
5811
|
+
const Zero = Num.Zero;
|
|
5812
|
+
const One = Num.One;
|
|
5815
5813
|
|
|
5816
5814
|
/* eslint-disable */
|
|
5817
5815
|
|
|
5818
5816
|
// Assumes that both expressions have already been parsed
|
|
5819
5817
|
// TODO(alex): be able to pass a random() function to compare()
|
|
5820
|
-
|
|
5818
|
+
const compare = function compare(expr1, expr2, options) {
|
|
5821
5819
|
var defaults = {
|
|
5822
5820
|
form: false,
|
|
5823
5821
|
// Check that the two expressions have the same form
|