main.c (3157B)
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 #include "stdlib/ndarray/base/broadcast_shapes.h" 20 #include <stdint.h> 21 22 /** 23 * Broadcasts array shapes to a single shape. 24 * 25 * ## Notes 26 * 27 * - Two respective dimensions in two shape arrays are compatible if 28 * 29 * 1. the dimensions are equal. 30 * 2. one dimension is `1`. 31 * 32 * - If successful, the function returns `0`; otherwise, the function returns `-1` (e.g., due to incompatible shapes). 33 * 34 * - Even if the function is unsuccessful, the function may still overwrite elements in the output array before returning. In other words, do not assume that providing incompatible shapes is a no-op with regard to the output array. 35 * 36 * @param M number of array shapes 37 * @param shapes pointer to an array containing shape arrays 38 * @param ndims array containing the number of dimensions for (i.e., length of) each respective shape array 39 * @param out pointer to output array 40 * @return status 41 * 42 * @example 43 * #include "stdlib/ndarray/base/broadcast_shapes.h" 44 * #include <stdint.h> 45 * 46 * int64_t N1 = 4; 47 * int64_t sh1[] = { 8, 1, 6, 1 }; 48 * 49 * int64_t N2 = 3; 50 * int64_t sh2[] = { 7, 1, 5 }; 51 * 52 * int64_t ndims[] = { N1, N2 }; 53 * int64_t *shapes[] = { sh1, sh2 }; 54 * 55 * int64_t out[] = { 0, 0, 0, 0 }; 56 * int8_t status = stdlib_ndarray_broadcast_shapes( 2, shapes, ndims, out ); 57 */ 58 int8_t stdlib_ndarray_broadcast_shapes( int64_t M, int64_t *shapes[], int64_t ndims[], int64_t *out ) { 59 int64_t dim; 60 int64_t *sh; 61 int64_t n1; 62 int64_t n2; 63 int64_t d; 64 int64_t N; 65 int64_t i; 66 int64_t j; 67 68 if ( M == 0 ) { 69 return 0; 70 } 71 sh = shapes[ 0 ]; 72 N = ndims[ 0 ]; 73 74 // If provided a single input shape array, then the broadcast shape is input shape... 75 if ( M == 1 ) { 76 for ( i = 0; i < N; i++ ) { 77 out[ i ] = sh[ i ]; 78 } 79 return 0; 80 } 81 // Determine the maximum dimensionality... 82 for ( i = 1; i < M; i++ ) { 83 if ( ndims[ i ] > N ) { 84 N = ndims[ i ]; 85 } 86 } 87 // Compute the broadcast shape... 88 i = N - 1; 89 while ( i >= 0 ) { 90 n1 = ndims[ 0 ] - N + i; 91 if ( n1 >= 0 ) { 92 dim = sh[ n1 ]; 93 } else { 94 dim = 1; 95 } 96 for ( j = 1; j < M; j++ ) { 97 n2 = ndims[ j ] - N + i; 98 if ( n2 >= 0 ) { 99 d = shapes[ j ][ n2 ]; 100 } else { 101 d = 1; 102 } 103 if ( dim == 1 ) { 104 dim = d; 105 continue; 106 } 107 if ( d == 1 || dim == d ) { 108 // When either `d` is `1` or `d` equals the current output shape dimension, the current output shape dimension remains the same... 109 continue; 110 } 111 // The current shape cannot be broadcast against one of the other shapes... 112 return -1; 113 } 114 out[ i ] = dim; 115 i -= 1; 116 } 117 return 0; 118 }