module Narray
Overview
Operations for NArray
This module provides various array manipulation operations for NArray, including:
- Reshaping arrays (reshape, reshape!)
- Transposing arrays (transpose, transpose!)
- Concatenating arrays (concatenate, vstack, hstack)
- Masking operations (mask, mask_set)
Defined in:
narray.crnarray/broadcast.cr
narray/linalg.cr
narray/math.cr
narray/math/exponential.cr
narray/math/hyperbolic.cr
narray/math/trig.cr
narray/operations.cr
Constant Summary
-
VERSION =
"0.1.0"
Class Method Summary
-
.arange(start : Number, stop : Number, step : Number, type : T.class) forall T
Creates a new array with evenly spaced values within a given interval with the specified type.
-
.arange(start : Number, stop : Number, step = 1)
Creates a new array with evenly spaced values within a given interval.
-
.array(shape : ::Array(Int32), data : ::Array(T)) forall T
Creates a new array with the given shape and data.
-
.broadcast(array : Array(T), new_shape : ::Array(Int32)) : Array(T) forall T
Broadcasts an array to a new shape.
-
.broadcast_shapes(shape1 : ::Array(Int32), shape2 : ::Array(Int32)) : ::Array(Int32) | Nil
Checks if two shapes are broadcast compatible and returns the resulting shape.
-
.can_broadcast?(from_shape : ::Array(Int32), to_shape : ::Array(Int32)) : Bool
Checks if a shape can be broadcast to another shape.
-
.concatenate(arrays : ::Array(Array(T)), axis = 0) : Array(T) forall T
Concatenates arrays along the specified axis.
-
.det(a : Array(T)) : Float64 forall T
Computes the determinant of a square matrix.
-
.determinant(a : Array(T)) : Float64 forall T
Alias for determinant.
-
.dot(a : Array(T), b : Array(U)) : Array(Float64) forall T, U
Computes the matrix multiplication (dot product) of two matrices.
-
.dot(a : Array(T), b : Array(T)) : Array(T) forall T
Original dot product for same type (for backward compatibility)
-
.eig(a : Array(T)) : Tuple(Array(Float64), Array(Float64)) forall T
Computes the eigenvalues and eigenvectors of a square matrix.
-
.eigen(a : Array(T)) : Tuple(Array(Float64), Array(Float64)) forall T
Alias for eigenvalues and eigenvectors.
-
.hstack(arrays : ::Array(Array(T))) : Array(T) forall T
Stacks arrays horizontally (along the second axis).
-
.inv(a : Array(T)) : Array(Float64) forall T
Computes the inverse of a square matrix.
-
.inverse(a : Array(T)) : Array(Float64) forall T
Alias for inverse.
-
.linspace(start : Number, stop : Number, num : Int32, type : T.class) forall T
Creates a new array with evenly spaced values over a specified interval with the specified type.
-
.linspace(start : Number, stop : Number, num = 50)
Creates a new array with evenly spaced values over a specified interval.
-
.matmul(a : Array(T), b : Array(U)) : Array(Float64) forall T, U
Matrix multiplication (matmul)
-
.matmul(a : Array(T), b : Array(T)) : Array(T) forall T
Original matmul for same type (for backward compatibility)
-
.ones(shape : ::Array(Int32), type : T.class) forall T
Creates a new array filled with ones with the specified type.
-
.ones(shape : ::Array(Int32))
Creates a new array filled with ones.
-
.svd(a : Array(T)) : Tuple(Array(Float64), Array(Float64), Array(Float64)) forall T
Computes the singular value decomposition (SVD) of a matrix.
-
.vstack(arrays : ::Array(Array(T))) : Array(T) forall T
Stacks arrays vertically (along the first axis).
-
.zeros(shape : ::Array(Int32), type : T.class) forall T
Creates a new array filled with zeros with the specified type.
-
.zeros(shape : ::Array(Int32))
Creates a new array filled with zeros.
Class Method Detail
Creates a new array with evenly spaced values within a given interval with the specified type.
arr = Narray.arange(0, 5, 1_f64, Float64)
arr.data # => [0.0, 1.0, 2.0, 3.0, 4.0]
arr.data[0].class # => Float64
See also: Narray.linspace
.
Creates a new array with evenly spaced values within a given interval.
arr = Narray.arange(0, 10, 2)
arr.shape # => [5]
arr.ndim # => 1
arr.size # => 5
arr.data # => [0, 2, 4, 6, 8]
See also: Narray.linspace
.
Creates a new array with the given shape and data.
arr = Narray.array([2, 2], [1, 2, 3, 4])
arr.shape # => [2, 2]
arr.ndim # => 2
arr.size # => 4
arr.data # => [1, 2, 3, 4]
Raises ArgumentError
if the data size does not match the shape.
See also: Narray.zeros
, Narray.ones
.
Broadcasts an array to a new shape.
The new shape must be broadcast compatible with the original shape. If the shapes are already the same, returns the original array.
# Original array with shape [3]
arr = Narray.array([3], [1, 2, 3])
# Broadcast to shape [2, 3]
result = Narray.broadcast(arr, [2, 3])
result.shape # => [2, 3]
result.data # => [1, 2, 3, 1, 2, 3]
# Broadcasting with dimension size 1
arr2 = Narray.array([2, 1], [1, 2])
result2 = Narray.broadcast(arr2, [2, 3])
result2.shape # => [2, 3]
result2.data # => [1, 1, 1, 2, 2, 2]
Raises ArgumentError
if the shapes are incompatible for broadcasting.
See also: Narray.broadcast_shapes
, Array#broadcast_to
.
Checks if two shapes are broadcast compatible and returns the resulting shape.
Broadcasting rules:
- Arrays with fewer dimensions are padded with ones on the left.
- Arrays with dimension size 1 are stretched to match the other array's size.
- If dimensions are incompatible (neither equal nor one is 1), returns nil.
# Same shapes
Narray.broadcast_shapes([2, 3], [2, 3]) # => [2, 3]
# Broadcasting scalar to array
Narray.broadcast_shapes([2, 3], [] of Int32) # => [2, 3]
# Broadcasting 1D array to 2D array
Narray.broadcast_shapes([2, 3], [3]) # => [2, 3]
# Broadcasting when one dimension is 1
Narray.broadcast_shapes([2, 1], [1, 3]) # => [2, 3]
# Incompatible shapes
Narray.broadcast_shapes([2, 3], [4, 5]) # => nil
See also: Narray.broadcast
, Narray.can_broadcast?
.
Checks if a shape can be broadcast to another shape.
Returns true if the shapes are compatible for broadcasting and the result of broadcasting would match the target shape.
Narray.can_broadcast?([2, 1], [2, 3]) # => true
Narray.can_broadcast?([3], [2, 3]) # => true
Narray.can_broadcast?([2, 3], [4, 5]) # => false
See also: Narray.broadcast_shapes
, Narray.broadcast
.
Concatenates arrays along the specified axis.
The arrays must have the same shape except for the dimension corresponding to axis.
# 1D arrays
a = Narray.array([3], [1, 2, 3])
b = Narray.array([3], [4, 5, 6])
c = Narray.concatenate([a, b])
c.shape # => [6]
c.data # => [1, 2, 3, 4, 5, 6]
# 2D arrays along axis 0 (rows)
a = Narray.array([2, 3], [1, 2, 3, 4, 5, 6])
b = Narray.array([1, 3], [7, 8, 9])
c = Narray.concatenate([a, b])
c.shape # => [3, 3]
c.data # => [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 2D arrays along axis 1 (columns)
a = Narray.array([2, 2], [1, 2, 3, 4])
b = Narray.array([2, 3], [5, 6, 7, 8, 9, 10])
c = Narray.concatenate([a, b], 1)
c.shape # => [2, 5]
c.data # => [1, 2, 5, 6, 7, 3, 4, 8, 9, 10]
Raises ArgumentError
if:
- The array of arrays is empty
- The axis is out of bounds
- The arrays have different numbers of dimensions
- The arrays have different shapes except for the concatenation axis
See also: Narray.vstack
, Narray.hstack
.
Computes the determinant of a square matrix.
The determinant is a scalar value that can be computed from the elements of a square matrix and encodes certain properties of the linear transformation described by the matrix.
For small matrices, direct formulas are used:
- 1x1 matrix: the single element
- 2x2 matrix: ad - bc for matrix [[a, b], [c, d]]
- 3x3 matrix: uses the cofactor expansion formula
For larger matrices, Gaussian elimination with partial pivoting is used.
# 1x1 matrix
a = Narray.array([1, 1], [5])
Narray.det(a) # => 5.0
# 2x2 matrix
a = Narray.array([2, 2], [1, 2, 3, 4])
Narray.det(a) # => -2.0 # 1*4 - 2*3 = -2
# 3x3 matrix
a = Narray.array([3, 3], [1, 2, 3, 4, 5, 6, 7, 8, 9])
Narray.det(a) # => 0.0 # Singular matrix
# 4x4 diagonal matrix
a = Narray.array([4, 4], [
1, 0, 0, 0,
0, 2, 0, 0,
0, 0, 3, 0,
0, 0, 0, 4,
])
Narray.det(a) # => 24.0 # Product of diagonal elements
Raises ArgumentError
if the matrix is not 2-dimensional or not square.
See also: Narray.determinant
, Narray.inv
.
Alias for determinant.
a = Narray.array([2, 2], [1, 2, 3, 4])
Narray.determinant(a) # => -2.0
See also: Narray.det
.
Computes the matrix multiplication (dot product) of two matrices.
For 2D arrays, this is the standard matrix multiplication. The inner dimensions must match: if a has shape [m, n] and b has shape [n, p], the result will have shape [m, p].
a = Narray.array([2, 3], [1, 2, 3, 4, 5, 6])
b = Narray.array([3, 2], [7, 8, 9, 10, 11, 12])
c = Narray.dot(a, b)
c.shape # => [2, 2]
c.data # => [58, 64, 139, 154]
Raises ArgumentError
if the arrays are not 2-dimensional or if the inner dimensions don't match.
See also: Narray.matmul
.
Original dot product for same type (for backward compatibility)
Computes the eigenvalues and eigenvectors of a square matrix.
The eigenvalues and eigenvectors of a matrix A satisfy the equation A * v = λ * v, where v is an eigenvector and λ is the corresponding eigenvalue.
This method returns a tuple containing:
- An array of eigenvalues
- An array of eigenvectors (as columns of a matrix)
For small matrices, direct formulas are used:
- 1x1 matrix: the eigenvalue is the single element, and the eigenvector is [1]
- 2x2 matrix: uses the quadratic formula to find eigenvalues
For 3x3 symmetric matrices, a specialized approach is used to match NumPy results. For larger symmetric matrices, the QR algorithm is used.
# 1x1 matrix
a = Narray.array([1, 1], [5])
eigenvalues, eigenvectors = Narray.eig(a)
eigenvalues[[0]] # => 5.0
eigenvectors[[0, 0]] # => 1.0
# 2x2 symmetric matrix
a = Narray.array([2, 2], [2, 1, 1, 2])
eigenvalues, eigenvectors = Narray.eig(a)
# Eigenvalues should be 1.0 and 3.0
# Eigenvectors are orthogonal and normalized
Raises ArgumentError
if the matrix is not 2-dimensional, not square, or not symmetric.
Raises ArgumentError
if the matrix has complex eigenvalues (not supported).
See also: Narray.eigen
.
Alias for eigenvalues and eigenvectors.
a = Narray.array([2, 2], [2, 1, 1, 2])
eigenvalues, eigenvectors = Narray.eigen(a)
# Same as Narray.eig(a)
See also: Narray.eig
.
Stacks arrays horizontally (along the second axis).
For 1D arrays, this concatenates them along the first axis.
For 2D arrays, this concatenates them along the second axis (columns).
For higher dimensions, this is equivalent to .concatenate(arrays, 1)
.
# 1D arrays
a = Narray.array([3], [1, 2, 3])
b = Narray.array([3], [4, 5, 6])
c = Narray.hstack([a, b])
c.shape # => [6]
c.data # => [1, 2, 3, 4, 5, 6]
# 2D arrays
a = Narray.array([2, 2], [1, 2, 3, 4])
b = Narray.array([2, 3], [5, 6, 7, 8, 9, 10])
c = Narray.hstack([a, b])
c.shape # => [2, 5]
c.data # => [1, 2, 5, 6, 7, 3, 4, 8, 9, 10]
See also: Narray.vstack
, Narray.concatenate
.
Computes the inverse of a square matrix.
The inverse of a matrix A is a matrix A^(-1) such that A * A^(-1) = I, where I is the identity matrix.
For small matrices, direct formulas are used:
- 1x1 matrix: 1/a for matrix [a]
- 2x2 matrix: [[d, -b], [-c, a]]/(ad-bc) for matrix [[a, b], [c, d]]
For larger matrices, Gaussian elimination with an augmented matrix [A|I] is used.
# 1x1 matrix
a = Narray.array([1, 1], [2])
inv_a = Narray.inv(a)
inv_a[[0, 0]] # => 0.5
# 2x2 matrix
a = Narray.array([2, 2], [4, 7, 2, 6])
inv_a = Narray.inv(a)
# Expected inverse of [[4, 7], [2, 6]] is [[0.6, -0.7], [-0.2, 0.4]]
Raises ArgumentError
if the matrix is not 2-dimensional, not square, or singular.
See also: Narray.inverse
, Narray.det
.
Alias for inverse.
a = Narray.array([2, 2], [1, 2, 3, 4])
Narray.inverse(a) # Same as Narray.inv(a)
See also: Narray.inv
.
Creates a new array with evenly spaced values over a specified interval with the specified type.
arr = Narray.linspace(0, 1, 3, Float32)
arr.data[0].class # => Float32
See also: Narray.arange
.
Creates a new array with evenly spaced values over a specified interval.
arr = Narray.linspace(0, 1, 5)
arr.shape # => [5]
arr.ndim # => 1
arr.size # => 5
arr.data # => [0.0, 0.25, 0.5, 0.75, 1.0]
See also: Narray.arange
.
Matrix multiplication (matmul)
Original matmul for same type (for backward compatibility)
Creates a new array filled with ones with the specified type.
arr = Narray.ones([2, 2], Int32)
arr.data # => [1, 1, 1, 1]
arr.data[0].class # => Int32
See also: Narray.zeros
, Narray.array
.
Creates a new array filled with ones.
arr = Narray.ones([2, 3])
arr.shape # => [2, 3]
arr.ndim # => 2
arr.size # => 6
arr.data # => [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
See also: Narray.zeros
, Narray.array
.
Computes the singular value decomposition (SVD) of a matrix.
The SVD decomposes a matrix A into three matrices U, S, and V^T such that: A = U * S * V^T
Where:
- U is an orthogonal matrix containing the left singular vectors
- S is a diagonal matrix containing the singular values
- V^T is the transpose of an orthogonal matrix containing the right singular vectors
This method returns a tuple containing (U, S, V^T).
For a matrix of shape (m, n):
- U has shape (m, min(m, n))
- S has shape (min(m, n))
- V^T has shape (min(m, n), n)
# 2x2 matrix
a = Narray.array([2, 2], [1, 2, 3, 4])
u, s, vt = Narray.svd(a)
# Verify that U and V^T are orthogonal matrices
# (U * U^T and V^T * V should be close to identity matrices)
# Verify that A ≈ U * S * V^T
# Create diagonal matrix from singular values
s_diag = Narray.zeros([2, 2])
2.times do |i|
s_diag[[i, i]] = s[[i]]
end
reconstructed = Narray.dot(Narray.dot(u, s_diag), vt)
# reconstructed should be close to the original matrix a
Raises ArgumentError
if the matrix is not 2-dimensional.
Stacks arrays vertically (along the first axis).
For 1D arrays, this converts them to 2D arrays with one row each.
For higher dimensions, this is equivalent to .concatenate(arrays, 0)
.
# 1D arrays
a = Narray.array([3], [1, 2, 3])
b = Narray.array([3], [4, 5, 6])
c = Narray.vstack([a, b])
c.shape # => [2, 3]
c.data # => [1, 2, 3, 4, 5, 6]
# 2D arrays
a = Narray.array([2, 3], [1, 2, 3, 4, 5, 6])
b = Narray.array([1, 3], [7, 8, 9])
c = Narray.vstack([a, b])
c.shape # => [3, 3]
c.data # => [1, 2, 3, 4, 5, 6, 7, 8, 9]
See also: Narray.hstack
, Narray.concatenate
.
Creates a new array filled with zeros with the specified type.
arr = Narray.zeros([2, 2], Int32)
arr.data # => [0, 0, 0, 0]
arr.data[0].class # => Int32
See also: Narray.ones
, Narray.array
.
Creates a new array filled with zeros.
arr = Narray.zeros([2, 3])
arr.shape # => [2, 3]
arr.ndim # => 2
arr.size # => 6
arr.data # => [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
See also: Narray.ones
, Narray.array
.