Skip to content

Commit 3b48bb5

Browse files
headlessNodekgryte
andauthored
feat: add accessor array support to blas/base/gscal
PR-URL: #5418 Co-authored-by: Athan Reines <kgryte@gmail.com> Reviewed-by: Athan Reines <kgryte@gmail.com>
1 parent 9d532b5 commit 3b48bb5

File tree

8 files changed

+432
-53
lines changed

8 files changed

+432
-53
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ gscal.ndarray( 3, 5.0, x, 1, x.length-3 );
109109

110110
- If `N <= 0`, both functions return `x` unchanged.
111111
- `gscal()` corresponds to the [BLAS][blas] level 1 function [`dscal`][dscal] with the exception that this implementation works with any array type, not just Float64Arrays. Depending on the environment, the typed versions ([`dscal`][@stdlib/blas/base/dscal], [`sscal`][@stdlib/blas/base/sscal], etc.) are likely to be significantly more performant.
112+
- 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]).
112113

113114
</section>
114115

@@ -166,6 +167,8 @@ console.log( x );
166167

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

170+
[@stdlib/array/base/accessor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/array/base/accessor
171+
169172
[@stdlib/blas/base/dscal]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/blas/base/dscal
170173

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

lib/node_modules/@stdlib/blas/base/gscal/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 `gscal`.
@@ -41,7 +46,7 @@ interface Routine {
4146
* gscal( x.length, 5.0, x, 1 );
4247
* // x => [ -10.0, 5.0, 15.0, -25.0, 20.0, 0.0, -5.0, -15.0 ]
4348
*/
44-
( N: number, alpha: number, x: NumericArray, stride: number ): NumericArray;
49+
<T extends InputArray>( N: number, alpha: number, x: T, stride: number ): T;
4550

4651
/**
4752
* Multiplies a vector `x` by a constant `alpha` using alternative indexing semantics.
@@ -59,7 +64,7 @@ interface Routine {
5964
* gscal.ndarray( x.length, 5.0, x, 1, 0 );
6065
* // x => [ -10.0, 5.0, 15.0, -25.0, 20.0, 0.0, -5.0, -15.0 ]
6166
*/
62-
ndarray( N: number, alpha: number, x: NumericArray, stride: number, offset: number ): NumericArray;
67+
ndarray<T extends InputArray>( N: number, alpha: number, x: T, stride: number, offset: number ): T;
6368
}
6469

6570
/**

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

Lines changed: 5 additions & 2 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 gscal = require( './index' );
2021

2122

@@ -25,7 +26,8 @@ import gscal = require( './index' );
2526
{
2627
const x = new Float64Array( 10 );
2728

28-
gscal( x.length, 5.0, x, 1 ); // $ExpectType NumericArray
29+
gscal( x.length, 5.0, x, 1 ); // $ExpectType Float64Array
30+
gscal( x.length, 5.0, new AccessorArray( x ), 1 ); // $ExpectType AccessorArray<number>
2931
}
3032

3133
// The compiler throws an error if the function is provided a first argument which is not a number...
@@ -100,7 +102,8 @@ import gscal = require( './index' );
100102
{
101103
const x = new Float64Array( 10 );
102104

103-
gscal.ndarray( x.length, 5.0, x, 1, 0 ); // $ExpectType NumericArray
105+
gscal.ndarray( x.length, 5.0, x, 1, 0 ); // $ExpectType Float64Array
106+
gscal.ndarray( x.length, 5.0, new AccessorArray( x ), 1, 0 ); // $ExpectType AccessorArray<number>
104107
}
105108

106109
// The compiler throws an error if the `ndarray` method is provided a first argument which is not a number...
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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+
* Multiplies `x` by a scalar `alpha`.
30+
*
31+
* @param {PositiveInteger} N - number of indexed elements
32+
* @param {number} alpha - scalar
33+
* @param {Object} x - input array object
34+
* @param {Collection} x.data - input array data
35+
* @param {Array<Function>} x.accessors - array element accessors
36+
* @param {integer} stride - index increment
37+
* @param {NonNegativeInteger} offset - starting index
38+
* @returns {NumericArray} input array
39+
*
40+
* @example
41+
* var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
42+
* var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
43+
*
44+
* var x = [ 1.0, -2.0, 3.0, -4.0, 5.0, -6.0 ];
45+
*
46+
* gscal( 3, 5.0, arraylike2object( toAccessorArray( x ) ), 1, x.length-3 );
47+
* // x => [ 1.0, -2.0, 3.0, -20.0, 25.0, -30.0 ]
48+
*/
49+
function gscal( N, alpha, x, stride, offset ) {
50+
var xbuf;
51+
var xget;
52+
var xset;
53+
var ix;
54+
var m;
55+
var i;
56+
57+
xbuf = x.data;
58+
xget = x.accessors[ 0 ];
59+
xset = x.accessors[ 1 ];
60+
61+
ix = offset;
62+
if ( stride === 0 ) {
63+
xset( xbuf, ix, xget( xbuf, ix ) * N * alpha );
64+
return x;
65+
}
66+
67+
// Use loop unrolling if the stride is equal to `1`...
68+
if ( stride === 1 ) {
69+
m = N % M;
70+
71+
// If we have a remainder, run a clean-up loop...
72+
if ( m > 0 ) {
73+
for ( i = 0; i < m; i++ ) {
74+
xset( xbuf, ix, xget( xbuf, ix ) * alpha );
75+
ix += stride;
76+
}
77+
}
78+
if ( N < M ) {
79+
return x;
80+
}
81+
for ( i = m; i < N; i += M ) {
82+
xset( xbuf, ix, xget( xbuf, ix ) * alpha );
83+
xset( xbuf, ix+1, xget( xbuf, ix+1 ) * alpha );
84+
xset( xbuf, ix+2, xget( xbuf, ix+2 ) * alpha );
85+
xset( xbuf, ix+3, xget( xbuf, ix+3 ) * alpha );
86+
xset( xbuf, ix+4, xget( xbuf, ix+4 ) * alpha );
87+
ix += M;
88+
}
89+
return x;
90+
}
91+
for ( i = 0; i < N; i++ ) {
92+
xset( xbuf, ix, xget( xbuf, ix ) * alpha );
93+
ix += stride;
94+
}
95+
return x;
96+
}
97+
98+
99+
// EXPORTS //
100+
101+
module.exports = gscal;

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

Lines changed: 4 additions & 35 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 //
@@ -41,39 +42,7 @@ var M = 5;
4142
* // x => [ -10.0, 5.0, 15.0, -25.0, 20.0, 0.0, -5.0, -15.0 ]
4243
*/
4344
function gscal( N, alpha, x, stride ) {
44-
var m;
45-
var i;
46-
47-
if ( N <= 0 || stride <= 0|| alpha === 1.0 ) {
48-
return x;
49-
}
50-
// Use loop unrolling if the stride is equal to `1`...
51-
if ( stride === 1 ) {
52-
m = N % M;
53-
54-
// If we have a remainder, run a clean-up loop...
55-
if ( m > 0 ) {
56-
for ( i = 0; i < m; i += 1 ) {
57-
x[ i ] *= alpha;
58-
}
59-
}
60-
if ( N < M ) {
61-
return x;
62-
}
63-
for ( i = m; i < N; i += M ) {
64-
x[ i ] *= alpha;
65-
x[ i+1 ] *= alpha;
66-
x[ i+2 ] *= alpha;
67-
x[ i+3 ] *= alpha;
68-
x[ i+4 ] *= alpha;
69-
}
70-
return x;
71-
}
72-
N *= stride;
73-
for ( i = 0; i < N; i += stride ) {
74-
x[ i ] *= alpha;
75-
}
76-
return x;
45+
return ndarray( N, alpha, x, stride, stride2offset( N, stride ) );
7746
}
7847

7948

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

Lines changed: 23 additions & 5 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;
@@ -44,12 +50,23 @@ var M = 5;
4450
function gscal( N, alpha, x, stride, offset ) {
4551
var ix;
4652
var m;
53+
var o;
4754
var i;
4855

4956
if ( N <= 0 || alpha === 1.0 ) {
5057
return x;
5158
}
59+
o = arraylike2object( x );
60+
if ( o.accessorProtocol ) {
61+
accessors( N, alpha, o, stride, offset );
62+
return x;
63+
}
64+
5265
ix = offset;
66+
if ( stride === 0 ) {
67+
x[ ix ] *= alpha * N;
68+
return x;
69+
}
5370

5471
// Use loop unrolling if the stride is equal to `1`...
5572
if ( stride === 1 ) {
@@ -66,11 +83,12 @@ function gscal( N, alpha, x, stride, offset ) {
6683
return x;
6784
}
6885
for ( i = m; i < N; i += M ) {
69-
x[ i ] *= alpha;
70-
x[ i+1 ] *= alpha;
71-
x[ i+2 ] *= alpha;
72-
x[ i+3 ] *= alpha;
73-
x[ i+4 ] *= alpha;
86+
x[ ix ] *= alpha;
87+
x[ ix+1 ] *= alpha;
88+
x[ ix+2 ] *= alpha;
89+
x[ ix+3 ] *= alpha;
90+
x[ ix+4 ] *= alpha;
91+
ix += M;
7492
}
7593
return x;
7694
}

0 commit comments

Comments
 (0)