@stdlib/ndarray-base-nullary-strided1d 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,399 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2025 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var ndarray2object = require( '@stdlib/ndarray-base-ndarraylike2object' );
24
+ var normalizeIndices = require( '@stdlib/ndarray-base-to-unique-normalized-indices' );
25
+ var indicesComplement = require( '@stdlib/array-base-indices-complement' );
26
+ var takeIndexed2 = require( '@stdlib/array-base-take-indexed2' );
27
+ var iterationOrder = require( '@stdlib/ndarray-base-iteration-order' );
28
+ var strides2order = require( '@stdlib/ndarray-base-strides2order' );
29
+ var numel = require( '@stdlib/ndarray-base-numel' );
30
+ var join = require( '@stdlib/array-base-join' );
31
+ var format = require( '@stdlib/string-format' );
32
+ var initializeViews = require( './initialize_array_views.js' );
33
+ var strategy = require( './strategy.js' );
34
+ var defaults = require( './defaults.js' );
35
+ var validate = require( './validate.js' );
36
+ var blockednullary2d = require( './2d_blocked.js' );
37
+ var blockednullary3d = require( './3d_blocked.js' );
38
+ var blockednullary4d = require( './4d_blocked.js' );
39
+ var blockednullary5d = require( './5d_blocked.js' );
40
+ var blockednullary6d = require( './6d_blocked.js' );
41
+ var blockednullary7d = require( './7d_blocked.js' );
42
+ var blockednullary8d = require( './8d_blocked.js' );
43
+ var blockednullary9d = require( './9d_blocked.js' );
44
+ var blockednullary10d = require( './10d_blocked.js' );
45
+ var nullary0d = require( './0d.js' );
46
+ var nullary1d = require( './1d.js' );
47
+ var nullary2d = require( './2d.js' );
48
+ var nullary3d = require( './3d.js' );
49
+ var nullary4d = require( './4d.js' );
50
+ var nullary5d = require( './5d.js' );
51
+ var nullary6d = require( './6d.js' );
52
+ var nullary7d = require( './7d.js' );
53
+ var nullary8d = require( './8d.js' );
54
+ var nullary9d = require( './9d.js' );
55
+ var nullary10d = require( './10d.js' );
56
+ var nullarynd = require( './nd.js' );
57
+
58
+
59
+ // VARIABLES //
60
+
61
+ var NULLARY = [
62
+ nullary0d,
63
+ nullary1d,
64
+ nullary2d,
65
+ nullary3d,
66
+ nullary4d,
67
+ nullary5d,
68
+ nullary6d,
69
+ nullary7d,
70
+ nullary8d,
71
+ nullary9d,
72
+ nullary10d
73
+ ];
74
+ var BLOCKED_NULLARY = [
75
+ blockednullary2d, // 0
76
+ blockednullary3d,
77
+ blockednullary4d,
78
+ blockednullary5d,
79
+ blockednullary6d,
80
+ blockednullary7d,
81
+ blockednullary8d,
82
+ blockednullary9d,
83
+ blockednullary10d // 8
84
+ ];
85
+ var MAX_DIMS = NULLARY.length - 1;
86
+
87
+
88
+ // MAIN //
89
+
90
+ /**
91
+ * Returns a function for applying a one-dimensional strided array function to a list of specified dimensions in an ndarray.
92
+ *
93
+ * @private
94
+ * @param {Options} [options] - function options
95
+ * @param {boolean} [options.strictTraversalOrder=false] - boolean specifying whether to require that element traversal match the memory layout of the target ndarray
96
+ * @throws {TypeError} options argument must be an object
97
+ * @throws {TypeError} must provide valid options
98
+ * @returns {Function} function for applying a strided array function
99
+ *
100
+ * @example
101
+ * var ndarray2array = require( '@stdlib/ndarray-base-to-array' );
102
+ * var getStride = require( '@stdlib/ndarray-base-stride' );
103
+ * var getOffset = require( '@stdlib/ndarray-base-offset' );
104
+ * var getData = require( '@stdlib/ndarray-base-data-buffer' );
105
+ * var numelDimension = require( '@stdlib/ndarray-base-numel-dimension' );
106
+ * var ndarraylike2scalar = require( '@stdlib/ndarray-base-ndarraylike2scalar' );
107
+ * var gsorthp = require( '@stdlib/blas-ext-base-gsorthp' ).ndarray;
108
+ *
109
+ * function wrapper( arrays ) {
110
+ * var x = arrays[ 0 ];
111
+ * var o = arrays[ 1 ];
112
+ * return gsorthp( numelDimension( x, 0 ), ndarraylike2scalar( o ), getData( x ), getStride( x, 0 ), getOffset( x ) );
113
+ * }
114
+ *
115
+ * // Create a data buffer:
116
+ * var xbuf = [ 12.0, 11.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 ];
117
+ *
118
+ * // Define an array shape:
119
+ * var xsh = [ 1, 3, 2, 2 ];
120
+ *
121
+ * // Define the array strides:
122
+ * var sx = [ 12, 4, 2, 1 ];
123
+ *
124
+ * // Define the index offset:
125
+ * var ox = 0;
126
+ *
127
+ * // Create an ndarray-like object:
128
+ * var x = {
129
+ * 'dtype': 'generic',
130
+ * 'data': xbuf,
131
+ * 'shape': xsh,
132
+ * 'strides': sx,
133
+ * 'offset': ox,
134
+ * 'order': 'row-major'
135
+ * };
136
+ *
137
+ * // Create an ndarray-like object for the sort order:
138
+ * var sortOrder = {
139
+ * 'dtype': 'generic',
140
+ * 'data': [ 1.0 ],
141
+ * 'shape': [ 1, 3 ],
142
+ * 'strides': [ 0, 0 ],
143
+ * 'offset': 0,
144
+ * 'order': 'row-major'
145
+ * };
146
+ *
147
+ * // Apply strided function:
148
+ * var f = factory();
149
+ * f( wrapper, [ x, sortOrder ], [ 2, 3 ] );
150
+ *
151
+ * var arr = ndarray2array( x.data, x.shape, x.strides, x.offset, x.order );
152
+ * // returns [ [ [ [ 9.0, 10.0 ], [ 11.0, 12.0 ] ], [ [ 5.0, 6.0 ], [ 7.0, 8.0 ] ], [ [ 1.0, 2.0 ], [ 3.0, 4.0 ] ] ] ]
153
+ *
154
+ * @example
155
+ * var ndarray2array = require( '@stdlib/ndarray-base-to-array' );
156
+ * var getStride = require( '@stdlib/ndarray-base-stride' );
157
+ * var getOffset = require( '@stdlib/ndarray-base-offset' );
158
+ * var getData = require( '@stdlib/ndarray-base-data-buffer' );
159
+ * var numelDimension = require( '@stdlib/ndarray-base-numel-dimension' );
160
+ * var ndarraylike2scalar = require( '@stdlib/ndarray-base-ndarraylike2scalar' );
161
+ * var gsorthp = require( '@stdlib/blas-ext-base-gsorthp' ).ndarray;
162
+ *
163
+ * function wrapper( arrays ) {
164
+ * var x = arrays[ 0 ];
165
+ * var o = arrays[ 1 ];
166
+ * return gsorthp( numelDimension( x, 0 ), ndarraylike2scalar( o ), getData( x ), getStride( x, 0 ), getOffset( x ) );
167
+ * }
168
+ *
169
+ * // Create a data buffer:
170
+ * var xbuf = [ 12.0, 11.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 ];
171
+ *
172
+ * // Define an array shape:
173
+ * var xsh = [ 1, 3, 2, 2 ];
174
+ *
175
+ * // Define the array strides:
176
+ * var sx = [ 12, 4, 2, 1 ];
177
+ *
178
+ * // Define the index offset:
179
+ * var ox = 0;
180
+ *
181
+ * // Create an ndarray-like object:
182
+ * var x = {
183
+ * 'dtype': 'generic',
184
+ * 'data': xbuf,
185
+ * 'shape': xsh,
186
+ * 'strides': sx,
187
+ * 'offset': ox,
188
+ * 'order': 'row-major'
189
+ * };
190
+ *
191
+ * // Create an ndarray-like object for the sort order:
192
+ * var sortOrder = {
193
+ * 'dtype': 'generic',
194
+ * 'data': [ 1.0 ],
195
+ * 'shape': [],
196
+ * 'strides': [ 0 ],
197
+ * 'offset': 0,
198
+ * 'order': 'row-major'
199
+ * };
200
+ *
201
+ * // Apply strided function:
202
+ * var f = factory();
203
+ * f( wrapper, [ x, sortOrder ], [ 0, 1, 2, 3 ] );
204
+ *
205
+ * var arr = ndarray2array( x.data, x.shape, x.strides, x.offset, x.order );
206
+ * // returns [ [ [ [ 1.0, 2.0 ], [ 3.0, 4.0 ] ], [ [ 5.0, 6.0 ], [ 7.0, 8.0 ] ], [ [ 9.0, 10.0 ], [ 11.0, 12.0 ] ] ] ]
207
+ */
208
+ function factory( options ) {
209
+ var OPTS;
210
+ var err;
211
+
212
+ OPTS = defaults();
213
+ if ( arguments.length ) {
214
+ err = validate( OPTS, options );
215
+ if ( err ) {
216
+ throw err;
217
+ }
218
+ }
219
+ return nullaryStrided1d;
220
+
221
+ /**
222
+ * Applies a one-dimensional strided array function to a list of specified dimensions in an ndarray.
223
+ *
224
+ * @private
225
+ * @param {Function} fcn - wrapper for a one-dimensional strided array function
226
+ * @param {ArrayLikeObject<Object>} arrays - array-like object containing ndarrays
227
+ * @param {IntegerArray} dims - list of dimensions to which to apply a strided array function
228
+ * @param {Options} [options] - function options
229
+ * @throws {Error} arrays must have the expected number of dimensions
230
+ * @throws {RangeError} dimension indices must not exceed target ndarray bounds
231
+ * @throws {RangeError} number of dimension indices must not exceed the number of target ndarray dimensions
232
+ * @throws {Error} must provide unique dimension indices
233
+ * @throws {Error} arrays must have the same loop dimension sizes
234
+ * @returns {void}
235
+ */
236
+ function nullaryStrided1d( fcn, arrays, dims, options ) {
237
+ var strategyX;
238
+ var views;
239
+ var ndims;
240
+ var ldims;
241
+ var opts;
242
+ var arr;
243
+ var tmp;
244
+ var len;
245
+ var shl;
246
+ var shc;
247
+ var shx;
248
+ var iox;
249
+ var scx;
250
+ var slx;
251
+ var ord;
252
+ var ns;
253
+ var d;
254
+ var s;
255
+ var N;
256
+ var M;
257
+ var K;
258
+ var x;
259
+ var i;
260
+ var j;
261
+
262
+ if ( arguments.length > 3 ) {
263
+ opts = options;
264
+ } else {
265
+ opts = {};
266
+ }
267
+ // Standardize ndarray meta data...
268
+ N = arrays.length;
269
+ arr = [];
270
+ for ( i = 0; i < N; i++ ) {
271
+ arr.push( ndarray2object( arrays[ i ] ) );
272
+ }
273
+ // Cache a reference to the input array:
274
+ x = arr[ 0 ];
275
+
276
+ // Resolve the number of input array dimensions:
277
+ shx = x.shape;
278
+ ndims = shx.length;
279
+
280
+ // Verify that we've been provided a list of unique dimension indices...
281
+ M = dims.length;
282
+ d = normalizeIndices( dims, ndims-1 );
283
+ if ( d === null ) {
284
+ throw new RangeError( format( 'invalid argument. Third argument contains an out-of-bounds dimension index. Value: [%s].', join( dims, ',' ) ) );
285
+ }
286
+ d.sort();
287
+ if ( d.length !== M ) {
288
+ throw new Error( format( 'invalid argument. Third argument must contain a list of unique dimension indices. Value: [%s].', join( dims, ',' ) ) );
289
+ }
290
+ // Check whether we've been provided a valid number of dimensions...
291
+ if ( M > ndims ) {
292
+ throw new RangeError( format( 'invalid argument. Number of specified dimensions cannot exceed the number of dimensions in the input array. Number of dimensions: %d. Value: [%s].', ndims, join( dims, ',' ) ) );
293
+ }
294
+ // Verify that provided ancillary ndarrays have the expected number of dimensions...
295
+ K = ndims - M;
296
+ for ( i = 1; i < N; i++ ) {
297
+ if ( arr[ i ].shape.length !== K ) {
298
+ throw new Error( format( 'invalid argument. Array arguments after the first array must have the same number of loop dimensions. Input array shape: [%s]. Number of loop dimensions: %d. Array shape: [%s] (index: %d).', join( shx, ',' ), K, join( arr[ i ].shape, ',' ), i ) );
299
+ }
300
+ }
301
+ // Resolve the loop dimensions and associated strides:
302
+ ldims = indicesComplement( shx.length, d );
303
+ tmp = takeIndexed2( shx, x.strides, ldims );
304
+ shl = tmp[ 0 ];
305
+ slx = tmp[ 1 ];
306
+
307
+ // Resolve the core dimensions and associated strides:
308
+ tmp = takeIndexed2( shx, x.strides, d );
309
+ shc = tmp[ 0 ];
310
+ scx = tmp[ 1 ];
311
+
312
+ // Verify that provided ancillary arrays have the same loop dimensions...
313
+ len = 1; // number of elements
314
+ ns = 0; // number of singleton dimensions
315
+ for ( i = 0; i < K; i++ ) {
316
+ s = shl[ i ];
317
+ for ( j = 2; j < N; j++ ) {
318
+ if ( s !== arr[ j ].shape[ i ] ) {
319
+ throw new Error( format( 'invalid argument. Loop dimensions must be consistent across all provided arrays. Input array shape: [%s]. Loop dimension indices: [%s]. Loop dimensions: [%s]. Array shape: [%s] (index: %d).', join( shx, ',' ), join( ldims, ',' ), join( shl, ',' ), join( arr[ j ].shape, ',' ), j ) );
320
+ }
321
+ }
322
+ // Note that, if one of the dimensions is `0`, the length will be `0`...
323
+ len *= s;
324
+
325
+ // Check whether the current dimension is a singleton dimension...
326
+ if ( s === 1 ) {
327
+ ns += 1;
328
+ }
329
+ }
330
+ // Check whether we were provided empty ndarrays...
331
+ if ( len === 0 || ( shc.length && numel( shc ) === 0 ) ) {
332
+ return;
333
+ }
334
+ // Initialize ndarray-like objects for representing sub-array views...
335
+ views = [
336
+ {
337
+ 'dtype': x.dtype,
338
+ 'data': x.data,
339
+ 'shape': shc,
340
+ 'strides': scx,
341
+ 'offset': x.offset,
342
+ 'order': x.order
343
+ }
344
+ ];
345
+ initializeViews( arr, views );
346
+
347
+ // Determine the strategy for marshaling data to and from sub-array views of the input array before and after performing an operation:
348
+ strategyX = strategy( views[ 0 ] );
349
+
350
+ // Determine whether we can avoid iteration altogether...
351
+ if ( K === 0 ) {
352
+ return NULLARY[ K ]( fcn, arr, strategyX, opts );
353
+ }
354
+ // Determine whether we only have one loop dimension and can thus readily perform one-dimensional iteration...
355
+ if ( K === 1 ) {
356
+ return NULLARY[ K ]( fcn, arr, views, shl, slx, strategyX, opts );
357
+ }
358
+ // Determine whether the loop dimensions have only **one** non-singleton dimension (e.g., shape=[10,1,1,1]) so that we can treat loop iteration as being equivalent to one-dimensional iteration...
359
+ if ( ns === K-1 ) {
360
+ // Get the index of the non-singleton dimension...
361
+ for ( i = 0; i < K; i++ ) {
362
+ if ( shl[ i ] !== 1 ) {
363
+ break;
364
+ }
365
+ }
366
+ for ( j = 0; j < N; j++ ) {
367
+ arr[ j ].strides = [ arr[j].strides[i] ];
368
+ }
369
+ slx = [ slx[i] ];
370
+ return NULLARY[ 1 ]( fcn, arr, views, [ shl[i] ], slx, strategyX, opts ); // eslint-disable-line max-len
371
+ }
372
+ iox = iterationOrder( slx ); // +/-1
373
+
374
+ // Determine whether we can avoid blocked iteration...
375
+ ord = strides2order( slx );
376
+ if ( iox !== 0 && K <= MAX_DIMS ) {
377
+ // So long as iteration for each respective array always moves in the same direction (i.e., no mixed sign strides) and the memory layouts are the same, we can leverage cache-optimal (i.e., normal) nested loops without resorting to blocked iteration...
378
+ return NULLARY[ K ]( fcn, arr, views, shl, slx, ord === 1, strategyX, opts ); // eslint-disable-line max-len
379
+ }
380
+ // Check whether blocked iteration is prohibited due to a requirement that the order of element traversal match the memory layout of a provided ndarray...
381
+ if ( OPTS.strictTraversalOrder && K <= MAX_DIMS ) {
382
+ // We have two choices here: (1) we could copy to contiguous memory or (2) we can perform normal nested loop iteration, even though this is not cache-optimal based on the assumption that, while this may hurt performance, for many cases (i.e., smaller ndarrays), this should be fine and likely better than performing a complete copy...
383
+ return NULLARY[ K ]( fcn, arr, views, shl, slx, ord === 1, strategyX, opts ); // eslint-disable-line max-len
384
+ }
385
+ // At this point, we're either dealing with non-contiguous n-dimensional arrays, high dimensional n-dimensional arrays, and/or arrays having differing memory layouts, so our only hope is that we can still perform blocked iteration...
386
+
387
+ // Determine whether we can perform blocked iteration...
388
+ if ( K <= MAX_DIMS ) {
389
+ return BLOCKED_NULLARY[ K-2 ]( fcn, arr, views, shl, slx, strategyX, opts ); // eslint-disable-line max-len
390
+ }
391
+ // Perform linear view iteration without regard for how data is stored in memory (i.e., take the slow path)...
392
+ nullarynd( fcn, arr, views, shl, slx, strategyX, opts );
393
+ }
394
+ }
395
+
396
+
397
+ // EXPORTS //
398
+
399
+ module.exports = factory;
package/lib/nd.js ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2025 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MODULES //
22
+
23
+ var numel = require( '@stdlib/ndarray-base-numel' );
24
+ var vind2bind = require( '@stdlib/ndarray-base-vind2bind' );
25
+ var copyIndexed = require( '@stdlib/array-base-copy-indexed' );
26
+ var zeros = require( '@stdlib/array-base-zeros' );
27
+ var setViewOffsets = require( './set_view_offsets.js' );
28
+ var offsets = require( './offsets.js' );
29
+
30
+
31
+ // VARIABLES //
32
+
33
+ var MODE = 'throw';
34
+
35
+
36
+ // MAIN //
37
+
38
+ /**
39
+ * Applies a one-dimensional strided array function to a list of specified dimensions in an ndarray.
40
+ *
41
+ * @private
42
+ * @param {Function} fcn - wrapper for a one-dimensional strided array reduction function
43
+ * @param {Array<Object>} arrays - ndarrays
44
+ * @param {Array<Object>} views - initialized ndarray-like objects representing sub-array views
45
+ * @param {NonNegativeIntegerArray} shape - loop dimensions
46
+ * @param {IntegerArray} stridesX - loop dimension strides for the ndarray
47
+ * @param {Object} strategyX - strategy for marshaling data to and from an ndarray view
48
+ * @param {Options} opts - function options
49
+ * @returns {void}
50
+ *
51
+ * @example
52
+ * var ndarray2array = require( '@stdlib/ndarray-base-to-array' );
53
+ * var getStride = require( '@stdlib/ndarray-base-stride' );
54
+ * var getOffset = require( '@stdlib/ndarray-base-offset' );
55
+ * var getData = require( '@stdlib/ndarray-base-data-buffer' );
56
+ * var numelDimension = require( '@stdlib/ndarray-base-numel-dimension' );
57
+ * var ndarraylike2scalar = require( '@stdlib/ndarray-base-ndarraylike2scalar' );
58
+ * var gsorthp = require( '@stdlib/blas-ext-base-gsorthp' ).ndarray;
59
+ *
60
+ * function wrapper( arrays ) {
61
+ * var x = arrays[ 0 ];
62
+ * var o = arrays[ 1 ];
63
+ * return gsorthp( numelDimension( x, 0 ), ndarraylike2scalar( o ), getData( x ), getStride( x, 0 ), getOffset( x ) );
64
+ * }
65
+ *
66
+ * // Create a data buffer:
67
+ * var xbuf = [ 12.0, 11.0, 10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 ];
68
+ *
69
+ * // Define an array shape:
70
+ * var xsh = [ 3, 2, 2 ];
71
+ *
72
+ * // Define the array strides:
73
+ * var sx = [ 4, 2, 1 ];
74
+ *
75
+ * // Define the index offset:
76
+ * var ox = 0;
77
+ *
78
+ * // Create an ndarray-like object:
79
+ * var x = {
80
+ * 'dtype': 'generic',
81
+ * 'data': xbuf,
82
+ * 'shape': xsh,
83
+ * 'strides': sx,
84
+ * 'offset': ox,
85
+ * 'order': 'row-major'
86
+ * };
87
+ *
88
+ * // Create an ndarray-like object for the sort order:
89
+ * var sortOrder = {
90
+ * 'dtype': 'generic',
91
+ * 'data': [ 1.0 ],
92
+ * 'shape': [ 1 ],
93
+ * 'strides': [ 0 ],
94
+ * 'offset': 0,
95
+ * 'order': 'row-major'
96
+ * };
97
+ *
98
+ * // Initialize ndarray-like objects representing sub-array views:
99
+ * var views = [
100
+ * {
101
+ * 'dtype': x.dtype,
102
+ * 'data': x.data,
103
+ * 'shape': [ 2, 2 ],
104
+ * 'strides': [ 2, 1 ],
105
+ * 'offset': x.offset,
106
+ * 'order': x.order
107
+ * },
108
+ * {
109
+ * 'dtype': sortOrder.dtype,
110
+ * 'data': sortOrder.data,
111
+ * 'shape': [],
112
+ * 'strides': [ 0 ],
113
+ * 'offset': sortOrder.offset,
114
+ * 'order': sortOrder.order
115
+ * }
116
+ * ];
117
+ *
118
+ * // Define an input strategy:
119
+ * function inputStrategy( x ) {
120
+ * return {
121
+ * 'dtype': x.dtype,
122
+ * 'data': x.data,
123
+ * 'shape': [ 4 ],
124
+ * 'strides': [ 1 ],
125
+ * 'offset': x.offset,
126
+ * 'order': x.order
127
+ * };
128
+ * }
129
+ *
130
+ * // Define an output strategy:
131
+ * function outputStrategy( x ) {
132
+ * return x;
133
+ * }
134
+ *
135
+ * var strategy = {
136
+ * 'input': inputStrategy,
137
+ * 'output': outputStrategy
138
+ * }
139
+ *
140
+ * // Apply strided function:
141
+ * nullarynd( wrapper, [ x, sortOrder ], views, [ 3 ], [ 4 ], strategy, {} );
142
+ *
143
+ * var arr = ndarray2array( x.data, x.shape, x.strides, x.offset, x.order );
144
+ * // returns [ [ [ 9.0, 10.0 ], [ 11.0, 12.0 ] ], [ [ 5.0, 6.0 ], [ 7.0, 8.0 ] ], [ [ 1.0, 2.0 ], [ 3.0, 4.0 ] ] ]
145
+ */
146
+ function nullarynd( fcn, arrays, views, shape, stridesX, strategyX, opts ) {
147
+ var len;
148
+ var arr;
149
+ var iv;
150
+ var io;
151
+ var N;
152
+ var v;
153
+ var i;
154
+ var j;
155
+
156
+ N = arrays.length;
157
+
158
+ // Compute the total number of elements over which to iterate:
159
+ len = numel( shape );
160
+
161
+ // Resolve a list of pointers to the first indexed elements in the respective ndarrays:
162
+ iv = offsets( arrays );
163
+
164
+ // Shallow copy the list of views to an internal array so that we can update with reshaped views without impacting the original list of views:
165
+ v = copyIndexed( views );
166
+
167
+ // Iterate based on the linear **view** index, regardless as to how the data is stored in memory...
168
+ io = zeros( N );
169
+ for ( i = 0; i < len; i++ ) {
170
+ for ( j = 0; j < N; j++ ) {
171
+ arr = arrays[ j ];
172
+ io[ j ] = vind2bind( shape, arr.strides, iv[ j ], arr.order, i, MODE ); // eslint-disable-line max-len
173
+ }
174
+ setViewOffsets( views, io );
175
+ v[ 0 ] = strategyX.input( views[ 0 ] );
176
+ fcn( v, opts );
177
+ strategyX.output( views[ 0 ] );
178
+ }
179
+ }
180
+
181
+
182
+ // EXPORTS //
183
+
184
+ module.exports = nullarynd;
package/lib/offsets.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2025 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MAIN //
22
+
23
+ /**
24
+ * Resolves index offsets from a list of ndarray-like objects.
25
+ *
26
+ * @private
27
+ * @param {ArrayLikeObject<Object>} arrays - list of ndarray-like objects
28
+ * @returns {NonNegativeIntegerArray} list of offsets
29
+ */
30
+ function offsets( arrays ) {
31
+ var out = [];
32
+ var i;
33
+ for ( i = 0; i < arrays.length; i++ ) {
34
+ out.push( arrays[ i ].offset );
35
+ }
36
+ return out;
37
+ }
38
+
39
+
40
+ // EXPORTS //
41
+
42
+ module.exports = offsets;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @license Apache-2.0
3
+ *
4
+ * Copyright (c) 2025 The Stdlib Authors.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ 'use strict';
20
+
21
+ // MAIN //
22
+
23
+ /**
24
+ * Sets view offsets according to a list of index offsets.
25
+ *
26
+ * ## Notes
27
+ *
28
+ * - This function mutates the provides view objects.
29
+ *
30
+ * @private
31
+ * @param {Array<Object>} views - list of ndarray-like objects representing ndarray views
32
+ * @param {NonNegativeIntegerArray} offsets - list of index offsets
33
+ * @returns {Array<Object>} updated views
34
+ */
35
+ function setViewOffsets( views, offsets ) {
36
+ var i;
37
+ for ( i = 0; i < offsets.length; i++ ) {
38
+ views[ i ].offset = offsets[ i ];
39
+ }
40
+ return views;
41
+ }
42
+
43
+
44
+ // EXPORTS //
45
+
46
+ module.exports = setViewOffsets;