@stdlib/ndarray-base-unary-reduce-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.
Files changed (57) hide show
  1. package/LICENSE +177 -0
  2. package/NOTICE +1 -0
  3. package/README.md +302 -0
  4. package/SECURITY.md +5 -0
  5. package/dist/index.js +101 -0
  6. package/dist/index.js.map +7 -0
  7. package/lib/0d.js +114 -0
  8. package/lib/0d_accessors.js +119 -0
  9. package/lib/10d.js +291 -0
  10. package/lib/10d_accessors.js +299 -0
  11. package/lib/10d_blocked.js +413 -0
  12. package/lib/10d_blocked_accessors.js +421 -0
  13. package/lib/1d.js +167 -0
  14. package/lib/1d_accessors.js +175 -0
  15. package/lib/2d.js +193 -0
  16. package/lib/2d_accessors.js +201 -0
  17. package/lib/2d_blocked.js +227 -0
  18. package/lib/2d_blocked_accessors.js +235 -0
  19. package/lib/3d.js +205 -0
  20. package/lib/3d_accessors.js +213 -0
  21. package/lib/3d_blocked.js +252 -0
  22. package/lib/3d_blocked_accessors.js +260 -0
  23. package/lib/4d.js +217 -0
  24. package/lib/4d_accessors.js +225 -0
  25. package/lib/4d_blocked.js +275 -0
  26. package/lib/4d_blocked_accessors.js +283 -0
  27. package/lib/5d.js +229 -0
  28. package/lib/5d_accessors.js +237 -0
  29. package/lib/5d_blocked.js +298 -0
  30. package/lib/5d_blocked_accessors.js +306 -0
  31. package/lib/6d.js +243 -0
  32. package/lib/6d_accessors.js +251 -0
  33. package/lib/6d_blocked.js +321 -0
  34. package/lib/6d_blocked_accessors.js +329 -0
  35. package/lib/7d.js +255 -0
  36. package/lib/7d_accessors.js +263 -0
  37. package/lib/7d_blocked.js +344 -0
  38. package/lib/7d_blocked_accessors.js +352 -0
  39. package/lib/8d.js +267 -0
  40. package/lib/8d_accessors.js +275 -0
  41. package/lib/8d_blocked.js +367 -0
  42. package/lib/8d_blocked_accessors.js +375 -0
  43. package/lib/9d.js +279 -0
  44. package/lib/9d_accessors.js +287 -0
  45. package/lib/9d_blocked.js +390 -0
  46. package/lib/9d_blocked_accessors.js +398 -0
  47. package/lib/factory.js +126 -0
  48. package/lib/increment_offsets.js +46 -0
  49. package/lib/index.js +161 -0
  50. package/lib/initialize_array_views.js +57 -0
  51. package/lib/main.js +498 -0
  52. package/lib/nd.js +177 -0
  53. package/lib/nd_accessors.js +185 -0
  54. package/lib/offsets.js +42 -0
  55. package/lib/reshape_strategy.js +260 -0
  56. package/lib/set_view_offsets.js +52 -0
  57. package/package.json +90 -0
