time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

main.js (10475B)


      1 /**
      2 * @license Apache-2.0
      3 *
      4 * Copyright (c) 2021 The Stdlib Authors.
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *    http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 'use strict';
     20 
     21 // MODULES //
     22 
     23 var iterationOrder = require( './../../../base/iteration-order' );
     24 var minmaxViewBufferIndex = require( './../../../base/minmax-view-buffer-index' );
     25 var copy = require( './copy_ndarray.js' );
     26 var blockedaccessorunary2d = require( './2d_blocked_accessors.js' );
     27 var blockedaccessorunary3d = require( './3d_blocked_accessors.js' );
     28 var blockedaccessorunary4d = require( './4d_blocked_accessors.js' );
     29 var blockedaccessorunary5d = require( './5d_blocked_accessors.js' );
     30 var blockedaccessorunary6d = require( './6d_blocked_accessors.js' );
     31 var blockedaccessorunary7d = require( './7d_blocked_accessors.js' );
     32 var blockedaccessorunary8d = require( './8d_blocked_accessors.js' );
     33 var blockedaccessorunary9d = require( './9d_blocked_accessors.js' );
     34 var blockedaccessorunary10d = require( './10d_blocked_accessors.js' );
     35 var blockedunary2d = require( './2d_blocked.js' );
     36 var blockedunary3d = require( './3d_blocked.js' );
     37 var blockedunary4d = require( './4d_blocked.js' );
     38 var blockedunary5d = require( './5d_blocked.js' );
     39 var blockedunary6d = require( './6d_blocked.js' );
     40 var blockedunary7d = require( './7d_blocked.js' );
     41 var blockedunary8d = require( './8d_blocked.js' );
     42 var blockedunary9d = require( './9d_blocked.js' );
     43 var blockedunary10d = require( './10d_blocked.js' );
     44 var accessorunary0d = require( './0d_accessors.js' );
     45 var accessorunary1d = require( './1d_accessors.js' );
     46 var accessorunary2d = require( './2d_accessors.js' );
     47 var accessorunary3d = require( './3d_accessors.js' );
     48 var accessorunary4d = require( './4d_accessors.js' );
     49 var accessorunary5d = require( './5d_accessors.js' );
     50 var accessorunary6d = require( './6d_accessors.js' );
     51 var accessorunary7d = require( './7d_accessors.js' );
     52 var accessorunary8d = require( './8d_accessors.js' );
     53 var accessorunary9d = require( './9d_accessors.js' );
     54 var accessorunary10d = require( './10d_accessors.js' );
     55 var accessorunarynd = require( './nd_accessors.js' );
     56 var unary0d = require( './0d.js' );
     57 var unary1d = require( './1d.js' );
     58 var unary2d = require( './2d.js' );
     59 var unary3d = require( './3d.js' );
     60 var unary4d = require( './4d.js' );
     61 var unary5d = require( './5d.js' );
     62 var unary6d = require( './6d.js' );
     63 var unary7d = require( './7d.js' );
     64 var unary8d = require( './8d.js' );
     65 var unary9d = require( './9d.js' );
     66 var unary10d = require( './10d.js' );
     67 var unarynd = require( './nd.js' );
     68 
     69 
     70 // VARIABLES //
     71 
     72 var UNARY = [
     73 	unary0d,
     74 	unary1d,
     75 	unary2d,
     76 	unary3d,
     77 	unary4d,
     78 	unary5d,
     79 	unary6d,
     80 	unary7d,
     81 	unary8d,
     82 	unary9d,
     83 	unary10d
     84 ];
     85 var ACCESSOR_UNARY = [
     86 	accessorunary0d,
     87 	accessorunary1d,
     88 	accessorunary2d,
     89 	accessorunary3d,
     90 	accessorunary4d,
     91 	accessorunary5d,
     92 	accessorunary6d,
     93 	accessorunary7d,
     94 	accessorunary8d,
     95 	accessorunary9d,
     96 	accessorunary10d
     97 ];
     98 var BLOCKED_UNARY = [
     99 	blockedunary2d, // 0
    100 	blockedunary3d,
    101 	blockedunary4d,
    102 	blockedunary5d,
    103 	blockedunary6d,
    104 	blockedunary7d,
    105 	blockedunary8d,
    106 	blockedunary9d,
    107 	blockedunary10d // 8
    108 ];
    109 var BLOCKED_ACCESSOR_UNARY = [
    110 	blockedaccessorunary2d, // 0
    111 	blockedaccessorunary3d,
    112 	blockedaccessorunary4d,
    113 	blockedaccessorunary5d,
    114 	blockedaccessorunary6d,
    115 	blockedaccessorunary7d,
    116 	blockedaccessorunary8d,
    117 	blockedaccessorunary9d,
    118 	blockedaccessorunary10d // 8
    119 ];
    120 var MAX_DIMS = UNARY.length - 1;
    121 
    122 
    123 // MAIN //
    124 
    125 /**
    126 * Applies a unary callback to elements in an input ndarray and assigns results to elements in an output ndarray.
    127 *
    128 * ## Notes
    129 *
    130 * -   Each provided ndarray should be an `object` with the following properties:
    131 *
    132 *     -   **dtype**: data type.
    133 *     -   **data**: data buffer.
    134 *     -   **shape**: dimensions.
    135 *     -   **strides**: stride lengths.
    136 *     -   **offset**: index offset.
    137 *     -   **order**: specifies whether an ndarray is row-major (C-style) or column major (Fortran-style).
    138 *
    139 * @param {ArrayLikeObject<Object>} arrays - array-like object containing one input array and one output array
    140 * @param {Callback} fcn - unary callback
    141 * @throws {Error} arrays must have the same number of dimensions
    142 * @throws {Error} arrays must have the same shape
    143 * @returns {void}
    144 *
    145 * @example
    146 * var Float64Array = require( '@stdlib/array/float64' );
    147 *
    148 * function scale( x ) {
    149 *     return x * 10.0;
    150 * }
    151 *
    152 * // Create data buffers:
    153 * var xbuf = new Float64Array( [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 ] );
    154 * var ybuf = new Float64Array( 6 );
    155 *
    156 * // Define the shape of the input and output arrays:
    157 * var shape = [ 3, 1, 2 ];
    158 *
    159 * // Define the array strides:
    160 * var sx = [ 4, 4, 1 ];
    161 * var sy = [ 2, 2, 1 ];
    162 *
    163 * // Define the index offsets:
    164 * var ox = 1;
    165 * var oy = 0;
    166 *
    167 * // Create the input and output ndarray-like objects:
    168 * var x = {
    169 *     'dtype': 'float64',
    170 *     'data': xbuf,
    171 *     'shape': shape,
    172 *     'strides': sx,
    173 *     'offset': ox,
    174 *     'order': 'row-major'
    175 * };
    176 * var y = {
    177 *     'dtype': 'float64',
    178 *     'data': ybuf,
    179 *     'shape': shape,
    180 *     'strides': sy,
    181 *     'offset': oy,
    182 *     'order': 'row-major'
    183 * };
    184 *
    185 * // Apply the unary function:
    186 * unary( [ x, y ], scale );
    187 *
    188 * console.log( y.data );
    189 * // => <Float64Array>[ 20.0, 30.0, 60.0, 70.0, 100.0, 110.0 ]
    190 */
    191 function unary( arrays, fcn ) {
    192 	var ndims;
    193 	var xmmv;
    194 	var ymmv;
    195 	var shx;
    196 	var shy;
    197 	var iox;
    198 	var ioy;
    199 	var len;
    200 	var sx;
    201 	var sy;
    202 	var ox;
    203 	var oy;
    204 	var ns;
    205 	var x;
    206 	var y;
    207 	var d;
    208 	var i;
    209 
    210 	// Unpack the ndarrays and standardize ndarray meta data:
    211 	x = copy( arrays[ 0 ] );
    212 	y = copy( arrays[ 1 ] );
    213 
    214 	// Verify that the input and output arrays have the same number of dimensions...
    215 	shx = x.shape;
    216 	shy = y.shape;
    217 	ndims = shx.length;
    218 	if ( ndims !== shy.length ) {
    219 		throw new Error( 'invalid arguments. Arrays must have the same number of dimensions (i.e., same rank). ndims(x) == '+ndims+'. ndims(y) == '+shy.length+'.' );
    220 	}
    221 	// Determine whether we can avoid iteration altogether...
    222 	if ( ndims === 0 ) {
    223 		if ( x.accessors || y.accessors ) {
    224 			return ACCESSOR_UNARY[ ndims ]( x, y, fcn );
    225 		}
    226 		return UNARY[ ndims ]( x, y, fcn );
    227 	}
    228 	// Verify that the input and output arrays have the same dimensions...
    229 	len = 1; // number of elements
    230 	ns = 0;  // number of singleton dimensions
    231 	for ( i = 0; i < ndims; i++ ) {
    232 		d = shx[ i ];
    233 		if ( d !== shy[ i ] ) {
    234 			throw new Error( 'invalid arguments. Arrays must have the same shape.' );
    235 		}
    236 		// Note that, if one of the dimensions is `0`, the length will be `0`...
    237 		len *= d;
    238 
    239 		// Check whether the current dimension is a singleton dimension...
    240 		if ( d === 1 ) {
    241 			ns += 1;
    242 		}
    243 	}
    244 	// Check whether we were provided empty ndarrays...
    245 	if ( len === 0 ) {
    246 		return;
    247 	}
    248 	// Determine whether the ndarrays are one-dimensional and thus readily translate to one-dimensional strided arrays...
    249 	if ( ndims === 1 ) {
    250 		if ( x.accessors || y.accessors ) {
    251 			return ACCESSOR_UNARY[ ndims ]( x, y, fcn );
    252 		}
    253 		return UNARY[ ndims ]( x, y, fcn );
    254 	}
    255 	sx = x.strides;
    256 	sy = y.strides;
    257 
    258 	// Determine whether the ndarray has only **one** non-singleton dimension (e.g., ndims=4, shape=[10,1,1,1]) so that we can treat the ndarrays as being equivalent to one-dimensional strided arrays...
    259 	if ( ns === ndims-1 ) {
    260 		// Get the index of the non-singleton dimension...
    261 		for ( i = 0; i < ndims; i++ ) {
    262 			if ( shx[ i ] !== 1 ) {
    263 				break;
    264 			}
    265 		}
    266 		x.shape = [ shx[i] ];
    267 		y.shape = x.shape;
    268 		x.strides = [ sx[i] ];
    269 		y.strides = [ sy[i] ];
    270 		if ( x.accessors || y.accessors ) {
    271 			return ACCESSOR_UNARY[ 1 ]( x, y, fcn );
    272 		}
    273 		return UNARY[ 1 ]( x, y, fcn );
    274 	}
    275 	iox = iterationOrder( sx ); // +/-1
    276 	ioy = iterationOrder( sy ); // +/-1
    277 
    278 	// Determine whether we can avoid blocked iteration...
    279 	if ( iox !== 0 && ioy !== 0 && x.order === y.order ) {
    280 		// Determine the minimum and maximum linear indices which are accessible by the array views:
    281 		xmmv = minmaxViewBufferIndex( shx, sx, x.offset );
    282 		ymmv = minmaxViewBufferIndex( shy, sy, y.offset );
    283 
    284 		// Determine whether we can ignore shape (and strides) and treat the ndarrays as linear one-dimensional strided arrays...
    285 		if ( len === ( xmmv[1]-xmmv[0]+1 ) && len === ( ymmv[1]-ymmv[0]+1 ) ) {
    286 			// Note: the above is equivalent to @stdlib/ndarray/base/assert/is-contiguous, but in-lined so we can retain computed values...
    287 			if ( iox === 1 ) {
    288 				ox = xmmv[ 0 ];
    289 			} else {
    290 				ox = xmmv[ 1 ];
    291 			}
    292 			if ( ioy === 1 ) {
    293 				oy = ymmv[ 0 ];
    294 			} else {
    295 				oy = ymmv[ 1 ];
    296 			}
    297 			x.shape = [ len ];
    298 			y.shape = x.shape;
    299 			x.strides = [ iox ];
    300 			y.strides = [ ioy ];
    301 			x.offset = ox;
    302 			y.offset = oy;
    303 			if ( x.accessors || y.accessors ) {
    304 				return ACCESSOR_UNARY[ 1 ]( x, y, fcn );
    305 			}
    306 			return UNARY[ 1 ]( x, y, fcn );
    307 		}
    308 		// At least one ndarray is non-contiguous, so we cannot directly use one-dimensional array functionality...
    309 
    310 		// Determine whether we can use simple nested loops...
    311 		if ( ndims <= MAX_DIMS ) {
    312 			// So long as iteration for each respective array always moves in the same direction (i.e., no mixed sign strides), we can leverage cache-optimal (i.e., normal) nested loops without resorting to blocked iteration...
    313 			if ( x.accessors || y.accessors ) {
    314 				return ACCESSOR_UNARY[ ndims ]( x, y, fcn );
    315 			}
    316 			return UNARY[ ndims ]( x, y, fcn );
    317 		}
    318 		// Fall-through to blocked iteration...
    319 	}
    320 	// At this point, we're either dealing with non-contiguous n-dimensional arrays, high dimensional n-dimensional arrays, and/or arrays having differing memory layouts, so our only hope is that we can still perform blocked iteration...
    321 
    322 	// Determine whether we can perform blocked iteration...
    323 	if ( ndims <= MAX_DIMS ) {
    324 		if ( x.accessors || y.accessors ) {
    325 			return BLOCKED_ACCESSOR_UNARY[ ndims-2 ]( x, y, fcn );
    326 		}
    327 		return BLOCKED_UNARY[ ndims-2 ]( x, y, fcn );
    328 	}
    329 	// Fall-through to linear view iteration without regard for how data is stored in memory (i.e., take the slow path)...
    330 	if ( x.accessors || y.accessors ) {
    331 		return accessorunarynd( x, y, fcn );
    332 	}
    333 	unarynd( x, y, fcn );
    334 }
    335 
    336 
    337 // EXPORTS //
    338 
    339 module.exports = unary;