Skip to content

Commit e74334e

Browse files
headlessNodekgryte
andauthored
feat: add ndarray/base/broadcast-array-except-dimensions
PR-URL: #7853 Ref: #2656 Co-authored-by: Athan Reines <[email protected]> Reviewed-by: Athan Reines <[email protected]>
1 parent b44e0a7 commit e74334e

File tree

10 files changed

+1378
-0
lines changed

10 files changed

+1378
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2025 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# broadcastArrayExceptDimensions
22+
23+
> Broadcast an input [ndarray][@stdlib/ndarray/base/ctor] to a target shape while keeping a list of specified dimensions unchanged.
24+
25+
<!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. -->
26+
27+
<section class="intro">
28+
29+
</section>
30+
31+
<!-- /.intro -->
32+
33+
<!-- Package usage documentation. -->
34+
35+
<section class="usage">
36+
37+
## Usage
38+
39+
<!-- eslint-disable id-length -->
40+
41+
```javascript
42+
var broadcastArrayExceptDimensions = require( '@stdlib/ndarray/base/broadcast-array-except-dimensions' );
43+
```
44+
45+
#### broadcastArrayExceptDimensions( arr, shape, dims )
46+
47+
Broadcasts an input [ndarray][@stdlib/ndarray/base/ctor] to a target shape while keeping a list of specified dimensions unchanged.
48+
49+
```javascript
50+
var array = require( '@stdlib/ndarray/array' );
51+
var getShape = require( '@stdlib/ndarray/shape' );
52+
53+
// Create a 2x2 ndarray:
54+
var x = array( [ [ 1, 2 ], [ 3, 4 ] ] );
55+
// returns <ndarray>
56+
57+
// Perform broadcasting:
58+
var y = broadcastArrayExceptDimensions( x, [ 3, 2, 2 ], [ -1 ] );
59+
// returns <ndarray>
60+
61+
var ysh = getShape( y );
62+
// returns [ 3, 2, 2 ]
63+
```
64+
65+
The function accepts the following arguments:
66+
67+
- **arr**: input ndarray.
68+
- **shape**: target shape.
69+
- **dims**: list of dimensions to exclude from broadcasting. Should be a list of negative integers.
70+
71+
</section>
72+
73+
<!-- /.usage -->
74+
75+
<!-- Package usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
76+
77+
<section class="notes">
78+
79+
## Notes
80+
81+
- The function throws an error if a provided [ndarray][@stdlib/ndarray/base/ctor] is [incompatible][@stdlib/ndarray/base/broadcast-shapes] with a provided shape.
82+
- The returned [ndarray][@stdlib/ndarray/base/ctor] is a "base" [ndarray][@stdlib/ndarray/base/ctor], and, thus, the returned [ndarray][@stdlib/ndarray/base/ctor] does not perform bounds checking or afford any of the guarantees of the non-base [ndarray][@stdlib/ndarray/ctor] constructor. The primary intent of this function is to broadcast an ndarray-like object within internal implementations and to do so with minimal overhead.
83+
- The function always returns a new [ndarray][@stdlib/ndarray/base/ctor] instance even if the input [ndarray][@stdlib/ndarray/base/ctor] shape and the desired shape are the same.
84+
85+
</section>
86+
87+
<!-- /.notes -->
88+
89+
<!-- Package usage examples. -->
90+
91+
<section class="examples">
92+
93+
## Examples
94+
95+
<!-- eslint no-undef: "error" -->
96+
97+
```javascript
98+
var array = require( '@stdlib/ndarray/array' );
99+
var numel = require( '@stdlib/ndarray/base/numel' );
100+
var ind2sub = require( '@stdlib/ndarray/ind2sub' );
101+
var getShape = require( '@stdlib/ndarray/shape' );
102+
var broadcastArrayExceptDimensions = require( '@stdlib/ndarray/base/broadcast-array-except-dimensions' );
103+
104+
// Create a 1x3 array:
105+
var x = array( [ [ 1, 2, 3 ] ] );
106+
// returns <ndarray>
107+
108+
// Broadcast the array to 3x2x2:
109+
var y = broadcastArrayExceptDimensions( x, [ 2, 2, 3 ], [ -2 ] );
110+
// returns <ndarray>
111+
112+
// Retrieve the shape:
113+
var sh = getShape( y );
114+
// returns [ 2, 1, 3 ]
115+
116+
// Retrieve the number of elements:
117+
var N = numel( sh );
118+
119+
// Loop through the array elements...
120+
var sub;
121+
var v;
122+
var i;
123+
for ( i = 0; i < N; i++ ) {
124+
v = y.iget( i );
125+
sub = ind2sub( sh, i );
126+
console.log( 'Y[%s] = %d', sub.join( ', ' ), v );
127+
}
128+
```
129+
130+
</section>
131+
132+
<!-- /.examples -->
133+
134+
<!-- Section to include cited references. If references are included, add a horizontal rule *before* the section. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
135+
136+
<section class="references">
137+
138+
</section>
139+
140+
<!-- /.references -->
141+
142+
<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->
143+
144+
<section class="related">
145+
146+
</section>
147+
148+
<!-- /.related -->
149+
150+
<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
151+
152+
<section class="links">
153+
154+
[@stdlib/ndarray/ctor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/ndarray/ctor
155+
156+
[@stdlib/ndarray/base/ctor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/ndarray/base/ctor
157+
158+
[@stdlib/ndarray/base/broadcast-shapes]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/ndarray/base/broadcast-shapes
159+
160+
</section>
161+
162+
<!-- /.links -->
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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+
/* eslint-disable max-len */
20+
21+
'use strict';
22+
23+
// MODULES //
24+
25+
var bench = require( '@stdlib/bench' );
26+
var Float64Array = require( '@stdlib/array/float64' );
27+
var ndarrayBase = require( '@stdlib/ndarray/base/ctor' );
28+
var ndarray = require( '@stdlib/ndarray/ctor' );
29+
var isndarrayLike = require( '@stdlib/assert/is-ndarray-like' );
30+
var pkg = require( './../package.json' ).name;
31+
var broadcastArrayExceptDimensions = require( './../lib' ); // eslint-disable-line id-length
32+
33+
34+
// MAIN //
35+
36+
bench( pkg+'::base_ndarray,2d', function benchmark( b ) {
37+
var strides;
38+
var values;
39+
var buffer;
40+
var offset;
41+
var dtype;
42+
var shape;
43+
var order;
44+
var out;
45+
var i;
46+
47+
dtype = 'float64';
48+
buffer = new Float64Array( 4 );
49+
shape = [ 2, 2 ];
50+
strides = [ 2, 1 ];
51+
offset = 0;
52+
order = 'row-major';
53+
54+
values = [
55+
ndarrayBase( dtype, buffer, shape, strides, offset, order ),
56+
ndarrayBase( dtype, buffer, shape, strides, offset, order ),
57+
ndarrayBase( dtype, buffer, shape, strides, offset, order ),
58+
ndarrayBase( dtype, buffer, shape, strides, offset, order ),
59+
ndarrayBase( dtype, buffer, shape, strides, offset, order )
60+
];
61+
62+
b.tic();
63+
for ( i = 0; i < b.iterations; i++ ) {
64+
out = broadcastArrayExceptDimensions( values[ i%values.length ], [ 2, 2, 2 ], [ -1 ] );
65+
if ( typeof out !== 'object' ) {
66+
b.fail( 'should return an object' );
67+
}
68+
}
69+
b.toc();
70+
if ( !isndarrayLike( out ) ) {
71+
b.fail( 'should return an ndarray' );
72+
}
73+
b.pass( 'benchmark finished' );
74+
b.end();
75+
});
76+
77+
bench( pkg+'::ndarray,2d', function benchmark( b ) {
78+
var strides;
79+
var values;
80+
var buffer;
81+
var offset;
82+
var dtype;
83+
var shape;
84+
var order;
85+
var out;
86+
var i;
87+
88+
dtype = 'float64';
89+
buffer = new Float64Array( 4 );
90+
shape = [ 2, 2 ];
91+
strides = [ 2, 1 ];
92+
offset = 0;
93+
order = 'row-major';
94+
95+
values = [
96+
ndarray( dtype, buffer, shape, strides, offset, order ),
97+
ndarray( dtype, buffer, shape, strides, offset, order ),
98+
ndarray( dtype, buffer, shape, strides, offset, order ),
99+
ndarray( dtype, buffer, shape, strides, offset, order ),
100+
ndarray( dtype, buffer, shape, strides, offset, order )
101+
];
102+
103+
b.tic();
104+
for ( i = 0; i < b.iterations; i++ ) {
105+
out = broadcastArrayExceptDimensions( values[ i%values.length ], [ 2, 2, 2 ], [ -1 ] );
106+
if ( typeof out !== 'object' ) {
107+
b.fail( 'should return an object' );
108+
}
109+
}
110+
b.toc();
111+
if ( !isndarrayLike( out ) ) {
112+
b.fail( 'should return an ndarray' );
113+
}
114+
b.pass( 'benchmark finished' );
115+
b.end();
116+
});
117+
118+
bench( pkg+'::ndarray_like,2d', function benchmark( b ) {
119+
var strides;
120+
var values;
121+
var buffer;
122+
var offset;
123+
var dtype;
124+
var shape;
125+
var order;
126+
var out;
127+
var obj;
128+
var i;
129+
130+
dtype = 'float64';
131+
buffer = new Float64Array( 4 );
132+
shape = [ 2, 2 ];
133+
strides = [ 2, 1 ];
134+
offset = 0;
135+
order = 'row-major';
136+
137+
values = [];
138+
for ( i = 0; i < 5; i++ ) {
139+
obj = {
140+
'dtype': dtype,
141+
'data': buffer,
142+
'shape': shape,
143+
'strides': strides,
144+
'offset': offset,
145+
'order': order
146+
};
147+
values.push( obj );
148+
}
149+
150+
b.tic();
151+
for ( i = 0; i < b.iterations; i++ ) {
152+
out = broadcastArrayExceptDimensions( values[ i%values.length ], [ 2, 2, 2 ], [ -1 ] );
153+
if ( typeof out !== 'object' ) {
154+
b.fail( 'should return an object' );
155+
}
156+
}
157+
b.toc();
158+
if ( !isndarrayLike( out ) ) {
159+
b.fail( 'should return an ndarray' );
160+
}
161+
b.pass( 'benchmark finished' );
162+
b.end();
163+
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
{{alias}}( arr, shape, dims )
3+
Broadcasts an input ndarray to a target shape while keeping a list of
4+
specified dimensions unchanged.
5+
6+
The returned array is a "base" ndarray, and, thus, the returned array does
7+
not perform bounds checking or afford any of the guarantees of the non-base
8+
ndarray constructor. The primary intent of this function is to broadcast an
9+
ndarray-like object within internal implementations and to do so with
10+
minimal overhead.
11+
12+
The function always returns a new ndarray instance even if the input ndarray
13+
shape and the desired shape are the same.
14+
15+
The function throws an error if a provided ndarray is incompatible with a
16+
provided shape.
17+
18+
Parameters
19+
----------
20+
arr: ndarray
21+
Input array.
22+
23+
shape: ArrayLikeObject
24+
Desired shape.
25+
26+
dims: Array<integer>
27+
List of dimensions to exclude from broadcasting. Should be a list of
28+
negative integers.
29+
30+
Returns
31+
-------
32+
out: ndarray
33+
Broadcasted array.
34+
35+
Examples
36+
--------
37+
> var x = {{alias:@stdlib/ndarray/array}}( [ [ 1, 2, 3 ] ] )
38+
<ndarray>
39+
> {{alias:@stdlib/ndarray/shape}}( x )
40+
[ 1, 3 ]
41+
> var y = {{alias}}( x, [ 2, 2, 3 ], [ -2 ] )
42+
<ndarray>
43+
> {{alias:@stdlib/ndarray/shape}}( y )
44+
[ 2, 1, 3 ]
45+
> var v = y.get( 0, 0, 0 )
46+
1
47+
> v = y.get( 0, 0, 1 )
48+
2
49+
> v = y.get( 0, 0, 2 )
50+
3
51+
> v = y.get( 1, 0, 0 )
52+
1
53+
> v = y.get( 1, 0, 1 )
54+
2
55+
> v = y.get( 1, 0, 2 )
56+
3
57+
58+
See Also
59+
--------

0 commit comments

Comments
 (0)