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