@khanacademy/kmath 0.0.8 → 0.1.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/.babelrc.js CHANGED
@@ -5,4 +5,4 @@
5
5
  *
6
6
  * We should remove this when jest is fixed.
7
7
  */
8
- module.exports = require("../../config/build/babel.config.js");
8
+ module.exports = require("../../config/build/babel.config");
package/.eslintrc.js CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-var-requires */
1
2
  /* eslint-disable import/no-commonjs */
2
3
  const path = require("path");
3
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @khanacademy/kmath
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 1f062e98: Bump all package versions since the build settings have been updated
8
+
9
+ ## 0.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 53fd3768: Migrate source code to TypeScript
14
+
3
15
  ## 0.0.8
4
16
 
5
17
  ### Patch Changes
package/dist/es/index.js CHANGED
@@ -4,9 +4,10 @@ import _ from 'underscore';
4
4
  * Number Utils
5
5
  * A number is a js-number, e.g. 5.12
6
6
  */
7
- var DEFAULT_TOLERANCE = 1e-9; // TODO: Should this just be Number.Epsilon
7
+ const DEFAULT_TOLERANCE = 1e-9;
8
8
 
9
- var EPSILON = Math.pow(2, -42);
9
+ // TODO: Should this just be Number.Epsilon
10
+ const EPSILON = Math.pow(2, -42);
10
11
  function is$2(x) {
11
12
  return _.isNumber(x) && !_.isNaN(x);
12
13
  }
@@ -15,34 +16,31 @@ function equal$4(x, y, tolerance) {
15
16
  // with vectors of different lengths that are _.zip'd together
16
17
  if (x == null || y == null) {
17
18
  return x === y;
18
- } // We check === here so that +/-Infinity comparisons work correctly
19
-
20
-
19
+ }
20
+ // We check === here so that +/-Infinity comparisons work correctly
21
21
  if (x === y) {
22
22
  return true;
23
23
  }
24
-
25
24
  if (tolerance == null) {
26
25
  tolerance = DEFAULT_TOLERANCE;
27
26
  }
28
-
29
27
  return Math.abs(x - y) < tolerance;
30
28
  }
31
- function sign(x, tolerance)
32
- /* Should be: 0 | 1 | -1 */
33
- {
29
+ function sign(x, tolerance) /* Should be: 0 | 1 | -1 */{
34
30
  return equal$4(x, 0, tolerance) ? 0 : Math.abs(x) / x;
35
31
  }
36
32
  function isInteger(num, tolerance) {
37
33
  return equal$4(Math.round(num), num, tolerance);
38
- } // Round a number to a certain number of decimal places
34
+ }
39
35
 
36
+ // Round a number to a certain number of decimal places
40
37
  function round$2(num, precision) {
41
- var factor = Math.pow(10, precision);
38
+ const factor = Math.pow(10, precision);
42
39
  return Math.round(num * factor) / factor;
43
- } // Round num to the nearest multiple of increment
44
- // i.e. roundTo(83, 5) -> 85
40
+ }
45
41
 
42
+ // Round num to the nearest multiple of increment
43
+ // i.e. roundTo(83, 5) -> 85
46
44
  function roundTo$2(num, increment) {
47
45
  return Math.round(num / increment) * increment;
48
46
  }
