Skip to content

Commit 03f35ad

Browse files
committed
feat: add accessor arrays support
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: passed - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: passed - task: lint_license_headers status: passed ---
1 parent 863aff4 commit 03f35ad

File tree

5 files changed

+211
-5
lines changed

5 files changed

+211
-5
lines changed

lib/node_modules/@stdlib/blas/ext/base/gsort2hp/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ console.log( y );
145145
## Notes
146146

147147
- If `N <= 0` or `order == 0.0`, both functions leave `x` and `y` unchanged.
148+
- 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])
148149
- The algorithm distinguishes between `-0` and `+0`. When sorted in increasing order, `-0` is sorted before `+0`. When sorted in decreasing order, `-0` is sorted after `+0`.
149150
- The algorithm sorts `NaN` values to the end. When sorted in increasing order, `NaN` values are sorted last. When sorted in decreasing order, `NaN` values are sorted first.
150151
- The algorithm has space complexity `O(1)` and worst case time complexity `O(N^2)`.
@@ -217,6 +218,8 @@ console.log( y );
217218

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

221+
[@stdlib/array/base/accessor]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/array/base/accessor
222+
220223
[@stdlib/blas/ext/base/dsort2hp]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/blas/ext/base/dsort2hp
221224

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

lib/node_modules/@stdlib/blas/ext/base/gsort2hp/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 `gsort2hp`.
@@ -49,7 +54,7 @@ interface Routine {
4954
* console.log( y );
5055
* // => [ 3.0, 1.0, 0.0, 2.0 ]
5156
*/
52-
( N: number, order: number, x: NumericArray, strideX: number, y: NumericArray, strideY: number ): NumericArray;
57+
<T extends InputArray>( N: number, order: number, x: T, strideX: number, y: T, strideY: number ): T;
5358

5459
/**
5560
* Simultaneously sorts two strided arrays based on the sort order of the first array using heapsort and alternative indexing semantics.
@@ -76,7 +81,7 @@ interface Routine {
7681
* console.log( y );
7782
* // => [ 3.0, 1.0, 0.0, 2.0 ]
7883
*/
79-
ndarray( N: number, order: number, x: NumericArray, strideX: number, offsetX: number, y: NumericArray, strideY: number, offsetY: number ): NumericArray;
84+
ndarray<T extends InputArray>( N: number, order: number, x: T, strideX: number, offsetX: number, y: T, strideY: number, offsetY: number ): T;
8085
}
8186

