Skip to content

Commit

Permalink
feat: add accessor array support to blas/base/gscal
Browse files Browse the repository at this point in the history
PR-URL: #5418
Co-authored-by: Athan Reines <[email protected]>
Reviewed-by: Athan Reines <[email protected]>
  • Loading branch information
headlessNode and kgryte authored Feb 25, 2025
1 parent 9d532b5 commit 3b48bb5
Show file tree
Hide file tree
Showing 8 changed files with 432 additions and 53 deletions.
3 changes: 3 additions & 0 deletions lib/node_modules/@stdlib/blas/base/gscal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ gscal.ndarray( 3, 5.0, x, 1, x.length-3 );

- If `N <= 0`, both functions return `x` unchanged.
- `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.
- 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]).

</section>

Expand Down Expand Up @@ -166,6 +167,8 @@ console.log( x );

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

[@stdlib/array/base/accessor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/array/base/accessor

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

[@stdlib/blas/base/sscal]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/blas/base/sscal
Expand Down
11 changes: 8 additions & 3 deletions lib/node_modules/@stdlib/blas/base/gscal/docs/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@

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

import { NumericArray } from '@stdlib/types/array';
import { NumericArray, Collection, AccessorArrayLike } from '@stdlib/types/array';

/**
* Input array.
*/
type InputArray = NumericArray | Collection<number> | AccessorArrayLike<number>;

/**
* Interface describing `gscal`.
Expand All @@ -41,7 +46,7 @@ interface Routine {
* gscal( x.length, 5.0, x, 1 );
* // x => [ -10.0, 5.0, 15.0, -25.0, 20.0, 0.0, -5.0, -15.0 ]
*/
( N: number, alpha: number, x: NumericArray, stride: number ): NumericArray;
<T extends InputArray>( N: number, alpha: number, x: T, stride: number ): T;

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

/**
Expand Down
7 changes: 5 additions & 2 deletions lib/node_modules/@stdlib/blas/base/gscal/docs/types/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* limitations under the License.
*/

import AccessorArray = require( '@stdlib/array/base/accessor' );
import gscal = require( './index' );


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

gscal( x.length, 5.0, x, 1 ); // $ExpectType NumericArray
gscal( x.length, 5.0, x, 1 ); // $ExpectType Float64Array
gscal( x.length, 5.0, new AccessorArray( x ), 1 ); // $ExpectType AccessorArray<number>
}

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

gscal.ndarray( x.length, 5.0, x, 1, 0 ); // $ExpectType NumericArray
gscal.ndarray( x.length, 5.0, x, 1, 0 ); // $ExpectType Float64Array
gscal.ndarray( x.length, 5.0, new AccessorArray( x ), 1, 0 ); // $ExpectType AccessorArray<number>
}

// The compiler throws an error if the `ndarray` method is provided a first argument which is not a number...
Expand Down
101 changes: 101 additions & 0 deletions lib/node_modules/@stdlib/blas/base/gscal/lib/accessors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* @license Apache-2.0
*
* Copyright (c) 2025 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// VARIABLES //

var M = 5;


// MAIN //

/**
* Multiplies `x` by a scalar `alpha`.
*
* @param {PositiveInteger} N - number of indexed elements
* @param {number} alpha - scalar
* @param {Object} x - input array object
* @param {Collection} x.data - input array data
* @param {Array<Function>} x.accessors - array element accessors
* @param {integer} stride - index increment
* @param {NonNegativeInteger} offset - starting index
* @returns {NumericArray} input array
*
* @example
* var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
* var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
*
* var x = [ 1.0, -2.0, 3.0, -4.0, 5.0, -6.0 ];
*
* gscal( 3, 5.0, arraylike2object( toAccessorArray( x ) ), 1, x.length-3 );
* // x => [ 1.0, -2.0, 3.0, -20.0, 25.0, -30.0 ]
*/
function gscal( N, alpha, x, stride, offset ) {
var xbuf;
var xget;
var xset;
var ix;
var m;
var i;

xbuf = x.data;
xget = x.accessors[ 0 ];
xset = x.accessors[ 1 ];

ix = offset;
if ( stride === 0 ) {
xset( xbuf, ix, xget( xbuf, ix ) * N * alpha );
return x;
}

// Use loop unrolling if the stride is equal to `1`...
if ( stride === 1 ) {
m = N % M;

// If we have a remainder, run a clean-up loop...
if ( m > 0 ) {
for ( i = 0; i < m; i++ ) {
xset( xbuf, ix, xget( xbuf, ix ) * alpha );
ix += stride;
}
}
if ( N < M ) {
return x;
}
for ( i = m; i < N; i += M ) {
xset( xbuf, ix, xget( xbuf, ix ) * alpha );
xset( xbuf, ix+1, xget( xbuf, ix+1 ) * alpha );
xset( xbuf, ix+2, xget( xbuf, ix+2 ) * alpha );
xset( xbuf, ix+3, xget( xbuf, ix+3 ) * alpha );
xset( xbuf, ix+4, xget( xbuf, ix+4 ) * alpha );
ix += M;
}
return x;
}
for ( i = 0; i < N; i++ ) {
xset( xbuf, ix, xget( xbuf, ix ) * alpha );
ix += stride;
}
return x;
}


// EXPORTS //

module.exports = gscal;
39 changes: 4 additions & 35 deletions lib/node_modules/@stdlib/blas/base/gscal/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@

'use strict';

// VARIABLES //
// MODULES //

var M = 5;
var stride2offset = require( '@stdlib/strided/base/stride2offset' );
var ndarray = require( './ndarray.js' );


// MAIN //
Expand All @@ -41,39 +42,7 @@ var M = 5;
* // x => [ -10.0, 5.0, 15.0, -25.0, 20.0, 0.0, -5.0, -15.0 ]
*/
function gscal( N, alpha, x, stride ) {
var m;
var i;

if ( N <= 0 || stride <= 0|| alpha === 1.0 ) {
return x;
}
// Use loop unrolling if the stride is equal to `1`...
if ( stride === 1 ) {
m = N % M;

// If we have a remainder, run a clean-up loop...
if ( m > 0 ) {
for ( i = 0; i < m; i += 1 ) {
x[ i ] *= alpha;
}
}
if ( N < M ) {
return x;
}
for ( i = m; i < N; i += M ) {
x[ i ] *= alpha;
x[ i+1 ] *= alpha;
x[ i+2 ] *= alpha;
x[ i+3 ] *= alpha;
x[ i+4 ] *= alpha;
}
return x;
}
N *= stride;
for ( i = 0; i < N; i += stride ) {
x[ i ] *= alpha;
}
return x;
return ndarray( N, alpha, x, stride, stride2offset( N, stride ) );
}


Expand Down
28 changes: 23 additions & 5 deletions lib/node_modules/@stdlib/blas/base/gscal/lib/ndarray.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@

'use strict';

// MODULES //

var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
var accessors = require( './accessors.js' );


// VARIABLES //

var M = 5;
Expand All @@ -44,12 +50,23 @@ var M = 5;
function gscal( N, alpha, x, stride, offset ) {
var ix;
var m;
var o;
var i;

if ( N <= 0 || alpha === 1.0 ) {
return x;
}
o = arraylike2object( x );
if ( o.accessorProtocol ) {
accessors( N, alpha, o, stride, offset );
return x;
}

ix = offset;
if ( stride === 0 ) {
x[ ix ] *= alpha * N;
return x;
}

// Use loop unrolling if the stride is equal to `1`...
if ( stride === 1 ) {
Expand All @@ -66,11 +83,12 @@ function gscal( N, alpha, x, stride, offset ) {
return x;
}
for ( i = m; i < N; i += M ) {
x[ i ] *= alpha;
x[ i+1 ] *= alpha;
x[ i+2 ] *= alpha;
x[ i+3 ] *= alpha;
x[ i+4 ] *= alpha;
x[ ix ] *= alpha;
x[ ix+1 ] *= alpha;
x[ ix+2 ] *= alpha;
x[ ix+3 ] *= alpha;
x[ ix+4 ] *= alpha;
ix += M;
}
return x;
}
Expand Down
Loading

1 comment on commit 3b48bb5

@stdlib-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage Report

Package Statements Branches Functions Lines
blas/base/gscal $\color{green}314/314$
$\color{green}+100.00\%$
$\color{green}34/34$
$\color{green}+100.00\%$
$\color{green}3/3$
$\color{green}+100.00\%$
$\color{green}314/314$
$\color{green}+100.00\%$

The above coverage report was generated for the changes in this push.

Please sign in to comment.