@@ -52,6 +50,7 @@ function floorTo$2(num, increment) {
52
50
  function ceilTo$2(num, increment) {
53
51
  return Math.ceil(num / increment) * increment;
54
52
  }
53
+
55
54
  /**
56
55
  * toFraction
57
56
  *
@@ -66,30 +65,27 @@ function ceilTo$2(num, increment) {
66
65
  * toFraction(0.66, 0.01) => [2/3]
67
66
  * toFraction(283 + 1/3) => [850, 3]
68
67
  */
69
-
70
- function toFraction(decimal) {
71
- var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : EPSILON;
72
- var maxDenominator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;
68
+ function toFraction(decimal,
69
+ // can't be 0
70
+ tolerance = EPSILON, maxDenominator = 1000) {
73
71
  // Initialize everything to compute successive terms of
74
72
  // continued-fraction approximations via recurrence relation
75
- var n = [1, 0];
76
- var d = [0, 1];
77
- var a = Math.floor(decimal);
78
- var rem = decimal - a;
79
-
73
+ let n = [1, 0];
74
+ let d = [0, 1];
75
+ let a = Math.floor(decimal);
76
+ let rem = decimal - a;
80
77
  while (d[0] <= maxDenominator) {
81
78
  if (equal$4(n[0] / d[0], decimal, tolerance)) {
82
79
  return [n[0], d[0]];
83
80
  }
84
-
85
81
  n = [a * n[0] + n[1], n[0]];
86
82
  d = [a * d[0] + d[1], d[0]];
87
83
  a = Math.floor(1 / rem);
88
84
  rem = 1 / rem - a;
89
- } // We failed to find a nice rational representation,
90
- // so return an irrational "fraction"
91
-
85
+ }
92
86
 
87
+ // We failed to find a nice rational representation,
88
+ // so return an irrational "fraction"
93
89
  return [decimal, 1];
94
90
  }
95
91
 
@@ -112,14 +108,13 @@ var number = /*#__PURE__*/Object.freeze({
112
108
  * Vector Utils
113
109
  * A vector is an array of numbers e.g. [0, 3, 4].
114
110
  */
115
-
116
111
  function arraySum(array) {
117
112
  return array.reduce((memo, arg) => memo + arg, 0);
118
113
  }
119
-
120
114
  function arrayProduct(array) {
121
115
  return array.reduce((memo, arg) => memo * arg, 1);
122
116
  }
117
+
123
118
  /**
124
119
  * Checks if the given vector contains only numbers and, optionally, is of the
125
120
  * right dimension (length).
@@ -128,59 +123,55 @@ function arrayProduct(array) {
128
123
  * is([1, "Hello", 3]) -> false
129
124
  * is([1, 2, 3], 1) -> false
130
125
  */
131
-
132
-
133
126
  function is$1(vec, dimension) {
134
127
  if (!_.isArray(vec)) {
135
128
  return false;
136
129
  }
137
-
138
130
  if (dimension !== undefined && vec.length !== dimension) {
139
131
  return false;
140
132
  }
141
-
142
133
  return vec.every(is$2);
143
- } // Normalize to a unit vector
134
+ }
144
135
 
136
+ // Normalize to a unit vector
145
137
  function normalize(v) {
146
138
  return scale(v, 1 / length(v));
147
- } // Length/magnitude of a vector
139
+ }
148
140
 
141
+ // Length/magnitude of a vector
149
142
  function length(v) {
150
143
  return Math.sqrt(dot(v, v));
151
- } // Dot product of two vectors
152
-
144
+ }
145
+ // Dot product of two vectors
153
146
  function dot(a, b) {
154
- // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
155
- var zipped = _.zip(a, b);
156
-
157
- var multiplied = zipped.map(arrayProduct);
147
+ const zipped = _.zip(a, b);
148
+ const multiplied = zipped.map(arrayProduct);
158
149
  return arraySum(multiplied);
159
150
  }
151
+
160
152
  /* vector-add multiple [x, y] coords/vectors
161
153
  *
162
154
  * add([1, 2], [3, 4]) -> [4, 6]
163
155
  */
164
-
165
- function add() {
166
- // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
167
- var zipped = _.zip(...arguments);
168
-
156
+ function add(...vecs) {
157
+ const zipped = _.zip(...vecs);
158
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
169
159
  return zipped.map(arraySum);
170
160
  }
171
161
  function subtract(v1, v2) {
172
- // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
162
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
173
163
  return _.zip(v1, v2).map(dim => dim[0] - dim[1]);
174
164
  }
175
165
  function negate(v) {
176
- // $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
166
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
177
167
  return v.map(x => {
178
168
  return -x;
179
169
  });
180
- } // Scale a vector
170
+ }
181
171
 
