From ade68cf38973383438fa21e9563991b97355f4bd Mon Sep 17 00:00:00 2001 From: nakul-krishnakumar Date: Wed, 27 May 2026 13:01:08 +0530 Subject: [PATCH 1/5] feat: add `ml/strided/dkmeans-init-plus-plus` --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../lib/dkmeans_init_plus_plus.js | 152 +++++++++++ .../dkmeans-init-plus-plus/lib/index.js | 94 +++++++ .../dkmeans-init-plus-plus/lib/main.js | 35 +++ .../dkmeans-init-plus-plus/lib/ndarray.js | 243 ++++++++++++++++++ 4 files changed, 524 insertions(+) create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/main.js create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js new file mode 100644 index 000000000000..1e60b8be16cc --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js @@ -0,0 +1,152 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var isLayout = require( '@stdlib/blas/base/assert/is-layout' ); +var isRowMajor = require( '@stdlib/ndarray/base/assert/is-row-major-string' ); +var isColumnMajor = require( '@stdlib/ndarray/base/assert/is-column-major-string' ); +var max = require( '@stdlib/math/base/special/fast/max' ); +var format = require( '@stdlib/string/format' ); +var ndarray = require( './ndarray.js' ); + + +// MAIN // + +/** +* Initializes centroids by performing the k-means++ initialization procedure. +* +* ## Method +* +* The k-means++ algorithm for choosing initial centroids is as follows: +* +* 1. Select a data point uniformly at random from a data set \\( X \\). This data point is first centroid and denoted \\( c_0 \\). +* +* 2. Compute the distance from each data point to \\( c_0 \\). Denote the distance between \\( c_j \\) and data point \\( m \\) as \\( d(x_m, c_j) \\). +* +* 3. Select the next centroid, \\( c_1 \\), at random from \\( X \\) with probability +* +* ```tex +* \frac{d^2(x_m, c_0)}{\sum_{j=0}^{n-1} d^2(x_j, c_0)} +* ``` +* +* where \\( n \\) is the number of data points. +* +* 4. To choose centroid \\( j \\), +* +* a. Compute the distances from each data point to each centroid and assign each data point to its closest centroid. +* +* b. For \\( i = 0,\ldots,n-1 \\) and \\( p = 0,\ldots,j-2 \\), select centroid \\( j \\) at random from \\( X \\) with probability +* +* ```tex +* \frac{d^2(x_i, c_p)}{\sum_{\{h; x_h \exits C_p\}} d^2(x_h, c_p)} +* ``` +* +* where \\( C_p \\) is the set of all data points closest to centroid \\( c_p \\) and \\( x_i \\) belongs to \\( c_p \\). +* +* Stated more plainly, select each subsequent centroid with a probability proportional to the distance from the centroid to the closest centroid already chosen. +* +* 5. Repeat step `4` until \\( k \\) centroids have been chosen. +* +* ## References +* +* - Arthur, David, and Sergei Vassilvitskii. 2007. "K-means++: The Advantages of Careful Seeding." In _Proceedings of the Eighteenth Annual Acm-Siam Symposium on Discrete Algorithms_, 1027–35. SODA '07. Philadelphia, PA, USA: Society for Industrial and Applied Mathematics. . +* +* @param {string} order - storage layout +* @param {PositiveInteger} k - number of clusters +* @param {PositiveInteger} M - number of data points +* @param {PositiveInteger} N - number of features +* @param {Float64Array} out - input array +* @param {integer} LDO - stride of the first dimension of `out` (a.k.a., leading dimension of the matrix `out`) +* @param {Float64Array} X - input array +* @param {integer} LDX - stride of the first dimension of `x` (a.k.a., leading dimension of the matrix `x`) +* @param {string} metric - distance metric +* @param {PositiveInteger} trials - number of potential centroids per iteration (>= 1) +* @param {*} seed - PRNG seed +* @throws {TypeError} first argument must be a valid order +* @throws {RangeError} sixth argument must be greater than or equal to max(1,N) +* @throws {RangeError} eighth argument must be greater than or equal to max(1,N) +* @returns {Float64Array} centroids +* +* @example +* var Float64Array = require( '@stdlib/array/float64' ); +* +* var k = 3; +* var M = 5; +* var N = 2; +* +* var out = new Float64Array( k*N ); +* +* // Specify data points: +* var xbuf = new Float64Array([ +* 0.0, 0.0, +* 1.0, 1.0, +* 1.0, -1.0, +* -1.0, -1.0, +* -1.0, 1.0 +* ]); +* +* var v = dkmeansInitPlusPlus( 'row-major', k, M, N, out, 2, xbuf, 2, 'sqeuclidean', 3, 44 ); +* // returns [0,0,1,-1,1,1] +*/ +function dkmeansInitPlusPlus( order, k, M, N, out, LDO, X, LDX, metric, trials, seed ) { // eslint-disable-line max-len, max-params + var so1; + var so2; + var sx1; + var sx2; + var so; + var sx; + + if ( !isLayout( order ) ) { + throw new TypeError( format( 'invalid argument. First argument must be a valid order. Value: `%s`.', order ) ); + } + if ( isRowMajor( order ) ) { + so = N; + sx = N; + } else { + so = k; + sx = M; + } + if ( LDO < max( 1, so ) ) { + throw new RangeError( format( 'invalid argument. Fifth argument must be greater than or equal to max(1,%d). Value: `%d`.', so, LDO ) ); + } + if ( LDX < max( 1, sx ) ) { + throw new RangeError( format( 'invalid argument. Fifth argument must be greater than or equal to max(1,%d). Value: `%d`.', sx, LDO ) ); + } + if ( isColumnMajor( order ) ) { + so1 = 1; + so2 = LDO; + + sx1 = 1; + sx2 = LDX; + } else { // order === 'row-major' + so1 = LDO; + so2 = 1; + + sx1 = LDX; + sx2 = 1; + } + return ndarray( k, M, N, out, so1, so2, 0, X, sx1, sx2, 0, metric, trials, seed ); // eslint-disable-line max-len +} + + +// EXPORTS // + +module.exports = dkmeansInitPlusPlus; diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js new file mode 100644 index 000000000000..89a2199da91b --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js @@ -0,0 +1,94 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +/** +* Initialize centroids by performing the k-means++ initialization procedure using alternative indexing semantics. +* +* @module @stdlib/ml/strided/dkmeans-init-plus-plus +* +* @example +* var Float64Array = require( '@stdlib/array/float64' ); +* var dkmeansInitPlusPlus = require( '@stdlib/ml/strided/dkmeans-init-plus-plus' ); +* +* var k = 3; +* var M = 5; +* var N = 2; +* +* var out = new Float64Array( k*N ); +* +* // Specify data points: +* var xbuf = new Float64Array([ +* 0.0, 0.0, +* 1.0, 1.0, +* 1.0, -1.0, +* -1.0, -1.0, +* -1.0, 1.0 +* ]); +* +* var v = dkmeansInitPlusPlus( 'row-major', k, M, N, out, 2, xbuf, 2, 'sqeuclidean', 3, 44 ); +* // returns [0,0,1,-1,1,1] +* +* @example +* var Float64Array = require( '@stdlib/array/float64' ); +* var dkmeansInitPlusPlus = require( '@stdlib/ml/strided/dkmeans-init-plus-plus' ); +* +* var k = 3; +* var M = 5; +* var N = 2; +* +* var out = new Float64Array( k*N ); +* +* // Specify data points: +* var xbuf = new Float64Array([ +* 0.0, 0.0, +* 1.0, 1.0, +* 1.0, -1.0, +* -1.0, -1.0, +* -1.0, 1.0 +* ]); +* +* var v = dkmeansInitPlusPlus.ndarray( k, M, N, out, 2, 1, 0, xbuf, 2, 1, 0, 'sqeuclidean', 3, 44 ); +* // returns [0,0,1,-1,1,1] +*/ + +// MODULES // + +var join = require( 'path' ).join; +var tryRequire = require( '@stdlib/utils/try-require' ); +var isError = require( '@stdlib/assert/is-error' ); +var main = require( './main.js' ); + + +// MAIN // + +var dkmeansInitPlusPlus; +var tmp = tryRequire( join( __dirname, './native.js' ) ); +if ( isError( tmp ) ) { + dkmeansInitPlusPlus = main; +} else { + dkmeansInitPlusPlus = tmp; +} + + +// EXPORTS // + +module.exports = dkmeansInitPlusPlus; + +// exports: { "ndarray": "dkmeansInitPlusPlus.ndarray" } diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/main.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/main.js new file mode 100644 index 000000000000..0745f2767c76 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/main.js @@ -0,0 +1,35 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var setReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' ); +var dkmeansInitPlusPlus = require( './dkmeans_init_plus_plus.js' ); +var ndarray = require( './ndarray.js' ); + + +// MAIN // + +setReadOnly( dkmeansInitPlusPlus, 'ndarray', ndarray ); + + +// EXPORTS // + +module.exports = dkmeansInitPlusPlus; diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js new file mode 100644 index 000000000000..148c6fa986b9 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js @@ -0,0 +1,243 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var randint = require( '@stdlib/random/base/discrete-uniform' ).factory; +var randu = require( '@stdlib/random/base/mt19937' ).factory; +var dcopy = require( '@stdlib/blas/base/dcopy' ).ndarray; +var Float64Array = require( '@stdlib/array/float64' ); +var PINF = require( '@stdlib/constants/float64/pinf' ); +var dsquaredEuclidean = require( '@stdlib/stats/strided/distances/dsquared-euclidean' ).ndarray; +var dcosine = require( '@stdlib/stats/strided/distances/dcosine-distance' ).ndarray; +var dcityblock = require( '@stdlib/stats/strided/distances/dcityblock' ).ndarray; +var dcorrelation = require( '@stdlib/stats/strided/distances/dcorrelation' ).ndarray; + + +// MAIN // + +/** +* Initializes centroids by performing the k-means++ initialization procedure using alternative indexing semantics. +* +* ## Method +* +* The k-means++ algorithm for choosing initial centroids is as follows: +* +* 1. Select a data point uniformly at random from a data set \\( X \\). This data point is first centroid and denoted \\( c_0 \\). +* +* 2. Compute the distance from each data point to \\( c_0 \\). Denote the distance between \\( c_j \\) and data point \\( m \\) as \\( d(x_m, c_j) \\). +* +* 3. Select the next centroid, \\( c_1 \\), at random from \\( X \\) with probability +* +* ```tex +* \frac{d^2(x_m, c_0)}{\sum_{j=0}^{n-1} d^2(x_j, c_0)} +* ``` +* +* where \\( n \\) is the number of data points. +* +* 4. To choose centroid \\( j \\), +* +* a. Compute the distances from each data point to each centroid and assign each data point to its closest centroid. +* +* b. For \\( i = 0,\ldots,n-1 \\) and \\( p = 0,\ldots,j-2 \\), select centroid \\( j \\) at random from \\( X \\) with probability +* +* ```tex +* \frac{d^2(x_i, c_p)}{\sum_{\{h; x_h \exits C_p\}} d^2(x_h, c_p)} +* ``` +* +* where \\( C_p \\) is the set of all data points closest to centroid \\( c_p \\) and \\( x_i \\) belongs to \\( c_p \\). +* +* Stated more plainly, select each subsequent centroid with a probability proportional to the distance from the centroid to the closest centroid already chosen. +* +* 5. Repeat step `4` until \\( k \\) centroids have been chosen. +* +* ## References +* +* - Arthur, David, and Sergei Vassilvitskii. 2007. "K-means++: The Advantages of Careful Seeding." In _Proceedings of the Eighteenth Annual Acm-Siam Symposium on Discrete Algorithms_, 1027–35. SODA '07. Philadelphia, PA, USA: Society for Industrial and Applied Mathematics. . +* +* @param {PositiveInteger} k - number of clusters +* @param {PositiveInteger} M - number of data points +* @param {PositiveInteger} N - number of features +* @param {Float64Array} out - input array +* @param {integer} so1 - first stride length of `out` +* @param {integer} so2 - second stride length of `out` +* @param {NonNegativeInteger} oo - starting index of `out` +* @param {Float64Array} X - input array +* @param {integer} sx1 - first stride length of `X` +* @param {integer} sx2 - second stride length of `X` +* @param {NonNegativeInteger} ox - starting index of `X` +* @param {string} metric - distance metric +* @param {PositiveInteger} trials - number of potential centroids per iteration (>= 1) +* @param {*} seed - PRNG seed +* @returns {Float64Array} centroids +* +* @example +* var Float64Array = require( '@stdlib/array/float64' ); +* +* var k = 3; +* var M = 5; +* var N = 2; +* +* var out = new Float64Array( k*N ); +* +* // Specify data points: +* var xbuf = new Float64Array([ +* 0.0, 0.0, +* 1.0, 1.0, +* 1.0, -1.0, +* -1.0, -1.0, +* -1.0, 1.0 +* ]); +* +* var v = dkmeansInitPlusPlus( k, M, N, out, 2, 1, 0, xbuf, 2, 1, 0, 'sqeuclidean', 3, 44 ); +* // returns [0,0,1,-1,1,1] +*/ +function dkmeansInitPlusPlus( k, M, N, out, so1, so2, oo, X, sx1, sx2, ox, metric, trials, seed ) { // eslint-disable-line max-len, max-params + var centroids; // array of indices + var dhash; + var randi; + var probs; + var rand; + var csum; + var bsum; + var dist; + var xidx; + var cidx; + var oidx; + var d2; + var bc; + var d; + var c; + var i; + var j; + var t; + var r; + + // Create seeded PRNGs: + rand = randu({ + 'seed': seed + }); + randi = randint({ + 'seed': rand() + }); + rand = rand.normalized; + + // 1. Select a data point at random for the first centroid... + c = randi( 0, M-1 ); + if ( k === 1 ) { + // For the trivial case of one centroid, we are done which means we can skip to setting the output centroid data... + return dcopy( N, X, sx2, ox + ( sx1*c ), out, so2, oo ); + } + centroids = [ c ]; + + if ( metric === 'sqeuclidean' ) { + dist = dsquaredEuclidean; + } else if ( metric === 'cosine' ) { + dist = dcosine; + } else if ( metric === 'cityblock' ) { + dist = dcityblock; + } else { + dist = dcorrelation; + } + + dhash = new Float64Array( M ); + for ( i = 0; i < M; i++ ) { + dhash[ i ] = PINF; // squared distance + } + // Create a scratch array for storing cumulative probabilities: + probs = new Float64Array( M ); + + // 2-5. For each data point, compute the distances to each centroid, find the closest centroid, and, based on the distance to the closest centroid, assign a probability to the data point to be chosen as centroid `c_j`... + for ( i = 1; i < k; i++ ) { + csum = 0.0; + xidx = ox; + cidx = ox + ( sx1*centroids[ i-1 ] ); + for ( j = 0; j < M; j++ ) { + d2 = dist( N, X, sx2, xidx, X, sx2, cidx ); + if ( d2 < dhash[ j ] ) { + dhash[ j ] = d2; + csum += d2; + } else { + csum += dhash[ j ]; + } + xidx += sx1; + } + + if ( csum === 0.0 ) { + centroids.push( randi( 0, M-1 ) ); + continue; + } + + // Compute the cumulative probabilities... + probs[ 0 ] = dhash[ 0 ] / csum; + for ( j = 1; j < M; j++ ) { + probs[ j ] = probs[ j-1 ] + ( dhash[ j ] / csum ); + } + // Based Arthur's and Vassilvitskii's paper "kmeans++: The Advantages of Careful Seeding" (see conclusion), randomly select candidate centroids and pick the candidate which minimizes the total squared distance... + bsum = PINF; // best sum + bc = -1; // best candidate + for ( t = 0; t < trials; t++ ) { + // Use rejection sampling to handle edge case where the total cumulative probability does not equal unity due to accumulated floating-point errors and is less than `r` (*very* rarely should this require more than one iteration)... + c = -1; + + // Note: the following should never choose an already chosen centroid (why? because a centroid's minimum squared distance is `0`, which means it will either correspond to a cumulative probability of `0` or will correspond to a cumulative probability equal to the previous cumulative probability, thus leading to the equivalent of a no-op iteration) + while ( c === -1 ) { + r = rand(); // Note: `r` exists on the interval `[0,1)` + for ( j = 0; j < M; j++ ) { + if ( r < probs[ j ] ) { + c = j; + break; + } + } + } + // Compute the sum of squared distances were we to include the candidate centroid... + csum = 0.0; + cidx = ox + ( sx1 * c ); + for ( j = 0; j < M; j++ ) { + d = dist( N, X, sx2, ox + ( sx1*j ), X, sx2, cidx ); + if ( d < dhash[ j ] ) { + csum += d; + } else { + csum += dhash[ j ]; + } + } + // Determine if the candidate is the best candidate we have seen thus far... + if ( csum < bsum ) { + bsum = csum; + bc = c; + } + } + // Push the "best" candidate to our list of centroids: + centroids.push( bc ); + } + // 6. Set centroid data... + oidx = oo; + for ( i = 0; i < k; i++ ) { + // Note: the following is likely to be an "out-of-order" copy... + dcopy( N, X, sx2, ox + ( sx1*centroids[i] ), out, so2, oidx ); + oidx += so1; + } + return out; +} + + +// EXPORTS // + +module.exports = dkmeansInitPlusPlus; From 910e515da5e0708f2df60f2156e521f0db4dc862 Mon Sep 17 00:00:00 2001 From: nakul-krishnakumar Date: Wed, 27 May 2026 13:15:47 +0530 Subject: [PATCH 2/5] fix: add argument validation for `trials` --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js | 4 ++++ .../ml/strided/dkmeans-init-plus-plus/lib/ndarray.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js index 1e60b8be16cc..50da5f0aabe0 100644 --- a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js @@ -81,6 +81,7 @@ var ndarray = require( './ndarray.js' ); * @param {PositiveInteger} trials - number of potential centroids per iteration (>= 1) * @param {*} seed - PRNG seed * @throws {TypeError} first argument must be a valid order +* @throws {TypeError} tenth argument must be a valid trials (>=1) * @throws {RangeError} sixth argument must be greater than or equal to max(1,N) * @throws {RangeError} eighth argument must be greater than or equal to max(1,N) * @returns {Float64Array} centroids @@ -117,6 +118,9 @@ function dkmeansInitPlusPlus( order, k, M, N, out, LDO, X, LDX, metric, trials, if ( !isLayout( order ) ) { throw new TypeError( format( 'invalid argument. First argument must be a valid order. Value: `%s`.', order ) ); } + if ( trials < 1 ) { + throw new TypeError( format( 'invalid argument. Tenth argument must be a valid trials (>=1). Value: `%s`.', trials ) ); + } if ( isRowMajor( order ) ) { so = N; sx = N; diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js index 148c6fa986b9..b56081bb39cd 100644 --- a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js @@ -25,6 +25,7 @@ var randu = require( '@stdlib/random/base/mt19937' ).factory; var dcopy = require( '@stdlib/blas/base/dcopy' ).ndarray; var Float64Array = require( '@stdlib/array/float64' ); var PINF = require( '@stdlib/constants/float64/pinf' ); +var format = require( '@stdlib/string/format' ); var dsquaredEuclidean = require( '@stdlib/stats/strided/distances/dsquared-euclidean' ).ndarray; var dcosine = require( '@stdlib/stats/strided/distances/dcosine-distance' ).ndarray; var dcityblock = require( '@stdlib/stats/strided/distances/dcityblock' ).ndarray; @@ -86,6 +87,7 @@ var dcorrelation = require( '@stdlib/stats/strided/distances/dcorrelation' ).nda * @param {string} metric - distance metric * @param {PositiveInteger} trials - number of potential centroids per iteration (>= 1) * @param {*} seed - PRNG seed +* @throws {TypeError} tenth argument must be a valid trials (>=1) * @returns {Float64Array} centroids * * @example @@ -130,6 +132,10 @@ function dkmeansInitPlusPlus( k, M, N, out, so1, so2, oo, X, sx1, sx2, ox, metri var t; var r; + if ( trials < 1 ) { + throw new TypeError( format( 'invalid argument. Thirteenth argument must be a valid trials (>=1). Value: `%s`.', trials ) ); + } + // Create seeded PRNGs: rand = randu({ 'seed': seed From 4d8fd8773aa5404c66435f01a772c11824f0c507 Mon Sep 17 00:00:00 2001 From: nakul-krishnakumar Date: Wed, 27 May 2026 22:10:20 +0530 Subject: [PATCH 3/5] test: add tests for `ml/strided/dkmeans-init-plus-plus --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../test/fixtures/column_major.json | 53 ++++ .../fixtures/large-strides/column_major.json | 62 +++++ .../fixtures/large-strides/row_major.json | 58 ++++ .../fixtures/mixed-strides/column_major.json | 48 ++++ .../fixtures/mixed-strides/row_major.json | 50 ++++ .../negative-strides/column_major.json | 50 ++++ .../fixtures/negative-strides/row_major.json | 50 ++++ .../test/fixtures/offsets/column_major.json | 51 ++++ .../test/fixtures/offsets/row_major.json | 49 ++++ .../test/fixtures/row_major.json | 49 ++++ .../test/test.dkmeans_init_plus_plus.js | 247 +++++++++++++++++ .../dkmeans-init-plus-plus/test/test.js | 82 ++++++ .../test/test.ndarray.js | 260 ++++++++++++++++++ 13 files changed, 1109 insertions(+) create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/column_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/column_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/row_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/column_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/row_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/column_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/row_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/column_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/row_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/row_major.json create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.dkmeans_init_plus_plus.js create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.js create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.ndarray.js diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/column_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/column_major.json new file mode 100644 index 000000000000..a8c767b24db9 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/column_major.json @@ -0,0 +1,53 @@ +{ + "order": "column-major", + "out": [ + 0.0, + 0.0, + 9999.0, + 9999.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 4, + "N": 2, + "strideO1": 1, + "strideO2": 4, + "offsetO": 0, + "LDO": 4, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 1.0, + 2.0, + 5.0, + 0.0, + 3.0, + 4.0, + 6.0, + 0.0 + ], + "strideX1": 1, + "strideX2": 4, + "offsetX": 0, + "LDX": 4, + "X_mat": [ + [ 1.0, 3.0 ], + [ 2.0, 4.0 ], + [ 5.0, 6.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 1.0, + 5.0, + 9999.0, + 9999.0, + 3.0, + 6.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/column_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/column_major.json new file mode 100644 index 000000000000..80ae77ae1bf8 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/column_major.json @@ -0,0 +1,62 @@ +{ + "order": "column-major", + "out": [ + 0.0, + 9999.0, + 0.0, + 9999.0, + 9999.0, + 9999.0, + 0.0, + 9999.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": 2, + "strideO2": 6, + "offsetO": 0, + "LDO": 3, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 1.0, + 9999.0, + 2.0, + 9999.0, + 0.0, + 9999.0, + 3.0, + 9999.0, + 4.0, + 9999.0, + 0.0, + 9999.0 + ], + "strideX1": 2, + "strideX2": 6, + "offsetX": 0, + "LDX": 3, + "X_mat": [ + [ 1.0, 3.0 ], + [ 2.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 1.0, + 9999.0, + 0.0, + 9999.0, + 9999.0, + 9999.0, + 3.0, + 9999.0, + 0.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/row_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/row_major.json new file mode 100644 index 000000000000..39192a0c1b22 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/large-strides/row_major.json @@ -0,0 +1,58 @@ +{ + "order": "row-major", + "out": [ + 0.0, + 9999.0, + 0.0, + 9999.0, + 0.0, + 9999.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": 4, + "strideO2": 2, + "offsetO": 0, + "LDO": 2, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 1.0, + 9999.0, + 2.0, + 9999.0, + 3.0, + 9999.0, + 4.0, + 9999.0, + 0.0, + 9999.0, + 0.0, + 9999.0 + ], + "strideX1": 4, + "strideX2": 2, + "offsetX": 0, + "LDX": 2, + "X_mat": [ + [ 1.0, 2.0 ], + [ 3.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 1.0, + 9999.0, + 2.0, + 9999.0, + 3.0, + 9999.0, + 4.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/column_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/column_major.json new file mode 100644 index 000000000000..9e5d79575b43 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/column_major.json @@ -0,0 +1,48 @@ +{ + "order": "column-major", + "out": [ + 0.0, + 0.0, + 9999.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": 1, + "strideO2": -3, + "offsetO": 3, + "LDO": 3, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 3.0, + 4.0, + 0.0, + 1.0, + 2.0, + 0.0 + ], + "strideX1": 1, + "strideX2": -3, + "offsetX": 3, + "LDX": 3, + "X_mat": [ + [ 1.0, 3.0 ], + [ 2.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 3.0, + 0.0, + 9999.0, + 1.0, + 0.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/row_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/row_major.json new file mode 100644 index 000000000000..49fcd8f5b807 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/mixed-strides/row_major.json @@ -0,0 +1,50 @@ +{ + "order": "row-major", + "out": [ + 9999.0, + 9999.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": -2, + "strideO2": 1, + "offsetO": 4, + "LDO": 2, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 0.0, + 0.0, + 3.0, + 4.0, + 1.0, + 2.0 + ], + "strideX1": -2, + "strideX2": 1, + "offsetX": 4, + "LDX": 2, + "X_mat": [ + [ 1.0, 2.0 ], + [ 3.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 9999.0, + 9999.0, + 3.0, + 4.0, + 1.0, + 2.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/column_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/column_major.json new file mode 100644 index 000000000000..dd77c49804ba --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/column_major.json @@ -0,0 +1,50 @@ +{ + "order": "column-major", + "out": [ + 9999.0, + 0.0, + 0.0, + 9999.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": -1, + "strideO2": -3, + "offsetO": 5, + "LDO": 3, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 0.0, + 4.0, + 3.0, + 0.0, + 2.0, + 1.0 + ], + "strideX1": -1, + "strideX2": -3, + "offsetX": 5, + "LDX": 3, + "X_mat": [ + [ 1.0, 3.0 ], + [ 2.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 9999.0, + 0.0, + 3.0, + 9999.0, + 0.0, + 1.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/row_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/row_major.json new file mode 100644 index 000000000000..490d9bbd708e --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/negative-strides/row_major.json @@ -0,0 +1,50 @@ +{ + "order": "row-major", + "out": [ + 9999.0, + 9999.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": -2, + "strideO2": -1, + "offsetO": 5, + "LDO": 2, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 0.0, + 0.0, + 4.0, + 3.0, + 2.0, + 1.0 + ], + "strideX1": -2, + "strideX2": -1, + "offsetX": 5, + "LDX": 2, + "X_mat": [ + [ 1.0, 2.0 ], + [ 3.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 9999.0, + 9999.0, + 4.0, + 3.0, + 2.0, + 1.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/column_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/column_major.json new file mode 100644 index 000000000000..546d081bface --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/column_major.json @@ -0,0 +1,51 @@ +{ + "order": "column-major", + "out": [ + 9999.0, + 0.0, + 0.0, + 9999.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": 1, + "strideO2": 3, + "offsetO": 1, + "LDO": 3, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 9999.0, + 1.0, + 2.0, + 0.0, + 3.0, + 4.0, + 0.0 + ], + "strideX1": 1, + "strideX2": 3, + "offsetX": 1, + "LDX": 3, + "X_mat": [ + [ 1.0, 3.0 ], + [ 2.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 9999.0, + 1.0, + 0.0, + 9999.0, + 3.0, + 0.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/row_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/row_major.json new file mode 100644 index 000000000000..94633bf04965 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/offsets/row_major.json @@ -0,0 +1,49 @@ +{ + "order": "row-major", + "out": [ + 9999.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 3, + "N": 2, + "strideO1": 2, + "strideO2": 1, + "offsetO": 1, + "LDO": 2, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 9999.0, + 1.0, + 2.0, + 3.0, + 4.0, + 0.0, + 0.0 + ], + "strideX1": 2, + "strideX2": 1, + "offsetX": 1, + "LDX": 2, + "X_mat": [ + [ 1.0, 2.0 ], + [ 3.0, 4.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 9999.0, + 1.0, + 2.0, + 3.0, + 4.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/row_major.json b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/row_major.json new file mode 100644 index 000000000000..d0d6c551c774 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/fixtures/row_major.json @@ -0,0 +1,49 @@ +{ + "order": "row-major", + "out": [ + 0.0, + 0.0, + 0.0, + 0.0 + ], + "k": 2, + "M": 4, + "N": 2, + "strideO1": 2, + "strideO2": 1, + "offsetO": 0, + "LDO": 2, + "out_mat": [ + [ 0.0, 0.0 ], + [ 0.0, 0.0 ] + ], + "X": [ + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 0.0, + 0.0 + ], + "strideX1": 2, + "strideX2": 1, + "offsetX": 0, + "LDX": 2, + "X_mat": [ + [ 1.0, 2.0 ], + [ 3.0, 4.0 ], + [ 5.0, 6.0 ], + [ 0.0, 0.0 ] + ], + "metric": "sqeuclidean", + "trials": 2, + "seed": 44, + "expected": [ + 1.0, + 2.0, + 5.0, + 6.0 + ] +} diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.dkmeans_init_plus_plus.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.dkmeans_init_plus_plus.js new file mode 100644 index 000000000000..3f2072acfa23 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.dkmeans_init_plus_plus.js @@ -0,0 +1,247 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable max-len */ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var Float64Array = require( '@stdlib/array/float64' ); +var isAlmostSameValue = require( '@stdlib/assert/is-almost-same-value' ); +var dkmeansInitPlusPlus = require( './../lib/dkmeans_init_plus_plus.js' ); + + +// FIXTURES // + +var ROW_MAJOR_DATA = require( './fixtures/row_major.json' ); +var COLUMN_MAJOR_DATA = require( './fixtures/column_major.json' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof dkmeansInitPlusPlus, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function has an arity of 11', function test( t ) { + t.strictEqual( dkmeansInitPlusPlus.length, 11, 'returns expected value' ); + t.end(); +}); + +tape( 'the function throws an error if provided a first argument which is not a valid order', function test( t ) { + var values; + var data; + var i; + + data = ROW_MAJOR_DATA; + + values = [ + 'foo', + 'bar', + 'beep', + 'boop', + -5, + NaN, + true, + false, + null, + void 0, + [], + {}, + function noop() {} + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), TypeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + dkmeansInitPlusPlus( value, data.k, data.M, data.N, new Float64Array( data.out ), data.LDO, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + }; + } +}); + +tape( 'the function throws an error if provided a sixth argument which is not a valid `LDO` value (row-major)', function test( t ) { + var values; + var data; + var i; + + data = ROW_MAJOR_DATA; + + values = [ + 0, + 1 + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), RangeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + dkmeansInitPlusPlus( data.order, data.k, data.M, data.N, new Float64Array( data.out ), value, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + }; + } +}); + +tape( 'the function throws an error if provided a sixth argument which is not a valid `LDO` value (column-major)', function test( t ) { + var values; + var data; + var i; + + data = COLUMN_MAJOR_DATA; + + values = [ + 0, + 1 + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), RangeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + dkmeansInitPlusPlus( data.order, data.k, data.M, data.N, new Float64Array( data.out ), value, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + }; + } +}); + +tape( 'the function throws an error if provided a eighth argument which is not a valid `LDX` value (row-major)', function test( t ) { + var values; + var data; + var i; + + data = ROW_MAJOR_DATA; + + values = [ + 0, + 1 + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), RangeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + dkmeansInitPlusPlus( data.order, data.k, data.M, data.N, new Float64Array( data.out ), data.LDO, new Float64Array( data.X ), value, data.metric, data.trials, data.seed ); + }; + } +}); + +tape( 'the function throws an error if provided a eighth argument which is not a valid `LDX ` value (column-major)', function test( t ) { + var values; + var data; + var i; + + data = COLUMN_MAJOR_DATA; + + values = [ + 0, + 1 + ]; + + for ( i = 0; i < values.length; i++ ) { + t.throws( badValue( values[ i ] ), RangeError, 'throws an error when provided ' + values[ i ] ); + } + t.end(); + + function badValue( value ) { + return function badValue() { + dkmeansInitPlusPlus( data.order, data.k, data.M, data.N, new Float64Array( data.out ), data.LDO, new Float64Array( data.X ), value, data.metric, data.trials, data.seed ); + }; + } +}); + +tape( 'the function throws an error when trials is less than or equal to zero', function test( t ) { + var data; + + data = ROW_MAJOR_DATA; + t.throws( badValue( 0 ), RangeError, 'throws an error when provided ' + 0 ); + t.end(); + + function badValue( value ) { + return function badValue() { + dkmeansInitPlusPlus( data.order, data.k, data.M, data.N, new Float64Array( data.out ), value, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + }; + } +}); + +tape( 'the function returns a NaN array when M is less than or equal to zero', function test( t ) { + var data; + var out; + + data = ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.order, data.k, 0, data.N, new Float64Array( data.out ), data.LDO, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + + t.strictEqual( isAlmostSameValue( out, NaN, 0), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns a NaN array when N is less than or equal to zero', function test( t ) { + var data; + var out; + + data = ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.order, data.k, data.M, 0, new Float64Array( data.out ), data.LDO, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + + t.strictEqual( isAlmostSameValue( out, NaN, 0), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns the centroids (row-major)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.order, data.k, data.M, data.N, new Float64Array( data.out ), data.LDO, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (column-major)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.order, data.k, data.M, data.N, new Float64Array( data.out ), data.LDO, new Float64Array( data.X ), data.LDX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.js new file mode 100644 index 000000000000..4df22faf26d4 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.js @@ -0,0 +1,82 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var proxyquire = require( 'proxyquire' ); +var IS_BROWSER = require( '@stdlib/assert/is-browser' ); +var dkmeansInitPlusPlus = require( './../lib' ); + + +// VARIABLES // + +var opts = { + 'skip': IS_BROWSER +}; + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof dkmeansInitPlusPlus, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'attached to the main export is a method providing an ndarray interface', function test( t ) { + t.strictEqual( typeof dkmeansInitPlusPlus.ndarray, 'function', 'method is a function' ); + t.end(); +}); + +tape( 'if a native implementation is available, the main export is the native implementation', opts, function test( t ) { + var dkmeansInitPlusPlus = proxyquire( './../lib', { + '@stdlib/utils/try-require': tryRequire + }); + + t.strictEqual( dkmeansInitPlusPlus, mock, 'returns expected value' ); + t.end(); + + function tryRequire() { + return mock; + } + + function mock() { + // Mock... + } +}); + +tape( 'if a native implementation is not available, the main export is a JavaScript implementation', opts, function test( t ) { + var dkmeansInitPlusPlus; + var main; + + main = require( './../lib/dkmeans_init_plus_plus.js' ); + + dkmeansInitPlusPlus = proxyquire( './../lib', { + '@stdlib/utils/try-require': tryRequire + }); + + t.strictEqual( dkmeansInitPlusPlus, main, 'returns expected value' ); + t.end(); + + function tryRequire() { + return new Error( 'Cannot find module' ); + } +}); diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.ndarray.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.ndarray.js new file mode 100644 index 000000000000..37e933408ff5 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/test/test.ndarray.js @@ -0,0 +1,260 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* eslint-disable max-len, id-length */ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var Float64Array = require( '@stdlib/array/float64' ); +var isAlmostSameValue = require( '@stdlib/assert/is-almost-same-value' ); +var dkmeansInitPlusPlus = require( './../lib/ndarray.js' ); + + +// FIXTURES // + +var ROW_MAJOR_DATA = require( './fixtures/row_major.json' ); +var COLUMN_MAJOR_DATA = require( './fixtures/column_major.json' ); +var OFFSET_ROW_MAJOR_DATA = require( './fixtures/offsets/row_major.json' ); +var OFFSET_COLUMN_MAJOR_DATA = require( './fixtures/offsets/column_major.json' ); +var NEGATIVE_STRIDES_ROW_MAJOR_DATA = require( './fixtures/negative-strides/row_major.json' ); +var NEGATIVE_STRIDES_COLUMN_MAJOR_DATA = require( './fixtures/negative-strides/column_major.json' ); +var MIXED_STRIDES_ROW_MAJOR_DATA = require( './fixtures/mixed-strides/row_major.json' ); +var MIXED_STRIDES_COLUMN_MAJOR_DATA = require( './fixtures/mixed-strides/column_major.json' ); +var LARGE_STRIDES_ROW_MAJOR_DATA = require( './fixtures/large-strides/row_major.json' ); +var LARGE_STRIDES_COLUMN_MAJOR_DATA = require( './fixtures/large-strides/column_major.json' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof dkmeansInitPlusPlus, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function has an arity of 14', function test( t ) { + t.strictEqual( dkmeansInitPlusPlus.length, 14, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns a NaN array when M is less than or equal to zero (row-major)', function test( t ) { + var data; + var out; + + data = ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, 0, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + t.strictEqual( isAlmostSameValue( out, NaN, 0), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns a NaN array when N is less than or equal to zero (row-major)', function test( t ) { + var data; + var out; + + data = ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, 0, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + t.strictEqual( isAlmostSameValue( out, NaN, 0), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns a NaN array when M is less than or equal to zero (column-major)', function test( t ) { + var data; + var out; + + data = COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, 0, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + t.strictEqual( isAlmostSameValue( out, NaN, 0), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns a NaN array when N is less than or equal to zero (column-major)', function test( t ) { + var data; + var out; + + data = COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, 0, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + t.strictEqual( isAlmostSameValue( out, NaN, 0), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns the centroids (row-major)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (column-major)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (row-major, offsets)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = OFFSET_ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (column-major, offsets)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = OFFSET_COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (row-major, mixed strides)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = MIXED_STRIDES_ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (column-major, mixed strides)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = MIXED_STRIDES_COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (row-major, negative strides)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = NEGATIVE_STRIDES_ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (column-major, negative strides)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = NEGATIVE_STRIDES_COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (row-major, large strides)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = LARGE_STRIDES_ROW_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); + +tape( 'the function returns the centroids (column-major, large strides)', function test( t ) { + var expected; + var data; + var out; + var i; + + data = LARGE_STRIDES_COLUMN_MAJOR_DATA; + out = dkmeansInitPlusPlus( data.k, data.M, data.N, new Float64Array( data.out ), data.strideO1, data.strideO2, data.offsetO, new Float64Array( data.X ), data.strideX1, data.strideX2, data.offsetX, data.metric, data.trials, data.seed ); + + expected = new Float64Array( data.expected ); + for ( i = 0; i < expected.length; i++ ) { + t.strictEqual( isAlmostSameValue( out[ i ], expected[ i ], 0 ), true, 'returns expected value' ); + } + t.end(); +}); From e45a3aa91363a88654e2453124a23181ac8e95fb Mon Sep 17 00:00:00 2001 From: nakul-krishnakumar Date: Wed, 27 May 2026 22:11:37 +0530 Subject: [PATCH 4/5] bench: add JS benchmarks for `ml/strided/dkmeans-init-plus-plus --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: passed - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../benchmark/benchmark.js | 159 ++++++++++++++++++ .../benchmark/benchmark.ndarray.js | 147 ++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.js create mode 100644 lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.ndarray.js diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.js new file mode 100644 index 000000000000..3d89160dc469 --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.js @@ -0,0 +1,159 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var uniform = require( '@stdlib/random/array/uniform' ); +var Float64Array = require( '@stdlib/array/float64' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var pow = require( '@stdlib/math/base/special/pow' ); +var format = require( '@stdlib/string/format' ); +var pkg = require( './../package.json' ).name; +var dkmeansInitPlusPlus = require( './../lib/dkmeans_init_plus_plus.js' ); + + +// VARIABLES // + +var LAYOUTS = [ + 'row-major', + 'column-major' +]; + +var options = { + 'dtype': 'float64' +}; + + +// FUNCTIONS // + +/** +* Creates a benchmark function. +* +* @private +* @param {string} order - storage layout +* @param {PositiveInteger} k - number of clusters +* @param {PositiveInteger} M - number of data points +* @param {PositiveInteger} N - number of features +* @param {string} metric - distance metric +* @param {PositiveInteger} trials - number of potential centroids per iteration (>= 1) +* @returns {Function} benchmark function +*/ +function createBenchmark( order, k, M, N, metric, trials ) { + var out = new Float64Array( k*N ); + var x = uniform( M*N, -100.0, 100.0, options ); + return benchmark; + + /** + * Benchmark function. + * + * @private + * @param {Benchmark} b - benchmark instance + */ + function benchmark( b ) { + var c; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + c = dkmeansInitPlusPlus( order, k, M, N, out, N, x, N, metric, trials, 44 ); // eslint-disable-line max-len + if ( isnan( c[ i%(k*N) ] ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( c[ 0 ] ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); + } +} + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var metrics; + var trials; + var min; + var max; + var M; + var N; + var k; + var t; + var m; + var i; + var j; + var f; + + min = 1; // 10^min + max = 4; // 10^max + + // Benchmark: vary order with defaults k=2, M=100, N=2, metric=sqeuclidean, trials=1... + for ( i = 0; i <= LAYOUTS.length; i++ ) { + f = createBenchmark( LAYOUTS[ i ], 2, 100, 2, 'sqeuclidean', 1 ); + bench( format( '%s::vary_M:order=%s,k=2,M=100,N=2,metric=sqeuclidean,trials=1', pkg, LAYOUTS[ i ] ), f ); + } + + // Benchmark: vary number of data points (M) with defaults k=2, N=2, metric=sqeuclidean, trials=1... + for ( i = min; i <= max; i++ ) { + M = pow( 10, i ); + f = createBenchmark( 'row-major', 2, M, 2, 'sqeuclidean', 1 ); + bench( format( '%s::vary_M:order=row-major,k=2,M=%d,N=2,metric=sqeuclidean,trials=1', pkg, M ), f ); + } + + // Benchmark: vary number of features (N) with defaults k=2, M=10, metric=sqeuclidean, trials=1... + for ( i = min; i <= max; i++ ) { + N = pow( 10, i ); + f = createBenchmark( 'row-major', 2, 10, N, 'sqeuclidean', 1 ); + bench( format( '%s::vary_N:order=row-major,k=2,M=1000,N=%d,metric=sqeuclidean,trials=1', pkg, N ), f ); + } + + // Benchmark: vary number of clusters (k) with defaults M=1000, N=2, metric=sqeuclidean, trials=1... + for ( i = 1; i <= 4; i++ ) { + k = pow( 2, i ); + f = createBenchmark( 'row-major', k, 1000, 2, 'sqeuclidean', 1 ); + bench( format( '%s::vary_k:order=row-major,k=%d,M=1000,N=2,metric=sqeuclidean,trials=1', pkg, k ), f ); + } + + // Benchmark: vary number of trials with defaults k=2, M=1000, N=2, metric=sqeuclidean... + trials = [ 1, 10, 100, 1000 ]; + for ( j = 0; j < trials.length; j++ ) { + t = trials[ j ]; + f = createBenchmark( 'row-major', 2, 1000, 2, 'sqeuclidean', t ); + bench( format( '%s::vary_trials:order=row-major,k=2,M=1000,N=2,metric=sqeuclidean,trials=%d', pkg, t ), f ); + } + + // Benchmark: vary metric with defaults k=2, M=1000, N=2, trials=1... + metrics = [ 'sqeuclidean', 'cosine', 'cityblock', 'correlation' ]; + for ( j = 0; j < metrics.length; j++ ) { + m = metrics[ j ]; + f = createBenchmark( 'row-major', 2, 1000, 2, m, 1 ); + bench( format( '%s::vary_metric:order=row-major,k=2,M=1000,N=2,metric=%s,trials=1', pkg, m ), f ); + } +} + +main(); diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.ndarray.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.ndarray.js new file mode 100644 index 000000000000..12505912673d --- /dev/null +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/benchmark/benchmark.ndarray.js @@ -0,0 +1,147 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var uniform = require( '@stdlib/random/array/uniform' ); +var Float64Array = require( '@stdlib/array/float64' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var pow = require( '@stdlib/math/base/special/pow' ); +var format = require( '@stdlib/string/format' ); +var pkg = require( './../package.json' ).name; +var dkmeansInitPlusPlus = require( './../lib/ndarray.js' ); + + +// VARIABLES // + +var options = { + 'dtype': 'float64' +}; + + +// FUNCTIONS // + +/** +* Creates a benchmark function. +* +* @private +* @param {PositiveInteger} k - number of clusters +* @param {PositiveInteger} M - number of data points +* @param {PositiveInteger} N - number of features +* @param {string} metric - distance metric +* @param {PositiveInteger} trials - number of potential centroids per iteration (>= 1) +* @returns {Function} benchmark function +*/ +function createBenchmark( k, M, N, metric, trials ) { + var out = new Float64Array( k*N ); + var x = uniform( M*N, -100.0, 100.0, options ); + return benchmark; + + /** + * Benchmark function. + * + * @private + * @param {Benchmark} b - benchmark instance + */ + function benchmark( b ) { + var c; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + c = dkmeansInitPlusPlus( k, M, N, out, N, 1, 0, x, N, 1, 0, metric, trials, 44 ); // eslint-disable-line max-len + if ( isnan( c[ i%(k*N) ] ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( c[ 0 ] ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); + } +} + + +// MAIN // + +/** +* Main execution sequence. +* +* @private +*/ +function main() { + var metrics; + var trials; + var min; + var max; + var M; + var N; + var k; + var t; + var m; + var i; + var j; + var f; + + min = 1; // 10^min + max = 4; // 10^max + + // Benchmark: vary number of data points (M) with defaults k=2, N=2, metric=sqeuclidean, trials=1... + for ( i = min; i <= max; i++ ) { + M = pow( 10, i ); + f = createBenchmark( 2, M, 2, 'sqeuclidean', 1 ); + bench( format( '%s::vary_M:k=2,M=%d,N=2,metric=sqeuclidean,trials=1', pkg, M ), f ); + } + + // Benchmark: vary number of features (N) with defaults k=2, M=10, metric=sqeuclidean, trials=1... + for ( i = min; i <= max; i++ ) { + N = pow( 10, i ); + f = createBenchmark( 2, 10, N, 'sqeuclidean', 1 ); + bench( format( '%s::vary_N:k=2,M=1000,N=%d,metric=sqeuclidean,trials=1', pkg, N ), f ); + } + + // Benchmark: vary number of clusters (k) with defaults M=1000, N=2, metric=sqeuclidean, trials=1... + for ( i = 1; i <= 4; i++ ) { + k = pow( 2, i ); + f = createBenchmark( k, 1000, 2, 'sqeuclidean', 1 ); + bench( format( '%s::vary_k:k=%d,M=1000,N=2,metric=sqeuclidean,trials=1', pkg, k ), f ); + } + + // Benchmark: vary number of trials with defaults k=2, M=1000, N=2, metric=sqeuclidean... + trials = [ 1, 10, 100 ]; + for ( j = 0; j < trials.length; j++ ) { + t = trials[ j ]; + f = createBenchmark( 2, 1000, 2, 'sqeuclidean', t ); + bench( format( '%s::vary_trials:k=2,M=1000,N=2,metric=sqeuclidean,trials=%d', pkg, t ), f ); + } + + // Benchmark: vary metric with defaults k=2, M=1000, N=2, trials=1... + metrics = [ 'sqeuclidean', 'cosine', 'cityblock', 'correlation' ]; + for ( j = 0; j < metrics.length; j++ ) { + m = metrics[ j ]; + f = createBenchmark( 2, 1000, 2, m, 1 ); + bench( format( '%s::vary_metric:k=2,M=1000,N=2,metric=%s,trials=1', pkg, m ), f ); + } +} + +main(); From 7c045c1eda9c0b09435c0e1b65a093ebc4228df2 Mon Sep 17 00:00:00 2001 From: nakul-krishnakumar Date: Wed, 27 May 2026 23:06:44 +0530 Subject: [PATCH 5/5] fix: add early return for invalid args --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- .../dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js | 2 +- .../@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js | 2 +- .../@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js index 50da5f0aabe0..ac2bab979598 100644 --- a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/dkmeans_init_plus_plus.js @@ -31,7 +31,7 @@ var ndarray = require( './ndarray.js' ); // MAIN // /** -* Initializes centroids by performing the k-means++ initialization procedure. +* Initializes centroids by performing the k-means++ initialization procedure on double-precision floating-point data points. * * ## Method * diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js index 89a2199da91b..19f4f3d116ca 100644 --- a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/index.js @@ -19,7 +19,7 @@ 'use strict'; /** -* Initialize centroids by performing the k-means++ initialization procedure using alternative indexing semantics. +* Initialize centroids by performing the k-means++ initialization procedure on double-precision floating-point data points using alternative indexing semantics. * * @module @stdlib/ml/strided/dkmeans-init-plus-plus * diff --git a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js index b56081bb39cd..bb1ff8d31539 100644 --- a/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js +++ b/lib/node_modules/@stdlib/ml/strided/dkmeans-init-plus-plus/lib/ndarray.js @@ -35,7 +35,7 @@ var dcorrelation = require( '@stdlib/stats/strided/distances/dcorrelation' ).nda // MAIN // /** -* Initializes centroids by performing the k-means++ initialization procedure using alternative indexing semantics. +* Initializes centroids by performing the k-means++ initialization procedure on double-precision floating-point data points using alternative indexing semantics. * * ## Method * @@ -135,6 +135,9 @@ function dkmeansInitPlusPlus( k, M, N, out, so1, so2, oo, X, sx1, sx2, ox, metri if ( trials < 1 ) { throw new TypeError( format( 'invalid argument. Thirteenth argument must be a valid trials (>=1). Value: `%s`.', trials ) ); } + if ( k < 1 || M < 1 || N < 1) { + return NaN; + } // Create seeded PRNGs: rand = randu({