Skip to content

Dense linear algebra

HMath re-exports the vector, matrix, and error APIs. They can also be imported independently from HMath.Linear, HMath.Matrix, and HMath.Error.

Shapes and storage

Matrices store an explicit (rows, columns) shape and a flat, row-major list. The constructor is private. fromListChecked requires exactly rows * columns values; toList returns them in the same order. Inputs to list-based APIs must be finite.

Negative dimensions and element counts larger than maxBound :: Int are rejected before allocation or element-count validation. This is a representability check, not a promise that every representable matrix fits in memory. Arithmetic follows the selected numeric type; for example, Int arithmetic can overflow and floating-point results can be non-finite.

Zero dimensions are supported. 0×0, m×0, and 0×n retain distinct shapes even though all have empty storage. Transpose swaps both dimensions, and transposing twice restores the original matrix. Multiplying m×0 by 0×n produces an m×n zero matrix, subject to the same output-size check.

import HMath

emptyProduct :: Either MathError ((Int, Int), [Integer])
emptyProduct = do
    a <- fromListChecked 2 0 []
    b <- fromListChecked 0 3 []
    result <- multiplyChecked a b
    pure (shape result, toList result)
-- Right ((2,3),[0,0,0,0,0,0])

Checked operations and compatibility

Fallible matrix operations have an Either MathError variant ending in Checked. Their Maybe variants return Nothing for the same invalid inputs. Existing signatures of fromList, identity, addMatrix, multiply, transposeMatrix, shape, and toList are preserved. The derived Show output reflects the flat internal storage and is not a serialization format.

Operation Result or requirement
fromListChecked rows cols values Exact row-major element count
zeroMatrixChecked rows cols All-zero matrix
identityChecked n Square identity, including n = 0
diagonalChecked values Square matrix with the supplied diagonal and zeros elsewhere
atChecked matrix row col Element at a zero-based index
sliceMatrixChecked start extent matrix Rectangular slice with (row, col) start and (rows, cols) extent
reshapeChecked rows cols matrix New shape with unchanged row-major element order and count
addMatrixChecked, subtractMatrixChecked, hadamardChecked Equal shapes; Hadamard multiplies corresponding elements
multiplyChecked left right Left column count equals right row count; output shape is representable
scaleMatrix scalar matrix Scalar multiplication preserving shape
transposeMatrix matrix Shape-preserving transpose, including empty dimensions

An index must be strictly inside both dimensions. A slice's start and extent must fit inside each dimension. Zero-extent slices may start at the corresponding dimension's endpoint. Bounds checks do not add potentially overflowing indices and extents.

matrixExample :: Either MathError ([Int], [Int])
matrixExample = do
    matrix <- fromListChecked 2 3 [1, 2, 3, 4, 5, 6]
    section <- sliceMatrixChecked (0, 1) (2, 2) matrix
    reshaped <- reshapeChecked 3 2 matrix
    pure (toList section, toList reshaped)
-- Right ([2,3,5,6],[1,2,3,4,5,6])

Errors distinguish negative dimensions, size overflow, element-count mismatch, incompatible shapes or inner dimensions, invalid indices, invalid slices, and unequal vector lengths. ElementCountMismatch carries expected then actual counts; bounds errors carry the source shape and requested coordinates. See HMath.Error and Haddock for constructor details.

List-based vectors

dotChecked, addChecked, and subtractChecked require equal list lengths and otherwise return VectorLengthMismatch leftLength rightLength. Empty lists are valid: their dot product is zero and their sum/difference is empty. The legacy dot and add preserve their exception behavior for unequal lengths.

magnitude, normalize, and scale retain their existing behavior. Normalization returns a vector unchanged when its computed magnitude is zero, including the empty vector. No finite-value or arithmetic-overflow policy is added to the underlying numeric type.

dotChecked [1, 2, 3 :: Int] [4, 5, 6]  -- Right 32
addChecked [1 :: Int] [2, 3]           -- Left (VectorLengthMismatch 1 2)
subtractChecked [1, 2 :: Int] [3, 4]    -- Right [-2,-2]

Validation

Run the complete checked-API example from the source tree with runghc -isrc examples/haskell/Main.hs.

cabal test hmath-tests --test-show-details=direct runs the Haskell suite. meson test -C builddir --print-errorlogs runs that suite together with the C/Python integration tests. A Haskell assertion failure makes the Meson test fail.

The suite checks boundary errors and a bounded family of small rectangular matrices, including empty shapes, against independent arithmetic and indexing expectations. It also checks transpose involution, identity products, additive identities, and distributivity using exact integer arithmetic. These are correctness checks, not performance benchmarks or broad floating-point accuracy guarantees.