172
+ // Scale a vector
182
173
  function scale(v1, scalar) {
183
- // $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
174
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
184
175
  return v1.map(x => {
185
176
  return x * scalar;
186
177
  });
@@ -190,7 +181,6 @@ function equal$3(v1, v2, tolerance) {
190
181
  // the length of the longest vector. knumber.equal then
191
182
  // returns false for any number compared to the undefined
192
183
  // passed in if one of the vectors is shorter.
193
- // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
194
184
  return _.zip(v1, v2).every(pair => equal$4(pair[0], pair[1], tolerance));
195
185
  }
196
186
  function codirectional(v1, v2, tolerance) {
@@ -200,101 +190,106 @@ function codirectional(v1, v2, tolerance) {
200
190
  if (equal$4(length(v1), 0, tolerance) || equal$4(length(v2), 0, tolerance)) {
201
191
  return true;
202
192
  }
203
-
204
193
  v1 = normalize(v1);
205
194
  v2 = normalize(v2);
206
195
  return equal$3(v1, v2, tolerance);
207
196
  }
208
197
  function collinear(v1, v2, tolerance) {
209
198
  return codirectional(v1, v2, tolerance) || codirectional(v1, negate(v2), tolerance);
210
- } // TODO(jeremy) These coordinate conversion functions really only handle 2D points (ie. [number, number])
211
- // Convert a cartesian coordinate into a radian polar coordinate
199
+ }
200
+
201
+ // TODO(jeremy) These coordinate conversion functions really only handle 2D points (ie. [number, number])
212
202
 
203
+ // Convert a cartesian coordinate into a radian polar coordinate
213
204
  function polarRadFromCart$1(v) {
214
- var radius = length(v);
215
- var theta = Math.atan2(v[1], v[0]); // Convert angle range from [-pi, pi] to [0, 2pi]
205
+ const radius = length(v);
206
+ let theta = Math.atan2(v[1], v[0]);
216
207
 
208
+ // Convert angle range from [-pi, pi] to [0, 2pi]
217
209
  if (theta < 0) {
218
210
  theta += 2 * Math.PI;
219
211
  }
220
-
221
212
  return [radius, theta];
222
- } // Converts a cartesian coordinate into a degree polar coordinate
213
+ }
223
214
 
224
- function polarDegFromCart$1(v)
225
- /* TODO: convert to tuple/Point */
226
- {
227
- var polar = polarRadFromCart$1(v);
215
+ // Converts a cartesian coordinate into a degree polar coordinate
216
+ function polarDegFromCart$1(v) /* TODO: convert to tuple/Point */{
217
+ const polar = polarRadFromCart$1(v);
228
218
  return [polar[0], polar[1] * 180 / Math.PI];
229
219
  }
220
+
230
221
  /* Convert a polar coordinate into a cartesian coordinate
231
222
  *
232
223
  * Examples:
233
224
  * cartFromPolarRad(5, Math.PI)
234
225
  */
235
-
236
- function cartFromPolarRad$1(radius)
237
- /* TODO: convert to tuple/Point */
238
- {
239
- var theta = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
226
+ function cartFromPolarRad$1(radius, theta = 0) /* TODO: convert to tuple/Point */{
240
227
  return [radius * Math.cos(theta), radius * Math.sin(theta)];
241
228
  }
229
+
242
230
  /* Convert a polar coordinate into a cartesian coordinate
243
231
  *
244
232
  * Examples:
245
233
  * cartFromPolarDeg(5, 30)
246
234
  */
247
-
248
- function cartFromPolarDeg$1(radius) {
249
- var theta = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
235
+ function cartFromPolarDeg$1(radius, theta = 0) {
250
236
  return cartFromPolarRad$1(radius, theta * Math.PI / 180);
251
- } // Rotate vector
237
+ }
252
238
 
239
+ // Rotate vector
253
240
  function rotateRad$1(v, theta) {
254
- var polar = polarRadFromCart$1(v);
255
- var angle = polar[1] + theta;
241
+ const polar = polarRadFromCart$1(v);
242
+ const angle = polar[1] + theta;
256
243
  return cartFromPolarRad$1(polar[0], angle);
257
244
  }
258
245
  function rotateDeg$1(v, theta) {
259
- var polar = polarDegFromCart$1(v);
260
- var angle = polar[1] + theta;
246
+ const polar = polarDegFromCart$1(v);
247
+ const angle = polar[1] + theta;
261
248
  return cartFromPolarDeg$1(polar[0], angle);
262
- } // Angle between two vectors
249
+ }
263
250
 
251
+ // Angle between two vectors
264
252
  function angleRad(v1, v2) {
265
253
  return Math.acos(dot(v1, v2) / (length(v1) * length(v2)));
266
254
  }
267
255
  function angleDeg(v1, v2) {
268
256
  return angleRad(v1, v2) * 180 / Math.PI;
269
- } // Vector projection of v1 onto v2
257
+ }
270
258
 
259
+ // Vector projection of v1 onto v2
271
260
  function projection(v1, v2) {
272
- var scalar = dot(v1, v2) / dot(v2, v2);
261
+ const scalar = dot(v1, v2) / dot(v2, v2);
273
262
  return scale(v2, scalar);
274
- } // Round each number to a certain number of decimal places
263
+ }
275
264
 
