From 950e47077007f3d39c58289c7a5856989263c338 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 09:49:49 -0700 Subject: [PATCH 01/28] feat: like methods and full function --- src/index.js | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/index.js b/src/index.js index 39c93ab..2b842ef 100644 --- a/src/index.js +++ b/src/index.js @@ -316,6 +316,73 @@ function ones (shape, dtype) { return arr; } +/** + * Return a new array of given shape and type, filled with the specified value. + * The fillValue + * + * @param {(Array|number)} shape - Shape of the new array, e.g., [2, 3] or 2. + * @param {(number|Array)} fillValue - number to fill the entire array with + * @param {(string|object)} dtype - The type of the output array. + * + * @return {NdArray} Array of ones with the given shape and dtype + */ +function full(shape, fillValue, dtype) { + if (_.isNumber(shape) && shape >= 0) { + shape = [shape]; + } + var s = _.shapeSize(shape); + var T = _.getType(dtype); + var ndarrayMemory = new T(s); + var arr = new NdArray(ndarrayMemory, shape); + + if(_.isNumber(fillValue)) { + ndarrayMemory.fill(fillValue); + } else { + // if array provided, fill out the array by repeating the fillValue + for(var i = 0; i < ndarrayMemory.length; i++) { + ndarrayMemory[i] = fillValue[i % fillValue.length]; + } + } + return arr; +} + +/** + * Return a new array filled with zeros shaped like another array + * + * @param {(NdArray)} array - the shape we want to use for a new array + * @param {(string|object)} dtype The type of the output array. + * + * @return {NdArray} Array of zeros shaped like the array argument + */ +function zerosLike (array, dtype) { + return zeros(array.shape, dtype); +} + +/** + * Return a new array filled with zeros shaped like another array + * + * @param {(NdArray)} array - the shape we want to use for a new array + * @param {(string|object)} dtype The type of the output array. + * + * @return {NdArray} Array of ones shaped like the array argument + */ +function onesLike (array, dtype) { + return ones(array.shape, dtype); +} + +/** + * Return a new array filled with fillValue shaped like another array + * + * @param {(NdArray)} array - the shape we want to use for a new array + * @param {(number|Array)} fillValue - number to fill the entire array with + * @param {(string|object)} dtype - The type of the output array. + * + * @return {NdArray} Array of fillValue shaped like the array argument + */ +function fullLike(array, fillValue, dtype) { + return full(array.shape, fillValue, dtype); +} + /** * Return a new array of given shape and type, filled with `undefined` values. * @@ -802,6 +869,10 @@ module.exports = { reshape: reshape, zeros: zeros, ones: ones, + full: full, + zerosLike: zerosLike, + onesLike: onesLike, + fullLike: fullLike, empty: empty, flatten: flatten, flip: flip, From 97e5ad3ae869033b82bbcf23459a94c004b48507 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 09:51:17 -0700 Subject: [PATCH 02/28] feat: tests for like methods and full function --- test/mocha/full.spec.js | 32 ++++++++++++++++++++++++++++++++ test/mocha/fullLike.spec.js | 23 +++++++++++++++++++++++ test/mocha/onesLike.spec.js | 23 +++++++++++++++++++++++ test/mocha/zerosLike.spec.js | 23 +++++++++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 test/mocha/full.spec.js create mode 100644 test/mocha/fullLike.spec.js create mode 100644 test/mocha/onesLike.spec.js create mode 100644 test/mocha/zerosLike.spec.js diff --git a/test/mocha/full.spec.js b/test/mocha/full.spec.js new file mode 100644 index 0000000..bab0d12 --- /dev/null +++ b/test/mocha/full.spec.js @@ -0,0 +1,32 @@ +/* eslint-env mocha */ +'use strict'; + +var expect = require('expect.js'); + +var nj = require('../../src'); + +describe('full', function () { + it('can generate from scalar fillValue', function () { + expect(nj.full(0, 5).tolist()).to.eql([]); + expect(nj.full(2, 5).tolist()).to.eql([5, 5]); + expect(nj.full([2], 5).tolist()).to.eql([5, 5]); + }); + + it('can generate matrix from scalar fillValue', function () { + expect(nj.full([2, 2], 5).tolist()) + .to.eql([ + [5, 5], + [5, 5]]); + }); + + it('can generate matrix from array fillValue', function () { + expect(nj.full([2, 2], [1, 2]).tolist()) + .to.eql([ + [1, 2], + [1, 2]]); + }); + + it('should accept a dtype', function () { + expect(nj.full(0, 5, 'uint8').dtype).to.equal('uint8'); + }); +}); diff --git a/test/mocha/fullLike.spec.js b/test/mocha/fullLike.spec.js new file mode 100644 index 0000000..bb8ac86 --- /dev/null +++ b/test/mocha/fullLike.spec.js @@ -0,0 +1,23 @@ +/* eslint-env mocha */ +"use strict"; + +var expect = require("expect.js"); + +var nj = require("../../src"); + +describe("fullLike", function () { + const A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate fillValue like shaped like a given matrix", function () { + expect(nj.fullLike(A, 5).tolist()).to.eql([ + [5, 5], + [5, 5], + ]); + }); + + it("should accept a dtype", function () { + expect(nj.fullLike(A, 5, "uint8").dtype).to.equal("uint8"); + }); +}); diff --git a/test/mocha/onesLike.spec.js b/test/mocha/onesLike.spec.js new file mode 100644 index 0000000..56d456a --- /dev/null +++ b/test/mocha/onesLike.spec.js @@ -0,0 +1,23 @@ +/* eslint-env mocha */ +"use strict"; + +var expect = require("expect.js"); + +var nj = require("../../src"); + +describe("zerosLike", function () { + const A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate zeros like shaped like a given matrix", function () { + expect(nj.onesLike(A).tolist()).to.eql([ + [1, 1], + [1, 1], + ]); + }); + + it("should accept a dtype", function () { + expect(nj.onesLike(A, "uint8").dtype).to.equal("uint8"); + }); +}); diff --git a/test/mocha/zerosLike.spec.js b/test/mocha/zerosLike.spec.js new file mode 100644 index 0000000..51f7ed1 --- /dev/null +++ b/test/mocha/zerosLike.spec.js @@ -0,0 +1,23 @@ +/* eslint-env mocha */ +"use strict"; + +var expect = require("expect.js"); + +var nj = require("../../src"); + +describe("zerosLike", function () { + const A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate zeros like shaped like a given matrix", function () { + expect(nj.zerosLike(A).tolist()).to.eql([ + [0, 0], + [0, 0], + ]); + }); + + it("should accept a dtype", function () { + expect(nj.zerosLike(A, "uint8").dtype).to.equal("uint8"); + }); +}); From 1bf885688f9481623be2ba935e02723bbec7ad76 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 09:54:42 -0700 Subject: [PATCH 03/28] feat: tri and eye with tests --- src/index.js | 66 ++++++++++++++++++++++++++++++++++++++++++ test/mocha/eye.spec.js | 20 +++++++++++++ test/mocha/tri.spec.js | 20 +++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 test/mocha/eye.spec.js create mode 100644 test/mocha/tri.spec.js diff --git a/src/index.js b/src/index.js index 2b842ef..fd67064 100644 --- a/src/index.js +++ b/src/index.js @@ -383,6 +383,70 @@ function fullLike(array, fillValue, dtype) { return full(array.shape, fillValue, dtype); } +/** + * Return a new array of given shape and type, with 1s in the diagonal as the identity matrix + * + * @param {number} M - the number of rows + * @param {number?} N - the number of columns, defaults to N + * @param {(string|object)} dtype - The type of the output array. + * + * @return {NdArray} Array of ones with the given shape and dtype + */ +function eye (N, M, dtype) { + // in the case where eye(N, dtype) + if (_.isString(M)) { + dtype = M + M = undefined; + } + if(M === undefined) M = N; + + var T = _.getType(dtype); + const flatData = new T(N*M).fill(0); + var arr = new NdArray(flatData, [N, M]); + + // then when i=j fill with 1s + for(let i = 0; i < N; i++) + for(let j = 0; j < M; j++) + if(i === j) arr.set(i, j, 1); + + return arr; +} + +/** + * Return a new array of given shape and type, with 1s in the lower triange + * + * @param {number} M - the number of rows + * @param {number?} N - the number of columns, defaults to N + * @param {number?} k - the diagonal to fill under, defaults to 0 + * @param {(string|object)} dtype - The type of the output array. + * + * @return {NdArray} Array of ones with the given shape and dtype + */ +function tri (N, M, k = 0, dtype) { + // in the case where tri(N, dtype) + if (_.isString(M)) { + dtype = M + M = undefined; + } + // in the case where tri(N, M, dtype) + else if (_.isString(k)) { + dtype = k; + k = 0; + }; + if(M === undefined) M = N; + + var T = _.getType(dtype); + const flatData = new T(N*M).fill(0); + var arr = new NdArray(flatData, [N, M]); + + // then when i>j fill with 1s (lower triangle) increase k to increase the diagonl to fill + for(let i = 0; i < N; i++) + for(let j = 0; j < M; j++) + if((i + k) > j) arr.set(i, j, 1); + + return arr; +} + /** * Return a new array of given shape and type, filled with `undefined` values. * @@ -870,6 +934,8 @@ module.exports = { zeros: zeros, ones: ones, full: full, + eye: eye, + tri: tri, zerosLike: zerosLike, onesLike: onesLike, fullLike: fullLike, diff --git a/test/mocha/eye.spec.js b/test/mocha/eye.spec.js new file mode 100644 index 0000000..a44cf76 --- /dev/null +++ b/test/mocha/eye.spec.js @@ -0,0 +1,20 @@ +/* eslint-env mocha */ +'use strict'; + +var expect = require('expect.js'); + +var nj = require('../../src'); + +describe('eye', function () { + it('can generate square matrix ', function () { + expect(nj.eye(2).tolist()).to.eql([[1, 0], [0, 1]]); + }); + + it('can generate matrix with different dimensions', function () { + expect(nj.eye(1, 2).tolist()).to.eql([[1, 0]]); + }); + + it('should accept a dtype', function () { + expect(nj.eye(0, 'uint8').dtype).to.equal('uint8'); + }); +}); diff --git a/test/mocha/tri.spec.js b/test/mocha/tri.spec.js new file mode 100644 index 0000000..f660af6 --- /dev/null +++ b/test/mocha/tri.spec.js @@ -0,0 +1,20 @@ +/* eslint-env mocha */ +'use strict'; + +var expect = require('expect.js'); + +var nj = require('../../src'); + +describe('tri', function () { + it('can generate square matrix ', function () { + expect(nj.tri(2).tolist()).to.eql([[0, 0], [1, 0]]); + }); + + it('can generate matrix with different dimensions', function () { + expect(nj.tri(3, 2).tolist()).to.eql([[0, 0], [1, 0], [1, 1]]); + }); + + it('should accept a dtype', function () { + expect(nj.tri(0, 'uint8').dtype).to.equal('uint8'); + }); +}); From cd26537433a0fd9c1946af6334901daa367d16f8 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 09:55:45 -0700 Subject: [PATCH 04/28] fix: functions styling --- src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index fd67064..b957b8d 100644 --- a/src/index.js +++ b/src/index.js @@ -326,7 +326,7 @@ function ones (shape, dtype) { * * @return {NdArray} Array of ones with the given shape and dtype */ -function full(shape, fillValue, dtype) { +function full (shape, fillValue, dtype) { if (_.isNumber(shape) && shape >= 0) { shape = [shape]; } @@ -379,7 +379,7 @@ function onesLike (array, dtype) { * * @return {NdArray} Array of fillValue shaped like the array argument */ -function fullLike(array, fillValue, dtype) { +function fullLike (array, fillValue, dtype) { return full(array.shape, fillValue, dtype); } From b414e84a3032e41b56fac9d7d8d23c16768fec83 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:02:25 -0700 Subject: [PATCH 05/28] docs: full function added to array creation --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 51ca10c..5ce1f5f 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,13 @@ array([ 1, 2, 3], dtype=uint8) __Note__: possible types are int8, uint8, int16, uint16, int32, uint32, float32, float64 and array (the default) -To create arrays with a given shape, you can use `zeros`, `ones` or `random` functions: +To create arrays with a given shape, you can use `zeros`, `ones`, `random`, and `full` functions: ```js > nj.zeros([2,3]); array([[ 0, 0, 0], [ 0, 0, 0]]) + > nj.ones([2,3,4], 'int32') // dtype can also be specified array([[[ 1, 1, 1, 1], [ 1, 1, 1, 1], @@ -81,6 +82,16 @@ array([[ 0.9182 , 0.85176, 0.22587], [ 0.50088, 0.74376, 0.84024], [ 0.74045, 0.23345, 0.20289], [ 0.00612, 0.37732, 0.06932]]) + +> nj.full([3,3], -3.14159) +array([[ -3.14159, -3.14159, -3.14159], + [ -3.14159, -3.14159, -3.14159], + [ -3.14159, -3.14159, -3.14159]]) + +> nj.full([3, 2], [1, 2]) +array([[ 1, 2], + [ 1, 2], + [ 1, 2]]) ``` To create sequences of numbers, __NumJs__ provides a function called `arange`: From 23b53885c29ac14caadf8f0d4003cb3cba36fa1b Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:15:48 -0700 Subject: [PATCH 06/28] feat: random like and test --- src/index.js | 12 ++++++++++++ test/mocha/randomLike.spec.js | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/mocha/randomLike.spec.js diff --git a/src/index.js b/src/index.js index b957b8d..9c32860 100644 --- a/src/index.js +++ b/src/index.js @@ -383,6 +383,17 @@ function fullLike (array, fillValue, dtype) { return full(array.shape, fillValue, dtype); } +/** + * Return a new array filled with random numbers + * + * @param {(NdArray)} array - the shape we want to use for a new array + * + * @return {NdArray} Array of random numbers shaped like the array argument + */ +function randomLike (array) { + return random(array.shape); +} + /** * Return a new array of given shape and type, with 1s in the diagonal as the identity matrix * @@ -939,6 +950,7 @@ module.exports = { zerosLike: zerosLike, onesLike: onesLike, fullLike: fullLike, + randomLike: randomLike, empty: empty, flatten: flatten, flip: flip, diff --git a/test/mocha/randomLike.spec.js b/test/mocha/randomLike.spec.js new file mode 100644 index 0000000..86373b0 --- /dev/null +++ b/test/mocha/randomLike.spec.js @@ -0,0 +1,17 @@ +/* eslint-env mocha */ +"use strict"; + +var expect = require("expect.js"); + +var nj = require("../../src"); + +describe("zerosLike", function () { + const A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate zeros like shaped like a given matrix", function () { + expect(nj.randomLike(A).shape).to.eql([2, 2 + ]); + }); +}); From 42d869c166b94a1f762bc87baa9c7f29ca478f9f Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:16:07 -0700 Subject: [PATCH 07/28] docs: *Like examples --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 5ce1f5f..7f2b5ee 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,28 @@ array([[ 1, 2], [ 1, 2]]) ``` +You can also infer the shape from another array with methods like `zerosLike`, `onesLike`, and `fullLike` + +Given `const arr = nj.array([[1,2], [3,4]]);` which has shape of (2,2) + +```js +> nj.zerosLike(arr); +array([[ 0, 0], + [ 0, 0]]) + +> nj.onesLike(arr, 'int32') // dtype can also be specified +array([[ 1, 1], + [ 1, 1]], dtype=int32) + +> nj.randomLike(arr) +array([[ 0.82251, 0.76331], + [ 0.22786, 0.73417]]) + +> nj.full(arr, -3.14159) +array([[ -3.14159, -3.14159], + [ -3.14159, -3.14159]]) +``` + To create sequences of numbers, __NumJs__ provides a function called `arange`: ```js From 0c34c9f4d4e5e37bb29aa68d6310825068c44fab Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:22:22 -0700 Subject: [PATCH 08/28] docs: example of eye and tri --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f2b5ee..2be7f1a 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ array([[ 1, 2], [ 1, 2]]) ``` -You can also infer the shape from another array with methods like `zerosLike`, `onesLike`, and `fullLike` +You can also infer the shape from another array with methods like `zerosLike`, `onesLike`, `randomLike`, and `fullLike` Given `const arr = nj.array([[1,2], [3,4]]);` which has shape of (2,2) @@ -129,6 +129,25 @@ array([ 10, 15, 20, 25]) array([ 1, 2, 3, 4], dtype=uint8) ``` +To generate matrices with nice properties like the identity `eye` or a triangular `tri`: + +```js +> nj.eye(3, 3) +array([[ 1, 0, 0], + [ 0, 1, 0], + [ 0, 0, 1]]) + +> nj.tri(3, 3) // fills diagonal under k=0 +array([[ 0, 0, 0], + [ 1, 0, 0], + [ 1, 1, 0]]) + +> nj.tri(3, 3, 1) // fills diagonal under k=1 +array([[ 1, 0, 0], + [ 1, 1, 0], + [ 1, 1, 1]]) +``` + ### More info about the array __NumJs__’s array class is called `NdArray`. It is also known by the alias `array`. The more important properties of an `NdArray` object are: From 8ef2b624c1c36826711c9b74c45e2ad486c9de8f Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:23:41 -0700 Subject: [PATCH 09/28] fix: colon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2be7f1a..4edf7ea 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ array([[ 1, 2], [ 1, 2]]) ``` -You can also infer the shape from another array with methods like `zerosLike`, `onesLike`, `randomLike`, and `fullLike` +You can also infer the shape from another array with methods like `zerosLike`, `onesLike`, `randomLike`, and `fullLike`: Given `const arr = nj.array([[1,2], [3,4]]);` which has shape of (2,2) From 6be83635dd70d935bbac508ddb45516f7f02cb0f Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:24:09 -0700 Subject: [PATCH 10/28] fix: full -> fullLike --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4edf7ea..1a4e16f 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ array([[ 1, 1], array([[ 0.82251, 0.76331], [ 0.22786, 0.73417]]) -> nj.full(arr, -3.14159) +> nj.fullLike(arr, -3.14159) array([[ -3.14159, -3.14159], [ -3.14159, -3.14159]]) ``` From efdb3177110b76b0ed3a2bbe19f416969df8b4fb Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:28:56 -0700 Subject: [PATCH 11/28] fix: tabs to spaces --- src/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index 9c32860..ed659d3 100644 --- a/src/index.js +++ b/src/index.js @@ -327,17 +327,17 @@ function ones (shape, dtype) { * @return {NdArray} Array of ones with the given shape and dtype */ function full (shape, fillValue, dtype) { - if (_.isNumber(shape) && shape >= 0) { - shape = [shape]; - } - var s = _.shapeSize(shape); - var T = _.getType(dtype); + if (_.isNumber(shape) && shape >= 0) { + shape = [shape]; + } + var s = _.shapeSize(shape); + var T = _.getType(dtype); var ndarrayMemory = new T(s); - var arr = new NdArray(ndarrayMemory, shape); + var arr = new NdArray(ndarrayMemory, shape); if(_.isNumber(fillValue)) { ndarrayMemory.fill(fillValue); - } else { + } else { // if array provided, fill out the array by repeating the fillValue for(var i = 0; i < ndarrayMemory.length; i++) { ndarrayMemory[i] = fillValue[i % fillValue.length]; @@ -380,7 +380,7 @@ function onesLike (array, dtype) { * @return {NdArray} Array of fillValue shaped like the array argument */ function fullLike (array, fillValue, dtype) { - return full(array.shape, fillValue, dtype); + return full(array.shape, fillValue, dtype); } /** From 8daa46b404f4d74792a1e95ec0862d1da7ec5087 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:29:36 -0700 Subject: [PATCH 12/28] fix: tab to space --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index ed659d3..e24f4ce 100644 --- a/src/index.js +++ b/src/index.js @@ -343,7 +343,7 @@ function full (shape, fillValue, dtype) { ndarrayMemory[i] = fillValue[i % fillValue.length]; } } - return arr; + return arr; } /** From 51af57050d9fd8ce71ad4c3aa2a96f223d6664d4 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:35:08 -0700 Subject: [PATCH 13/28] feat: argmax and argmin --- src/index.js | 22 ++++++++++++++++++++++ src/ndarray.js | 24 ++++++++++++++++++++++++ test/mocha/argmax.spec.js | 22 ++++++++++++++++++++++ test/mocha/argmin.spec.js | 22 ++++++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 test/mocha/argmax.spec.js create mode 100644 test/mocha/argmin.spec.js diff --git a/src/index.js b/src/index.js index e24f4ce..7ed4007 100644 --- a/src/index.js +++ b/src/index.js @@ -195,6 +195,26 @@ function max (x) { return NdArray.new(x).max(); } +/** + * Return the index of the minimum value of the array + * + * @param {(Array|NdArray|number)} x + * @returns {Number} + */ +function argmin (x) { + return NdArray.new(x).argmin(); +} + +/** + * Return the index of the maximum value of the array + * + * @param {(Array|NdArray|number)} x + * @returns {Number} + */ +function argmax (x) { + return NdArray.new(x).argmax(); +} + /** * Return element-wise remainder of division. * Computes the remainder complementary to the `floor` function. It is equivalent to the Javascript modulus operator``x1 % x2`` and has the same sign as the divisor x2. @@ -983,6 +1003,8 @@ module.exports = { equal: equal, max: max, min: min, + argmax: argmax, + argmin: argmin, mod: mod, remainder: mod, concatenate: concatenate, diff --git a/src/ndarray.js b/src/ndarray.js index 89e9422..9ae6a4c 100644 --- a/src/ndarray.js +++ b/src/ndarray.js @@ -555,6 +555,30 @@ NdArray.prototype.min = function () { return ops.inf(this.selection); }; +/** +* Return the index of the maximum value of the array +* +* @returns {Array} +*/ +NdArray.prototype.argmax = function () { + if (this.selection.size === 0) { + return null; + } + return ops.argmax(this.selection); +}; + +/** +* Return the index of the minimum value of the array +* +* @returns {Array} +*/ +NdArray.prototype.argmin = function () { + if (this.selection.size === 0) { + return null; + } + return ops.argmin(this.selection); +}; + /** * Sum of array elements. * diff --git a/test/mocha/argmax.spec.js b/test/mocha/argmax.spec.js new file mode 100644 index 0000000..eda1143 --- /dev/null +++ b/test/mocha/argmax.spec.js @@ -0,0 +1,22 @@ +'use strict'; + +var expect = require('expect.js'); + +var nj = require('../../src'); + +describe('argmax', function () { + it('should be null for an empty array', function () { + var arr = nj.array([]); + expect(arr.argmax()).to.equal(null); + }); + it('should return the max element in array', function () { + var arr = nj.arange(10); + expect(arr.argmax()[0]).to.equal(9); + }); + it('should return the max element in matrix', function () { + var arr = nj.arange(10).reshape(2, 5); + const a = arr.argmax(); + expect(a[0]).to.equal(1); + expect(a[1]).to.equal(4); + }); +}); diff --git a/test/mocha/argmin.spec.js b/test/mocha/argmin.spec.js new file mode 100644 index 0000000..27a1f9d --- /dev/null +++ b/test/mocha/argmin.spec.js @@ -0,0 +1,22 @@ +'use strict'; + +var expect = require('expect.js'); + +var nj = require('../../src'); + +describe('argmin', function () { + it('should be null for an empty array', function () { + var arr = nj.array([]); + expect(arr.argmin()).to.equal(null); + }); + it('should return the min element in array', function () { + var arr = nj.arange(10); + expect(arr.argmin()[0]).to.equal(0); + }); + it('should return the min element in matrix', function () { + var arr = nj.arange(10).reshape(2, 5); + const a = arr.argmin(); + expect(a[0]).to.equal(0); + expect(a[1]).to.equal(0); + }); +}); From afc88f05130fbf3d4765816bee17f35fab4b15d1 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 10:37:00 -0700 Subject: [PATCH 14/28] docs: argmax and argmin --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 1a4e16f..18dfc99 100644 --- a/README.md +++ b/README.md @@ -421,9 +421,15 @@ array([[0.62755, 0.8278,0.21384], > a.min() 0.2138431086204946 > +> a.argmin() // index of a.min() +[[0, 2]] +> > a.max() 0.8278025290928781 > +> a.argmax() // index of a.max() +[[0, 1]] +> > a.mean() 0.5187748112172509 > From 5c59d9a618b65229ac7bb9afb9fc50322d8a265e Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 12:41:52 -0700 Subject: [PATCH 15/28] fix: randomLike --- test/mocha/randomLike.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mocha/randomLike.spec.js b/test/mocha/randomLike.spec.js index 86373b0..6ffce5e 100644 --- a/test/mocha/randomLike.spec.js +++ b/test/mocha/randomLike.spec.js @@ -5,7 +5,7 @@ var expect = require("expect.js"); var nj = require("../../src"); -describe("zerosLike", function () { +describe("randomLike", function () { const A = nj.array([ [1, 2], [3, 4], From 4041c5152108f933ea2727dd4c6a7078f0be6db8 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 12:48:36 -0700 Subject: [PATCH 16/28] fix: eslint mocha --- test/mocha/argmax.spec.js | 1 + test/mocha/argmin.spec.js | 1 + 2 files changed, 2 insertions(+) diff --git a/test/mocha/argmax.spec.js b/test/mocha/argmax.spec.js index eda1143..83e2658 100644 --- a/test/mocha/argmax.spec.js +++ b/test/mocha/argmax.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ 'use strict'; var expect = require('expect.js'); diff --git a/test/mocha/argmin.spec.js b/test/mocha/argmin.spec.js index 27a1f9d..45b0923 100644 --- a/test/mocha/argmin.spec.js +++ b/test/mocha/argmin.spec.js @@ -1,3 +1,4 @@ +/* eslint-env mocha */ 'use strict'; var expect = require('expect.js'); From 5dafc3ef2acbfb4dee481abc7fde7254c5efe5cd Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 12:50:41 -0700 Subject: [PATCH 17/28] fix: tabs to spaces --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 7ed4007..ba7fb07 100644 --- a/src/index.js +++ b/src/index.js @@ -411,7 +411,7 @@ function fullLike (array, fillValue, dtype) { * @return {NdArray} Array of random numbers shaped like the array argument */ function randomLike (array) { - return random(array.shape); + return random(array.shape); } /** From ef36e6b96a12eba879d23d5b1390490b68da6dcd Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 17:30:43 -0700 Subject: [PATCH 18/28] feat: applyOverAxis function --- src/index.js | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/index.js b/src/index.js index ba7fb07..196cd40 100644 --- a/src/index.js +++ b/src/index.js @@ -954,6 +954,92 @@ function rot90 (m, k, axes) { } } +/** + * Apply an aggregate operation across an axis for all of the array + * + * @param {Array|NdArray} arr array to apply to + * @param {(vectorInput: NdArray) => number} vectorFunc a function that takes in a vector and returns a number + * @param {{axis: number|undefined, keepdims: boolean}?} optional takes in which axis you are applyOverAxising over + * and keepdims=true will put 1 for the axis dimension instead of removing it + * + * axis refers to the dimension you applyOverAxis over. So axis:1 will apply the vectorFunc to the vector rows in a matrix + * if axis=-1 this just means to applyOverAxis over the last axis, -2 second to last and so on + * + * @example here I apply nj.sum across the rows of a matrix + * ```js + * > const A = nj.array([[1,2], + * [3,4]]); + * > nj.applyOverAxis(A, nj.sum, {axis: 1}) + * array([3, 7]) + * > + * > nj.applyOverAxis(A, nj.sum, {axis: 1, keepdims: true}) + * array([[3], + * [7]]); + * ``` + * + * @throws error if axis is too large for the given arr + * @return {NdArray} An array of the results from the vectorFunc batched over the axis + */ +function applyOverAxis(arr, vectorFunc, { axis=undefined, keepdims=false } = {}) { + // by default, compute across the flat array + if(axis === undefined) return vectorFunc(arr); + // ie when the axis is negative refer to end axes + if(axis < 0) { + axis = arr.shape.length + axis; // axis is - so will be < arr.shape.length + } + // if the axis is negative then wrap to end + if(axis > arr.shape.length || axis < 0) throw new errors.ValueError('the axis exceeds max number of axes (shape.length)'); + + // + // Now iterate over all vectors around the given axis and apply the vectorFunc to it + // + var results = []; + var iterShape = arr.shape.filter((d, i) => i !== axis); + // all possible indices we need to iterate over around the axis + var p = _allIndexCombinationsUpTo(iterShape); + for(let i = 0; i < p.length; i++) { + // put the null back where the axis is + var sliceLocation = p[i]; + sliceLocation.splice(axis, 0, null); + + // select the vector given location and apply the vectorOperation + var vector = arr.pick(...sliceLocation); // column at axis + var apply = vectorFunc(vector); + + // accumulate results + results.push(apply); + } + + // reshape back to original array, but with the reduced axis dimension + var resultShape = [...arr.shape]; + if(keepdims) { + resultShape[axis] = 1; + } else { + resultShape.splice(axis, 1); + } + return NdArray.new(results).reshape(resultShape); +} + +/** + * Given a shape like [2,2] will generate [[0, 0], [0, 1], [1, 0], [1, 1]] + * Basically a grid of values + * @private + * @param {Array} shape + * @returns permutations of results of length == shape.length per element + */ +function _allIndexCombinationsUpTo(shape) { + let indices = []; + function _permutations(shape, ...pastIndices) { + if(shape.length === 0) return pastIndices; + for(let i = 0; i < shape[0]; i++) { + indices.push(_permutations(shape.slice(1), ...[...pastIndices, i])); + } + return pastIndices; + } + _permutations(shape); + return indices.filter(d => d.length === shape.length); +} + module.exports = { config: CONF, dtypes: DTYPES, @@ -1028,5 +1114,6 @@ module.exports = { uint32: function (array) { return NdArray.new(array, 'uint32'); }, float32: function (array) { return NdArray.new(array, 'float32'); }, float64: function (array) { return NdArray.new(array, 'float64'); }, + applyOverAxis: applyOverAxis, images: require('./images') }; From 9992c5633d412e5b1be8b0202228919d9f6425fb Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 17:51:38 -0700 Subject: [PATCH 19/28] feat: better nestedIteration --- src/index.js | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/index.js b/src/index.js index 196cd40..0e7b57f 100644 --- a/src/index.js +++ b/src/index.js @@ -980,7 +980,7 @@ function rot90 (m, k, axes) { * @throws error if axis is too large for the given arr * @return {NdArray} An array of the results from the vectorFunc batched over the axis */ -function applyOverAxis(arr, vectorFunc, { axis=undefined, keepdims=false } = {}) { +function applyOverAxis (arr, vectorFunc, { axis=undefined, keepdims=false } = {}) { // by default, compute across the flat array if(axis === undefined) return vectorFunc(arr); // ie when the axis is negative refer to end axes @@ -996,8 +996,8 @@ function applyOverAxis(arr, vectorFunc, { axis=undefined, keepdims=false } = {}) var results = []; var iterShape = arr.shape.filter((d, i) => i !== axis); // all possible indices we need to iterate over around the axis - var p = _allIndexCombinationsUpTo(iterShape); - for(let i = 0; i < p.length; i++) { + var p = nestedIteration(iterShape); + for(var i = 0; i < p.length; i++) { // put the null back where the axis is var sliceLocation = p[i]; sliceLocation.splice(axis, 0, null); @@ -1021,23 +1021,28 @@ function applyOverAxis(arr, vectorFunc, { axis=undefined, keepdims=false } = {}) } /** - * Given a shape like [2,2] will generate [[0, 0], [0, 1], [1, 0], [1, 1]] - * Basically a grid of values - * @private - * @param {Array} shape - * @returns permutations of results of length == shape.length per element + * Helper method to essentially dynamically generated nestex for loops + * + * for(let i = 0; i < shape[0]; i++) { + * for(let j = 0; j < shape[1]; j++) { + * ... and so on + * } + * } + * + * @param {Array} shape + * @returns i,j,k... indices for a nested for loop based on shape */ -function _allIndexCombinationsUpTo(shape) { - let indices = []; - function _permutations(shape, ...pastIndices) { - if(shape.length === 0) return pastIndices; - for(let i = 0; i < shape[0]; i++) { - indices.push(_permutations(shape.slice(1), ...[...pastIndices, i])); +function nestedIteration (shape) { + var result = []; + function _iterate(shapeIndex, temp=[]) { + if(temp.length === shape.length) return temp; + for(var i = 0; i < shape[shapeIndex]; i++) { + var nested = _iterate(shapeIndex+1, [...temp, i]); + if (nested) result.push(nested); } - return pastIndices; } - _permutations(shape); - return indices.filter(d => d.length === shape.length); + _iterate(0); + return result; } module.exports = { From 24609ee2cace2b62646193defb5ffd1d2f2b623c Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 17:52:51 -0700 Subject: [PATCH 20/28] fix: stick with var for consistency --- src/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/index.js b/src/index.js index 0e7b57f..17cef61 100644 --- a/src/index.js +++ b/src/index.js @@ -432,12 +432,12 @@ function eye (N, M, dtype) { if(M === undefined) M = N; var T = _.getType(dtype); - const flatData = new T(N*M).fill(0); + var flatData = new T(N*M).fill(0); var arr = new NdArray(flatData, [N, M]); // then when i=j fill with 1s - for(let i = 0; i < N; i++) - for(let j = 0; j < M; j++) + for(var i = 0; i < N; i++) + for(var j = 0; j < M; j++) if(i === j) arr.set(i, j, 1); return arr; @@ -467,12 +467,12 @@ function tri (N, M, k = 0, dtype) { if(M === undefined) M = N; var T = _.getType(dtype); - const flatData = new T(N*M).fill(0); + var flatData = new T(N*M).fill(0); var arr = new NdArray(flatData, [N, M]); // then when i>j fill with 1s (lower triangle) increase k to increase the diagonl to fill - for(let i = 0; i < N; i++) - for(let j = 0; j < M; j++) + for(var i = 0; i < N; i++) + for(var j = 0; j < M; j++) if((i + k) > j) arr.set(i, j, 1); return arr; @@ -967,7 +967,7 @@ function rot90 (m, k, axes) { * * @example here I apply nj.sum across the rows of a matrix * ```js - * > const A = nj.array([[1,2], + * > var A = nj.array([[1,2], * [3,4]]); * > nj.applyOverAxis(A, nj.sum, {axis: 1}) * array([3, 7]) @@ -1023,8 +1023,8 @@ function applyOverAxis (arr, vectorFunc, { axis=undefined, keepdims=false } = {} /** * Helper method to essentially dynamically generated nestex for loops * - * for(let i = 0; i < shape[0]; i++) { - * for(let j = 0; j < shape[1]; j++) { + * for(var i = 0; i < shape[0]; i++) { + * for(var j = 0; j < shape[1]; j++) { * ... and so on * } * } From ee231e2e6476dd0a000a450af06916fe1f357274 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:03:09 -0700 Subject: [PATCH 21/28] feat: tests for applyOverAxis --- test/mocha/nestedIteration.spec.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/mocha/nestedIteration.spec.js diff --git a/test/mocha/nestedIteration.spec.js b/test/mocha/nestedIteration.spec.js new file mode 100644 index 0000000..b4f6b58 --- /dev/null +++ b/test/mocha/nestedIteration.spec.js @@ -0,0 +1,26 @@ +/* eslint-env mocha */ +'use strict'; + +var expect = require('expect.js'); + +var nj = require('../../src'); + +describe('nestedIteration', function () { + var A = nj.arange(4).reshape(2, 2); + var B = nj.arange(8).reshape(2, 2 ,2); + + it('Works across no axis (flat)', function () { + expect(nj.applyOverAxis(A, nj.sum)).to.eql(6); + expect(nj.applyOverAxis(B, nj.sum)).to.eql(28); + }); + + it('Works across last axis', function () { + expect(nj.applyOverAxis(A, nj.sum, {axis: -1}).tolist()).to.eql([ 1, 5]); + expect(nj.applyOverAxis(B, nj.sum, {axis: -1}).tolist()).to.eql([[ 1, 5], [ 9, 13]]); + }); + + it('keepdims works', function () { + expect(nj.applyOverAxis(A, nj.sum, {axis: -1, keepdims: true}).tolist()).to.eql([ [1], [5]]); + expect(nj.applyOverAxis(B, nj.sum, {axis: -1, keepdims: true}).tolist()).to.eql([[[ 1], [ 5]], [[ 9], [ 13]]]); + }); +}); From c4a0ea6f7ec246a75798b307cbfe2f4e0b8f3be4 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:03:22 -0700 Subject: [PATCH 22/28] feat: include print method for ease of use --- src/ndarray.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ndarray.js b/src/ndarray.js index 9ae6a4c..ec78fba 100644 --- a/src/ndarray.js +++ b/src/ndarray.js @@ -699,6 +699,13 @@ NdArray.prototype.toString = function () { } }; +/** +* Calls console.log(this.toString()) +*/ +NdArray.prototype.print = function () { + console.log(this.toString()); +}; + /** * Stringify the array to make it readable in the console, by a human. * From cc430a6e93320514a85c7ffba235e8ea5f637ab8 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:17:18 -0700 Subject: [PATCH 23/28] docs: applyOverAxis --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/README.md b/README.md index 18dfc99..03fef73 100644 --- a/README.md +++ b/README.md @@ -437,6 +437,51 @@ array([[0.62755, 0.8278,0.21384], 0.22216977543691244 ``` +### Applying Functions over an Axis + +Commonly, you might want to apply a vector function across an axis of a matrix. You can do this with the `applyOverAxis` function. For example suppose I have a matrix a + +```js +> a = nj.array([[0, 1, 2], + [3, 4, 5]]) +``` + +You can sum across the ith axis. For example the last axis is the rows, so I can specify the last axis -1 + +```js +> nj.applyOverAxis(a, nj.sum, { axis: -1 }) +array([ 3, 12]) +``` + +Or find the max down the columns (first axis is 0) +```js +> nj.applyOverAxis(a, nj.max, { axis: 0 }) +array([ 3, 4, 5]) +``` + +If you don't want to reduce the shape/dimensions of the output, you can put `keepdims: true`. For example when we summed across the rows I can maintain those row dimensions like + +```js +> nj.applyOverAxis(a, nj.sum, { axis: -1, keepdims: true }) +array([[ 3], + [ 12]]) +``` + +This also works for tensors for example an array with (2,2,2) shape I can find the mean across the last axis: + +```js +> b = array([[[ 0, 1], + [ 2, 3]], + [[ 4, 5], + [ 6, 7]]]) +> +> nj.applyOverAxis(b, nj.mean, { axis: -1, keepdims: true }) +array([[[ 0.5], + [ 2.5]], + [[ 4.5], + [ 6.5]]]) +``` + ### Universal Functions __NumJs__ provides familiar mathematical functions such as `sin`, `cos`, and `exp`. These functions operate element-wise on an array, producing an `NdArray` as output: From f4f43d807783b84b55eb3928f8cf91deabf9ff6c Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:20:07 -0700 Subject: [PATCH 24/28] fix: name test correctly --- test/mocha/{nestedIteration.spec.js => applyOverAxis.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/mocha/{nestedIteration.spec.js => applyOverAxis.js} (100%) diff --git a/test/mocha/nestedIteration.spec.js b/test/mocha/applyOverAxis.js similarity index 100% rename from test/mocha/nestedIteration.spec.js rename to test/mocha/applyOverAxis.js From c5bdaf3ac2e79bdb78db4b249cf312f7ffb2527b Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:20:55 -0700 Subject: [PATCH 25/28] spec --- test/mocha/{applyOverAxis.js => applyOverAxis.spec.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/mocha/{applyOverAxis.js => applyOverAxis.spec.js} (100%) diff --git a/test/mocha/applyOverAxis.js b/test/mocha/applyOverAxis.spec.js similarity index 100% rename from test/mocha/applyOverAxis.js rename to test/mocha/applyOverAxis.spec.js From 0def27b8283e506680533e1b1185fc2a1642c81a Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:39:42 -0700 Subject: [PATCH 26/28] fix: tabs to spaces --- src/index.js | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/index.js b/src/index.js index 17cef61..8f5d28a 100644 --- a/src/index.js +++ b/src/index.js @@ -993,31 +993,31 @@ function applyOverAxis (arr, vectorFunc, { axis=undefined, keepdims=false } = {} // // Now iterate over all vectors around the given axis and apply the vectorFunc to it // - var results = []; - var iterShape = arr.shape.filter((d, i) => i !== axis); - // all possible indices we need to iterate over around the axis - var p = nestedIteration(iterShape); - for(var i = 0; i < p.length; i++) { + var results = []; + var iterShape = arr.shape.filter((d, i) => i !== axis); + // all possible indices we need to iterate over around the axis + var p = nestedIteration(iterShape); + for(var i = 0; i < p.length; i++) { // put the null back where the axis is - var sliceLocation = p[i]; - sliceLocation.splice(axis, 0, null); + var sliceLocation = p[i]; + sliceLocation.splice(axis, 0, null); // select the vector given location and apply the vectorOperation - var vector = arr.pick(...sliceLocation); // column at axis - var apply = vectorFunc(vector); + var vector = arr.pick(...sliceLocation); // column at axis + var apply = vectorFunc(vector); // accumulate results - results.push(apply); - } + results.push(apply); + } // reshape back to original array, but with the reduced axis dimension - var resultShape = [...arr.shape]; + var resultShape = [...arr.shape]; if(keepdims) { resultShape[axis] = 1; } else { resultShape.splice(axis, 1); } - return NdArray.new(results).reshape(resultShape); + return NdArray.new(results).reshape(resultShape); } /** @@ -1033,16 +1033,16 @@ function applyOverAxis (arr, vectorFunc, { axis=undefined, keepdims=false } = {} * @returns i,j,k... indices for a nested for loop based on shape */ function nestedIteration (shape) { - var result = []; - function _iterate(shapeIndex, temp=[]) { - if(temp.length === shape.length) return temp; - for(var i = 0; i < shape[shapeIndex]; i++) { - var nested = _iterate(shapeIndex+1, [...temp, i]); - if (nested) result.push(nested); - } - } - _iterate(0); - return result; + var result = []; + function _iterate(shapeIndex, temp=[]) { + if(temp.length === shape.length) return temp; + for(var i = 0; i < shape[shapeIndex]; i++) { + var nested = _iterate(shapeIndex+1, [...temp, i]); + if (nested) result.push(nested); + } + } + _iterate(0); + return result; } module.exports = { From 9fc521250eeba5b01e3365a0d02157479ced86f5 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:46:01 -0700 Subject: [PATCH 27/28] fix: tabs to spaces --- test/mocha/fullLike.spec.js | 26 +++++++++++++------------- test/mocha/onesLike.spec.js | 26 +++++++++++++------------- test/mocha/randomLike.spec.js | 15 +++++++-------- test/mocha/zerosLike.spec.js | 26 +++++++++++++------------- 4 files changed, 46 insertions(+), 47 deletions(-) diff --git a/test/mocha/fullLike.spec.js b/test/mocha/fullLike.spec.js index bb8ac86..7bc5a4d 100644 --- a/test/mocha/fullLike.spec.js +++ b/test/mocha/fullLike.spec.js @@ -6,18 +6,18 @@ var expect = require("expect.js"); var nj = require("../../src"); describe("fullLike", function () { - const A = nj.array([ - [1, 2], - [3, 4], - ]); - it("can generate fillValue like shaped like a given matrix", function () { - expect(nj.fullLike(A, 5).tolist()).to.eql([ - [5, 5], - [5, 5], - ]); - }); + const A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate fillValue like shaped like a given matrix", function () { + expect(nj.fullLike(A, 5).tolist()).to.eql([ + [5, 5], + [5, 5], + ]); + }); - it("should accept a dtype", function () { - expect(nj.fullLike(A, 5, "uint8").dtype).to.equal("uint8"); - }); + it("should accept a dtype", function () { + expect(nj.fullLike(A, 5, "uint8").dtype).to.equal("uint8"); + }); }); diff --git a/test/mocha/onesLike.spec.js b/test/mocha/onesLike.spec.js index 56d456a..6e8f8ac 100644 --- a/test/mocha/onesLike.spec.js +++ b/test/mocha/onesLike.spec.js @@ -6,18 +6,18 @@ var expect = require("expect.js"); var nj = require("../../src"); describe("zerosLike", function () { - const A = nj.array([ - [1, 2], - [3, 4], - ]); - it("can generate zeros like shaped like a given matrix", function () { - expect(nj.onesLike(A).tolist()).to.eql([ - [1, 1], - [1, 1], - ]); - }); + var A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate zeros like shaped like a given matrix", function () { + expect(nj.onesLike(A).tolist()).to.eql([ + [1, 1], + [1, 1], + ]); + }); - it("should accept a dtype", function () { - expect(nj.onesLike(A, "uint8").dtype).to.equal("uint8"); - }); + it("should accept a dtype", function () { + expect(nj.onesLike(A, "uint8").dtype).to.equal("uint8"); + }); }); diff --git a/test/mocha/randomLike.spec.js b/test/mocha/randomLike.spec.js index 6ffce5e..0a01b56 100644 --- a/test/mocha/randomLike.spec.js +++ b/test/mocha/randomLike.spec.js @@ -6,12 +6,11 @@ var expect = require("expect.js"); var nj = require("../../src"); describe("randomLike", function () { - const A = nj.array([ - [1, 2], - [3, 4], - ]); - it("can generate zeros like shaped like a given matrix", function () { - expect(nj.randomLike(A).shape).to.eql([2, 2 - ]); - }); + var A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate zeros like shaped like a given matrix", function () { + expect(nj.randomLike(A).shape).to.eql([2, 2]); + }); }); diff --git a/test/mocha/zerosLike.spec.js b/test/mocha/zerosLike.spec.js index 51f7ed1..8a5270e 100644 --- a/test/mocha/zerosLike.spec.js +++ b/test/mocha/zerosLike.spec.js @@ -6,18 +6,18 @@ var expect = require("expect.js"); var nj = require("../../src"); describe("zerosLike", function () { - const A = nj.array([ - [1, 2], - [3, 4], - ]); - it("can generate zeros like shaped like a given matrix", function () { - expect(nj.zerosLike(A).tolist()).to.eql([ - [0, 0], - [0, 0], - ]); - }); + var A = nj.array([ + [1, 2], + [3, 4], + ]); + it("can generate zeros like shaped like a given matrix", function () { + expect(nj.zerosLike(A).tolist()).to.eql([ + [0, 0], + [0, 0], + ]); + }); - it("should accept a dtype", function () { - expect(nj.zerosLike(A, "uint8").dtype).to.equal("uint8"); - }); + it("should accept a dtype", function () { + expect(nj.zerosLike(A, "uint8").dtype).to.equal("uint8"); + }); }); From b8f3a22f3cad8bf90656c2d7adb1a3df89250c18 Mon Sep 17 00:00:00 2001 From: xnought Date: Thu, 30 May 2024 18:46:33 -0700 Subject: [PATCH 28/28] fix: use var --- test/mocha/fullLike.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mocha/fullLike.spec.js b/test/mocha/fullLike.spec.js index 7bc5a4d..ba8ecae 100644 --- a/test/mocha/fullLike.spec.js +++ b/test/mocha/fullLike.spec.js @@ -6,7 +6,7 @@ var expect = require("expect.js"); var nj = require("../../src"); describe("fullLike", function () { - const A = nj.array([ + var A = nj.array([ [1, 2], [3, 4], ]);