package/lib/main.js ADDED
@@ -0,0 +1,498 @@
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 reshapeStrategy = require( './reshape_strategy.js' );
34
+ var blockedaccessorunary2d = require( './2d_blocked_accessors.js' );
35
+ var blockedaccessorunary3d = require( './3d_blocked_accessors.js' );
36
+ var blockedaccessorunary4d = require( './4d_blocked_accessors.js' );
37
+ var blockedaccessorunary5d = require( './5d_blocked_accessors.js' );
38
+ var blockedaccessorunary6d = require( './6d_blocked_accessors.js' );
39
+ var blockedaccessorunary7d = require( './7d_blocked_accessors.js' );
40
+ var blockedaccessorunary8d = require( './8d_blocked_accessors.js' );
41
+ var blockedaccessorunary9d = require( './9d_blocked_accessors.js' );
42
+ var blockedaccessorunary10d = require( './10d_blocked_accessors.js' );
43
+ var blockedunary2d = require( './2d_blocked.js' );
44
+ var blockedunary3d = require( './3d_blocked.js' );
45
+ var blockedunary4d = require( './4d_blocked.js' );
46
+ var blockedunary5d = require( './5d_blocked.js' );
47
+ var blockedunary6d = require( './6d_blocked.js' );
48
+ var blockedunary7d = require( './7d_blocked.js' );
49
+ var blockedunary8d = require( './8d_blocked.js' );
50
+ var blockedunary9d = require( './9d_blocked.js' );
51
+ var blockedunary10d = require( './10d_blocked.js' );
52
+ var accessorunary0d = require( './0d_accessors.js' );
53
+ var accessorunary1d = require( './1d_accessors.js' );
54
+ var accessorunary2d = require( './2d_accessors.js' );
55
+ var accessorunary3d = require( './3d_accessors.js' );
56
+ var accessorunary4d = require( './4d_accessors.js' );
57
+ var accessorunary5d = require( './5d_accessors.js' );
58
+ var accessorunary6d = require( './6d_accessors.js' );
59
+ var accessorunary7d = require( './7d_accessors.js' );
60
+ var accessorunary8d = require( './8d_accessors.js' );
61
+ var accessorunary9d = require( './9d_accessors.js' );
62
+ var accessorunary10d = require( './10d_accessors.js' );
63
+ var accessorunarynd = require( './nd_accessors.js' );
64
+ var unary0d = require( './0d.js' );
65
+ var unary1d = require( './1d.js' );
66
+ var unary2d = require( './2d.js' );
67
+ var unary3d = require( './3d.js' );
68
+ var unary4d = require( './4d.js' );
69
+ var unary5d = require( './5d.js' );
70
+ var unary6d = require( './6d.js' );
71
+ var unary7d = require( './7d.js' );
72
+ var unary8d = require( './8d.js' );
73
+ var unary9d = require( './9d.js' );
74
+ var unary10d = require( './10d.js' );
75
+ var unarynd = require( './nd.js' );
76
+
77
+
78
+ // VARIABLES //
79
+
80
+ var UNARY = [
81
+ unary0d,
82
+ unary1d,
83
+ unary2d,
84
+ unary3d,
85
+ unary4d,
86
+ unary5d,
87
+ unary6d,
88
+ unary7d,
89
+ unary8d,
90
+ unary9d,
91
+ unary10d
92
+ ];
93
+ var ACCESSOR_UNARY = [
94
+ accessorunary0d,
95
+ accessorunary1d,
96
+ accessorunary2d,
97
+ accessorunary3d,
98
+ accessorunary4d,
99
+ accessorunary5d,
100
+ accessorunary6d,
101
+ accessorunary7d,
102
+ accessorunary8d,
103
+ accessorunary9d,
104
+ accessorunary10d
105
+ ];
106
+ var BLOCKED_UNARY = [
107
+ blockedunary2d, // 0
108
+ blockedunary3d,
109
+ blockedunary4d,
110
+ blockedunary5d,
111
+ blockedunary6d,
112
+ blockedunary7d,
113
+ blockedunary8d,
114
+ blockedunary9d,
115
+ blockedunary10d // 8
116
+ ];
117
+ var BLOCKED_ACCESSOR_UNARY = [
118
+ blockedaccessorunary2d, // 0
119
+ blockedaccessorunary3d,
120
+ blockedaccessorunary4d,
121
+ blockedaccessorunary5d,
122
+ blockedaccessorunary6d,
123
+ blockedaccessorunary7d,
124
+ blockedaccessorunary8d,
125
+ blockedaccessorunary9d,
126
+ blockedaccessorunary10d // 8
127
+ ];
128
+ var MAX_DIMS = UNARY.length - 1;
129
+
130
+
131
+ // MAIN //
132
+
133
+ /**
134
+ * Performs a reduction over a list of specified dimensions in an input ndarray via a one-dimensional strided array reduction function and assigns results to a provided output ndarray.
135
+ *
136
+ * @private
137
+ * @param {Function} fcn - wrapper for a one-dimensional strided array reduction function
138
+ * @param {ArrayLikeObject<Object>} arrays - array-like object containing ndarrays
139
+ * @param {IntegerArray} dims - list of dimensions over which to perform a reduction
140
+ * @param {Options} [options] - function options
141
+ * @throws {Error} arrays must have the expected number of dimensions
142
+ * @throws {RangeError} dimension indices must not exceed input ndarray bounds
143
+ * @throws {RangeError} number of dimension indices must not exceed the number of input ndarray dimensions
144
+ * @throws {Error} must provide unique dimension indices
145
+ * @throws {Error} arrays must have the same loop dimension sizes
146
+ * @returns {void}
147
+ *
148
+ * @example
149
+ * var Float64Array = require( '@stdlib/array-float64' );
150
+ * var ndarray2array = require( '@stdlib/ndarray-base-to-array' );
151
+ * var getStride = require( '@stdlib/ndarray-base-stride' );
152
+ * var getOffset = require( '@stdlib/ndarray-base-offset' );
153
+ * var getData = require( '@stdlib/ndarray-base-data-buffer' );
154
+ * var numelDimension = require( '@stdlib/ndarray-base-numel-dimension' );
155
+ * var gsum = require( '@stdlib/blas-ext-base-gsum' ).ndarray;
156
+ *
157
+ * function wrapper( arrays ) {
158
+ * var x = arrays[ 0 ];
159
+ * return gsum( numelDimension( x, 0 ), getData( x ), getStride( x, 0 ), getOffset( x ) );
160
+ * }
161
+ *
162
+ * // Create data buffers:
163
+ * var xbuf = new Float64Array( [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ] );
164
+ * var ybuf = new Float64Array( [ 0.0, 0.0, 0.0 ] );
165
+ *
166
+ * // Define the array shapes:
167
+ * var xsh = [ 1, 3, 2, 2 ];
168
+ * var ysh = [ 1, 3 ];
169
+ *
170
+ * // Define the array strides:
171
+ * var sx = [ 12, 4, 2, 1 ];
172
+ * var sy = [ 3, 1 ];
173
+ *
174
+ * // Define the index offsets:
175
+ * var ox = 0;
176
+ * var oy = 0;
177
+ *
178
+ * // Create an input ndarray-like object:
179
+ * var x = {
180
+ * 'dtype': 'float64',
181
+ * 'data': xbuf,
182
+ * 'shape': xsh,
183
+ * 'strides': sx,
184
+ * 'offset': ox,
185
+ * 'order': 'row-major'
186
+ * };
187
+ *
188
+ * // Create an output ndarray-like object:
189
+ * var y = {
190
+ * 'dtype': 'float64',
191
+ * 'data': ybuf,
192
+ * 'shape': ysh,
193
+ * 'strides': sy,
194
+ * 'offset': oy,
195
+ * 'order': 'row-major'
196
+ * };
197
+ *
198
+ * // Perform a reduction:
199
+ * unaryReduceStrided1d( wrapper, [ x, y ], [ 2, 3 ] );
200
+ *
201
+ * var arr = ndarray2array( y.data, y.shape, y.strides, y.offset, y.order );
202
+ * // returns [ [ 10.0, 26.0, 42.0 ] ]
203
+ *
204
+ * @example
205
+ * var Float64Array = require( '@stdlib/array-float64' );
206
+ * var getStride = require( '@stdlib/ndarray-base-stride' );
207
+ * var getOffset = require( '@stdlib/ndarray-base-offset' );
208
+ * var getData = require( '@stdlib/ndarray-base-data-buffer' );
209
+ * var numelDimension = require( '@stdlib/ndarray-base-numel-dimension' );
210
+ * var gsum = require( '@stdlib/blas-ext-base-gsum' ).ndarray;
211
+ *
212
+ * function wrapper( arrays ) {
213
+ * var x = arrays[ 0 ];
214
+ * return gsum( numelDimension( x, 0 ), getData( x ), getStride( x, 0 ), getOffset( x ) );
215
+ * }
216
+ *
217
+ * // Create data buffers:
218
+ * var xbuf = new Float64Array( [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ] );
219
+ * var ybuf = new Float64Array( [ 0.0 ] );
220
+ *
221
+ * // Define the array shapes:
222
+ * var xsh = [ 1, 3, 2, 2 ];
223
+ * var ysh = [];
224
+ *
225
+ * // Define the array strides:
226
+ * var sx = [ 12, 4, 2, 1 ];
227
+ * var sy = [ 0 ];
228
+ *
229
+ * // Define the index offsets:
230
+ * var ox = 0;
231
+ * var oy = 0;
232
+ *
233
+ * // Create an input ndarray-like object:
234
+ * var x = {
235
+ * 'dtype': 'float64',
236
+ * 'data': xbuf,
237
+ * 'shape': xsh,
238
+ * 'strides': sx,
239
+ * 'offset': ox,
240
+ * 'order': 'row-major'
241
+ * };
242
+ *
243
+ * // Create an output ndarray-like object:
244
+ * var y = {
245
+ * 'dtype': 'float64',
246
+ * 'data': ybuf,
247
+ * 'shape': ysh,
248
+ * 'strides': sy,
249
+ * 'offset': oy,
250
+ * 'order': 'row-major'
251
+ * };
252
+ *
253
+ * // Perform a reduction:
254
+ * unaryReduceStrided1d( wrapper, [ x, y ], [ 0, 1, 2, 3 ] );
255
+ *
256
+ * var v = y.data;
257
+ * // returns <Float64Array>[ 78.0 ]
258
+ *
259
+ * @example
260
+ * var Float64Array = require( '@stdlib/array-float64' );
261
+ * var ndarray2array = require( '@stdlib/ndarray-base-to-array' );
262
+ * var getStride = require( '@stdlib/ndarray-base-stride' );
263
+ * var getOffset = require( '@stdlib/ndarray-base-offset' );
264
+ * var getData = require( '@stdlib/ndarray-base-data-buffer' );
265
+ * var numelDimension = require( '@stdlib/ndarray-base-numel-dimension' );
266
+ * var gsum = require( '@stdlib/blas-ext-base-gsum' ).ndarray;
267
+ *
268
+ * function wrapper( arrays ) {
269
+ * var x = arrays[ 0 ];
270
+ * return gsum( numelDimension( x, 0 ), getData( x ), getStride( x, 0 ), getOffset( x ) );
271
+ * }
272
+ *
273
+ * // Create data buffers:
274
+ * var xbuf = new Float64Array( [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ] );
275
+ * var ybuf = new Float64Array( [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ] );
276
+ *
277
+ * // Define the array shapes:
278
+ * var xsh = [ 3, 2, 2 ];
279
+ * var ysh = [ 3, 2, 2 ];
280
+ *
281
+ * // Define the array strides:
282
+ * var sx = [ 4, 2, 1 ];
283
+ * var sy = [ 4, 2, 1 ];
284
+ *
285
+ * // Define the index offsets:
286
+ * var ox = 0;
287
+ * var oy = 0;
288
+ *
289
+ * // Create an input ndarray-like object:
290
+ * var x = {
291
+ * 'dtype': 'float64',
292
+ * 'data': xbuf,
293
+ * 'shape': xsh,
294
+ * 'strides': sx,
295
+ * 'offset': ox,
296
+ * 'order': 'row-major'
297
+ * };
298
+ *
299
+ * // Create an output ndarray-like object:
300
+ * var y = {
301
+ * 'dtype': 'float64',
302
+ * 'data': ybuf,
303
+ * 'shape': ysh,
304
+ * 'strides': sy,
305
+ * 'offset': oy,
306
+ * 'order': 'row-major'
307
+ * };
308
+ *
309
+ * // Perform a reduction:
310
+ * unaryReduceStrided1d( wrapper, [ x, y ], [] );
311
+ *
312
+ * var arr = ndarray2array( y.data, y.shape, y.strides, y.offset, y.order );
313
+ * // 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 ] ] ]
314
+ */
315
+ function unaryReduceStrided1d( fcn, arrays, dims, options ) { // eslint-disable-line max-statements
316
+ var strategy;
317
+ var views;
318
+ var ndims;
319
+ var ldims;
320
+ var opts;
321
+ var arr;
322
+ var tmp;
323
+ var len;
324
+ var shx;
325
+ var shc;
326
+ var shl;
327
+ var iox;
328
+ var ioy;
329
+ var ord;
330
+ var sc;
331
+ var sl;
332
+ var sy;
333
+ var ns;
334
+ var d;
335
+ var s;
336
+ var N;
337
+ var M;
338
+ var K;
339
+ var x;
340
+ var y;
341
+ var i;
342
+ var j;
343
+
344
+ if ( arguments.length > 3 ) {
345
+ opts = options;
346
+ } else {
347
+ opts = {};
348
+ }
349
+ // Standardize ndarray meta data...
350
+ N = arrays.length;
351
+ arr = [];
352
+ for ( i = 0; i < N; i++ ) {
353
+ arr.push( ndarray2object( arrays[ i ] ) );
354
+ }
355
+ // Cache references to the input and output arrays:
356
+ x = arr[ 0 ];
357
+ y = arr[ 1 ];
358
+
359
+ // Resolve the number of input array dimensions:
360
+ shx = x.shape;
361
+ ndims = shx.length;
362
+
363
+ // Verify that we've been provided a list of unique dimension indices...
364
+ M = dims.length;
365
+ d = normalizeIndices( dims, ndims-1 );
366
+ if ( d === null ) {
367
+ throw new RangeError( format( 'invalid argument. Third argument contains an out-of-bounds dimension index. Value: [%s].', join( dims, ',' ) ) );
368
+ }
369
+ d.sort();
370
+ if ( d.length !== M ) {
371
+ throw new Error( format( 'invalid argument. Third argument must contain a list of unique dimension indices. Value: [%s].', join( dims, ',' ) ) );
372
+ }
373
+ // Check whether we've been provided a valid number of dimensions to reduce...
374
+ if ( M > ndims ) {
375
+ 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, ',' ) ) );
376
+ }
377
+ // Verify that provided ndarrays have the expected number of dimensions...
378
+ K = ndims - M;
379
+ for ( i = 1; i < N; i++ ) {
380
+ if ( arr[ i ].shape.length !== K ) {
381
+ throw new Error( format( 'invalid argument. Arrays which are not being reduced must have the same number of non-reduced dimensions. Input array shape: [%s]. Number of non-reduced dimensions: %d. Array shape: [%s] (index: %d).', join( shx, ',' ), K, join( arr[ i ].shape, ',' ), i ) );
382
+ }
383
+ }
384
+ // Resolve the non-reduced ("loop") dimensions and associated strides:
385
+ ldims = indicesComplement( shx.length, d );
386
+ tmp = takeIndexed2( shx, x.strides, ldims );
387
+ shl = tmp[ 0 ];
388
+ sl = tmp[ 1 ];
389
+
390
+ // Resolve the reduced ("core") dimensions and associated strides:
391
+ tmp = takeIndexed2( shx, x.strides, d );
392
+ shc = tmp[ 0 ];
393
+ sc = tmp[ 1 ];
394
+
395
+ // Verify that the provided arrays have the same loop dimensions...
396
+ len = 1; // number of elements
397
+ ns = 0; // number of singleton dimensions
398
+ for ( i = 0; i < K; i++ ) {
399
+ s = shl[ i ];
400
+ for ( j = 1; j < N; j++ ) {
401
+ if ( s !== arr[ j ].shape[ i ] ) {
402
+ throw new Error( format( 'invalid argument. Non-reduced dimensions must be consistent across all provided arrays. Input array shape: [%s]. Non-reduced dimension indices: [%s]. Non-reduced dimensions: [%s]. Array shape: [%s] (index: %d).', join( shx, ',' ), join( ldims, ',' ), join( shl, ',' ), join( arr[ j ].shape, ',' ), j ) );
403
+ }
404
+ }
405
+ // Note that, if one of the dimensions is `0`, the length will be `0`...
406
+ len *= s;
407
+
408
+ // Check whether the current dimension is a singleton dimension...
409
+ if ( s === 1 ) {
410
+ ns += 1;
411
+ }
412
+ }
413
+ // Check whether we were provided empty ndarrays...
414
+ if ( len === 0 || ( shc.length && numel( shc ) === 0 ) ) {
415
+ return;
416
+ }
417
+ // Initialize ndarray-like objects for representing sub-array views...
418
+ views = [
419
+ {
420
+ 'dtype': x.dtype,
421
+ 'data': x.data,
422
+ 'shape': shc,
423
+ 'strides': sc,
424
+ 'offset': x.offset,
425
+ 'order': x.order
426
+ }
427
+ ];
428
+ initializeViews( arr, views );
429
+
430
+ // Determine the strategy for reshaping sub-array views of the input array prior to performing a reduction:
431
+ strategy = reshapeStrategy( views[ 0 ] );
432
+
433
+ // Determine whether we can avoid iteration altogether...
434
+ if ( K === 0 ) {
435
+ if ( y.accessorProtocol ) {
436
+ return ACCESSOR_UNARY[ K ]( fcn, arr, strategy, opts );
437
+ }
438
+ return UNARY[ K ]( fcn, arr, strategy, opts );
439
+ }
440
+ // Determine whether we only have one loop dimension and can thus readily perform one-dimensional iteration...
441
+ if ( K === 1 ) {
442
+ if ( y.accessorProtocol ) {
443
+ return ACCESSOR_UNARY[ K ]( fcn, arr, views, sl, strategy, opts );
444
+ }
445
+ return UNARY[ K ]( fcn, arr, views, sl, strategy, opts );
446
+ }
447
+ sy = y.strides;
448
+
449
+ // 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...
450
+ if ( ns === K-1 ) {
451
+ // Get the index of the non-singleton dimension...
452
+ for ( i = 0; i < K; i++ ) {
453
+ if ( shl[ i ] !== 1 ) {
454
+ break;
455
+ }
456
+ }
457
+ y.shape = [ shl[i] ];
458
+ for ( j = 0; j < N; j++ ) {
459
+ arr[ j ].strides = [ arr[j].strides[i] ];
460
+ }
461
+ sl = [ sl[i] ];
462
+ if ( y.accessorProtocol ) {
463
+ return ACCESSOR_UNARY[ 1 ]( fcn, arr, views, sl, strategy, opts );
464
+ }
465
+ return UNARY[ 1 ]( fcn, arr, views, sl, strategy, opts );
466
+ }
467
+ iox = iterationOrder( sl ); // +/-1
468
+ ioy = iterationOrder( sy ); // +/-1
469
+
470
+ // Determine whether we can avoid blocked iteration...
471
+ ord = strides2order( sl );
472
+ if ( iox !== 0 && ioy !== 0 && ord === strides2order( sy ) && K <= MAX_DIMS ) { // eslint-disable-line max-len
473
+ // 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...
474
+ if ( y.accessorProtocol ) {
475
+ return ACCESSOR_UNARY[ K ]( fcn, arr, views, sl, ord === 1, strategy, opts ); // eslint-disable-line max-len
476
+ }
477
+ return UNARY[ K ]( fcn, arr, views, sl, ord === 1, strategy, opts );
478
+ }
479
+ // 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...
480
+
481
+ // Determine whether we can perform blocked iteration...
482
+ if ( K <= MAX_DIMS ) {
483
+ if ( y.accessorProtocol ) {
484
+ return BLOCKED_ACCESSOR_UNARY[ K-2 ]( fcn, arr, views, sl, strategy, opts ); // eslint-disable-line max-len
485
+ }
486
+ return BLOCKED_UNARY[ K-2 ]( fcn, arr, views, sl, strategy, opts );
487
+ }
488
+ // Fall-through to linear view iteration without regard for how data is stored in memory (i.e., take the slow path)...
489
+ if ( y.accessorProtocol ) {
490
+ return accessorunarynd( fcn, arr, views, sl, strategy, opts );
491
+ }
492
+ unarynd( fcn, arr, views, sl, strategy, opts );
493
+ }
494
+
495
+
496
+ // EXPORTS //
497
+
498
+ module.exports = unaryReduceStrided1d;
package/lib/nd.js ADDED
@@ -0,0 +1,177 @@
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
+ * Performs a reduction over an input ndarray and assigns results to a provided output 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 {IntegerArray} strides - loop dimension strides for the input ndarray
46
+ * @param {Function} strategy - input ndarray reshape strategy
47
+ * @param {Options} opts - function options
48
+ * @returns {void}
49
+ *
50
+ * @example
51
+ * var Float64Array = require( '@stdlib/array-float64' );
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 gsum = require( '@stdlib/blas-ext-base-gsum' ).ndarray;
58
+ *
59
+ * function wrapper( arrays ) {
60
+ * var x = arrays[ 0 ];
61
+ * return gsum( numelDimension( x, 0 ), getData( x ), getStride( x, 0 ), getOffset( x ) );
62
+ * }
63
+ *
64
+ * // Create data buffers:
65
+ * var xbuf = new Float64Array( [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ] );
66
+ * var ybuf = new Float64Array( [ 0.0, 0.0, 0.0 ] );
67
+ *
68
+ * // Define the array shapes:
69
+ * var xsh = [ 3, 2, 2 ];
70
+ * var ysh = [ 3 ];
71
+ *
72
+ * // Define the array strides:
73
+ * var sx = [ 4, 2, 1 ];
74
+ * var sy = [ 1 ];
75
+ *
76
+ * // Define the index offsets:
77
+ * var ox = 0;
78
+ * var oy = 0;
79
+ *
80
+ * // Create an input ndarray-like object:
81
+ * var x = {
82
+ * 'dtype': 'float64',
83
+ * 'data': xbuf,
84
+ * 'shape': xsh,
85
+ * 'strides': sx,
86
+ * 'offset': ox,
87
+ * 'order': 'row-major'
88
+ * };
89
+ *
90
+ * // Create an output ndarray-like object:
91
+ * var y = {
92
+ * 'dtype': 'float64',
93
+ * 'data': ybuf,
94
+ * 'shape': ysh,
95
+ * 'strides': sy,
96
+ * 'offset': oy,
97
+ * 'order': 'row-major'
98
+ * };
99
+ *
100
+ * // Initialize ndarray-like objects representing sub-array views:
101
+ * var views = [
102
+ * {
103
+ * 'dtype': x.dtype,
104
+ * 'data': x.data,
105
+ * 'shape': [ 2, 2 ],
106
+ * 'strides': [ 2, 1 ],
107
+ * 'offset': x.offset,
108
+ * 'order': x.order
109
+ * }
110
+ * ];
111
+ *
112
+ * // Define a reshape strategy:
113
+ * function strategy( x ) {
114
+ * return {
115
+ * 'dtype': x.dtype,
116
+ * 'data': x.data,
117
+ * 'shape': [ 4 ],
118
+ * 'strides': [ 1 ],
119
+ * 'offset': x.offset,
120
+ * 'order': x.order
121
+ * };
122
+ * }
123
+ *
124
+ * // Perform a reduction:
125
+ * unarynd( wrapper, [ x, y ], views, [ 4 ], strategy, {} );
126
+ *
127
+ * var arr = ndarray2array( y.data, y.shape, y.strides, y.offset, y.order );
128
+ * // returns [ 10.0, 26.0, 42.0 ]
129
+ */
130
+ function unarynd( fcn, arrays, views, strides, strategy, opts ) {
131
+ var ybuf;
132
+ var len;
133
+ var arr;
134
+ var sh;
135
+ var iv;
136
+ var io;
137
+ var N;
138
+ var y;
139
+ var v;
140
+ var i;
141
+ var j;
142
+
143
+ N = arrays.length;
144
+
145
+ // Resolve the output ndarray and associated shape:
146
+ y = arrays[ 1 ];
147
+ sh = y.shape;
148
+
149
+ // Compute the total number of elements over which to iterate:
150
+ len = numel( sh );
151
+
152
+ // Resolve a list of pointers to the first indexed elements in the respective ndarrays:
153
+ iv = offsets( arrays );
154
+
155
+ // 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:
156
+ v = copyIndexed( views );
157
+
158
+ // Cache a reference to the output ndarray buffer:
159
+ ybuf = y.data;
160
+
161
+ // Iterate based on the linear **view** index, regardless as to how the data is stored in memory...
162
+ io = zeros( N );
163
+ for ( i = 0; i < len; i++ ) {
164
+ for ( j = 0; j < N; j++ ) {
165
+ arr = arrays[ j ];
166
+ io[ j ] = vind2bind( sh, arr.strides, iv[ j ], arr.order, i, MODE );
167
+ }
168
+ setViewOffsets( views, io );
169
+ v[ 0 ] = strategy( views[ 0 ] );
170
+ ybuf[ io[1] ] = fcn( v, opts );
171
+ }
172
+ }
173
+
174
+
175
+ // EXPORTS //
176
+
177
+ module.exports = unarynd;