8287
/**

lib/node_modules/@stdlib/blas/ext/base/gsort2hp/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 gsort2hp = require( './index' );
2021

2122

@@ -26,7 +27,8 @@ import gsort2hp = require( './index' );
2627
const x = new Float64Array( 10 );
2728
const y = new Float64Array( 10 );
2829

29-
gsort2hp( x.length, 1, x, 1, y, 1 ); // $ExpectType NumericArray
30+
gsort2hp( x.length, 1, x, 1, y, 1 ); // $ExpectType Float64Array
31+
gsort2hp( x.length, 1, new AccessorArray( x ), 1, new AccessorArray( y ), 1 ); // $ExpectType AccessorArray<number>
3032
}
3133

3234
// The compiler throws an error if the function is provided a first argument which is not a number...
@@ -139,7 +141,8 @@ import gsort2hp = require( './index' );
139141
const x = new Float64Array( 10 );
140142
const y = new Float64Array( 10 );
141143

142-
gsort2hp.ndarray( x.length, 1, x, 1, 0, y, 1, 0 ); // $ExpectType NumericArray
144+
gsort2hp.ndarray( x.length, 1, x, 1, 0, y, 1, 0 ); // $ExpectType Float64Array
145+
gsort2hp.ndarray( x.length, 1, new AccessorArray( x ), 1, 0, new AccessorArray( y ), 1, 0 ); // $ExpectType AccessorArray<number>
143146
}
144147

145148
// The compiler throws an error if the `ndarray` method is provided a first argument which is not a number...
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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 isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' );
24+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
25+
var floor = require( '@stdlib/math/base/special/floor' );
26+
27+
28+
// MAIN //
29+
30+
/**
31+
* Simultaneously sorts two double-precision floating-point strided arrays based on the sort order of the first array using heapsort.
32+
*
33+
* ## Notes
34+
*
35+
* - This implementation uses an in-place algorithm derived from the work of Floyd (1964).
36+
*
37+
* ## References
38+
*
39+
* - Williams, John William Joseph. 1964. "Algorithm 232: Heapsort." _Communications of the ACM_ 7 (6). New York, NY, USA: Association for Computing Machinery: 347–49. doi:[10.1145/512274.512284](https://doi.org/10.1145/512274.512284).
40+
* - Floyd, Robert W. 1964. "Algorithm 245: Treesort." _Communications of the ACM_ 7 (12). New York, NY, USA: Association for Computing Machinery: 701. doi:[10.1145/355588.365103](https://doi.org/10.1145/355588.365103).
41+
*
42+
* @private
43+
* @param {PositiveInteger} N - number of indexed elements
44+
* @param {number} order - sort order
45+
* @param {Object} x - input array object
46+
* @param {Collection} x.data - input array data
47+
* @param {Array<Function>} x.accessors - array element accessors
48+
* @param {integer} strideX - stride length for `x`
49+
* @param {NonNegativeInteger} offsetX - starting index for `x`
50+
* @param {Object} y - second input array object
51+
* @param {Collection} y.data - second input array data
52+
* @param {Array<Function>} y.accessors - array element accessors
53+
* @param {integer} strideY - stride length for `y`
54+
* @param {NonNegativeInteger} offsetY - starting index for `y`
55+
* @returns {Object} `x`
56+
*
57+
* @example
58+
* var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' );
59+
* var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
60+
*
61+
* var x = [ 1.0, -2.0, 3.0, -4.0 ];
62+
* var y = [ 0.0, 1.0, 2.0, 3.0 ];
63+
*
64+
* gsort2hp( x.length, 1.0, arraylike2object( toAccessorArray( x ) ), 1, 0, arraylike2object( toAccessorArray( y ) ), 1, 0 );
65+
*
66+
* console.log( x );
67+
* // => [ -4.0, -2.0, 1.0, 3.0 ]
68+
*
69+
* console.log( y );
70+
* // => [ 3.0, 1.0, 0.0, 2.0 ]
71+
*/
72+
function gsort2hp( N, order, x, strideX, offsetX, y, strideY, offsetY ) {
73+
var parent;
74+
var child;
75+
var xbuf;
76+
var ybuf;
77+
var xget;
78+
var yget;
79+
var xset;
80+
var yset;
81+
var v1;
82+
var v2;
83+
var tx;
84+
var ty;
85+
var ix;
86+
var iy;
87+
var n;
88+
var j;
89+
var k;
90+
91+
// Cache reference to array data:
92+
xbuf = x.data;
93+
ybuf = y.data;
94+
95+
// Cache reference to the element accessors:
96+
xget = x.accessors[ 0 ];
97+
xset = x.accessors[ 1 ];
98+
yget = y.accessors[ 0 ];
99+
yset = y.accessors[ 1 ];
100+
101+
// For a positive stride, sorting in decreasing order is equivalent to providing a negative stride and sorting in increasing order, and, for a negative stride, sorting in decreasing order is equivalent to providing a positive stride and sorting in increasing order...
102+
if ( order < 0.0 ) {
103+
strideX *= -1;
104+
strideY *= -1;
105+
offsetX -= (N-1) * strideX;
106+
offsetY -= (N-1) * strideY;
107+
}
108+
// Set the initial heap size:
109+
n = N;
110+
111+
// Specify an initial "parent" index for building the heap:
112+
parent = floor( N / 2 );
113+
114+
// Continue looping until the array is sorted...
115+
while ( true ) {
116+
if ( parent > 0 ) {
117+
// We need to build the heap...
118+
parent -= 1;
119+
tx = xget( xbuf, offsetX+(parent*strideX) );
120+
ty = yget( ybuf, offsetY+(parent*strideY) );
121+
} else {
122+
// Reduce the heap size:
123+
n -= 1;
124+
125+
// Check if the heap is empty, and, if so, we are finished sorting...
126+
if ( n === 0 ) {
127+
return x;
128+
}
129+
// Store the last heap value in a temporary variable in order to make room for the heap root being placed into its sorted position:
130+
ix = offsetX + (n*strideX);
131+
tx = xget( xbuf, ix );
132+
iy = offsetY + (n*strideY);
133+
ty = yget( ybuf, iy );
134+
135+
// Move the heap root to its sorted position:
136+
xset( xbuf, ix, xget( xbuf, offsetX ) );
137+
yset( ybuf, iy, yget( ybuf, offsetY ) );
138+
}
139+
// We need to "sift down", pushing `t` down the heap to in order to replace the parent and satisfy the heap property...
140+
141+
// Start at the parent index:
142+
j = parent;
143+
144+
// Get the "left" child index:
145+
child = (j*2) + 1;
146+
147+
while ( child < n ) {
148+
// Find the largest child...
149+
k = child + 1;
150+
if ( k < n ) {
151+
v1 = xget( xbuf, offsetX+(k*strideX) );
152+
v2 = xget( xbuf, offsetX+(child*strideX) );
153+
154+
// Check if a "right" child exists and is "bigger"...
155+
if ( v1 > v2 || isnan( v1 ) || (v1 === v2 && isPositiveZero( v1 ) ) ) { // eslint-disable-line max-len
156+
child += 1;
157+
}
158+
}
159+
// Check if the largest child is bigger than `t`...
160+
v1 = xget( xbuf, offsetX+(child*strideX) );
161+
if ( v1 > tx || isnan( v1 ) || ( v1 === tx && isPositiveZero( v1 ) ) ) { // eslint-disable-line max-len
162+
// Insert the larger child value:
163+
xset( xbuf, offsetX+(j*strideX), v1 );
164+
yset( ybuf, offsetY+(j*strideY), yget( ybuf, offsetY+(child*strideY) ) ); // eslint-disable-line max-len
165+
166+
// Update `j` to point to the child index:
167+
j = child;
168+
169+
// Get the "left" child index and repeat...
170+
child = (j*2) + 1;
171+
} else {
172+
// We've found `t`'s place in the heap...
173+
break;
174+
}
175+
}
176+
// Insert `t` into the heap:
177+
xset( xbuf, offsetX+(j*strideX), tx );
178+
yset( ybuf, offsetY+(j*strideY), ty );
179+
}
180+
}
181+
182+
183+
// EXPORTS //
184+
185+
module.exports = gsort2hp;

lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/ndarray.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020

2121
// MODULES //
2222

23+
var arraylike2object = require( '@stdlib/array/base/arraylike2object' );
2324
var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' );
2425
var isnan = require( '@stdlib/math/base/assert/is-nan' );
2526
var floor = require( '@stdlib/math/base/special/floor' );
27+
var accessors = require( './accessors.js' );
2628

2729

2830
// MAIN //
@@ -70,13 +72,21 @@ function gsort2hp( N, order, x, strideX, offsetX, y, strideY, offsetY ) {
7072
var ty;
7173
var ix;
7274
var iy;
75+
var ox;
76+
var oy;
7377
var n;
7478
var j;
7579
var k;
7680

7781
if ( N <= 0 || order === 0.0 ) {
7882
return x;
7983
}
84+
ox = arraylike2object( x );
85+
oy = arraylike2object( y );
86+
if ( ox.accessorProtocol || oy.accessorProtocol ) {
87+
accessors( N, order, ox, strideX, offsetX, oy, strideY, offsetY );
88+
return x;
89+
}
8090
// For a positive stride, sorting in decreasing order is equivalent to providing a negative stride and sorting in increasing order, and, for a negative stride, sorting in decreasing order is equivalent to providing a positive stride and sorting in increasing order...
8191
if ( order < 0.0 ) {
8292
strideX *= -1;

0 commit comments

Comments
 (0)