Skip to content

Commit 24ba370

Browse files
headlessNodekgryte
andauthored
feat: add accessor array support to blas/base/gdot
PR-URL: #5878 Closes: stdlib-js/metr-issue-tracker#23 Co-authored-by: Athan Reines <[email protected]> Reviewed-by: Athan Reines <[email protected]> Signed-off-by: Athan Reines <[email protected]>
1 parent 3c63b7b commit 24ba370

File tree

8 files changed

+514
-55
lines changed

8 files changed

+514
-55
lines changed

lib/node_modules/@stdlib/blas/base/gdot/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ var z = gdot.ndarray( 3, x, 2, 1, y, -1, y.length-1 );
137137

138138
- If `N <= 0` both functions return `0.0`.
139139
- `gdot()` corresponds to the [BLAS][blas] level 1 function [`ddot`][ddot] with the exception that this implementation works with any array type, not just Float64Arrays. Depending on the environment, the typed versions ([`ddot`][@stdlib/blas/base/ddot], [`sdot`][@stdlib/blas/base/sdot], etc.) are likely to be significantly more performant.
140+
- Both functions support array-like objects having getter and setter accessors for array element access (e.g., [`@stdlib/array/base/accessor`][@stdlib/array/base/accessor]).
140141

141142
</section>
142143

@@ -199,6 +200,8 @@ console.log( out );
199200

200201
[mdn-typed-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
201202

203+
[@stdlib/array/base/accessor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/array/base/accessor
204+
202205
[@stdlib/blas/base/ddot]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/blas/base/ddot
203206

204207
[@stdlib/blas/base/sdot]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/blas/base/sdot

lib/node_modules/@stdlib/blas/base/gdot/docs/types/index.d.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@
2020

2121
/// <reference types="@stdlib/types"/>
2222

23-
import { NumericArray } from '@stdlib/types/array';
23+
import { NumericArray, Collection, AccessorArrayLike } from '@stdlib/types/array';
24+
25+
/**
26+
* Input array.
27+
*/
28+
type InputArray = NumericArray | Collection<number> | AccessorArrayLike<number>;
2429

2530
/**
2631
* Interface describing `gdot`.
@@ -43,7 +48,7 @@ interface Routine {
4348
* var z = gdot( x.length, x, 1, y, 1 );
4449
* // returns -5.0
4550
*/
46-
( N: number, x: NumericArray, strideX: number, y: NumericArray, strideY: number ): number;
51+
( N: number, x: InputArray, strideX: number, y: InputArray, strideY: number ): number;
4752

4853
/**
4954
* Computes the dot product of two vectors using alternative indexing semantics.
@@ -64,7 +69,7 @@ interface Routine {
6469
* var z = gdot.ndarray( x.length, x, 1, 0, y, 1, 0 );
6570
* // returns -5.0
6671
*/
67-
ndarray( N: number, x: NumericArray, strideX: number, offsetX: number, y: NumericArray, strideY: number, offsetY: number ): number;
72+
ndarray( N: number, x: InputArray, strideX: number, offsetX: number, y: InputArray, strideY: number, offsetY: number ): number;
6873
}
6974

7075
/**

lib/node_modules/@stdlib/blas/base/gdot/docs/types/test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* limitations under the License.
1717
*/
1818

19+
import AccessorArray = require( '@stdlib/array/base/accessor' );
1920
import gdot = require( './index' );
2021

2122

@@ -27,6 +28,7 @@ import gdot = require( './index' );
2728
const y = new Float64Array( 10 );
2829

2930
gdot( x.length, x, 1, y, 1 ); // $ExpectType number
31+
gdot( x.length, new AccessorArray( x ), 1, y, 1 ); // $ExpectType number
3032
}
3133

3234
// The compiler throws an error if the function is provided a first argument which is not a number...
@@ -124,6 +126,7 @@ import gdot = require( './index' );
124126
const y = new Float64Array( 10 );
125127

126128
gdot.ndarray( x.length, x, 1, 0, y, 1, 0 ); // $ExpectType number
129+
gdot.ndarray( x.length, new AccessorArray( x ), 1, 0, y, 1, 0 ); // $ExpectType number
127130
}
128131

