main.c (10702B)
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/ctor.h" 20 #include "stdlib/ndarray/base/bytes_per_element.h" 21 #include "stdlib/ndarray/base/iteration_order.h" 22 #include "stdlib/ndarray/base/minmax_view_buffer_index.h" 23 #include "stdlib/ndarray/base/numel.h" 24 #include "stdlib/ndarray/base/strides2order.h" 25 #include "stdlib/ndarray/dtypes.h" 26 #include "stdlib/ndarray/index_modes.h" 27 #include "stdlib/ndarray/orders.h" 28 #include <stdlib.h> 29 #include <stdint.h> 30 31 // NOTE: keep functions in alphabetical order... 32 33 /** 34 * Returns a pointer to a dynamically allocated ndarray. 35 * 36 * ## Notes 37 * 38 * - The user is responsible for freeing the allocated memory. 39 * 40 * @param dtype data type 41 * @param data pointer to the underlying byte array 42 * @param ndims number of dimensions 43 * @param shape array shape (dimensions) 44 * @param strides array strides (in bytes) 45 * @param offset byte offset specifying the location of the first element 46 * @param order specifies whether an array is row-major (C-style) or column-major (Fortran-style) 47 * @param imode specifies how to handle indices which exceed array dimensions 48 * @param nsubmodes number of subscript modes 49 * @param submodes specifies how to handle subscripts which exceed array dimensions on a per dimension basis (if provided fewer submodes than dimensions, submodes are recycled using modulo arithmetic) 50 * @return pointer to a dynamically allocated ndarray or, if unable to allocate memory, a null pointer 51 * 52 * @example 53 * #include "stdlib/ndarray/ctor.h" 54 * #include "stdlib/ndarray/dtypes.h" 55 * #include "stdlib/ndarray/index_modes.h" 56 * #include "stdlib/ndarray/orders.h" 57 * #include "stdlib/ndarray/base/bytes_per_element.h" 58 * #include <stdlib.h> 59 * #include <stdio.h> 60 * #include <stdint.h> 61 * 62 * // Specify the underlying data type: 63 * enum STDLIB_NDARRAY_DTYPE dtype = STDLIB_NDARRAY_FLOAT64; 64 * 65 * // Create an underlying byte array: 66 * uint8_t buffer[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 67 * 68 * // Specify the number of array dimensions: 69 * int64_t ndims = 1; 70 * 71 * // Specify the array shape: 72 * int64_t shape[] = { 3 }; // vector consisting of 3 doubles 73 * 74 * // Specify the array strides: 75 * int64_t strides[] = { STDLIB_NDARRAY_FLOAT64_BYTES_PER_ELEMENT }; 76 * 77 * // Specify the byte offset: 78 * int64_t offset = 0; 79 * 80 * // Specify the array order (note: this does not matter for a 1-dimensional array): 81 * enum STDLIB_NDARRAY_ORDER order = STDLIB_NDARRAY_ROW_MAJOR; 82 * 83 * // Specify the index mode: 84 * enum STDLIB_NDARRAY_INDEX_MODE imode = STDLIB_NDARRAY_INDEX_ERROR; 85 * 86 * // Specify the subscript index modes: 87 * int8_t submodes[] = { STDLIB_NDARRAY_INDEX_ERROR }; 88 * int64_t nsubmodes = 1; 89 * 90 * // Create an ndarray: 91 * struct ndarray *x = stdlib_ndarray_allocate( dtype, buffer, ndims, shape, strides, offset, order, imode, nsubmodes, submodes ); 92 * if ( x == NULL ) { 93 * fprintf( stderr, "Error allocating memory.\n" ); 94 * exit( 1 ); 95 * } 96 * 97 * // Free allocated memory: 98 * stdlib_ndarray_free( x ); 99 */ 100 struct ndarray * stdlib_ndarray_allocate( int16_t dtype, uint8_t *data, int64_t ndims, int64_t *shape, int64_t *strides, int64_t offset, int8_t order, int8_t imode, int64_t nsubmodes, int8_t *submodes ) { 101 int64_t len; 102 103 struct ndarray *arr = malloc( sizeof( struct ndarray ) ); 104 if ( arr == NULL ) { 105 return NULL; 106 } 107 arr->data = data; 108 arr->dtype = dtype; 109 arr->imode = imode; 110 arr->ndims = ndims; 111 arr->nsubmodes = nsubmodes; 112 arr->offset = offset; 113 arr->order = order; 114 arr->shape = shape; 115 arr->strides = strides; 116 arr->submodes = submodes; 117 118 len = stdlib_ndarray_numel( ndims, shape ); 119 arr->length = len; 120 121 arr->BYTES_PER_ELEMENT = stdlib_ndarray_bytes_per_element( dtype ); 122 arr->byteLength = len * (arr->BYTES_PER_ELEMENT); 123 arr->flags = stdlib_ndarray_flags( arr ); 124 125 return arr; 126 } 127 128 /** 129 * Returns the size of an ndarray (in bytes). 130 * 131 * @param arr input ndarray 132 * @return array size 133 */ 134 int64_t stdlib_ndarray_bytelength( const struct ndarray *arr ) { 135 return arr->byteLength; 136 } 137 138 /** 139 * Returns a pointer to an ndarray's underlying byte array. 140 * 141 * @param arr input ndarray 142 * @return underlying byte array 143 */ 144 uint8_t * stdlib_ndarray_data( const struct ndarray *arr ) { 145 return arr->data; 146 } 147 148 /** 149 * Returns an ndarray dimension. 150 * 151 * ## Notes 152 * 153 * - The function does not perform any sanity checks. 154 * 155 * @param arr input ndarray 156 * @param i dimension index 157 * @return dimension 158 */ 159 int64_t stdlib_ndarray_dimension( const struct ndarray *arr, const int64_t i ) { 160 return arr->shape[ i ]; 161 } 162 163 /** 164 * Disables specified ndarray flags. 165 * 166 * ## Notes 167 * 168 * - The function does not perform any sanity checks and **assumes** the user knows what s/he is doing. 169 * 170 * @param arr input ndarray 171 * @param flags bit mask to disable flags 172 * @return status code 173 */ 174 int8_t stdlib_ndarray_disable_flags( struct ndarray *arr, const int64_t flags ) { 175 arr->flags &= ~flags; 176 return 0; 177 } 178 179 /** 180 * Returns an ndarray data type. 181 * 182 * @param arr input ndarray 183 * @return array data type 184 */ 185 int16_t stdlib_ndarray_dtype( const struct ndarray *arr ) { 186 return arr->dtype; 187 } 188 189 /** 190 * Enables specified ndarray flags. 191 * 192 * ## Notes 193 * 194 * - The function does not perform any sanity checks and **assumes** the user knows what s/he is doing. 195 * 196 * @param arr input ndarray 197 * @param flags bit mask to enable flags 198 * @return status code 199 */ 200 int8_t stdlib_ndarray_enable_flags( struct ndarray *arr, const int64_t flags ) { 201 arr->flags |= flags; 202 return 0; 203 } 204 205 /** 206 * Returns ndarray flags. 207 * 208 * @param arr input ndarray 209 * @return flags 210 */ 211 int64_t stdlib_ndarray_flags( const struct ndarray *arr ) { 212 uint8_t contiguous; 213 int64_t *strides; 214 int64_t nbytes; 215 int64_t tmp[2]; 216 int64_t ndims; 217 int64_t flags; 218 int64_t len; 219 int8_t ord; 220 221 // Cache various ndarray data: 222 len = arr->length; 223 ndims = arr->ndims; 224 strides = arr->strides; 225 nbytes = arr->BYTES_PER_ELEMENT; 226 227 // Initialize the memory for `flags`: 228 flags = 0; 229 230 // Determine if the array can be stored contiguously... 231 if ( len == 0 || stdlib_ndarray_iteration_order( ndims, strides ) == 0 ) { 232 // If an array does not contain any elements, then no data to store, and, if the array is unordered, adjacent array elements are not guaranteed to be stored next to each other. 233 contiguous = 0; 234 } else { 235 // Ensure that the array is compatible with a single memory segment: 236 stdlib_ndarray_minmax_view_buffer_index( ndims, arr->shape, strides, arr->offset, tmp ); 237 if ( (len*nbytes) == ( (tmp[1]-tmp[0])+nbytes ) ) { 238 // Compatible: 239 contiguous = 1; 240 } else { 241 // Incompatible: 242 contiguous = 0; 243 } 244 } 245 // Determine if the array is row-major/column-major contiguous: 246 if ( contiguous == 1 ) { 247 // Infer the array "order" from the stride array (this is supplementary to `arr->order`): 248 ord = stdlib_ndarray_strides2order( ndims, strides ); 249 250 if ( ord == 1 || ord == 3 ) { 251 flags |= STDLIB_NDARRAY_ROW_MAJOR_CONTIGUOUS_FLAG; 252 } 253 if ( ord == 2 || ord == 3 ) { 254 flags |= STDLIB_NDARRAY_COLUMN_MAJOR_CONTIGUOUS_FLAG; 255 } 256 } 257 return flags; 258 } 259 260 /** 261 * Frees an ndarray's allocated memory. 262 * 263 * @param arr input ndarray 264 */ 265 void stdlib_ndarray_free( struct ndarray *arr ) { 266 free( arr ); 267 } 268 269 /** 270 * Tests whether an ndarray has specified flags enabled. 271 * 272 * @param arr input ndarray 273 * @param flags bit mask specifying the flags to test against 274 * @return `1` if flags are set and `0` otherwise 275 */ 276 int8_t stdlib_ndarray_has_flags( const struct ndarray *arr, const int64_t flags ) { 277 if ( ( arr->flags & flags ) == flags ) { 278 return 1; 279 } 280 return 0; 281 } 282 283 /** 284 * Returns the index mode of an ndarray. 285 * 286 * @param arr input ndarray 287 * @return index mode 288 */ 289 int8_t stdlib_ndarray_index_mode( const struct ndarray *arr ) { 290 return arr->imode; 291 } 292 293 /** 294 * Returns the number of elements in an ndarray. 295 * 296 * @param arr input ndarray 297 * @return number of elements 298 */ 299 int64_t stdlib_ndarray_length( const struct ndarray *arr ) { 300 return arr->length; 301 } 302 303 /** 304 * Returns the number of ndarray dimensions. 305 * 306 * @param arr input ndarray 307 * @return number of dimensions 308 */ 309 int64_t stdlib_ndarray_ndims( const struct ndarray *arr ) { 310 return arr->ndims; 311 } 312 313 /** 314 * Returns the number of ndarray subscript modes. 315 * 316 * @param arr input ndarray 317 * @return number of subscript modes 318 */ 319 int64_t stdlib_ndarray_nsubmodes( const struct ndarray *arr ) { 320 return arr->nsubmodes; 321 } 322 323 /** 324 * Returns an ndarray index offset (in bytes). 325 * 326 * @param arr input ndarray 327 * @return array strides 328 */ 329 int64_t stdlib_ndarray_offset( const struct ndarray *arr ) { 330 return arr->offset; 331 } 332 333 /** 334 * Returns the order of an ndarray. 335 * 336 * @param arr input ndarray 337 * @return array order 338 */ 339 int8_t stdlib_ndarray_order( const struct ndarray *arr ) { 340 return arr->order; 341 } 342 343 /** 344 * Returns a pointer to an array containing an ndarray shape (dimensions). 345 * 346 * @param arr input ndarray 347 * @return array shape (dimensions) 348 */ 349 int64_t * stdlib_ndarray_shape( const struct ndarray *arr ) { 350 return arr->shape; 351 } 352 353 /** 354 * Returns an ndarray stride (in bytes). 355 * 356 * ## Notes 357 * 358 * - The function does not perform any sanity checks. 359 * 360 * @param arr input ndarray 361 * @param i dimension index 362 * @return array stride 363 */ 364 int64_t stdlib_ndarray_stride( const struct ndarray *arr, const int64_t i ) { 365 return arr->strides[ i ]; 366 } 367 368 /** 369 * Returns a pointer to an array containing ndarray strides (in bytes). 370 * 371 * @param arr input ndarray 372 * @return array strides 373 */ 374 int64_t * stdlib_ndarray_strides( const struct ndarray *arr ) { 375 return arr->strides; 376 } 377 378 /** 379 * Returns an ndarray subscript mode. 380 * 381 * ## Notes 382 * 383 * - If an ndarray has fewer subscript modes than dimensions, modes are recycled using modulo arithmetic. 384 * - The function does not perform any sanity checks. 385 * 386 * @param arr input ndarray 387 * @param i dimension index 388 * @return subscript mode 389 */ 390 int8_t stdlib_ndarray_submode( const struct ndarray *arr, const int64_t i ) { 391 return arr->submodes[ i%(arr->nsubmodes) ]; 392 } 393 394 /** 395 * Returns ndarray subscript modes. 396 * 397 * @param arr input ndarray 398 * @return subscript modes 399 */ 400 int8_t * stdlib_ndarray_submodes( const struct ndarray *arr ) { 401 return arr->submodes; 402 }