On this page
Typed dense matrices
Status: stable since 1.5.0. The implementation is native Object Pascal and has no third-party runtime dependency.
Typed QR/CPQR, SVD, symmetric/Hermitian eigen, triangular, least-squares, and minimum-norm workflows added in 1.6 are documented in Typed dense decompositions and solvers.
Version 1.8 adds MultiplyBlockedInto and MultiplyAutoInto for all four scalar families. The serial blocked traversal preserves the portable kernel's increasing-inner-index accumulation order; the portable path remains the correctness oracle. See Portable performance.
60-second solve
uses
AlgebraLib.DenseMatrices,
AlgebraLib.DenseSolvers;
var
A, B, X: IDenseDoubleMatrix;
begin
A := TDenseDoubleMatrix.FromValues(2, 2, [4.0, 1.0, 2.0, 3.0]);
B := TDenseDoubleMatrix.FromValues(2, 1, [9.0, 8.0]);
X := Solve(A, B); // LU factorisation followed by triangular solves
WriteLn(X[0, 0]:0:6, ' ', X[1, 0]:0:6);
end.
The result is approximately [1.9, 1.4]. Solve supports a vector or several right-hand-side columns and does not compute an inverse. The complete runnable version is examples/15_typed_dense_solve.pas.
Choose an entry point
| Task | Entry point | Allocation |
|---|---|---|
| Construct an owned matrix | TDense*Matrix.Zeros, FromValues, FromArray, FromVector |
One aligned allocation |
| Tiny 2x2 or batch | TSmall*Matrix2.Create; +, -, * |
Allocation-free value record |
| Read or write an element | A[Row, Col] |
None |
| Work on a region | View, RowView, ColumnView, DiagonalView |
Small handle; storage is shared |
| Make independent storage | Clone |
Deep copy |
| Copy into existing storage | CopyInto |
None; temporary on overlapping views |
| Ordinary matrix product | Multiply / MultiplyInto |
Result / none for non-overlapping Into; temporary on overlap |
| Elementwise product | ElementWiseMultiply / ElementWiseMultiplyInto |
Result / none for non-overlapping Into; temporary on overlap |
| Linear combination | Axpy(Alpha, X, Y) / AxpyInto |
Result / none for non-overlapping Into; temporary on overlap |
| Reduction or stable magnitude | Sum, Dot, DotConjugate, Norm2 |
None |
| Apply a scalar function | Apply(A, Callback) / ApplyInto |
Result / alias-safe temporary |
| Solve once | Solve(A, B) |
LU factor plus result |
| Solve repeatedly | FactorLU(A).Solve(B) |
Factor once, result per solve |
| Symmetric/Hermitian positive-definite solve | FactorCholesky(A).Solve(B) |
Factor once, result per solve |
| Least squares, minimum norm, or full symmetric/Hermitian eigen | See the dense solver-selection guide | Reusable typed factors |
| Use the old API | FromIMatrix, ToIMatrix |
Explicit deep copy |
Use LU for a general square system. Use Cholesky only when the matrix is real symmetric or complex Hermitian positive definite; it is cheaper and preserves that structure. Use the 1.6 selection table for triangular, QR, CPQR, SVD, and symmetric/Hermitian eigen workflows. Sparse and iterative solvers remain outside the stable typed API.
Types and matching operation sets
| Precision | Real handle / factory | Complex handle / factory |
|---|---|---|
| Single | IDenseSingleMatrix / TDenseSingleMatrix |
IDenseSingleComplexMatrix / TDenseSingleComplexMatrix |
| Double | IDenseDoubleMatrix / TDenseDoubleMatrix |
IDenseComplexMatrix / TDenseComplexMatrix |
All four paths provide checked storage, views, clones, add, subtract, elementwise multiply, scale, AXPY, transpose, matrix multiply, compensated sums/dot products, scale-safe norms, LU, and direct solve. Complex paths additionally provide conjugation, conjugate transpose, and a conjugating dot product. All four paths provide Cholesky; complex Cholesky uses the Hermitian A = L Lᴴ convention.
Single kernels accumulate dot products and products in Double before rounding to Single. This reduces avoidable summation loss but does not change the result type or promise double-precision accuracy.
Apply and ApplyInto run a typed unary scalar callback through the shared matrix traversal. This is the path for applying an existing elementary or special scalar function without duplicating its formula in a matrix unit. Inputs are validated first; callback failure is propagated and leaves an ApplyInto destination unchanged.
TSmallSingleMatrix2, TSmallDoubleMatrix2, TSmallSingleComplexMatrix2, and TSmallComplexMatrix2 are fixed-size value records for tiny expressions. Addition, subtraction, ordinary multiplication, and scalar multiplication use natural operators without heap allocation or general-kernel startup. Their matching ...Batch arrays keep many such values contiguous; batch iteration remains explicit and deterministic.
Complete storage contract
Matrices use zero-based SizeInt indices and aligned contiguous row-major owned storage. Dimensions, element counts, offsets, strides, and byte counts are checked for native-size overflow. Empty dimensions are valid. Checked access and all public operations raise EDenseMatrixError for an invalid index, shape, finite-value condition, allocation size, or factorisation.
Views are retained-owner mutable aliases. Clone is a deep copy. A view stays valid after its original handle goes out of scope. Concurrent reads are safe; overlapping writes require caller synchronisation. See the design decision record for the full ownership, copy, alias, mutation, and thread-safety rules.
There is no broadcasting. Multiply is ordinary matrix multiplication; ElementWiseMultiply is the Hadamard product; Transpose, Conjugate, and ConjugateTranspose are distinct.
API reference
AlgebraLib.DenseMatrices publishes:
const DENSE_ALIGNMENT = 32;
type
EDenseMatrixError = class(Exception);
TSingleMatrixArray = array of array of Single;
TComplexMatrixArray = array of array of TComplex;
TSingleComplexMatrixArray = array of array of TSingleComplex;
TSizeIntArray = array of SizeInt;
TDenseShape = record Rows, Cols: SizeInt; end;
Each IDense*Matrix handle has Rows, Cols, checked Values[Row, Col], IsContiguous, DataPointer, opaque StorageIdentity, Clone, View, RowView, ColumnView, and DiagonalView. StorageIdentity is only an alias-comparison token; callers must not dereference it or infer layout from it. Each matching TDense*Matrix factory has Zeros, FromValues, FromArray, and FromVector; TDenseDoubleMatrix additionally has FromIMatrix.
function ToArray(Matrix): matching nested array;
function ToVector(Matrix): matching flat array;
function ToIMatrix(const Matrix: IDenseDoubleMatrix): IMatrix;
function ConvertToDouble(const Matrix: IDenseSingleMatrix): IDenseDoubleMatrix;
function ConvertToSingle(const Matrix: IDenseDoubleMatrix): IDenseSingleMatrix;
function ConvertToComplex(real matrix): matching complex matrix;
function ConvertToReal(complex matrix): matching real matrix;
function ConvertToDoubleComplex(...): IDenseComplexMatrix;
function ConvertToSingleComplex(...): IDenseSingleComplexMatrix;
TSmallSingleMatrix2, TSmallDoubleMatrix2, TSmallSingleComplexMatrix2, and TSmallComplexMatrix2 have Create, read-only checked Values, and +, -, matrix *, and scalar *. TSmallSingleMatrix2Batch, TSmallDoubleMatrix2Batch, TSmallSingleComplexMatrix2Batch, and TSmallComplexMatrix2Batch are their dynamic batch containers.
AlgebraLib.DenseKernels overloads these names across every matching scalar path:
CopyInto
Add / AddInto
Subtract / SubtractInto
ElementWiseMultiply / ElementWiseMultiplyInto
Scale / ScaleInto
Axpy / AxpyInto
Apply / ApplyInto
Transpose / TransposeInto
Conjugate / ConjugateInto // complex only
ConjugateTranspose / ConjugateTransposeInto // complex only
Multiply / MultiplyInto
Sum / Dot / DotConjugate / Norm2 // conjugating dot is complex only
Apply callbacks are TSingleUnaryKernel, TDoubleUnaryKernel, TSingleComplexUnaryKernel, and TComplexUnaryKernel. They receive one value and return the same scalar type.
AlgebraLib.DenseSolvers overloads Solve, SolveWithInfo, SolvePositiveDefinite, FactorLU, and FactorCholesky. Reusable factor handles are IDenseSingleLU, IDenseDoubleLU, IDenseSingleComplexLU, and IDenseComplexLU. Cholesky handles are IDenseSingleCholesky, IDenseDoubleCholesky, IDenseSingleComplexCholesky, and IDenseComplexCholesky. LU exposes Size, PivotRatio, ConditionIndicator, IsIllConditioned, copied L/U/Permutation, Solve, and SolveWithInfo; Cholesky exposes Size, ConditionIndicator, copied L, Solve, and SolveWithInfo.
All creation and conversion functions allocate a result unless their name is View or they return a fixed 2x2 value. Every Into procedure requires the exact output shape. Validation errors include the operation and expected shape/condition.
Factorisation outcomes
FactorLU uses partial pivoting. Exact and precision-relative numerical singularity raise EDenseMatrixError. A successful factor exposes:
L,U, andPermutationas copies;PivotRatio, the smallest accepted pivot magnitude divided by the largest input magnitude;IsIllConditioned, set when that ratio is below the square root of the scalar precision epsilon;Solve(B)for one or many right-hand sides.
FactorCholesky rejects a non-Hermitian or non-positive-definite matrix. Validation and factorisation never mutate A or B.
The concise Solve(A, B) raises when the reusable factor's IsIllConditioned diagnostic is true, so it cannot return an unlabelled sensitive answer. Expert callers can use FactorLU, inspect PivotRatio and IsIllConditioned, and then deliberately call the factor's Solve.
Complexity and numerical behavior
| Operation | Time | Additional storage |
|---|---|---|
| Elementwise kernel | O(rows × cols) | result, or none for non-overlapping Into |
| Transpose | O(rows × cols) | result, or temporary only for overlapping Into |
| Matrix multiply | O(mkn) | result, or temporary only for overlapping Into |
| LU or Cholesky factor | O(n³) | O(n²) |
Factor solve with r RHS |
O(n²r) | O(nr) result |
Real and complex products use compensated component sums; the single paths use double accumulators. Inputs must be finite. Overflow or underflow in an individual scalar product follows the target IEEE-754 behavior; the API does not silently rescale the mathematical problem.
Compatibility and copy costs
Read the 1.5 migration guide before moving a hot loop. Nested arrays and IMatrix are copied because they are not compatible with aligned contiguous storage. TDoubleArray, TComplexArray, and their single equivalents are likewise copied by FromVector; a future view must not be inferred from the name.
ToVector copies a row or column back to the matching flat array. ConvertToDouble/ConvertToSingle, ConvertToDoubleComplex/ConvertToSingleComplex, and the real/complex ConvertToComplex/ConvertToReal pairs also copy. Narrowing rejects finite overflow. Complex-to-real conversion requires an exactly zero imaginary component, so it cannot silently discard information. NaN and infinity retain their IEEE category during a same-kind precision conversion.