129132
// The compiler throws an error if the `ndarray` method is provided a first argument which is not a number...
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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+
// VARIABLES //
22+
23+
var M = 5;
24+
25+
26+
// MAIN //
27+
28+
/**
29+
* Computes the dot product of `x` and `y`.
30+
*
31+
* @private
32+
* @param {integer} N - number of indexed elements
33+
* @param {Object} x - first input array object
34+
* @param {Collection} x.data - first input array data
35+
* @param {Array<Function>} x.accessors - first array element accessors
36+
* @param {integer} strideX - `x` stride length
37+
* @param {NonNegativeInteger} offsetX - starting index for `x`
38+
* @param {Object} y - second input array object
39+
* @param {Collection} y.data - second input array data
40+
* @param {Array<Function>} y.accessors - second array element accessors
41+
* @param {integer} strideY - `y` stride length
42+
* @param {NonNegativeInteger} offsetY - starting index for `y`
43+
* @returns {number} dot product
44+
*
45+
* @example
46+
* var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
47+
* var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
48+
*
49+
* var x = [ 4.0, 2.0, -3.0, 5.0, -1.0 ];
50+
* var y = [ 2.0, 6.0, -1.0, -4.0, 8.0 ];
51+
*
52+
* var z = gdot( x.length, arraylike2object( toAccessorArray( x ) ), 1, 0, arraylike2object( toAccessorArray( y ) ), 1, 0 );
53+
* // returns -5.0
54+
*/
55+
function gdot( N, x, strideX, offsetX, y, strideY, offsetY ) {
56+
var xbuf;
57+
var ybuf;
58+
var xget;
59+
var yget;
60+
var dot;
61+
var ix;
62+
var iy;
63+
var m;
64+
var i;
65+
66+
xbuf = x.data;
67+
ybuf = y.data;
68+
xget = x.accessors[ 0 ];
69+
yget = y.accessors[ 0 ];
70+
71+
dot = 0.0;
72+
ix = offsetX;
73+
iy = offsetY;
74+
75+
// Use unrolled loops if both strides are equal to `1`...
76+
if ( strideX === 1 && strideY === 1 ) {
77+
m = N % M;
78+
79+
// If we have a remainder, run a clean-up loop...
80+
if ( m > 0 ) {
81+
for ( i = 0; i < m; i++ ) {
82+
dot += xget( xbuf, ix ) * yget( ybuf, iy );
83+
ix += 1;
84+
iy += 1;
85+
}
86+
}
87+
if ( N < M ) {
88+
return dot;
89+
}
90+
for ( i = m; i < N; i += M ) {
91+
dot += ( xget( xbuf, ix ) * yget( ybuf, iy ) ) + ( xget( xbuf, ix+1 ) * yget( ybuf, iy+1 ) ) + ( xget( xbuf, ix+2 ) * yget( ybuf, iy+2 ) ) + ( xget( xbuf, ix+3 ) * yget( ybuf, iy+3 ) ) + ( xget( xbuf, ix+4 ) * yget( ybuf, iy+4 ) ); // eslint-disable-line max-len
92+
ix += M;
93+
iy += M;
94+
}
95+
return dot;
96+
}
97+
for ( i = 0; i < N; i++ ) {
98+
dot += xget( xbuf, ix ) * yget( ybuf, iy );
99+
ix += strideX;
100+
iy += strideY;
101+
}
102+
return dot;
103+
}
104+
105+
106+
// EXPORTS //
107+
108+
module.exports = gdot;

lib/node_modules/@stdlib/blas/base/gdot/lib/main.js

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818

1919
'use strict';
2020

21-
// VARIABLES //
21+
// MODULES //
2222

23-
var M = 5;
23+
var stride2offset = require( '@stdlib/strided/base/stride2offset' );
24+
var ndarray = require( './ndarray.js' );
2425

2526

2627
// MAIN //
@@ -43,50 +44,7 @@ var M = 5;
4344
* // returns -5.0
4445
*/
4546
function gdot( N, x, strideX, y, strideY ) {
46-
var dot;
47-
var ix;
48-
var iy;
49-
var m;
50-
var i;
51-
52-
dot = 0.0;
53-
if ( N <= 0 ) {
54-
return dot;
55-
}
56-
// Use unrolled loops if both strides are equal to `1`...
57-
if ( strideX === 1 && strideY === 1 ) {
58-
m = N % M;
59-
60-
// If we have a remainder, run a clean-up loop...
61-
if ( m > 0 ) {
62-
for ( i = 0; i < m; i++ ) {
63-
dot += x[ i ] * y[ i ];
64-
}
65-
}
66-
if ( N < M ) {
67-
return dot;
68-
}
69-
for ( i = m; i < N; i += M ) {
70-
dot += ( x[i]*y[i] ) + ( x[i+1]*y[i+1] ) + ( x[i+2]*y[i+2] ) + ( x[i+3]*y[i+3] ) + ( x[i+4]*y[i+4] ); // eslint-disable-line max-len
71-
}
72-
return dot;
73-
}
74-
if ( strideX < 0 ) {
75-
ix = ( 1-N ) * strideX;
76-
} else {
77-
ix = 0;
78-
}
79-
if ( strideY < 0 ) {
80-
iy = ( 1-N ) * strideY;
81-
} else {
82-
iy = 0;
83-
}
84-
for ( i = 0; i < N; i++ ) {
85-
dot += ( x[ ix ] * y[ iy ] );
86-
ix += strideX;
87-
iy += strideY;
88-
}
89-
return dot;
47+
return ndarray( N, x, strideX, stride2offset( N, strideX ), y, strideY, stride2offset( N, strideY ) ); // eslint-disable-line max-len
9048
}
9149

9250

lib/node_modules/@stdlib/blas/base/gdot/lib/ndarray.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818

1919
'use strict';
2020

21+
// MODULES //
22+
23+
var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
24+
var accessors = require( './accessors.js' );
25+
26+
2127
// VARIABLES //
2228

2329
var M = 5;
@@ -48,13 +54,20 @@ function gdot( N, x, strideX, offsetX, y, strideY, offsetY ) {
4854
var dot;
4955
var ix;
5056
var iy;
57+
var ox;
58+
var oy;
5159
var m;
5260
var i;
5361

5462
dot = 0.0;
5563
if ( N <= 0 ) {
5664
return dot;
5765
}
66+
ox = arraylike2object( x );
67+
oy = arraylike2object( y );
68+
if ( ox.accessorProtocol || oy.accessorProtocol ) {
69+
return accessors( N, ox, strideX, offsetX, oy, strideY, offsetY );
70+
}
5871
ix = offsetX;
5972
iy = offsetY;
6073

0 commit comments

Comments
 (0)