// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT // Package linalg is the dense and sparse linear algebra of the library: // the factorisations, the solvers, the eigensolvers, the matrix // functions and the Krylov methods, over the array types the core // provides. Every symbol here is re-exported by the root package, so // user code may import that facade alone and write tensor.Solve. // // # Dense // // The dense surface takes a 2-D array and answers arrays. Solve, Inv // and Det run one LU decomposition with partial pivoting; Cholesky, // QR, LeastSquares, RRQR and the tridiagonal pair SolveTridiagonal and // SolveCyclicTridiagonal are the other factorisations and their solves. // Eigen, EigenComplex, EigenGeneral, EigenGeneralised, SVD, SVDComplex // and SchurComplex are the spectral decompositions, and Pinverse, // MatrixRank and Cond read the singular spectrum that SVD produces. // SolveTikhonov, SolveTruncated and SolveRRQR answer a system whose // data does not determine the solution. MatrixExp, MatrixSqrt and // MatrixLog are the matrix functions; FitPolynomial, PolynomialRoots // and CubicSpline carry the polynomial work; GMRES solves a system // presented as an operator rather than as a matrix. // // # Sparse // // The sparse surface starts from a COO matrix (the root package's // tensor.SparseCOO) and converts it once into the compressed view the // algorithm wants: SparseCSR for the iterative solvers, the Lanczos // eigensolver and the row-wise products, SparseCSC for the direct // factorisations and the column-wise scatter. The direct route is // NewSparseCholesky for a symmetric positive definite matrix, under a // fill-reducing SparseOrdering, and NewSparseLU for a general square // matrix; NewSparseILU builds the incomplete factorisation the Krylov // solvers take as a preconditioner. SpSolve and SpSolveBiCGSTAB, with // their two complex counterparts, are the iterative solves; SpLSQR and // SpLSMR are the least-squares iterations; SpEigen, SpEigenGeneral and // the two complex forms are the Krylov eigensolvers; SpExpApply // applies a matrix exponential to a vector without forming the matrix. // // # The pipeline // // Pipe and Pipeline read a sequence of array transformations as one // expression. The evaluation is eager and each step allocates a new // array. There is no lazy graph, no autograd and no backpropagation // here: a failed step is recorded, the steps after it become no-ops, // and Result returns the first error alongside the array. // // # Conventions // // The dense routines compute in float64 and complex128: int and float32 // inputs promote on the way in, and one complex operand promotes the // whole call. A sparse routine with no complex form refuses a complex // input instead of promoting it, and the four complex entry points name // their element type in the name: SpSolveComplexCG, // SpSolveComplexBiCGSTAB, SpEigenComplex and SpEigenGeneralComplex. // // Symmetry is checked where the algorithm depends on it, within a // scale-relative 1e-12 tolerance by Eigen, EigenComplex, SpEigen, // SpEigenComplex, SpSolve, SpSolveComplexCG and SpExpApply. It is not // checked where the algorithm does not need it: EigenGeneralised // requires a symmetric a and does not verify it, and the two general // sparse eigensolvers do not screen for non-finite entries, which come // back as NaN Ritz pairs. // // A shape mismatch, a singular matrix, a rank-deficient system, a // matrix that leaves the positive definite cone during a rank-one // update, and a Krylov iteration that exhausts its budget with the // tolerance unmet are all errors naming themselves. An unconverged // iterative solve returns no estimate, never a silent approximation. // // Results are reproducible: the kernels that dispatch over workers // split the output space rather than the reduction, so an element is // computed by the same arithmetic sequence whatever the worker count. // // # Constructors // // The array type belongs to the core, and its general constructors are // re-exported by the root package as tensor.FromFloats, tensor.Zeros, // tensor.Identity and their neighbours. A caller that imports this // package on its own, without the root facade, has ArrayFromFloatsSafe // for building the input to a call: it copies the slice it is given, // so the caller keeps ownership of the values it passed in. package linalg