From 44624ca1dbb36774eddc987dfda25e3809a8890d Mon Sep 17 00:00:00 2001 From: headlessNode Date: Wed, 26 Aug 2026 21:36:11 +0500 Subject: [PATCH] feat: add index normalization support to blas/ext/base/ndarray/gcopy-within --- .../ext/base/ndarray/gcopy-within/README.md | 1 + .../base/ndarray/gcopy-within/docs/repl.txt | 4 + .../gcopy-within/docs/types/index.d.ts | 2 + .../ext/base/ndarray/gcopy-within/lib/main.js | 11 ++- .../base/ndarray/gcopy-within/test/test.js | 90 +++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) diff --git a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/README.md b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/README.md index 9522c4f627a2..6e6b06a343de 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/README.md +++ b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/README.md @@ -78,6 +78,7 @@ The function has the following parameters: ## Notes - The input ndarray is copied **in-place** (i.e., the input ndarray is **mutated**). +- If a `target`, `start`, and/or `end` index is negative, the respective index is resolved by counting backward from the last element (where `-1` refers to the last element). - If the `start` and `target` index ranges do not overlap, the `workspace` ndarray is unused and thus ignored. diff --git a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/repl.txt b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/repl.txt index cfcd1b783422..1c821ed321fd 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/repl.txt +++ b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/repl.txt @@ -5,6 +5,10 @@ The input ndarray is copied *in-place* (i.e., the input ndarray is *mutated*). + If a `target`, `start`, and/or `end` index is negative, the respective + index is resolved by counting backward from the last element (where `-1` + refers to the last element). + If the `start` and `target` index ranges do not overlap, the `workspace` ndarray is unused and thus ignored. diff --git a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/types/index.d.ts b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/types/index.d.ts index 43d1b001ea2d..45835e18256f 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/types/index.d.ts +++ b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/docs/types/index.d.ts @@ -35,6 +35,8 @@ import { typedndarray } from '@stdlib/types/ndarray'; * - a zero-dimensional ndarray specifying a source end index (exclusive). * - a one-dimensional workspace ndarray. * +* - If the `start` and `target` index ranges do not overlap, the `workspace` ndarray is unused and thus ignored. +* * @param arrays - array-like object containing ndarrays * @returns input ndarray * diff --git a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/lib/main.js b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/lib/main.js index 017303b21900..9c1dfe0e39c0 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/lib/main.js +++ b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/lib/main.js @@ -22,6 +22,7 @@ var ndarraylike2scalar = require( '@stdlib/ndarray/base/ndarraylike2scalar' ); var numelDimension = require( '@stdlib/ndarray/base/numel-dimension' ); +var clipIndex = require( '@stdlib/ndarray/base/clip-index' ); var getStride = require( '@stdlib/ndarray/base/stride' ); var getOffset = require( '@stdlib/ndarray/base/offset' ); var getData = require( '@stdlib/ndarray/base/data-buffer' ); @@ -67,24 +68,32 @@ var strided = require( '@stdlib/blas/ext/base/gcopy-within' ).ndarray; * // returns [ 1.0, 2.0, 3.0, 2.0, 3.0, 4.0 ] */ function gcopyWithin( arrays ) { + var target; + var start; + var end; var ws; var wo; var wd; var xs; var xo; var xd; + var N; var x; var w; x = arrays[ 0 ]; w = arrays[ 4 ]; + N = numelDimension( x, 0 ); + target = clipIndex( ndarraylike2scalar( arrays[ 1 ] ), N ); + start = clipIndex( ndarraylike2scalar( arrays[ 2 ] ), N ); + end = clipIndex( ndarraylike2scalar( arrays[ 3 ] ), N ); xd = getData( x ); xs = getStride( x, 0 ); xo = getOffset( x ); wd = getData( w ); ws = getStride( w, 0 ); wo = getOffset( w ); - strided( numelDimension( x, 0 ), ndarraylike2scalar( arrays[ 1 ] ), ndarraylike2scalar( arrays[ 2 ] ), ndarraylike2scalar( arrays[ 3 ] ), xd, xs, xo, wd, ws, wo ); // eslint-disable-line max-len + strided( N, target, start, end, xd, xs, xo, wd, ws, wo ); return x; } diff --git a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/test/test.js b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/test/test.js index da72c74275dc..9448cdcb946e 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/test/test.js +++ b/lib/node_modules/@stdlib/blas/ext/base/ndarray/gcopy-within/test/test.js @@ -199,6 +199,96 @@ tape( 'if the `end` index is greater than the number of elements, the function c t.end(); }); +tape( 'the function supports a negative `target` index', function test( t ) { + var actual; + var xbuf; + var wbuf; + var x; + var w; + + xbuf = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ]; + wbuf = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]; + + x = vector( xbuf, 6, 1, 0 ); + w = vector( wbuf, 6, 1, 0 ); + + actual = gcopyWithin( [ x, scalar( -3 ), scalar( 1 ), scalar( 4 ), w ] ); + t.strictEqual( actual, x, 'returns expected value' ); + t.deepEqual( getData( actual ), [ 1.0, 2.0, 3.0, 2.0, 3.0, 4.0 ], 'returns expected value' ); + + xbuf = [ 1.0, 2.0, 3.0, 4.0, 5.0 ]; + wbuf = [ 0.0, 0.0, 0.0, 0.0, 0.0 ]; + + x = vector( xbuf, 5, 1, 0 ); + w = vector( wbuf, 5, 1, 0 ); + + actual = gcopyWithin( [ x, scalar( -100 ), scalar( 2 ), scalar( 5 ), w ] ); + t.strictEqual( actual, x, 'returns expected value' ); + t.deepEqual( getData( actual ), [ 3.0, 4.0, 5.0, 4.0, 5.0 ], 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports a negative `start` index', function test( t ) { + var actual; + var xbuf; + var wbuf; + var x; + var w; + + xbuf = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ]; + wbuf = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]; + + x = vector( xbuf, 6, 1, 0 ); + w = vector( wbuf, 6, 1, 0 ); + + actual = gcopyWithin( [ x, scalar( 3 ), scalar( -5 ), scalar( 4 ), w ] ); + t.strictEqual( actual, x, 'returns expected value' ); + t.deepEqual( getData( actual ), [ 1.0, 2.0, 3.0, 2.0, 3.0, 4.0 ], 'returns expected value' ); + + xbuf = [ 1.0, 2.0, 3.0, 4.0, 5.0 ]; + wbuf = [ 0.0, 0.0, 0.0, 0.0, 0.0 ]; + + x = vector( xbuf, 5, 1, 0 ); + w = vector( wbuf, 5, 1, 0 ); + + actual = gcopyWithin( [ x, scalar( 2 ), scalar( -100 ), scalar( 5 ), w ] ); + t.strictEqual( actual, x, 'returns expected value' ); + t.deepEqual( getData( actual ), [ 1.0, 2.0, 1.0, 2.0, 3.0 ], 'returns expected value' ); + + t.end(); +}); + +tape( 'the function supports a negative `end` index', function test( t ) { + var actual; + var xbuf; + var wbuf; + var x; + var w; + + xbuf = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ]; + wbuf = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]; + + x = vector( xbuf, 6, 1, 0 ); + w = vector( wbuf, 6, 1, 0 ); + + actual = gcopyWithin( [ x, scalar( 3 ), scalar( 1 ), scalar( -2 ), w ] ); + t.strictEqual( actual, x, 'returns expected value' ); + t.deepEqual( getData( actual ), [ 1.0, 2.0, 3.0, 2.0, 3.0, 4.0 ], 'returns expected value' ); + + xbuf = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ]; + wbuf = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]; + + x = vector( xbuf, 6, 1, 0 ); + w = vector( wbuf, 6, 1, 0 ); + + actual = gcopyWithin( [ x, scalar( 0 ), scalar( 0 ), scalar( -100 ), w ] ); + t.strictEqual( actual, x, 'returns expected value' ); + t.deepEqual( getData( actual ), [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ], 'returns expected value' ); + + t.end(); +}); + tape( 'the function supports an input ndarray having a non-unit stride', function test( t ) { var actual; var xbuf;