Nim bindings for ndarray-c library
A numpy-like ndarray library for C with multi-dimensional arrays, OpenMP parallelization, and BLAS-optimized operations.
Features automatic memory management using Nim's destructors and move semantics.
Examples
Basic usage:
import ndarray # Create a 2x3 array of ones (simple int syntax) let arr = newOnes(@[2, 3]) # Set value at position (1, 2) arr.set(@[1, 2], 42.0) # Get value at position let val = arr.get(@[1, 2]) # Print the array arr.print("My Array", 2) # No manual cleanup needed - automatic memory management!
Note: You can use regular int arrays (@[2, 3]) or csize_t arrays (@[2.csize_t, 3]) - both work!
Procs
proc copy(arr: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a deep copy of the array.
Allocates a new array with the same dimensions and copies all data.
Returns: New NDArray with copied data
Raises: ValueError if copy fails
Example:
let arr = newOnes(@[3, 4]) let arrCopy = arr.copy() # Independent copy arrCopy.set(@[0, 0], 5.0) # Doesn't affect arr
proc copySlice(src: NDArray; srcAxis: cint; srcIdx: csize_t; dst: NDArray; dstAxis: cint; dstIdx: csize_t) {....raises: [], tags: [], forbids: [].}
-
Copies a slice from one array to another.
Parameters:
- src - Source array
- srcAxis - Axis in source array
- srcIdx - Index along source axis
- dst - Destination array
- dstAxis - Axis in destination array
- dstIdx - Index along destination axis
Example:
let src = newOnes(@[3, 4]) let dst = newZeros(@[3, 4]) copySlice(src, 0, 0, dst, 0, 1) # Copy first row of src to second row of dst
proc fillSlice(arr: NDArray; axis: cint; index: csize_t; value: cdouble) {. ...raises: [], tags: [], forbids: [].}
-
Fills a slice with a scalar value at a specific index on an axis.
For 2D: axis=0 fills a row, axis=1 fills a column. For higher dimensions: fills the hyperplane perpendicular to the axis.
Parameters:
- axis - The axis along which to fill the slice
- index - The index along the axis
- value - The scalar value to fill with
Example:
let arr = newZeros(@[3, 4]) arr.fillSlice(0, 1, 5.0) # Fill second row with 5.0
proc free(arr: NDArray) {....raises: [], tags: [], forbids: [].}
-
Manually frees the ndarray.
Normally not needed thanks to automatic memory management via destructors. Only use this if you need explicit control over memory deallocation.
Warning: Do not use the array after calling this function.
Example:
var arr = newOnes(@[3, 4]) # ... use arr ... arr.free() # Manual cleanup
Note: With automatic memory management, this is not needed as arrays are freed automatically when they go out of scope via the =destroy hook
proc get(arr: NDArray; pos: openArray[csize_t]): cdouble {....raises: [ValueError], tags: [], forbids: [].}
-
Gets the value at the specified position.
Parameters:
- pos - Array of indices for each dimension
Returns: The value at the specified position
Example:
let arr = newOnes(@[3, 4]) let val = arr.get(@[1.csize_t, 2])
proc getSlicePtr(arr: NDArray; axis: cint; index: csize_t): ptr cdouble {. ...raises: [], tags: [], forbids: [].}
-
Gets a pointer to a slice along an axis.
Warning: Advanced operation for direct memory access. Use with caution as it bypasses bounds checking.
Parameters:
- axis - The axis along which to get the slice
- index - The index along the axis
Returns: Pointer to the first element of the slice
proc getSliceSize(arr: NDArray; axis: cint): csize_t {....raises: [], tags: [], forbids: [].}
-
Gets the size of a slice along an axis.
Parameters:
- axis - The axis to query
Returns: Number of elements in a slice along that axis
proc newAggregate(arr: NDArray; axis: cint; aggrType: AggrType): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Aggregates along an axis (returns new array).
Reduces the array along the specified axis using the given aggregation type.
Parameters:
- axis - Axis to aggregate along (use ALL_AXES for all)
- aggrType - Type of aggregation (sum, mean, max, min, std)
Returns: New array with aggregated values
Example:
let arr = newArange(@[3, 4], 0.0, 12.0, 1.0) let rowSums = arr.newAggregate(0, aggrSum) # Sum along axis 0 let colMeans = arr.newAggregate(1, aggrMean) # Mean along axis 1
proc newArange(dims: openArray[csize_t]; start: cdouble; stop: cdouble; step: cdouble): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with evenly spaced values in a range. Values are generated sequentially: start, start+step, start+2*step, ... and filled in row-major order. **Parameters:** * `dims` - Array of dimension sizes (must have at least 2 elements) * `start` - Starting value (inclusive) * `stop` - Ending value (exclusive) * `step` - Step size between values **Returns:** New NDArray with evenly spaced values **Raises:** ValueError if creation fails Example: .. code-block:: nim let arr = newArange(@[2, 5], 0.0, 10.0, 1.0) # Values 0 to 9
proc newConcat(axis: cint; arrays: openArray[NDArray]): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Concatenates arrays along an existing axis (returns new array).
Joins arrays along the specified axis.
Parameters:
- axis - Axis along which to concatenate
- arrays - Arrays to concatenate (shapes must match except on concat axis)
Returns: New array with concatenated data
Example:
let a = newOnes(@[2, 3]) let b = newZeros(@[2, 3]) let concatenated = newConcat(0, @[a, b]) # Shape [4, 3]
proc newEqual(arr: NDArray; other: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Element-wise equality comparison (returns new array).
Returns 1.0 where arr == other, 0.0 elsewhere.
Parameters:
- other - Array to compare (must have same shape)
Returns: New array with comparison results
Example:
let a = newOnes(@[2, 3]) let b = newOnes(@[2, 3]) let result = a.newEqual(b) # All 1.0
proc newEqualScalar(arr: NDArray; value: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Scalar equality comparison (returns new array).
Returns 1.0 where arr == value, 0.0 elsewhere.
Parameters:
- value - Scalar value to compare
Returns: New array with comparison results
Example:
let arr = newArange(@[2, 3], 0.0, 6.0, 1.0) let result = arr.newEqualScalar(3.0) # 1.0 only at position with value 3
proc newFromData(dims: openArray[csize_t]; data: openArray[cdouble]): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray from existing data.
The data is copied into the new array. Data should be in row-major order.
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
- data - Array of values to copy (size must match product of dims)
Returns: New NDArray with copied data
Raises: ValueError if creation fails
Example:
let data = @[1.0, 2.0, 3.0, 4.0, 5.0, 6.0] let arr = newFromData(@[2, 3], data) # 2x3 array from data
proc newFromData(dims: openArray[int]; data: openArray[cdouble]): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray from existing data (int version).
Convenience overload that accepts int arrays instead of csize_t.
See also:
proc newFull(dims: openArray[csize_t]; value: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray filled with a specific value.
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
- value - The value to fill the array with
Returns: New NDArray filled with the specified value
Raises: ValueError if creation fails
Example:
let arr = newFull(@[3, 4], 5.0) # 3x4 array filled with 5.0
proc newGreater(arr: NDArray; other: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Element-wise greater-than comparison (returns new array).
Returns 1.0 where arr > other, 0.0 elsewhere.
Parameters:
- other - Array to compare (must have same shape)
Returns: New array with comparison results
Example:
let a = newArange(@[2, 3], 0.0, 6.0, 1.0) let b = newFull(@[2, 3], 2.5) let result = a.newGreater(b) # [0, 0, 0, 1, 1, 1]
proc newGreaterScalar(arr: NDArray; value: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Scalar greater-than comparison (returns new array).
Returns 1.0 where arr > value, 0.0 elsewhere.
Parameters:
- value - Scalar value to compare
Returns: New array with comparison results
Example:
let arr = newArange(@[2, 3], 0.0, 6.0, 1.0) let result = arr.newGreaterScalar(2.5) # 1.0 where values > 2.5
proc newLess(arr: NDArray; other: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Element-wise less-than comparison (returns new array).
Returns 1.0 where arr < other, 0.0 elsewhere.
Parameters:
- other - Array to compare (must have same shape)
Returns: New array with comparison results
Example:
let a = newArange(@[2, 3], 0.0, 6.0, 1.0) let b = newFull(@[2, 3], 3.0) let result = a.newLess(b) # [1, 1, 1, 0, 0, 0]
proc newLessScalar(arr: NDArray; value: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Scalar less-than comparison (returns new array).
Returns 1.0 where arr < value, 0.0 elsewhere.
Parameters:
- value - Scalar value to compare
Returns: New array with comparison results
Example:
let arr = newArange(@[2, 3], 0.0, 6.0, 1.0) let result = arr.newLessScalar(3.0) # 1.0 where values < 3
proc newLinspace(dims: openArray[csize_t]; start: cdouble; stop: cdouble; num: csize_t): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with linearly spaced values.
Values are evenly distributed between start and stop (both inclusive).
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
- start - Starting value (inclusive)
- stop - Ending value (inclusive)
- num - Number of values to generate
Returns: New NDArray with linearly spaced values
Raises: ValueError if creation fails
Example:
let arr = newLinspace(@[2, 5], 0.0, 1.0, 10) # 10 values from 0 to 1
proc newLinspace(dims: openArray[int]; start: cdouble; stop: cdouble; num: csize_t): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with linearly spaced values (int version).
Convenience overload that accepts int arrays instead of csize_t.
See also:
proc newLoad(filename: string): NDArray {....raises: [IOError], tags: [], forbids: [].}
-
Loads array from binary file.
Parameters:
- filename - Path to input file
Returns: New NDArray with loaded data
Raises: IOError if file cannot be read
Example:
let arr = newLoad("myarray.nda") arr.print("Loaded array", 2)
proc newLogicalAnd(arr: NDArray; other: NDArray): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Logical AND operation (returns new array).
Returns 1.0 where both arr and other are non-zero, 0.0 elsewhere.
Parameters:
- other - Array to AND with (must have same shape)
Returns: New array with logical AND results
Example:
let a = newArange(@[2, 3], 0.0, 6.0, 1.0) let b = newGreaterScalar(a, 2.5) let c = newLessScalar(a, 4.5) let result = b.newLogicalAnd(c) # 1.0 where 2.5 < val < 4.5
proc newLogicalNot(arr: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Logical NOT operation (returns new array).
Returns 1.0 where arr is zero, 0.0 where arr is non-zero.
Returns: New array with logical NOT results
Example:
let arr = newArange(@[2, 3], 0.0, 6.0, 1.0) let mask = newLessScalar(arr, 3.0) let inverted = mask.newLogicalNot() # Inverts the mask
proc newLogicalOr(arr: NDArray; other: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Logical OR operation (returns new array).
Returns 1.0 where either arr or other is non-zero, 0.0 elsewhere.
Parameters:
- other - Array to OR with (must have same shape)
Returns: New array with logical OR results
Example:
let a = newArange(@[2, 3], 0.0, 6.0, 1.0) let b = newLessScalar(a, 2.0) let c = newGreaterScalar(a, 4.0) let result = b.newLogicalOr(c) # 1.0 where val < 2 OR val > 4
proc newMatmul(arr: NDArray; other: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Matrix multiplication (returns new array).
Performs matrix multiplication using BLAS-optimized routines.
Parameters:
- other - Matrix to multiply with (inner dimensions must match)
Returns: New array with matrix product
Example:
let a = newOnes(@[2, 3]) # 2x3 matrix let b = newOnes(@[3, 4]) # 3x4 matrix let c = a.newMatmul(b) # 2x4 result
proc newNDArray(dims: openArray[csize_t]): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with specified dimensions.
All elements are uninitialized. Use newZeros, newOnes, or newFull for initialized arrays.
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
Returns: New NDArray with uninitialized data
Raises: ValueError if creation fails
Example:
let arr = newNDArray(@[3, 4]) # 3x4 uninitialized array
proc newNDArray(dims: openArray[int]): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with specified dimensions (int version).
Convenience overload that accepts int arrays instead of csize_t.
See also:
proc newOnes(dims: openArray[csize_t]): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray filled with ones.
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
Returns: New NDArray filled with 1.0
Raises: ValueError if creation fails
Example:
let arr = newOnes(@[3, 4]) # 3x4 array of ones
proc newRandomNormal(dims: openArray[csize_t]; mean: cdouble; stddev: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with random values from normal distribution.
Values follow a Gaussian distribution with specified mean and standard deviation.
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
- mean - Mean of the distribution
- stddev - Standard deviation of the distribution
Returns: New NDArray with random normal values
Raises: ValueError if creation fails
Example:
let arr = newRandomNormal(@[3, 4], 0.0, 1.0) # Standard normal distribution
proc newRandomNormal(dims: openArray[int]; mean: cdouble; stddev: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with random normal values (int version).
Convenience overload that accepts int arrays instead of csize_t.
See also:
proc newRandomUniform(dims: openArray[csize_t]; low: cdouble; high: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with random values from uniform distribution.
Values are uniformly distributed in the range [low, high).
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
- low - Lower bound (inclusive)
- high - Upper bound (exclusive)
Returns: New NDArray with random uniform values
Raises: ValueError if creation fails
Example:
let arr = newRandomUniform(@[3, 4], 0.0, 1.0) # Random values in [0, 1)
proc newRandomUniform(dims: openArray[int]; low: cdouble; high: cdouble): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray with random uniform values (int version).
Convenience overload that accepts int arrays instead of csize_t.
See also:
proc newStack(axis: cint; arrays: openArray[NDArray]): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Stacks arrays along a new axis (returns new array).
Creates a new dimension and stacks arrays along it.
Parameters:
- axis - Position of new axis in result
- arrays - Arrays to stack (must have same shape)
Returns: New array with stacked data
Example:
let a = newOnes(@[2, 3]) let b = newZeros(@[2, 3]) let stacked = newStack(0, @[a, b]) # Shape [2, 2, 3]
proc newTake(arr: NDArray; axis: cint; start: csize_t; end: csize_t): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
Extracts a slice along an axis (returns new array).
Parameters:
- axis - Axis along which to slice
- start - Starting index (inclusive)
- end - Ending index (exclusive)
Returns: New array with extracted slice
Example:
let arr = newArange(@[4, 5], 0.0, 20.0, 1.0) let slice = arr.newTake(0, 1, 3) # Rows 1 and 2 (indices 1, 2)
proc newTensordot(arr: NDArray; other: NDArray; axesA: openArray[cint]; axesB: openArray[cint]): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Tensor contraction over specified axes (returns new array).
Generalized tensor product contracting specified axes.
Parameters:
- other - Tensor to contract with
- axesA - Axes of arr to contract
- axesB - Axes of other to contract (must match length of axesA)
Returns: New array with contracted tensor
Example:
let a = newOnes(@[2, 3, 4]) let b = newOnes(@[4, 5]) let c = a.newTensordot(b, @[2.cint], @[0.cint]) # Contract axis 2 of a with axis 0 of b
proc newTranspose(arr: NDArray): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Transposes the array (returns new array).
Reverses the order of axes. For 2D arrays, swaps rows and columns.
Returns: New array with transposed data
Example:
let arr = newArange(@[2, 3], 0.0, 6.0, 1.0) # 2x3 matrix let transposed = arr.newTranspose() # 3x2 matrix
proc newWhere(condition: NDArray; x: NDArray; y: NDArray): NDArray {. ...raises: [ValueError], tags: [], forbids: [].}
-
NumPy-style conditional selection (returns new array).
Returns x where condition is non-zero, y where condition is zero.
Parameters:
- condition - Boolean array (non-zero = true)
- x - Array to select from when condition is true
- y - Array to select from when condition is false
Returns: New array with selected values
Example:
let data = newArange(@[2, 3], 0.0, 6.0, 1.0) let mask = data.newGreaterScalar(2.5) let zeros = newZeros(@[2, 3]) let filtered = newWhere(mask, data, zeros) # Keep values > 2.5, rest = 0
proc newZeros(dims: openArray[csize_t]): NDArray {....raises: [ValueError], tags: [], forbids: [].}
-
Creates a new ndarray filled with zeros.
Parameters:
- dims - Array of dimension sizes (must have at least 2 elements)
Returns: New NDArray filled with 0.0
Raises: ValueError if creation fails
Example:
let arr = newZeros(@[3, 4]) # 3x4 array of zeros
proc reshape(arr: NDArray; newDims: openArray[int]) {....raises: [ValueError], tags: [], forbids: [].}
-
Reshapes the array in-place to new dimensions.
Total number of elements must remain the same. Use -1 for one dimension to automatically infer its size.
Parameters:
- newDims - New shape (use -1 for auto-infer)
Example:
let arr = newArange(@[2, 6], 0.0, 12.0, 1.0) # 2x6 arr.reshape(@[3, 4]) # Now 3x4 arr.reshape(@[2, -1]) # Now 2x6 (inferred)
proc scalarAggregate(arr: NDArray; aggrType: AggrType): cdouble {....raises: [], tags: [], forbids: [].}
-
Aggregates all elements to a scalar value.
Parameters:
- aggrType - Type of aggregation (sum, mean, max, min, std)
Returns: Scalar result of aggregation
Example:
let arr = newArange(@[3, 4], 0.0, 12.0, 1.0) let total = arr.scalarAggregate(aggrSum) # Sum of all elements = 66 let average = arr.scalarAggregate(aggrMean) # Mean = 5.5
proc scaleShift(arr: var NDArray; alpha: cdouble; beta: cdouble): var NDArray {. discardable, ...raises: [], tags: [], forbids: [].}
proc set(arr: NDArray; pos: openArray[csize_t]; value: cdouble) {. ...raises: [ValueError], tags: [], forbids: [].}
-
Sets the value at the specified position.
Parameters:
- pos - Array of indices for each dimension
- value - The value to set
Example:
let arr = newZeros(@[3, 4]) arr.set(@[0.csize_t, 0], 42.0)
proc setSlice(arr: NDArray; axis: cint; index: csize_t; values: openArray[cdouble]) {....raises: [], tags: [], forbids: [].}
-
Sets values along a slice at a specific index on an axis.
For 2D: axis=0 sets a row, axis=1 sets a column. For higher dimensions: sets the hyperplane perpendicular to the axis.
Parameters:
- axis - The axis along which to set the slice
- index - The index along the axis
- values - Array of values to set (size must match slice size)
Example:
let arr = newZeros(@[3, 4]) let rowData = @[1.0, 2.0, 3.0, 4.0] arr.setSlice(0, 0, rowData) # Set first row