time-to-botec

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

main.js (4754B)


      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 // MAIN //
     22 
     23 /**
     24 * Broadcasts array shapes to a single shape.
     25 *
     26 * ## Notes
     27 *
     28 * -   Two respective dimensions in two shape arrays are compatible if
     29 *
     30 *     1.  the dimensions are equal.
     31 *     2.  one dimension is `1`.
     32 *
     33 * -   The function returns `null` if provided incompatible shapes (i.e., shapes which cannot be broadcast with one another).
     34 *
     35 * @param {Array<NonNegativeIntegerArray>} shapes - array of shape arrays
     36 * @returns {(NonNegativeIntegerArray|null)} broadcast shape (or `null`)
     37 *
     38 * @example
     39 * var shapes = [
     40 *     [ 8, 1, 6, 1 ],
     41 *     [ 7, 1, 5 ]
     42 * ];
     43 *
     44 * var out = broadcastShapes( shapes );
     45 * // returns [ 8, 7, 6, 5 ]
     46 *
     47 * @example
     48 * var shapes = [
     49 *     [ 5, 4 ],
     50 *     [ 1 ]
     51 * ];
     52 *
     53 * var out = broadcastShapes( shapes );
     54 * // returns [ 5, 4 ]
     55 *
     56 * @example
     57 * var shapes = [
     58 *     [ 5, 4 ],
     59 *     [ 4 ]
     60 * ];
     61 *
     62 * var out = broadcastShapes( shapes );
     63 * // returns [ 5, 4 ]
     64 *
     65 * @example
     66 * var shapes = [
     67 *     [ 15, 3, 5 ],
     68 *     [ 15, 1, 5 ]
     69 * ];
     70 *
     71 * var out = broadcastShapes( shapes );
     72 * // returns [ 15, 3, 5 ]
     73 *
     74 * @example
     75 * var shapes = [
     76 *     [ 15, 3, 5 ],
     77 *     [ 3, 5 ]
     78 * ];
     79 *
     80 * var out = broadcastShapes( shapes );
     81 * // returns [ 15, 3, 5 ]
     82 *
     83 * @example
     84 * var shapes = [
     85 *     [ 15, 3, 5 ],
     86 *     [ 3, 1 ]
     87 * ];
     88 *
     89 * var out = broadcastShapes( shapes );
     90 * // returns [ 15, 3, 5 ]
     91 *
     92 * @example
     93 * var shapes = [
     94 *     [ 8, 1, 1, 6, 1 ],
     95 *     [ 1, 7, 1, 5 ],
     96 *     [ 8, 4, 1, 6, 5 ]
     97 * ];
     98 *
     99 * var out = broadcastShapes( shapes );
    100 * // returns [ 8, 4, 7, 6, 5 ]
    101 *
    102 * @example
    103 * var shapes = [
    104 *     [ 8, 1, 1, 6, 1 ],
    105 *     [ 0 ]
    106 * ];
    107 *
    108 * var out = broadcastShapes( shapes );
    109 * // returns [ 8, 1, 1, 6, 0 ]
    110 *
    111 * @example
    112 * var shapes = [
    113 *     [ 8, 1, 1, 6, 1 ],
    114 *     [ 8, 0, 1, 6, 1 ]
    115 * ];
    116 *
    117 * var out = broadcastShapes( shapes );
    118 * // returns [ 8, 0, 1, 6, 1 ]
    119 *
    120 * @example
    121 * var shapes = [
    122 *     [ 8, 8, 1, 6, 1 ],
    123 *     [ 8, 0, 1, 6, 1 ]
    124 * ];
    125 *
    126 * var out = broadcastShapes( shapes );
    127 * // returns null
    128 *
    129 * @example
    130 * var shapes = [
    131 *     [ 8, 0, 1, 6, 1 ],
    132 *     [ 8, 8, 1, 6, 1 ]
    133 * ];
    134 *
    135 * var out = broadcastShapes( shapes );
    136 * // returns null
    137 *
    138 * @example
    139 * var shapes = [
    140 *     []
    141 * ];
    142 *
    143 * var out = broadcastShapes( shapes );
    144 * // returns []
    145 *
    146 * @example
    147 * var shapes = [
    148 *     [],
    149 *     []
    150 * ];
    151 *
    152 * var out = broadcastShapes( shapes );
    153 * // returns []
    154 *
    155 * @example
    156 * var shapes = [];
    157 *
    158 * var out = broadcastShapes( shapes );
    159 * // returns []
    160 *
    161 * @example
    162 * var shapes = [
    163 *     [ 3, 2, 1 ],
    164 *     []
    165 * ];
    166 *
    167 * var out = broadcastShapes( shapes );
    168 * // returns [ 3, 2, 1 ]
    169 *
    170 * @example
    171 * var shapes = [
    172 *     [],
    173 *     [ 3, 2, 1 ]
    174 * ];
    175 *
    176 * var out = broadcastShapes( shapes );
    177 * // returns [ 3, 2, 1 ]
    178 */
    179 function broadcastShapes( shapes ) {
    180 	var ndims;
    181 	var out;
    182 	var dim;
    183 	var sh;
    184 	var n1;
    185 	var n2;
    186 	var d;
    187 	var M;
    188 	var N;
    189 	var i;
    190 	var j;
    191 
    192 	M = shapes.length;
    193 	out = [];
    194 	if ( M === 0 ) {
    195 		return out;
    196 	}
    197 	sh = shapes[ 0 ];
    198 	N = sh.length;
    199 
    200 	// If provided a single input shape array, then the broadcast shape is input shape...
    201 	if ( M === 1 ) {
    202 		// Need to manually copy to output shape, as shapes could be array-like objects...
    203 		for ( i = 0; i < N; i++ ) {
    204 			out.push( sh[ i ] );
    205 		}
    206 		return out;
    207 	}
    208 	// Determine the maximum dimensionality...
    209 	ndims = [ N ];
    210 	for ( i = 1; i < M; i++ ) {
    211 		ndims.push( shapes[ i ].length );
    212 		if ( ndims[ i ] > N ) {
    213 			N = ndims[ i ];
    214 		}
    215 	}
    216 	// Initialize the output array...
    217 	for ( i = 0; i < N; i++ ) {
    218 		out.push( 0 );
    219 	}
    220 	// Compute the broadcast shape...
    221 	i = N - 1;
    222 	while ( i >= 0 ) {
    223 		n1 = ndims[ 0 ] - N + i;
    224 		if ( n1 >= 0 ) {
    225 			dim = sh[ n1 ];
    226 		} else {
    227 			dim = 1;
    228 		}
    229 		for ( j = 1; j < M; j++ ) {
    230 			n2 = ndims[ j ] - N + i;
    231 			if ( n2 >= 0 ) {
    232 				d = shapes[ j ][ n2 ];
    233 			} else {
    234 				d = 1;
    235 			}
    236 			if ( dim === 1 ) {
    237 				dim = d;
    238 				continue;
    239 			}
    240 			if ( d === 1 || dim === d ) {
    241 				// When either `d` is `1` or `d` equals the current output shape dimension, the current output shape dimension remains the same...
    242 				continue;
    243 			}
    244 			// The current shape cannot be broadcast against one of the other shapes...
    245 			return null;
    246 		}
    247 		out[ i ] = dim;
    248 		i -= 1;
    249 	}
    250 	return out;
    251 }
    252 
    253 
    254 // EXPORTS //
    255 
    256 module.exports = broadcastShapes;