265
+ // Round each number to a certain number of decimal places
276
266
  function round$1(vec, precision) {
277
- // $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
278
- return vec.map((elem, i) => // $FlowFixMe[prop-missing]
267
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
268
+ return vec.map((elem, i) =>
269
+ // $FlowFixMe[prop-missing]
279
270
  // $FlowFixMe[incompatible-call]
280
271
  round$2(elem, precision[i] || precision));
281
- } // Round each number to the nearest increment
272
+ }
282
273
 
274
+ // Round each number to the nearest increment
283
275
  function roundTo$1(vec, increment) {
284
- // $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
285
- return vec.map((elem, i) => // $FlowFixMe[prop-missing]
276
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
277
+ return vec.map((elem, i) =>
278
+ // $FlowFixMe[prop-missing]
286
279
  // $FlowFixMe[incompatible-call]
287
280
  roundTo$2(elem, increment[i] || increment));
288
281
  }
289
282
  function floorTo$1(vec, increment) {
290
- // $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
291
- return vec.map((elem, i) => // $FlowFixMe[prop-missing]
283
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
284
+ return vec.map((elem, i) =>
285
+ // $FlowFixMe[prop-missing]
292
286
  // $FlowFixMe[incompatible-call]
293
287
  floorTo$2(elem, increment[i] || increment));
294
288
  }
295
289
  function ceilTo$1(vec, increment) {
296
- // $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
297
- return vec.map((elem, i) => // $FlowFixMe[prop-missing]
290
+ // @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
291
+ return vec.map((elem, i) =>
292
+ // $FlowFixMe[prop-missing]
298
293
  // $FlowFixMe[incompatible-call]
299
294
  ceilTo$2(elem, increment[i] || increment));
300
295
  }
@@ -332,6 +327,8 @@ var vector = /*#__PURE__*/Object.freeze({
332
327
  * A point is an array of two numbers e.g. [0, 0].
333
328
  */
334
329
 
330
+ // A point, in 2D, 3D, or nD space.
331
+
335
332
  // Rotate point (around origin unless a center is specified)
336
333
  function rotateRad(point, theta, center) {
337
334
  if (center === undefined) {
@@ -346,27 +343,31 @@ function rotateDeg(point, theta, center) {
346
343
  } else {
347
344
  return add(center, rotateDeg$1(subtract(point, center), theta));
348
345
  }
349
- } // Distance between two points
346
+ }
350
347
 
348
+ // Distance between two points
351
349
  function distanceToPoint$1(point1, point2) {
352
350
  return length(subtract(point1, point2));
353
- } // Distance between point and line
351
+ }
354
352
 
353
+ // Distance between point and line
355
354
  function distanceToLine(point, line) {
356
- var lv = subtract(line[1], line[0]);
357
- var pv = subtract(point, line[0]);
358
- var projectedPv = projection(pv, lv);
359
- var distancePv = subtract(projectedPv, pv);
355
+ const lv = subtract(line[1], line[0]);
356
+ const pv = subtract(point, line[0]);
357
+ const projectedPv = projection(pv, lv);
358
+ const distancePv = subtract(projectedPv, pv);
360
359
  return length(distancePv);
361
- } // Reflect point over line
360
+ }
362
361
 
362
+ // Reflect point over line
363
363
  function reflectOverLine(point, line) {
364
- var lv = subtract(line[1], line[0]);
365
- var pv = subtract(point, line[0]);
366
- var projectedPv = projection(pv, lv);
367
- var reflectedPv = subtract(scale(projectedPv, 2), pv);
364
+ const lv = subtract(line[1], line[0]);
365
+ const pv = subtract(point, line[0]);
366
+ const projectedPv = projection(pv, lv);
367
+ const reflectedPv = subtract(scale(projectedPv, 2), pv);
368
368
  return add(line[0], reflectedPv);
369
369
  }
370
+
370
371
  /**
371
372
  * Compares two points, returning -1, 0, or 1, for use with
372
373
  * Array.prototype.sort
@@ -376,39 +377,38 @@ function reflectOverLine(point, line) {
376
377
  * is 0. In some cases very close points that compare within a
377
378
  * few equalityTolerances could appear in the wrong order.
378
379
  */
379
-
380
- function compare(point1, point2, equalityTolerance)
381
- /* TODO: convert to -1 | 0 | 1 type */
382
- {
380
+ function compare(point1, point2, equalityTolerance) /* TODO: convert to -1 | 0 | 1 type */{
383
381
  if (point1.length !== point2.length) {
384
382
  return point1.length - point2.length;
385
383
  }
386
-
387
- for (var i = 0; i < point1.length; i++) {
384
+ for (let i = 0; i < point1.length; i++) {
388
385
  if (!equal$4(point1[i], point2[i], equalityTolerance)) {
389
386
  return point1[i] - point2[i];
390
387
  }
391
388
  }
392
-
393
389
  return 0;
394
- } // Check if a value is a point
390
+ }
395
391
 
396
- var is = is$1; // Add and subtract vector(s)
392
+ // Check if a value is a point
393
+ const is = is$1;
397
394
 
398
- var addVector = add;
399
- var addVectors = add;
400
- var subtractVector = subtract;
401
- var equal$2 = equal$3; // Convert from cartesian to polar and back
395
+ // Add and subtract vector(s)
396
+ const addVector = add;
397
+ const addVectors = add;
398
+ const subtractVector = subtract;
399
+ const equal$2 = equal$3;
402
400
 
403
- var polarRadFromCart = polarRadFromCart$1;
404
- var polarDegFromCart = polarDegFromCart$1;
405
- var cartFromPolarRad = cartFromPolarRad$1;
406
- var cartFromPolarDeg = cartFromPolarDeg$1; // Rounding
401
+ // Convert from cartesian to polar and back
402
+ const polarRadFromCart = polarRadFromCart$1;
403
+ const polarDegFromCart = polarDegFromCart$1;
404
+ const cartFromPolarRad = cartFromPolarRad$1;
405
+ const cartFromPolarDeg = cartFromPolarDeg$1;
407
406
 
408
- var round = round$1;
409
- var roundTo = roundTo$1;
410
- var floorTo = floorTo$1;
411
- var ceilTo = ceilTo$1;
407
+ // Rounding
408
+ const round = round$1;
409
+ const roundTo = roundTo$1;
410
+ const floorTo = floorTo$1;
411
+ const ceilTo = ceilTo$1;
412
412
 
413
413
  var point = /*#__PURE__*/Object.freeze({
414
414
  __proto__: null,
@@ -450,21 +450,18 @@ function equal$1(line1, line2, tolerance) {
450
450
  // TODO: A nicer implementation might just check collinearity of
451
451
  // vectors using underscore magick
452
452
  // Compare the directions of the lines
453
- var v1 = subtract(line1[1], line1[0]);
454
- var v2 = subtract(line2[1], line2[0]);
455
-
453
+ const v1 = subtract(line1[1], line1[0]);
454
+ const v2 = subtract(line2[1], line2[0]);
456
455
  if (!collinear(v1, v2, tolerance)) {
457
456
  return false;
458
- } // If the start point is the same for the two lines, then they are the same
459
-
460
-
457
+ }
458
+ // If the start point is the same for the two lines, then they are the same
461
459
  if (equal$2(line1[0], line2[0])) {
462
460
  return true;
463
- } // Make sure that the direction to get from line1 to
461
+ }
462
+ // Make sure that the direction to get from line1 to
464
463
  // line2 is the same as the direction of the lines
465
-
466
-
467
- var line1ToLine2Vector = subtract(line2[0], line1[0]);
464
+ const line1ToLine2Vector = subtract(line2[0], line1[0]);
468
465
  return collinear(v1, line1ToLine2Vector, tolerance);
469
466
  }
470
467
 
@@ -484,10 +481,10 @@ var line = /*#__PURE__*/Object.freeze({
484
481
  */
485
482
  function equal(ray1, ray2, tolerance) {
486
483
  // Compare the directions of the rays
487
- var v1 = subtract(ray1[1], ray1[0]);
488
- var v2 = subtract(ray2[1], ray2[0]);
489
- var sameOrigin = equal$2(ray1[0], ray2[0]);
490
- var codirectional$1 = codirectional(v1, v2, tolerance);
484
+ const v1 = subtract(ray1[1], ray1[0]);
485
+ const v2 = subtract(ray2[1], ray2[0]);
486
+ const sameOrigin = equal$2(ray1[0], ray2[0]);
487
+ const codirectional$1 = codirectional(v1, v2, tolerance);
491
488
  return sameOrigin && codirectional$1;
492
489
  }
493
490