diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/README.md b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/README.md index 24ea41b60cf7..9509614d15e4 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/README.md +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/README.md @@ -32,7 +32,7 @@ var gsort2hp = require( '@stdlib/blas/ext/base/gsort2hp' ); #### gsort2hp( N, order, x, strideX, y, strideY ) -Simultaneously sorts two strided arrays based on the sort order of the first array `x` using heapsort. +Simultaneously sorts two strided arrays based on the sort order of the first array using heapsort. ```javascript var x = [ 1.0, -2.0, 3.0, -4.0 ]; @@ -52,20 +52,17 @@ The function has the following parameters: - **N**: number of indexed elements. - **order**: sort order. If `order < 0.0`, the input strided array `x` is sorted in **decreasing** order. If `order > 0.0`, the input strided array `x` is sorted in **increasing** order. If `order == 0.0`, the input strided arrays are left unchanged. - **x**: first input [`Array`][mdn-array] or [`typed array`][mdn-typed-array]. -- **strideX**: `x` index increment. +- **strideX**: stride length for `x`. - **y**: second input [`Array`][mdn-array] or [`typed array`][mdn-typed-array]. -- **strideY**: `y` index increment. +- **strideY**: stride length for `y`. -The `N` and `stride` parameters determine which elements in `x` and `y` are accessed at runtime. For example, to sort every other element +The `N` and stride parameters determine which elements in the strided arrays are accessed at runtime. For example, to sort every other element: ```javascript -var floor = require( '@stdlib/math/base/special/floor' ); - var x = [ 1.0, -2.0, 3.0, -4.0 ]; var y = [ 0.0, 1.0, 2.0, 3.0 ]; -var N = floor( x.length / 2 ); -gsort2hp( N, -1.0, x, 2, y, 2 ); +gsort2hp( 2, -1.0, x, 2, y, 2 ); console.log( x ); // => [ 3.0, -2.0, 1.0, -4.0 ] @@ -78,7 +75,6 @@ Note that indexing is relative to the first index. To introduce an offset, use [ ```javascript var Float64Array = require( '@stdlib/array/float64' ); -var floor = require( '@stdlib/math/base/special/floor' ); // Initial arrays... var x0 = new Float64Array( [ 1.0, 2.0, 3.0, 4.0 ] ); @@ -87,10 +83,9 @@ var y0 = new Float64Array( [ 0.0, 1.0, 2.0, 3.0 ] ); // Create offset views... var x1 = new Float64Array( x0.buffer, x0.BYTES_PER_ELEMENT*1 ); // start at 2nd element var y1 = new Float64Array( y0.buffer, y0.BYTES_PER_ELEMENT*1 ); // start at 2nd element -var N = floor( x0.length/2 ); // Sort every other element... -gsort2hp( N, -1.0, x1, 2, y1, 2 ); +gsort2hp( 2, -1.0, x1, 2, y1, 2 ); console.log( x0 ); // => [ 1.0, 4.0, 3.0, 2.0 ] @@ -101,7 +96,7 @@ console.log( y0 ); #### gsort2hp.ndarray( N, order, x, strideX, offsetX, y, strideY, offsetY ) -Simultaneously sorts two strided arrays based on the sort order of the first array `x` using heapsort and alternative indexing semantics. +Simultaneously sorts two strided arrays based on the sort order of the first array using heapsort and alternative indexing semantics. ```javascript var x = [ 1.0, -2.0, 3.0, -4.0 ]; @@ -118,10 +113,10 @@ console.log( y ); The function has the following additional parameters: -- **offsetX**: `x` starting index. -- **offsetY**: `y` starting index. +- **offsetX**: starting index for `x`. +- **offsetY**: starting index for `y`. -While [`typed array`][mdn-typed-array] views mandate a view offset based on the underlying `buffer`, the `offset` parameter supports indexing semantics based on a starting index. For example, to access only the last three elements of `x` +While [`typed array`][mdn-typed-array] views mandate a view offset based on the underlying buffer, the offset parameters support indexing semantics based on starting indices. For example, to access only the last three elements: ```javascript var x = [ 1.0, -2.0, 3.0, -4.0, 5.0, -6.0 ]; @@ -145,6 +140,7 @@ console.log( y ); ## Notes - If `N <= 0` or `order == 0.0`, both functions leave `x` and `y` unchanged. +- 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]) - 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`. - 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. - The algorithm has space complexity `O(1)` and worst case time complexity `O(N^2)`. @@ -164,30 +160,15 @@ console.log( y ); ```javascript -var round = require( '@stdlib/math/base/special/round' ); -var randu = require( '@stdlib/random/base/randu' ); -var Float64Array = require( '@stdlib/array/float64' ); +var discreteUniform = require( '@stdlib/random/array/discrete-uniform' ); var gsort2hp = require( '@stdlib/blas/ext/base/gsort2hp' ); -var rand; -var sign; -var x; -var y; -var i; - -x = new Float64Array( 10 ); -y = new Float64Array( 10 ); // index array -for ( i = 0; i < x.length; i++ ) { - rand = round( randu()*100.0 ); - sign = randu(); - if ( sign < 0.5 ) { - sign = -1.0; - } else { - sign = 1.0; - } - x[ i ] = sign * rand; - y[ i ] = i; -} +var x = discreteUniform( 10, -100, 100, { + 'dtype': 'float64' +}); +var y = discreteUniform( 10, -100, 100, { + 'dtype': 'float64' +}); console.log( x ); console.log( y ); @@ -217,6 +198,8 @@ console.log( y ); [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/ext/base/dsort2hp]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/blas/ext/base/dsort2hp [@stdlib/blas/ext/base/ssort2hp]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/blas/ext/base/ssort2hp diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/repl.txt b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/repl.txt index 8367162c6097..0b184490ba75 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/repl.txt +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/repl.txt @@ -3,8 +3,8 @@ Simultaneously sorts two strided arrays based on the sort order of the first array using heapsort. - The `N` and `stride` parameters determine which elements in `x` and `y` are - accessed at runtime. + The `N` and stride parameters determine which elements in the strided + arrays are accessed at runtime. Indexing is relative to the first index. To introduce an offset, use typed array views. @@ -41,13 +41,13 @@ First input array. strideX: integer - Index increment for `x`. + Stride length for `x`. y: Array|TypedArray Second input array. strideY: integer - Index increment for `y`. + Stride length for `y`. Returns ------- @@ -64,11 +64,10 @@ > y [ 3.0, 1.0, 0.0, 2.0 ] - // Using `N` and `stride` parameters: + // Using `N` and stride parameters: > x = [ 1.0, -2.0, 3.0, -4.0 ]; > y = [ 0.0, 1.0, 2.0, 3.0 ]; - > var N = {{alias:@stdlib/math/base/special/floor}}( x.length / 2 ); - > {{alias}}( N, -1, x, 2, y, 2 ) + > {{alias}}( 2, -1, x, 2, y, 2 ) [ 3.0, -2.0, 1.0, -4.0 ] > y [ 2.0, 1.0, 0.0, 3.0 ] @@ -78,21 +77,21 @@ > var x1 = new {{alias:@stdlib/array/float64}}( x0.buffer, x0.BYTES_PER_ELEMENT*1 ); > var y0 = new {{alias:@stdlib/array/float64}}( [ 0.0, 1.0, 2.0, 3.0 ] ); > var y1 = new {{alias:@stdlib/array/float64}}( y0.buffer, y0.BYTES_PER_ELEMENT*1 ); - > N = {{alias:@stdlib/math/base/special/floor}}( x0.length / 2 ); - > {{alias}}( N, 1, x1, 2, y1, 2 ) + > {{alias}}( 2, 1, x1, 2, y1, 2 ) [ -4.0, 3.0, -2.0 ] > x0 [ 1.0, -4.0, 3.0, -2.0 ] > y0 [ 0.0, 3.0, 2.0, 1.0 ] + {{alias}}.ndarray( N, order, x, strideX, offsetX, y, strideY, offsetY ) Simultaneously sorts two strided arrays based on the sort order of the first array using heapsort and alternative indexing semantics. While typed array views mandate a view offset based on the underlying - buffer, the `offset` parameter supports indexing semantics based on a - starting index. + buffer, the offset parameters support indexing semantics based on starting + indices. Parameters ---------- @@ -107,7 +106,7 @@ First input array. strideX: integer - Index increment for `x`. + Stride length for `x`. offsetX: integer Starting index of `x`. @@ -116,7 +115,7 @@ Second input array. strideY: integer - Index increment for `y`. + Stride length for `y`. offsetY: integer Starting index of `y`. @@ -139,8 +138,7 @@ // Using an index offset: > x = [ 1.0, -2.0, 3.0, -4.0 ]; > y = [ 0.0, 1.0, 2.0, 3.0 ]; - > var N = {{alias:@stdlib/math/base/special/floor}}( x.length / 2 ); - > {{alias}}.ndarray( N, 1, x, 2, 1, y, 2, 1 ) + > {{alias}}.ndarray( 2, 1, x, 2, 1, y, 2, 1 ) [ 1.0, -4.0, 3.0, -2.0 ] > y [ 0.0, 3.0, 2.0, 1.0 ] diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/index.d.ts b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/index.d.ts index 6f5417185ed1..5da12633428a 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/index.d.ts +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/index.d.ts @@ -20,7 +20,12 @@ /// -import { NumericArray } from '@stdlib/types/array'; +import { NumericArray, Collection, AccessorArrayLike } from '@stdlib/types/array'; + +/** +* Input array. +*/ +type InputArray = NumericArray | Collection | AccessorArrayLike; /** * Interface describing `gsort2hp`. @@ -32,9 +37,9 @@ interface Routine { * @param N - number of indexed elements * @param order - sort order * @param x - first input array - * @param strideX - `x` stride length + * @param strideX - stride length for `x` * @param y - second input array - * @param strideY - `y` stride length + * @param strideY - stride length for `x` * @returns `x` * * @example @@ -49,7 +54,7 @@ interface Routine { * console.log( y ); * // => [ 3.0, 1.0, 0.0, 2.0 ] */ - ( N: number, order: number, x: NumericArray, strideX: number, y: NumericArray, strideY: number ): NumericArray; + ( N: number, order: number, x: InputArray, strideX: number, y: T, strideY: number ): T; /** * Simultaneously sorts two strided arrays based on the sort order of the first array using heapsort and alternative indexing semantics. @@ -57,11 +62,11 @@ interface Routine { * @param N - number of indexed elements * @param order - sort order * @param x - first input array - * @param strideX - `x` stride length - * @param offsetX - `x` starting index + * @param strideX - stride length for `x` + * @param offsetX - starting index for `x` * @param y - second input array - * @param strideY - `y` stride length - * @param offsetY - `y` starting index + * @param strideY - stride length for `x` + * @param offsetY - starting index for `y` * @returns `x` * * @example @@ -76,7 +81,7 @@ interface Routine { * console.log( y ); * // => [ 3.0, 1.0, 0.0, 2.0 ] */ - ndarray( N: number, order: number, x: NumericArray, strideX: number, offsetX: number, y: NumericArray, strideY: number, offsetY: number ): NumericArray; + ndarray( N: number, order: number, x: InputArray, strideX: number, offsetX: number, y: T, strideY: number, offsetY: number ): T; } /** @@ -85,9 +90,9 @@ interface Routine { * @param N - number of indexed elements * @param order - sort order * @param x - first input array -* @param strideX - `x` stride length +* @param strideX - stride length for `x` * @param y - second input array -* @param strideY - `y` stride length +* @param strideY - stride length for `x` * @returns `x` * * @example diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/test.ts b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/test.ts index c59a56ed691f..06b535218047 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/test.ts +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/docs/types/test.ts @@ -16,6 +16,7 @@ * limitations under the License. */ +import AccessorArray = require( '@stdlib/array/base/accessor' ); import gsort2hp = require( './index' ); @@ -26,7 +27,8 @@ import gsort2hp = require( './index' ); const x = new Float64Array( 10 ); const y = new Float64Array( 10 ); - gsort2hp( x.length, 1, x, 1, y, 1 ); // $ExpectType NumericArray + gsort2hp( x.length, 1, x, 1, y, 1 ); // $ExpectType Float64Array + gsort2hp( x.length, 1, new AccessorArray( x ), 1, new AccessorArray( y ), 1 ); // $ExpectType AccessorArray } // 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' ); const x = new Float64Array( 10 ); const y = new Float64Array( 10 ); - gsort2hp.ndarray( x.length, 1, x, 1, 0, y, 1, 0 ); // $ExpectType NumericArray + gsort2hp.ndarray( x.length, 1, x, 1, 0, y, 1, 0 ); // $ExpectType Float64Array + gsort2hp.ndarray( x.length, 1, new AccessorArray( x ), 1, 0, new AccessorArray( y ), 1, 0 ); // $ExpectType AccessorArray } // The compiler throws an error if the `ndarray` method is provided a first argument which is not a number... diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/examples/index.js b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/examples/index.js index 707907a7019c..f1dc91d24c0f 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/examples/index.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/examples/index.js @@ -18,34 +18,15 @@ 'use strict'; -var round = require( '@stdlib/math/base/special/round' ); -var randu = require( '@stdlib/random/base/randu' ); -var Float64Array = require( '@stdlib/array/float64' ); +var discreteUniform = require( '@stdlib/random/array/discrete-uniform' ); var gsort2hp = require( './../lib' ); -var rand; -var sign; -var x; -var y; -var i; - -x = new Float64Array( 10 ); -y = new Float64Array( 10 ); // index array -for ( i = 0; i < x.length; i++ ) { - if ( randu() < 0.2 ) { - x[ i ] = NaN; - } else { - rand = round( randu()*100.0 ); - sign = randu(); - if ( sign < 0.5 ) { - sign = -1.0; - } else { - sign = 1.0; - } - x[ i ] = sign * rand; - } - y[ i ] = i; -} +var x = discreteUniform( 10, -100, 100, { + 'dtype': 'float64' +}); +var y = discreteUniform( 10, -100, 100, { + 'dtype': 'float64' +}); console.log( x ); console.log( y ); diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/accessors.js b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/accessors.js new file mode 100644 index 000000000000..27665b27d36d --- /dev/null +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/accessors.js @@ -0,0 +1,185 @@ +/** +* @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'; + +// MODULES // + +var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var floor = require( '@stdlib/math/base/special/floor' ); + + +// MAIN // + +/** +* Simultaneously sorts two double-precision floating-point strided arrays based on the sort order of the first array using heapsort. +* +* ## Notes +* +* - This implementation uses an in-place algorithm derived from the work of Floyd (1964). +* +* ## References +* +* - 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). +* - 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). +* +* @private +* @param {PositiveInteger} N - number of indexed elements +* @param {number} order - sort order +* @param {Object} x - first input array object +* @param {Collection} x.data - first input array data +* @param {Array} x.accessors - first input array element accessors +* @param {integer} strideX - stride length for `x` +* @param {NonNegativeInteger} offsetX - starting index for `x` +* @param {Object} y - second input array object +* @param {Collection} y.data - second input array data +* @param {Array} y.accessors - second input array element accessors +* @param {integer} strideY - stride length for `y` +* @param {NonNegativeInteger} offsetY - starting index for `y` +* @returns {Object} `x` +* +* @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 ]; +* var y = [ 0.0, 1.0, 2.0, 3.0 ]; +* +* gsort2hp( x.length, 1.0, arraylike2object( toAccessorArray( x ) ), 1, 0, arraylike2object( toAccessorArray( y ) ), 1, 0 ); +* +* console.log( x ); +* // => [ -4.0, -2.0, 1.0, 3.0 ] +* +* console.log( y ); +* // => [ 3.0, 1.0, 0.0, 2.0 ] +*/ +function gsort2hp( N, order, x, strideX, offsetX, y, strideY, offsetY ) { + var parent; + var child; + var xbuf; + var ybuf; + var xget; + var yget; + var xset; + var yset; + var v1; + var v2; + var tx; + var ty; + var ix; + var iy; + var n; + var j; + var k; + + // Cache reference to array data: + xbuf = x.data; + ybuf = y.data; + + // Cache reference to the element accessors: + xget = x.accessors[ 0 ]; + xset = x.accessors[ 1 ]; + yget = y.accessors[ 0 ]; + yset = y.accessors[ 1 ]; + + // 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... + if ( order < 0.0 ) { + strideX *= -1; + strideY *= -1; + offsetX -= (N-1) * strideX; + offsetY -= (N-1) * strideY; + } + // Set the initial heap size: + n = N; + + // Specify an initial "parent" index for building the heap: + parent = floor( N / 2 ); + + // Continue looping until the array is sorted... + while ( true ) { + if ( parent > 0 ) { + // We need to build the heap... + parent -= 1; + tx = xget( xbuf, offsetX+(parent*strideX) ); + ty = yget( ybuf, offsetY+(parent*strideY) ); + } else { + // Reduce the heap size: + n -= 1; + + // Check if the heap is empty, and, if so, we are finished sorting... + if ( n === 0 ) { + return x; + } + // Store the last heap value in a temporary variable in order to make room for the heap root being placed into its sorted position: + ix = offsetX + (n*strideX); + tx = xget( xbuf, ix ); + iy = offsetY + (n*strideY); + ty = yget( ybuf, iy ); + + // Move the heap root to its sorted position: + xset( xbuf, ix, xget( xbuf, offsetX ) ); + yset( ybuf, iy, yget( ybuf, offsetY ) ); + } + // We need to "sift down", pushing `t` down the heap to in order to replace the parent and satisfy the heap property... + + // Start at the parent index: + j = parent; + + // Get the "left" child index: + child = (j*2) + 1; + + while ( child < n ) { + // Find the largest child... + k = child + 1; + if ( k < n ) { + v1 = xget( xbuf, offsetX+(k*strideX) ); + v2 = xget( xbuf, offsetX+(child*strideX) ); + + // Check if a "right" child exists and is "bigger"... + if ( v1 > v2 || isnan( v1 ) || (v1 === v2 && isPositiveZero( v1 ) ) ) { // eslint-disable-line max-len + child += 1; + } + } + // Check if the largest child is bigger than `t`... + v1 = xget( xbuf, offsetX+(child*strideX) ); + if ( v1 > tx || isnan( v1 ) || ( v1 === tx && isPositiveZero( v1 ) ) ) { // eslint-disable-line max-len + // Insert the larger child value: + xset( xbuf, offsetX+(j*strideX), v1 ); + yset( ybuf, offsetY+(j*strideY), yget( ybuf, offsetY+(child*strideY) ) ); // eslint-disable-line max-len + + // Update `j` to point to the child index: + j = child; + + // Get the "left" child index and repeat... + child = (j*2) + 1; + } else { + // We've found `t`'s place in the heap... + break; + } + } + // Insert `t` into the heap: + xset( xbuf, offsetX+(j*strideX), tx ); + yset( ybuf, offsetY+(j*strideY), ty ); + } +} + + +// EXPORTS // + +module.exports = gsort2hp; diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/main.js b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/main.js index 50b69035d645..a3b6995aad60 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/main.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/main.js @@ -20,9 +20,8 @@ // MODULES // -var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' ); -var isnan = require( '@stdlib/math/base/assert/is-nan' ); -var floor = require( '@stdlib/math/base/special/floor' ); +var stride2offset = require( '@stdlib/strided/base/stride2offset' ); +var ndarray = require( './ndarray.js' ); // MAIN // @@ -42,9 +41,9 @@ var floor = require( '@stdlib/math/base/special/floor' ); * @param {PositiveInteger} N - number of indexed elements * @param {number} order - sort order * @param {NumericArray} x - first input array -* @param {integer} strideX - `x` index increment +* @param {integer} strideX - stride length for `x` * @param {NumericArray} y - second input array -* @param {integer} strideY - `y` index increment +* @param {integer} strideY - stride length for `y` * @returns {NumericArray} `x` * * @example @@ -60,110 +59,9 @@ var floor = require( '@stdlib/math/base/special/floor' ); * // => [ 3.0, 1.0, 0.0, 2.0 ] */ function gsort2hp( N, order, x, strideX, y, strideY ) { - var offsetX; - var offsetY; - var parent; - var child; - var v1; - var v2; - var tx; - var ty; - var ix; - var iy; - var n; - var j; - var k; - - if ( N <= 0 || order === 0.0 ) { - return x; - } - // 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... - if ( order < 0.0 ) { - strideX *= -1; - strideY *= -1; - } - if ( strideX < 0 ) { - offsetX = (1-N) * strideX; - } else { - offsetX = 0; - } - if ( strideY < 0 ) { - offsetY = (1-N) * strideY; - } else { - offsetY = 0; - } - // Set the initial heap size: - n = N; - - // Specify an initial "parent" index for building the heap: - parent = floor( N / 2 ); - - // Continue looping until the array is sorted... - while ( true ) { - if ( parent > 0 ) { - // We need to build the heap... - parent -= 1; - tx = x[ offsetX+(parent*strideX) ]; - ty = y[ offsetY+(parent*strideY) ]; - } else { - // Reduce the heap size: - n -= 1; - - // Check if the heap is empty, and, if so, we are finished sorting... - if ( n === 0 ) { - return x; - } - // Store the last heap value in a temporary variable in order to make room for the heap root being placed into its sorted position: - ix = offsetX + (n*strideX); - tx = x[ ix ]; - iy = offsetY + (n*strideY); - ty = y[ iy ]; - - // Move the heap root to its sorted position: - x[ ix ] = x[ offsetX ]; - y[ iy ] = y[ offsetY ]; - } - // We need to "sift down", pushing `t` down the heap to in order to replace the parent and satisfy the heap property... - - // Start at the parent index: - j = parent; - - // Get the "left" child index: - child = (j*2) + 1; - - while ( child < n ) { - // Find the largest child... - k = child + 1; - if ( k < n ) { - v1 = x[ offsetX+(k*strideX) ]; - v2 = x[ offsetX+(child*strideX) ]; - - // Check if a "right" child exists and is "bigger"... - if ( v1 > v2 || isnan( v1 ) || (v1 === v2 && isPositiveZero( v1 ) ) ) { // eslint-disable-line max-len - child += 1; - } - } - // Check if the largest child is bigger than `t`... - v1 = x[ offsetX+(child*strideX) ]; - if ( v1 > tx || isnan( v1 ) || ( v1 === tx && isPositiveZero( v1 ) ) ) { // eslint-disable-line max-len - // Insert the larger child value: - x[ offsetX+(j*strideX) ] = v1; - y[ offsetY+(j*strideY) ] = y[ offsetY+(child*strideY) ]; - - // Update `j` to point to the child index: - j = child; - - // Get the "left" child index and repeat... - child = (j*2) + 1; - } else { - // We've found `t`'s place in the heap... - break; - } - } - // Insert `t` into the heap: - x[ offsetX+(j*strideX) ] = tx; - y[ offsetY+(j*strideY) ] = ty; - } + var ix = stride2offset( N, strideX ); + var iy = stride2offset( N, strideY ); + return ndarray( N, order, x, strideX, ix, y, strideY, iy ); } diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/ndarray.js b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/ndarray.js index a7ee21faa523..dfcee6c252f2 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/ndarray.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/lib/ndarray.js @@ -20,9 +20,11 @@ // MODULES // +var arraylike2object = require( '@stdlib/array/base/arraylike2object' ); var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var floor = require( '@stdlib/math/base/special/floor' ); +var accessors = require( './accessors.js' ); // MAIN // @@ -42,11 +44,11 @@ var floor = require( '@stdlib/math/base/special/floor' ); * @param {PositiveInteger} N - number of indexed elements * @param {number} order - sort order * @param {NumericArray} x - first input array -* @param {integer} strideX - `x` index increment -* @param {NonNegativeInteger} offsetX - `x` starting index +* @param {integer} strideX - stride length for `x` +* @param {NonNegativeInteger} offsetX - starting index for `x` * @param {NumericArray} y - second input array -* @param {integer} strideY - `y` index increment -* @param {NonNegativeInteger} offsetY - `y` starting index +* @param {integer} strideY - stride length for `y` +* @param {NonNegativeInteger} offsetY - starting index for `y` * @returns {NumericArray} `x` * * @example @@ -70,6 +72,8 @@ function gsort2hp( N, order, x, strideX, offsetX, y, strideY, offsetY ) { var ty; var ix; var iy; + var ox; + var oy; var n; var j; var k; @@ -77,6 +81,12 @@ function gsort2hp( N, order, x, strideX, offsetX, y, strideY, offsetY ) { if ( N <= 0 || order === 0.0 ) { return x; } + ox = arraylike2object( x ); + oy = arraylike2object( y ); + if ( ox.accessorProtocol || oy.accessorProtocol ) { + accessors( N, order, ox, strideX, offsetX, oy, strideY, offsetY ); + return x; + } // 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... if ( order < 0.0 ) { strideX *= -1; diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.main.js b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.main.js index 5028cfba78cf..7f3460e614c8 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.main.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.main.js @@ -24,6 +24,7 @@ var tape = require( 'tape' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' ); var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' ); +var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' ); var Float64Array = require( '@stdlib/array/float64' ); var num2str = require( './fixtures/num2str.js' ); var gsort2hp = require( './../lib' ); @@ -86,6 +87,50 @@ tape( 'the function sorts a strided array (increasing order)', function test( t t.end(); }); +tape( 'the function sorts a strided array (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, -2.0, 2.0, -3.0, 3.0, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]; + + xc = x.slice(); + + expectedX = [ -3.0, -3.0, -2.0, -1.0, 1.0, 2.0, 2.0, 3.0 ]; + expectedY = [ 5.0, 7.0, 3.0, 1.0, 0.0, 2.0, 4.0, 6.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + tape( 'the function sorts a strided array (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -130,6 +175,50 @@ tape( 'the function sorts a strided array (decreasing order)', function test( t t.end(); }); +tape( 'the function sorts a strided array (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, -2.0, 2.0, -3.0, 3.0, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]; + + xc = x.slice(); + + expectedX = [ 3.0, 2.0, 2.0, 1.0, -1.0, -2.0, -3.0, -3.0 ]; + expectedY = [ 6.0, 2.0, 4.0, 0.0, 1.0, 3.0, 5.0, 7.0 ]; + + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + tape( 'the function sorts a strided array which includes NaNs (increasing order)', function test( t ) { var expectedX; var expectedY; @@ -139,13 +228,431 @@ tape( 'the function sorts a strided array which includes NaNs (increasing order) var v; var i; - x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; - y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + + xc = x.slice(); + + expectedX = [ -3.0, -3.0, -2.0, -1.0, 1.0, 2.0, 2.0, 3.0, NaN, NaN ]; + expectedY = [ 6.0, 9.0, 4.0, 1.0, 0.0, 2.0, 5.0, 7.0, 3.0, 8.0 ]; + + gsort2hp( x.length, 1.0, x, 1, y, 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array which includes NaNs (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + + xc = x.slice(); + + expectedX = [ -3.0, -3.0, -2.0, -1.0, 1.0, 2.0, 2.0, 3.0, NaN, NaN ]; + expectedY = [ 6.0, 9.0, 4.0, 1.0, 0.0, 2.0, 5.0, 7.0, 3.0, 8.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array which includes NaNs (decreasing order)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + + xc = x.slice(); + + expectedX = [ NaN, NaN, 3.0, 2.0, 2.0, 1.0, -1.0, -2.0, -3.0, -3.0 ]; + expectedY = [ 3.0, 8.0, 7.0, 2.0, 5.0, 0.0, 1.0, 4.0, 6.0, 9.0 ]; + + gsort2hp( x.length, -1.0, x, 1, y, 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array which includes NaNs (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + + xc = x.slice(); + + expectedX = [ NaN, NaN, 3.0, 2.0, 2.0, 1.0, -1.0, -2.0, -3.0, -3.0 ]; + expectedY = [ 3.0, 8.0, 7.0, 2.0, 5.0, 0.0, 1.0, 4.0, 6.0, 9.0 ]; + + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array which includes positive and negative zeros (increasing order)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 0.0, -0.0, 0.0, -0.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0 ]; + + xc = x.slice(); + + expectedX = [ -0.0, -0.0, 0.0, 0.0 ]; + expectedY = [ 1.0, 3.0, 0.0, 2.0 ]; + + gsort2hp( x.length, 1.0, x, 1, y, 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array which includes positive and negative zeros (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 0.0, -0.0, 0.0, -0.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0 ]; + + xc = x.slice(); + + expectedX = [ -0.0, -0.0, 0.0, 0.0 ]; + expectedY = [ 1.0, 3.0, 0.0, 2.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array which includes positive and negative zeros (decreasing order)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 0.0, -0.0, 0.0, -0.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0 ]; + + xc = x.slice(); + + expectedX = [ 0.0, 0.0, -0.0, -0.0 ]; + expectedY = [ 0.0, 2.0, 1.0, 3.0 ]; + + gsort2hp( x.length, -1.0, x, 1, y, 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array which includes positive and negative zeros (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 0.0, -0.0, 0.0, -0.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0 ]; + + xc = x.slice(); + + expectedX = [ 0.0, 0.0, -0.0, -0.0 ]; + expectedY = [ 0.0, 2.0, 1.0, 3.0 ]; + + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array (increasing order, special cases)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ NaN, 1.0, -1.0, 2.0, 2.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; + + xc = x.slice(); + + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; + expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0 ]; + + gsort2hp( x.length, 1.0, x, 1, y, 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + + x = [ 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; + + xc = x.slice(); + + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; + expectedY = [ 1.0, 0.0, 2.0, 3.0, 4.0 ]; + + gsort2hp( x.length, 1.0, x, 1, y, 1 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + + x = [ NaN, 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 ]; xc = x.slice(); - expectedX = [ -3.0, -3.0, -2.0, -1.0, 1.0, 2.0, 2.0, 3.0, NaN, NaN ]; - expectedY = [ 6.0, 9.0, 4.0, 1.0, 0.0, 2.0, 5.0, 7.0, 3.0, 8.0 ]; + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN, NaN ]; + expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0, 5.0 ]; gsort2hp( x.length, 1.0, x, 1, y, 1 ); for ( i = 0; i < expectedX.length; i++ ) { @@ -174,7 +681,7 @@ tape( 'the function sorts a strided array which includes NaNs (increasing order) t.end(); }); -tape( 'the function sorts a strided array which includes NaNs (decreasing order)', function test( t ) { +tape( 'the function sorts a strided array (increasing order, special cases, accessors)', function test( t ) { var expectedX; var expectedY; var xc; @@ -183,15 +690,15 @@ tape( 'the function sorts a strided array which includes NaNs (decreasing order) var v; var i; - x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; - y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + x = [ NaN, 1.0, -1.0, 2.0, 2.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; xc = x.slice(); - expectedX = [ NaN, NaN, 3.0, 2.0, 2.0, 1.0, -1.0, -2.0, -3.0, -3.0 ]; - expectedY = [ 3.0, 8.0, 7.0, 2.0, 5.0, 0.0, 1.0, 4.0, 6.0, 9.0 ]; + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; + expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0 ]; - gsort2hp( x.length, -1.0, x, 1, y, 1 ); + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -215,27 +722,16 @@ tape( 'the function sorts a strided array which includes NaNs (decreasing order) t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); } } - t.end(); -}); - -tape( 'the function sorts a strided array which includes positive and negative zeros (increasing order)', function test( t ) { - var expectedX; - var expectedY; - var xc; - var x; - var y; - var v; - var i; - x = [ 0.0, -0.0, 0.0, -0.0 ]; - y = [ 0.0, 1.0, 2.0, 3.0 ]; + x = [ 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; xc = x.slice(); - expectedX = [ -0.0, -0.0, 0.0, 0.0 ]; - expectedY = [ 1.0, 3.0, 0.0, 2.0 ]; + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; + expectedY = [ 1.0, 0.0, 2.0, 3.0, 4.0 ]; - gsort2hp( x.length, 1.0, x, 1, y, 1 ); + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -259,27 +755,16 @@ tape( 'the function sorts a strided array which includes positive and negative z t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); } } - t.end(); -}); - -tape( 'the function sorts a strided array which includes positive and negative zeros (decreasing order)', function test( t ) { - var expectedX; - var expectedY; - var xc; - var x; - var y; - var v; - var i; - x = [ 0.0, -0.0, 0.0, -0.0 ]; - y = [ 0.0, 1.0, 2.0, 3.0 ]; + x = [ NaN, 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 ]; xc = x.slice(); - expectedX = [ 0.0, 0.0, -0.0, -0.0 ]; - expectedY = [ 0.0, 2.0, 1.0, 3.0 ]; + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN, NaN ]; + expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0, 5.0 ]; - gsort2hp( x.length, -1.0, x, 1, y, 1 ); + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -306,7 +791,7 @@ tape( 'the function sorts a strided array which includes positive and negative z t.end(); }); -tape( 'the function sorts a strided array (increasing order; special cases)', function test( t ) { +tape( 'the function sorts a strided array (decreasing order, special cases)', function test( t ) { var expectedX; var expectedY; var xc; @@ -320,10 +805,10 @@ tape( 'the function sorts a strided array (increasing order; special cases)', fu xc = x.slice(); - expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; - expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0 ]; + expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; + expectedY = [ 0.0, 3.0, 4.0, 1.0, 2.0 ]; - gsort2hp( x.length, 1.0, x, 1, y, 1 ); + gsort2hp( x.length, -1.0, x, 1, y, 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -353,10 +838,10 @@ tape( 'the function sorts a strided array (increasing order; special cases)', fu xc = x.slice(); - expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; - expectedY = [ 1.0, 0.0, 2.0, 3.0, 4.0 ]; + expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; + expectedY = [ 4.0, 2.0, 3.0, 0.0, 1.0 ]; - gsort2hp( x.length, 1.0, x, 1, y, 1 ); + gsort2hp( x.length, -1.0, x, 1, y, 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -386,10 +871,10 @@ tape( 'the function sorts a strided array (increasing order; special cases)', fu xc = x.slice(); - expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN, NaN ]; - expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0, 5.0 ]; + expectedX = [ NaN, NaN, 2.0, 2.0, 1.0, -1.0 ]; + expectedY = [ 0.0, 5.0, 3.0, 4.0, 1.0, 2.0 ]; - gsort2hp( x.length, 1.0, x, 1, y, 1 ); + gsort2hp( x.length, -1.0, x, 1, y, 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -416,7 +901,7 @@ tape( 'the function sorts a strided array (increasing order; special cases)', fu t.end(); }); -tape( 'the function sorts a strided array (decreasing order; special cases)', function test( t ) { +tape( 'the function sorts a strided array (decreasing order, special cases, accessors)', function test( t ) { var expectedX; var expectedY; var xc; @@ -433,7 +918,7 @@ tape( 'the function sorts a strided array (decreasing order; special cases)', fu expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; expectedY = [ 0.0, 3.0, 4.0, 1.0, 2.0 ]; - gsort2hp( x.length, -1.0, x, 1, y, 1 ); + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -466,7 +951,7 @@ tape( 'the function sorts a strided array (decreasing order; special cases)', fu expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; expectedY = [ 4.0, 2.0, 3.0, 0.0, 1.0 ]; - gsort2hp( x.length, -1.0, x, 1, y, 1 ); + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -499,7 +984,7 @@ tape( 'the function sorts a strided array (decreasing order; special cases)', fu expectedX = [ NaN, NaN, 2.0, 2.0, 1.0, -1.0 ]; expectedY = [ 0.0, 5.0, 3.0, 4.0, 1.0, 2.0 ]; - gsort2hp( x.length, -1.0, x, 1, y, 1 ); + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, toAccessorArray( y ), 1 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -540,6 +1025,20 @@ tape( 'the function returns a reference to the first input array', function test t.end(); }); +tape( 'the function returns a reference to the first input array (accessors)', function test( t ) { + var out; + var x; + var y; + + x = toAccessorArray( [ 1.0, 2.0, 3.0, 4.0, 5.0 ] ); + y = toAccessorArray( [ 0.0, 1.0, 2.0, 3.0, 4.0 ] ); + out = gsort2hp( x.length, 1.0, x, 1, y, 1 ); + + t.strictEqual( out, x, 'same reference' ); + t.notEqual( out, y, 'different reference' ); + t.end(); +}); + tape( 'if provided an `N` parameter less than or equal to `0`, the function leaves `x` and `y` unchanged', function test( t ) { var expectedX; var expectedY; @@ -623,6 +1122,47 @@ tape( 'the function supports specifying strides (increasing order)', function te t.end(); }); +tape( 'the function supports specifying strides (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 0 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 2 + ]; + y = [ + 0.0, // 0 + 1.0, + 2.0, // 1 + 3.0, + 4.0 // 2 + ]; + expectedX = [ + -5.0, // 0 + -3.0, + 2.0, // 1 + 7.0, + 6.0 // 2 + ]; + expectedY = [ + 2.0, // 0 + 1.0, + 0.0, // 1 + 3.0, + 4.0 // 2 + ]; + + gsort2hp( 3, 1.0, toAccessorArray( x ), 2, toAccessorArray( y ), 2 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying strides (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -664,6 +1204,47 @@ tape( 'the function supports specifying strides (decreasing order)', function te t.end(); }); +tape( 'the function supports specifying strides (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 0 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 2 + ]; + y = [ + 0.0, // 0 + 1.0, + 2.0, // 1 + 3.0, + 4.0 // 2 + ]; + expectedX = [ + 6.0, // 0 + -3.0, + 2.0, // 1 + 7.0, + -5.0 // 2 + ]; + expectedY = [ + 4.0, // 0 + 1.0, + 0.0, // 1 + 3.0, + 2.0 // 2 + ]; + + gsort2hp( 3, -1.0, toAccessorArray( x ), 2, toAccessorArray( y ), 2 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying negative strides (increasing order)', function test( t ) { var expectedX; var expectedY; @@ -705,6 +1286,47 @@ tape( 'the function supports specifying negative strides (increasing order)', fu t.end(); }); +tape( 'the function supports specifying negative strides (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 2 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 0 + ]; + y = [ + 4.0, // 2 + 3.0, + 2.0, // 1 + 1.0, + 0.0 // 0 + ]; + expectedX = [ + 6.0, // 2 + -3.0, + 2.0, // 1 + 7.0, + -5.0 // 0 + ]; + expectedY = [ + 0.0, // 2 + 3.0, + 4.0, // 1 + 1.0, + 2.0 // 0 + ]; + + gsort2hp( 3, 1.0, toAccessorArray( x ), -2, toAccessorArray( y ), -2 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying negative strides (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -746,6 +1368,47 @@ tape( 'the function supports specifying negative strides (decreasing order)', fu t.end(); }); +tape( 'the function supports specifying negative strides (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 2 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 0 + ]; + y = [ + 4.0, // 2 + 3.0, + 2.0, // 1 + 1.0, + 0.0 // 0 + ]; + expectedX = [ + -5.0, // 2 + -3.0, + 2.0, // 1 + 7.0, + 6.0 // 0 + ]; + expectedY = [ + 2.0, // 2 + 3.0, + 4.0, // 1 + 1.0, + 0.0 // 0 + ]; + + gsort2hp( 3, -1.0, toAccessorArray( x ), -2, toAccessorArray( y ), -2 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports view offsets (increasing order)', function test( t ) { var expectedX; var expectedY; diff --git a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.ndarray.js b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.ndarray.js index ccde6b1dfbb4..6c39d8fb917f 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.ndarray.js +++ b/lib/node_modules/@stdlib/blas/ext/base/gsort2hp/test/test.ndarray.js @@ -24,6 +24,7 @@ var tape = require( 'tape' ); var isnan = require( '@stdlib/math/base/assert/is-nan' ); var isPositiveZero = require( '@stdlib/math/base/assert/is-positive-zero' ); var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' ); +var toAccessorArray = require( '@stdlib/array/base/to-accessor-array' ); var num2str = require( './fixtures/num2str.js' ); var gsort2hp = require( './../lib/ndarray.js' ); @@ -85,6 +86,50 @@ tape( 'the function sorts a strided array (increasing order)', function test( t t.end(); }); +tape( 'the function sorts a strided array (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, -2.0, 2.0, -3.0, 3.0, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]; + + xc = x.slice(); + + expectedX = [ -3.0, -3.0, -2.0, -1.0, 1.0, 2.0, 2.0, 3.0 ]; + expectedY = [ 5.0, 7.0, 3.0, 1.0, 0.0, 2.0, 4.0, 6.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + tape( 'the function sorts a strided array (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -129,6 +174,50 @@ tape( 'the function sorts a strided array (decreasing order)', function test( t t.end(); }); +tape( 'the function sorts a strided array (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, -2.0, 2.0, -3.0, 3.0, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]; + + xc = x.slice(); + + expectedX = [ 3.0, 2.0, 2.0, 1.0, -1.0, -2.0, -3.0, -3.0 ]; + expectedY = [ 6.0, 2.0, 4.0, 0.0, 1.0, 3.0, 5.0, 7.0 ]; + + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + tape( 'the function sorts a strided array which includes NaNs (increasing order)', function test( t ) { var expectedX; var expectedY; @@ -173,6 +262,50 @@ tape( 'the function sorts a strided array which includes NaNs (increasing order) t.end(); }); +tape( 'the function sorts a strided array which includes NaNs (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + + xc = x.slice(); + + expectedX = [ -3.0, -3.0, -2.0, -1.0, 1.0, 2.0, 2.0, 3.0, NaN, NaN ]; + expectedY = [ 6.0, 9.0, 4.0, 1.0, 0.0, 2.0, 5.0, 7.0, 3.0, 8.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + tape( 'the function sorts a strided array which includes NaNs (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -217,6 +350,50 @@ tape( 'the function sorts a strided array which includes NaNs (decreasing order) t.end(); }); +tape( 'the function sorts a strided array which includes NaNs (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 1.0, -1.0, 2.0, NaN, -2.0, 2.0, -3.0, 3.0, NaN, -3.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 ]; + + xc = x.slice(); + + expectedX = [ NaN, NaN, 3.0, 2.0, 2.0, 1.0, -1.0, -2.0, -3.0, -3.0 ]; + expectedY = [ 3.0, 8.0, 7.0, 2.0, 5.0, 0.0, 1.0, 4.0, 6.0, 9.0 ]; + + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + tape( 'the function sorts a strided array which includes positive and negative zeros (increasing order)', function test( t ) { var expectedX; var expectedY; @@ -261,6 +438,50 @@ tape( 'the function sorts a strided array which includes positive and negative z t.end(); }); +tape( 'the function sorts a strided array which includes positive and negative zeros (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 0.0, -0.0, 0.0, -0.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0 ]; + + xc = x.slice(); + + expectedX = [ -0.0, -0.0, 0.0, 0.0 ]; + expectedY = [ 1.0, 3.0, 0.0, 2.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + tape( 'the function sorts a strided array which includes positive and negative zeros (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -305,7 +526,51 @@ tape( 'the function sorts a strided array which includes positive and negative z t.end(); }); -tape( 'the function sorts a strided array (increasing order; special cases)', function test( t ) { +tape( 'the function sorts a strided array which includes positive and negative zeros (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ 0.0, -0.0, 0.0, -0.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0 ]; + + xc = x.slice(); + + expectedX = [ 0.0, 0.0, -0.0, -0.0 ]; + expectedY = [ 0.0, 2.0, 1.0, 3.0 ]; + + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array (increasing order, special cases)', function test( t ) { var expectedX; var expectedY; var xc; @@ -415,7 +680,227 @@ tape( 'the function sorts a strided array (increasing order; special cases)', fu t.end(); }); -tape( 'the function sorts a strided array (decreasing order; special cases)', function test( t ) { +tape( 'the function sorts a strided array (increasing order, special cases, accessors)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ NaN, 1.0, -1.0, 2.0, 2.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; + + xc = x.slice(); + + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; + expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + + x = [ 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; + + xc = x.slice(); + + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN ]; + expectedY = [ 1.0, 0.0, 2.0, 3.0, 4.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + + x = [ NaN, 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 ]; + + xc = x.slice(); + + expectedX = [ -1.0, 1.0, 2.0, 2.0, NaN, NaN ]; + expectedY = [ 2.0, 1.0, 3.0, 4.0, 0.0, 5.0 ]; + + gsort2hp( x.length, 1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array (decreasing order, special cases)', function test( t ) { + var expectedX; + var expectedY; + var xc; + var x; + var y; + var v; + var i; + + x = [ NaN, 1.0, -1.0, 2.0, 2.0 ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; + + xc = x.slice(); + + expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; + expectedY = [ 0.0, 3.0, 4.0, 1.0, 2.0 ]; + + gsort2hp( x.length, -1.0, x, 1, 0, y, 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + + x = [ 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0 ]; + + xc = x.slice(); + + expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; + expectedY = [ 4.0, 2.0, 3.0, 0.0, 1.0 ]; + + gsort2hp( x.length, -1.0, x, 1, 0, y, 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + + x = [ NaN, 1.0, -1.0, 2.0, 2.0, NaN ]; + y = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 ]; + + xc = x.slice(); + + expectedX = [ NaN, NaN, 2.0, 2.0, 1.0, -1.0 ]; + expectedY = [ 0.0, 5.0, 3.0, 4.0, 1.0, 2.0 ]; + + gsort2hp( x.length, -1.0, x, 1, 0, y, 1, 0 ); + for ( i = 0; i < expectedX.length; i++ ) { + v = expectedX[ i ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( x[ i ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( x[i] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( x[ i ], v, 'returns expected value. index: '+i+'. actual: '+x[i]+'. expected: '+v+'.' ); + } + // Account for unstable sort... + v = xc[ expectedY[i] ]; + if ( isnan( v ) ) { + t.strictEqual( isnan( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } else if ( isNegativeZero( v ) ) { + t.strictEqual( isNegativeZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+num2str( v )+'.' ); + } else if ( isPositiveZero( v ) ) { + t.strictEqual( isPositiveZero( xc[ y[i] ] ), true, 'returns expected value. index: '+i+'. actual: '+num2str( xc[ y[i] ] )+'. expected: '+v+'.' ); + } else { + t.strictEqual( xc[ y[i] ], v, 'returns expected value. index: '+i+'. actual: '+xc[ y[i] ]+'. expected: '+v+'.' ); + } + } + t.end(); +}); + +tape( 'the function sorts a strided array (decreasing order, special cases, accessors)', function test( t ) { var expectedX; var expectedY; var xc; @@ -432,7 +917,7 @@ tape( 'the function sorts a strided array (decreasing order; special cases)', fu expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; expectedY = [ 0.0, 3.0, 4.0, 1.0, 2.0 ]; - gsort2hp( x.length, -1.0, x, 1, 0, y, 1, 0 ); + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -465,7 +950,7 @@ tape( 'the function sorts a strided array (decreasing order; special cases)', fu expectedX = [ NaN, 2.0, 2.0, 1.0, -1.0 ]; expectedY = [ 4.0, 2.0, 3.0, 0.0, 1.0 ]; - gsort2hp( x.length, -1.0, x, 1, 0, y, 1, 0 ); + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -498,7 +983,7 @@ tape( 'the function sorts a strided array (decreasing order; special cases)', fu expectedX = [ NaN, NaN, 2.0, 2.0, 1.0, -1.0 ]; expectedY = [ 0.0, 5.0, 3.0, 4.0, 1.0, 2.0 ]; - gsort2hp( x.length, -1.0, x, 1, 0, y, 1, 0 ); + gsort2hp( x.length, -1.0, toAccessorArray( x ), 1, 0, toAccessorArray( y ), 1, 0 ); for ( i = 0; i < expectedX.length; i++ ) { v = expectedX[ i ]; if ( isnan( v ) ) { @@ -539,6 +1024,20 @@ tape( 'the function returns a reference to the first input array', function test t.end(); }); +tape( 'the function returns a reference to the first input array (accessors)', function test( t ) { + var out; + var x; + var y; + + x = toAccessorArray( [ 1.0, 2.0, 3.0, 4.0, 5.0 ] ); + y = toAccessorArray( [ 0.0, 1.0, 2.0, 3.0, 4.0 ] ); + out = gsort2hp( x.length, 1.0, x, 1, 0, y, 1, 0 ); + + t.strictEqual( out, x, 'same reference' ); + t.notEqual( out, y, 'different reference' ); + t.end(); +}); + tape( 'if provided an `N` parameter less than or equal to `0`, the function leaves `x` and `y` unchanged', function test( t ) { var expectedX; var expectedY; @@ -622,6 +1121,47 @@ tape( 'the function supports specifying strides (increasing order)', function te t.end(); }); +tape( 'the function supports specifying strides (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 0 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 2 + ]; + y = [ + 0.0, // 0 + 1.0, + 2.0, // 1 + 3.0, + 4.0 // 2 + ]; + expectedX = [ + -5.0, // 0 + -3.0, + 2.0, // 1 + 7.0, + 6.0 // 2 + ]; + expectedY = [ + 2.0, // 0 + 1.0, + 0.0, // 1 + 3.0, + 4.0 // 2 + ]; + + gsort2hp( 3, 1.0, toAccessorArray( x ), 2, 0, toAccessorArray( y ), 2, 0 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying strides (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -663,6 +1203,47 @@ tape( 'the function supports specifying strides (decreasing order)', function te t.end(); }); +tape( 'the function supports specifying strides (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 0 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 2 + ]; + y = [ + 0.0, // 0 + 1.0, + 2.0, // 1 + 3.0, + 4.0 // 2 + ]; + expectedX = [ + 6.0, // 0 + -3.0, + 2.0, // 1 + 7.0, + -5.0 // 2 + ]; + expectedY = [ + 4.0, // 0 + 1.0, + 0.0, // 1 + 3.0, + 2.0 // 2 + ]; + + gsort2hp( 3, -1.0, toAccessorArray( x ), 2, 0, toAccessorArray( y ), 2, 0 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying negative strides (increasing order)', function test( t ) { var expectedX; var expectedY; @@ -704,6 +1285,47 @@ tape( 'the function supports specifying negative strides (increasing order)', fu t.end(); }); +tape( 'the function supports specifying negative strides (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 2 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 0 + ]; + y = [ + 4.0, // 2 + 3.0, + 2.0, // 1 + 1.0, + 0.0 // 0 + ]; + expectedX = [ + 6.0, // 2 + -3.0, + 2.0, // 1 + 7.0, + -5.0 // 0 + ]; + expectedY = [ + 0.0, // 2 + 3.0, + 4.0, // 1 + 1.0, + 2.0 // 0 + ]; + + gsort2hp( 3, 1.0, toAccessorArray( x ), -2, x.length-1, toAccessorArray( y ), -2, y.length-1 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying negative strides (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -745,6 +1367,47 @@ tape( 'the function supports specifying negative strides (decreasing order)', fu t.end(); }); +tape( 'the function supports specifying negative strides (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 2.0, // 2 + -3.0, + -5.0, // 1 + 7.0, + 6.0 // 0 + ]; + y = [ + 4.0, // 2 + 3.0, + 2.0, // 1 + 1.0, + 0.0 // 0 + ]; + expectedX = [ + -5.0, // 2 + -3.0, + 2.0, // 1 + 7.0, + 6.0 // 0 + ]; + expectedY = [ + 2.0, // 2 + 3.0, + 4.0, // 1 + 1.0, + 0.0 // 0 + ]; + + gsort2hp( 3, -1.0, toAccessorArray( x ), -2, x.length-1, toAccessorArray( y ), -2, y.length-1 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying offsets (increasing order)', function test( t ) { var expectedX; var expectedY; @@ -790,6 +1453,51 @@ tape( 'the function supports specifying offsets (increasing order)', function te t.end(); }); +tape( 'the function supports specifying offsets (increasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 1.0, + -2.0, // 0 + 3.0, + -4.0, // 1 + 5.0, + -6.0 // 2 + ]; + y = [ + 0.0, + 1.0, // 0 + 2.0, + 3.0, // 1 + 4.0, + 5.0 // 2 + ]; + expectedX = [ + 1.0, + -6.0, // 0 + 3.0, + -4.0, // 1 + 5.0, + -2.0 // 2 + ]; + expectedY = [ + 0.0, + 5.0, // 0 + 2.0, + 3.0, // 1 + 4.0, + 1.0 // 2 + ]; + + gsort2hp( 3, 1.0, toAccessorArray( x ), 2, 1, toAccessorArray( y ), 2, 1 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports specifying offsets (decreasing order)', function test( t ) { var expectedX; var expectedY; @@ -835,6 +1543,51 @@ tape( 'the function supports specifying offsets (decreasing order)', function te t.end(); }); +tape( 'the function supports specifying offsets (decreasing order, accessors)', function test( t ) { + var expectedX; + var expectedY; + var x; + var y; + + x = [ + 1.0, + -6.0, // 0 + 3.0, + -4.0, // 1 + 5.0, + -2.0 // 2 + ]; + y = [ + 0.0, + 1.0, // 0 + 2.0, + 3.0, // 1 + 4.0, + 5.0 // 2 + ]; + expectedX = [ + 1.0, + -2.0, // 0 + 3.0, + -4.0, // 1 + 5.0, + -6.0 // 2 + ]; + expectedY = [ + 0.0, + 5.0, // 0 + 2.0, + 3.0, // 1 + 4.0, + 1.0 // 2 + ]; + + gsort2hp( 3, -1.0, toAccessorArray( x ), 2, 1, toAccessorArray( y ), 2, 1 ); + t.deepEqual( x, expectedX, 'returns expected value' ); + t.deepEqual( y, expectedY, 'returns expected value' ); + t.end(); +}); + tape( 'the function supports complex access patterns (increasing order)', function test( t ) { var expectedX; var expectedY;