main.c (4518B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 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/ind2sub.h" 20 #include "stdlib/ndarray/index_modes.h" 21 #include "stdlib/ndarray/orders.h" 22 #include <stdint.h> 23 #include <stdlib.h> 24 25 /** 26 * Converts a linear index to an array of subscripts. 27 * 28 * ## Notes 29 * 30 * - When provided a stride array containing negative strides, if an `offset` is greater than `0`, the function interprets the linear index as an index into the underlying data buffer for the array, thus returning subscripts from the perspective of that buffer. If an `offset` is equal to `0`, the function treats the linear index as an index into an array view, thus returning subscripts from the perspective of that view. In short, from the perspective of a view, view data is always ordered. 31 * 32 * - In "error" mode, the function returns `-1` if an index is out-of-bounds. 33 * 34 * @param ndims number of dimensions 35 * @param shape array shape (dimensions) 36 * @param strides array strides 37 * @param offset location of the first indexed value **based** on the stride array 38 * @param order specifies whether an array is row-major (C-style) or column-major (Fortran-style) 39 * @param idx linear index in an array view 40 * @param mode specifies how to handle a linear index which exceeds array dimensions 41 * @param out output array 42 * @return status code 43 * 44 * @example 45 * #include "stdlib/ndarray/base/ind2sub.h" 46 * #include "stdlib/ndarray/index_modes.h" 47 * #include "stdlib/ndarray/orders.h" 48 * #include <stdint.h> 49 * 50 * int64_t ndims = 2; 51 * int64_t shape[] = { 3, 3 }; 52 * int64_t strides[] = { -3, 1 }; 53 * int64_t offset = 6; 54 * 55 * int64_t out[ 2 ]; 56 * 57 * int8_t status = stdlib_ndarray_ind2sub( ndims, shape, strides, offset, STDLIB_NDARRAY_ROW_MAJOR, 7, STDLIB_NDARRAY_INDEX_ERROR, out ); 58 * if ( status == -1 ) { 59 * // Handle error... 60 * } 61 */ 62 int8_t stdlib_ndarray_ind2sub( int64_t ndims, int64_t *shape, int64_t *strides, int64_t offset, enum STDLIB_NDARRAY_ORDER order, int64_t idx, enum STDLIB_NDARRAY_INDEX_MODE mode, int64_t *out ) { 63 int64_t len; 64 int64_t s; 65 int64_t k; 66 int64_t i; 67 68 len = 1; 69 for ( i = 0; i < ndims; i++ ) { 70 len *= shape[ i ]; 71 } 72 if ( mode == STDLIB_NDARRAY_INDEX_CLAMP ) { 73 if ( idx < 0 ) { 74 idx = 0; 75 } else if ( idx >= len ) { 76 idx = len - 1; 77 } 78 } else if ( mode == STDLIB_NDARRAY_INDEX_WRAP ) { 79 if ( idx < 0 ) { 80 idx += len; // slight optimization to avoid modulo arithmetic when |idx| <= len 81 if ( idx < 0 ) { 82 idx -= len*( (int64_t)( idx/len ) ); // this is equivalent to `idx mod len`, where the result has same sign as dividend (i.e., `idx`); cannot use `%` as the sign of the result is implementation defined in C 83 if ( idx != 0 ) { 84 idx += len; 85 } 86 } 87 } else if ( idx >= len ) { 88 idx -= len; // slight optimization to avoid modulo arithmetic when len < idx <= 2*len 89 if ( idx >= len ) { 90 idx %= len; 91 } 92 } 93 } else if ( idx < 0 || idx >= len ) { // mode == 'error' 94 return -1; 95 } 96 if ( offset == 0 ) { 97 if ( order == STDLIB_NDARRAY_COLUMN_MAJOR ) { 98 for ( i = 0; i < ndims; i++ ) { 99 s = idx % shape[ i ]; 100 idx -= s; 101 idx /= shape[ i ]; 102 out[ i ] = s; 103 } 104 return 0; 105 } 106 // Case: row-major 107 for ( i = ndims-1; i >= 0; i-- ) { 108 s = idx % shape[ i ]; 109 idx -= s; 110 idx /= shape[ i ]; 111 out[ i ] = s; 112 } 113 return 0; 114 } 115 if ( order == STDLIB_NDARRAY_COLUMN_MAJOR ) { 116 for ( i = ndims-1; i >= 0; i-- ) { 117 s = strides[ i ]; 118 if ( s < 0 ) { 119 k = idx / s; // truncates 120 idx -= k * s; 121 out[ i ] = shape[ i ] - 1 + k; 122 } else { 123 k = idx / s; // cppcheck-suppress zerodivcond // truncates 124 idx -= k * s; 125 out[ i ] = k; 126 } 127 } 128 return 0; 129 } 130 // Case: row-major 131 for ( i = 0; i < ndims; i++ ) { 132 s = strides[ i ]; 133 if ( s < 0 ) { 134 k = idx / s; // truncates 135 idx -= k * s; 136 out[ i ] = shape[ i ] - 1 + k; 137 } else { 138 k = idx / s; // cppcheck-suppress zerodivcond // truncates 139 idx -= k * s; 140 out[ i ] = k; 141 } 142 } 143 return 0; 144 }