The reference for the exported surface of Tensor, one section per
package. Each section lists every exported symbol in the groups the
package is read by, documents the options and result structs field by
field with their defaults, names the conditions that come back as
errors, and ends with the package's flagship call sequence.
The signatures live in the source, where `go doc` is the authority on
them and the godoc comments explain each one. This document is the
map: what each part of the surface is for, how the parts fit together,
and which options a call takes. Every package carries runnable
`Example` functions beside its tests, compiled and executed by the
suite, so the documented call sequences cannot rot; the longer
workflows are the programs in [`examples/`](../examples).
Conventions every package shares: functions return `(value, error)`
and wrap errors with context, every error message carries the
`tensor: ` prefix, operations never modify their inputs, and scalars
come back as `Scalar` when the dtype follows the input.
## Library
### Package `tensor` (root)
The facade and the array core. `import "sourcedock.dev/petrbalvin/tensor"` is the
one import the library needs: the domain packages are re-exported here under
their own names, so `tensor.Solve` and `linalg.Solve` are one function, and the
shared array core, which has no domain package of its own, is exported here
outright. What the documented surface of a call looks like in `go doc
sourcedock.dev/petrbalvin/tensor` is therefore the whole library in one place.
The value everything is built on is `Array`: an immutable, shape-checked
n-dimensional array in which every operation returns a new array and writes
neither its receiver nor its arguments. Elements are `int64`, IEEE 754 binary16
bits, `float32`, `float64` or `complex128`, any rank is allowed, and storage is
row-major. Mixing dtypes promotes along one ladder and shapes never broadcast
silently, so a mismatch is an error naming both shapes rather than a wrong
number.
#### Importing
```go
import(
tensor"sourcedock.dev/petrbalvin/tensor"
)
```
`tensor.Array` is a type alias for the core array, not a wrapper: `type Array =
core.Array` in `facade_generated.go`, and the same holds for `Dtype`, `Scalar`,
`Generator`, `SparseCOO` and `JacobianOptions`. Everything the array core
offers is exported here directly, so the root package is the only import a core
user needs. The domain packages are importable on their own
(`sourcedock.dev/petrbalvin/tensor/linalg` and its siblings) for a caller that
wants one of them without the rest, but their entry points take the core array
as `*core.Array`, so a caller who imports one of them alone needs this package
beside it to build the argument: the general constructors are rooted here.
`linalg.ArrayFromFloatsSafe` is the one constructor that exists outside this
package, a float vector of a given length built from a slice the caller keeps,
and it is there for exactly that caller.
#### Dtypes
| Name | What it is |
|---|---|
| `Bool` | the boolean element type: the comparisons' answer, and logical vectors for masking, `Where` and masked reads. It carries no arithmetic of its own; the logic entries `And`, `Or`, `Xor` and `Not` are its surface. |
| `Int8` | the `int8` element type. |
| `Uint8` | the `uint8` element type: byte payloads for images, masks and the byte classes of the file formats. |
| `Int16` | the `int16` element type. |
| `Uint16` | the `uint16` element type. |
| `Int32` | the `int32` element type. |
| `Uint32` | the `uint32` element type. |
| `Int` | the `int64` element type. |
| `Float16` | the IEEE 754 binary16 element type: the payload holds `uint16` bit patterns, widened exactly on every read. |
| `Float32` | the `float32` element type. |
| `Float` | the `float64` element type, the default real dtype. |
| `Complex` | the `complex128` element type. |
| `Dtype` | the element type of an `Array`; `Dtype.String()` renders it as it appears in diagnostics ("bool", "int8", "uint8", "int16", "uint16", "int32", "uint32", "int", "float16", "float32", "float", "complex"). |
| `BoolAt(a, index...)` | reads any element as a bool: the boolean payload's own value, and every other dtype read against zero. |
| `HalfFromFloat64(f)` | narrows a float64 to the half bit pattern with round-to-nearest-even, gradual underflow through the subnormals, overflow to the signed infinity at `\|f\| >= 65520`, NaN canonicalised, signed zero preserved. |
| `HalfToFloat64(h)` | widens a half bit pattern back to float64 exactly, with no rounding and no range loss. |
The ladder runs the integer class first, then the floats, then complex:
`Bool` below the small integers below `Int` below `Float16` below
promote to the smallest dtype whose value range contains both operands,
so `Int8` with `Uint8` answers `Int16`, `Int16` with `Uint16` answers
`Int32` and `Int32` with `Uint32` answers `Int`; across classes the
higher ladder position decides, the rule the int-to-float-to-complex
promotions have always walked. The constants' numeric order is
deliberately not the ladder's order: the seven new dtypes append after
`Float16`, because the recorded oracle digests pin the ordinals, and
the promotion tables are explicit rather than those numbers. The
element-wise kernels compute the narrow integers at their own width
with the machine's wrap-around semantics; reductions widen exactly, so
`Sum` of a `Bool` array counts its trues into an int scalar; `Astype`
range-checks every conversion into a narrow target with a loud error
naming the value and its index, while the conversions among the
original five dtypes keep their historical cast semantics. Surfaces a
later round will carry refuse the new dtypes with an error naming
`Astype`: the matrix products and `Einsum`, the sparse constructors
and products, `Kron`, `Sort` and `ArgSort`, `Prod`, `CumSum`,
`CumProd`, the `Norm` family, the clipping entries, `Sqrt` and the
transcendental families (`Abs` answers nil, its signature having no
error channel). `Interpolate2D` refuses a narrow grid the same way.
`Bytes` and `FromBytes` keep their `Int`-only contract for this round.
#### Constructors
| Call | What it does |
|---|---|
| `FromInts(values, shape...)` | builds an int array of the given shape from values, copying them. |
| `FromFloats(values, shape...)` | builds a float array of the given shape from values, copying them. |
| `FromFloat16s(values, shape...)` | builds a float16 array from float64 values, copying them and narrowing each to the nearest half. |
| `FromFloat32s(values, shape...)` | builds a float32 array of the given shape from values, copying them. |
| `FromComplexes(values, shape...)` | builds a complex array of the given shape from values, copying them. |
| `FromBools(values, shape...)` | builds a bool array from values, copying them. |
| `FromInt8s(values, shape...)` | builds an int8 array from values, copying them. |
| `FromUint8s(values, shape...)` | builds a uint8 array from values, copying them. |
| `FromInt16s(values, shape...)` | builds an int16 array from values, copying them. |
| `FromUint16s(values, shape...)` | builds a uint16 array from values, copying them. |
| `FromInt32s(values, shape...)` | builds an int32 array from values, copying them. |
| `FromUint32s(values, shape...)` | builds a uint32 array from values, copying them. |
| `FloatsFromArray(values, shape...)` | builds a float array that takes ownership of values: no copy, and the caller must not touch the slice afterwards. |
| `IntsFromArray(values, shape...)` | the same ownership contract for an int array. |
| `BoolsFromArray(values, shape...)` | the same ownership contract for a bool array. |
| `Int8sFromArray(values, shape...)` | the same ownership contract for an int8 array. |
| `Uint8sFromArray(values, shape...)` | the same for a uint8 array. |
| `Int16sFromArray(values, shape...)` | the same for an int16 array. |
| `Uint16sFromArray(values, shape...)` | the same for a uint16 array. |
| `Int32sFromArray(values, shape...)` | the same for an int32 array. |
| `Uint32sFromArray(values, shape...)` | the same for a uint32 array. |
| `HalvesFromArray(values, shape...)` | the same for a float16 array, taking raw half bit patterns with no conversion. |
| `ComplexFromArray(values, shape...)` | the same for a complex array. |
| `FromFloatSlice(values, shape...)` | aliases a `[]float64` into a float array with no copy at all: reads reflect later writes, so it fits build-then-consume windows and nothing else. |
| `FromFloat32Slice(values, shape...)` | the float32 twin, the same contract. |
| `Zeros(dt, shape...)` | builds an array of the given dtype and shape filled with zeros. |
| `Ones(dt, shape...)` | builds an array of the given dtype and shape filled with ones. |
| `FullI(v, shape...)` | fills an int array with an int. |
| `FullF(v, shape...)` | fills a float array with a float64. |
| `FullF16(v, shape...)` | fills a float16 array with a float64, narrowed to the nearest half. |
| `FullF32s(v, shape...)` | fills a float32 array with a float32. |
| `FullC(v, shape...)` | fills a complex array with a complex128. |
| `Range(start, stop)` | builds the int array start, start+1, …, stop-1; start at or above stop yields an empty array. |
| `RangeBy(start, stop, step)` | builds the int array start, start+step, …, staying below stop for a positive step and above it for a negative one. |
| `Linspace(start, stop, n)` | returns n evenly spaced float values from start to stop, both inclusive. |
| `Grid(x, y)` | builds the two coordinate matrices of the meshgrid pattern from two 1-D vectors, x varying along the columns and y along the rows. |
| `New(dt, shape...)` | allocates a zeroed array with no error return, for internally derived shapes: an invalid argument yields a nil array, not a panic. |
| `FromBytes(b)` | wraps raw bytes as an int array, the inverse of `Array.Bytes`. |
| `Identity(dt, n)` | builds the n×n identity matrix of the given dtype. |
| `Copy(a)` | returns a fresh array with the same data, shape and dtype. |
| `ZerosLike(a)` | returns a zero-filled array of the same shape and dtype, as a copy. |
| `OnesLike(a)` | the same filled with ones. |
#### The array value
| Call | What it does |
|---|---|
| `Array.Shape()` | returns a copy of the dimensions. |
| `Array.NDim()` | returns the number of dimensions. |
| `Array.Len()` | returns the number of elements, the product of the shape, which for a view is shorter than the storage it aliases. |
| `Array.Dtype()` | returns the element type. |
| `Array.String()` | renders the dtype, the shape and the values, as in `int (2, 2) [1, 2, 3, 4]`; a debugging aid, not a format. |
| `Array.Strided()` | reports whether the array carries a non-trivial stride layout; a dense array answers false. |
| `Array.CopyRows(indices)` | returns a new array holding the rows of a 2+-D array at the given leading-dimension indices, preserving every other dimension and the dtype. |
| `Equal(a, b)` | reports whether two arrays have the same dtype, shape and values; the dtype is part of the identity, so an int 1 does not equal a float 1.0, and arrays holding NaN are never equal. |
| `Astype(a, dt)` | returns a copy converted to dt: int and float convert like Go's casts, complex to float keeps the real part, complex to int or float16 is an error, real to complex adds a zero imaginary part, and a conversion to the array's own dtype still copies. |
| `Array.Bytes()` | returns the payload interpreted as raw bytes; only int arrays carry one, other dtypes return nil. |
#### Element-wise operations
| Call | What it does |
|---|---|
| `Add(a, b)` | the element-wise sum of two arrays of the same shape. |
| `Sub(a, b)` | the element-wise difference. |
| `Mul(a, b)` | the element-wise product. |
| `Div(a, b)` | the element-wise true division; the result is float for real operands and complex when a complex operand takes part, and division by zero follows IEEE 754 rather than raising an error. |
| `Quo(a, b)` | the element-wise integer division of two int arrays; a float or complex operand, or a zero divisor element, is an error. |
| `QuoI(a, v)` | the same against an int scalar, with a zero scalar refused. |
| `AddI(a, v)` / `SubI(a, v)` / `MulI(a, v)` / `DivI(a, v)` | the int scalar variants. Each dtype keeps its kind, except `DivI`, which is true division and therefore lifts an int array to float. |
| `AddF(a, v)` / `SubF(a, v)` / `MulF(a, v)` / `DivF(a, v)` | the float scalar variants: an int array becomes float64, a floating array keeps its dtype, a complex array stays complex. |
| `AddC(a, v)` / `SubC(a, v)` / `MulC(a, v)` / `DivC(a, v)` | the complex scalar variants; the result is always complex. All of these return the array alone, with no error, because a scalar cannot make a shape disagree. |
| `Pow(a, b)` | the element-wise power: int with int stays int with wrapping on overflow, a negative exponent on int operands is an error, and any float or complex operand promotes per the ladder. |
| `PowI(a, n)` | raises each element to an int exponent; complex arrays use exact repeated squaring and a negative exponent takes the reciprocal. |
| `Maximum(a, b)` | the element-wise larger of two same-shape arrays; NaN propagates. |
| `Minimum(a, b)` | the element-wise smaller; NaN propagates. |
| `Where(cond, x, y)` | selects element-wise between x and y: a set element of cond picks x, an unset one picks y, all three shapes must agree, and the result promotes like the arithmetic. cond is a bool mask or an int array, whose non-zero elements stand for true. |
| `Select(a, mask)` | a 1-D copy of the elements where the mask is set: a bool mask selects where it reads true, an int mask where it reads non-zero. |
| `ClipF(a, lo, hi)` | clamps a real array into `[lo, hi]`; an int array becomes float, a float16 or float32 array keeps its dtype, and `lo > hi` is an error. |
| `ClipI(a, lo, hi)` | the same clamp with int bounds, the dtype keeping its kind. |
| `Abs(a)` | the element-wise absolute value; a complex array yields its float magnitudes. |
| `Sign(a)` | the sign of every element as a float array; a NaN element reports 0. |
| `Sqrt(a)` | the square root of each element; negatives yield NaN. |
| `Exp(a)` | e raised to each element. |
| `Log(a)` / `Log2(a)` / `Log10(a)` | the natural, base-2 and base-10 logarithms; negatives yield NaN. |
| `Sin(a)` / `Cos(a)` / `Tan(a)` / `Tanh(a)` | the trigonometric and hyperbolic elements of the library, in radians. |
| `Sigmoid(a)` | the logistic function `1/(1+e^-x)` of each element. |
| `Sinc(a)` | the normalised `sin(πx)/(πx)` with `Sinc(0) = 1`. |
| `Cosm1(a)` | `cos(x) − 1` kept accurate for small arguments, where the direct float64 subtraction has no correct significant bit under about `\|x\| ≈ 1e-8`; the factored series holds full precision down to the smallest representable argument, where the answer is exactly `−x²/2` as far as the format can see it. |
| `Ceil(a)` / `Floor(a)` / `Round(a)` / `Trunc(a)` | the rounding family: up, down, half away from zero, and toward zero. An int array is an identity copy in all four. |
#### Comparisons and masks
| Call | What it does |
|---|---|
| `Eq(a, b)` / `Ne(a, b)` | a bool mask, true where the operands are equal, respectively different, element-wise. |
| `Lt(a, b)` / `Le(a, b)` / `Gt(a, b)` / `Ge(a, b)` | a bool mask, true where a is below, at most, above, at least b. |
| `EqI` / `NeI` / `LtI` / `LeI` / `GtI` / `GeI` | each comparison against an int scalar, answered as a bool mask; the names follow the same order as the pairs above. |
| `EqF` / `NeF` / `LtF` / `LeF` / `GtF` / `GeF` | each comparison against a float scalar, answered as a bool mask. |
| `IsNaN(a)` | an int mask marking NaN elements; complex arrays are not supported. |
| `IsInf(a)` | an int mask marking positive and negative infinity. |
| `IsFinite(a)` | an int mask marking values that are neither NaN nor infinite. |
The comparisons answer bool masks, one byte per element, the predicate
itself. `Select` and `Where` take a bool mask, and they still take the
int mask of 0 and 1 `IsNaN`, `IsInf` and `IsFinite` answer, so a mask of
either dtype feeds both directly and `And`, `Or`, `Xor` and `Not`
compose the bool ones.
`Sum`, `Dot`, `Min` and `Max` answer a `Scalar`, which boxes one numeric result
whose dtype is known only at runtime.
| Call | What it does |
|---|---|
| `Scalar.Int()` | the value as an int64, converting a float or complex scalar by truncation. |
| `Scalar.Float()` | the value as a float64; a complex scalar contributes its real part. |
| `Scalar.Complex()` | the value as a complex128. |
| `Scalar.IsFloat()` | whether the scalar came from a float computation. |
| `Scalar.IsComplex()` | whether the scalar came from a complex computation. |
| `Scalar.String()` | renders the scalar with its dtype, as in `int 7` or `complex (4-2i)`. |
Use `IsFloat` and `IsComplex` where the distinction between an integer result
and a converted one matters, because `Int` alone truncates silently.
#### Reductions
| Call | What it does |
|---|---|
| `Sum(a)` | the sum of all elements as a `Scalar`, which is int for an int array, float when a float16 or float32 array accumulated in float64, and complex for a complex array; an empty array sums to zero. |
| `SumAxis(a, dim)` | the sums along the given dimension. |
| `Mean(a)` | the arithmetic mean as a float64, computed in float64 even for an int array; an empty or complex array is an error. |
| `MeanAxis(a, dim)` | the float means along the given dimension. |
| `Prod(a, dim, keepDim)` | the product along dim; a complex array is refused. |
| `Min(a)` | the smallest element as a `Scalar`; an empty or complex array is an error. |
| `Max(a)` | the largest element as a `Scalar`. |
| `MinAxis(a, dim)` / `MaxAxis(a, dim)` | the smallest and largest values along a dimension, with NaN elements never winning. |
| `ArgMin(a)` / `ArgMax(a)` | the index of the smallest and largest element of a 1-D array, with NaN elements skipped as missing. |
| `ArgMinAxis(a, dim)` / `ArgMaxAxis(a, dim)` | the same along a dimension; the result is an int array with the reduced dimension dropped. |
| `Norm(a, p, dim, keepDim)` | the Lp norm along dim, `(sum \|x\|^p)^(1/p)`, always a float64 result. p must be positive, and `math.Inf` selects the max-abs. |
| `Dot(a, b)` | the dot product of two 1-D arrays of equal length as a `Scalar`; two int arrays produce an int, float32 operands accumulate in float64, and any complex operand promotes the result. |
| `All(a)` | whether every element is non-zero; the mask semantics match `Select`. |
| `Any(a)` | whether at least one element is non-zero. |
| `CountNonzero(a)` | the number of non-zero elements. |
| `TopK(a, k, dim)` | the top-k values and their original indices along a dimension, sorted descending by value; NaN elements never rank. |
#### Shape and indexing
| Call | What it does |
|---|---|
| `Reshape(a, shape...)` | returns a copy with a new shape of the same element count. |
| `Flatten(a, startDim, endDim)` | returns a copy with the dimensions in `[startDim, endDim]` collapsed into one; negative indices count from the end. |
| `Squeeze(a, dim)` | returns a copy with size-1 dimensions removed: all of them when dim is -1, otherwise that one, which must have size 1. |
| `Unsqueeze(a, dim)` | returns a copy with a new size-1 dimension inserted at dim. |
| `Transpose(a)` | returns a new array with the dimensions reversed; infallible. |
| `TransposeAxes(a, dims...)` | returns a copy with the dimensions reordered according to a permutation of the axis indices. |
| `MoveAxis(a, from, to)` | moves one axis to a new position in the shape. |
| `Tile(a, reps...)` | repeats a whole array reps times per dimension; the result never aliases the input. |
| `Repeat(a, repeats, dim)` | repeats each element `repeats` times along dim. |
| `Flip(a, dims...)` | reverses along the given dimensions, all of them by default. |
| `Roll(a, shift, dim)` | shifts along dim by shift, wrapping around, with a negative shift moving elements backward. |
| `Stack(a, b, dim)` | joins b after a along a new dimension inserted at dim; the two shapes must be identical. |
| `Concat(a, b, dim)` | joins b after a along an existing dimension, every other dimension agreeing. |
| `Pad(a, pad, mode, value)` | extends an array along its trailing dimensions, pad being a flat sequence of pairs `(left, right, top, bottom, …)`; mode is `"constant"`, `"reflect"`, `"replicate"` or `"circular"`. |
| `Slice(a, dim, start, stop)` | selects the half-open range `[start, stop)` along one dimension. A contiguous selection is a read-only view sharing the source's storage, rebased so element i is still payload[i]; an interior range is copied. |
| `Take(a, indices)` | a 1-D copy whose elements are the flat-indexed `a[indices[i]]`; a negative index is an error. |
| `Gather(src, dim, index)` | a copy indexed by index along dim, the output shape being the index shape. |
| `Scatter(self, dim, index, src)` | the inverse of `Gather`, writing src values into a new array at the positions index names; unindexed positions keep the receiver's values. |
| `Row(a, i)` | a 1-D copy of row i of a 2-D array. |
| `Col(a, j)` | a 1-D copy of column j of a 2-D array. |
| `Diag(a)` | extracts the main diagonal of a 2-D array, or builds a diagonal matrix from a 1-D array. |
| `Diagonal(a, offset)` | the elements on the offset-th diagonal of a 2-D matrix as a 1-D array; zero is the main diagonal. |
| `UpperTriangle(a)` / `LowerTriangle(a)` | the triangular part of a square matrix as a copy with the other side zeroed. |
| `BroadcastTo(a, shape...)` | a new array expanded to the target shape: size-1 dimensions replicate, missing leading dimensions prepend, anything else is an error naming both shapes. |
| `BroadcastWith(a, b)` | broadcasts both operands to their common shape and returns the pair, ready for an ordinary element-wise operation. |
| `Nonzero(a)` | the multi-dimensional indices of every non-zero element, one slice per dimension; a complex array is refused. |
| `Argwhere(a)` | the coordinates of every non-zero element as an (nnz, ndim) int array. |
| `SearchSorted(haystack, needles)` | insertion positions for each needle in the sorted haystack, rightmost after equal elements. |
| `AssignBins(a, edges)` | maps every value to its bin index given ascending edges, bin k covering `[edges[k], edges[k+1])`, with values outside clamping to the outer bins. |
| `OneHot(codes, classes)` | expands int class codes into indicator vectors appended as a new last axis, so shape (…) becomes (…, classes); the result is float32. A code outside `[0, classes)` is an error. |
#### Ordering
| Call | What it does |
|---|---|
| `Sort(a)` | an ascending copy, NaN elements at the end; the copy carries +0.0 wherever the input held -0.0, and sorted NaNs are fresh quiet NaNs. |
| `ArgSort(a)` | the stable int permutation of indices that would sort the array ascending, NaN at the end. |
| `Reverse(a)` | a copy with the elements in the opposite order; it works for every dtype, complex included. |
| `Unique(a)` | the sorted unique values of a real array; NaN counts once. |
| `Permutation(g, n)` | a uniform permutation of `0..n-1`, Fisher-Yates over unbiased bounded draws. |
| `Shuffle(g, a)` | a shuffled copy of a; the receiver itself is never touched. |
#### Scans, differences and quadrature
| Call | What it does |
|---|---|
| `CumSum(a, dim)` | the cumulative sum along dim, with the same shape as the input. |
| `CumProd(a, dim)` | the cumulative product along dim. |
| `Diff(a, order, axis)` | the successive differences along one axis, taken order times; the axis shrinks by order, int arrays keep their dtype, and everything else produces float. |
| `Integrate(y, dx)` | the definite integral of y over uniform spacing dx by the trapezoidal rule, as a float64. |
| `CumulativeIntegrate(y, dx)` | the running trapezoidal integral over uniform spacing, the first element being zero. |
| `EvaluatePolynomial(coeffs, x)` | evaluates coefficients, lowest power first, at the given points. |
| `Jacobian(f, x, opts)` | the Jacobian of f at x as an (m × n) float array, entry (i, j) holding ∂f_i/∂x_j by central differences; f must map the point and every probe to a real rank-1 array of one fixed length, and the probe arrays it is handed are reused between columns. |
| `Covariance(a, b)` | the sample covariance of two equally sized 1-D samples, denominator n-1. |
| `Correlation(a, b)` | the Pearson correlation coefficient of two 1-D samples. |
#### Core matrix operations
| Call | What it does |
|---|---|
| `MatMul2D(a, b)` | the matrix product: 2-D×2-D, a matrix times a vector, or a vector times a matrix. The dtype follows the promotion ladder, and float16 operands are refused loudly. |
| `Kron(a, b)` | the Kronecker product of two 2-D matrices; for shapes (m, n) and (p, q) the result is (m·p, n·q). |
| `Einsum(spec, operands...)` | Einstein summation over a spec of the form `"lhs[,lhs,...]->rhs"`, where each ASCII letter names a dimension; an invalid character is an error, so a bad spec can never silently compute. Broadcasting over an ellipsis and batched products go through the same entry point. |
| `Trace(a)` | the sum along the main diagonal of a 2-D square matrix, always as a float64; a complex matrix is answered by `TraceComplex`. |
| `TraceComplex(a)` | the main-diagonal sum of a complex square matrix. |
| `CrossProduct(u, v)` | the vector cross product of two length-3 vectors. |
#### Sparse construction
| Call | What it does |
|---|---|
| `NewSparseCOO(indices, values, shape)` | creates a coordinate-format sparse array from explicit indices, values and shape; a nil array, a disagreement on the non-zero count, or a wrong index rank is an error. |
| `SparseFrom(dense)` | extracts a sparse array from a dense one by keeping only the non-zero elements; the values keep the dense array's dtype. |
| `SparseCOO.NNZ()` | the number of stored non-zero entries. |
| `SparseCOO.Dense()` | materialises the sparse array as a dense `Array`. |
| `SpAdd(a, b)` | the element-wise sum of two sparse arrays of the same shape, as a dense array, because addition can collapse zeros into non-zeros. |
| `SpMul(s, dense)` | the element-wise product of a sparse array and a dense array of the same shape, as a dense array. |
| `SpMatMul(s, dense)` | a sparse (n×k) matrix times a dense (k×m) matrix, as a dense n×m result; every stored coordinate is validated, so an out-of-range index is an error rather than a panic. |
The compressed views and their solvers live in `linalg`, not here: see
[Package `linalg`](#package-linalg).
#### Special functions
| Call | What it does |
|---|---|
| `Gamma(a)` | the gamma function Γ(x) of each element. |
| `LnGamma(a)` | the natural logarithm of `\|Γ(x)\|`; the sign for negative arguments is dropped. |
| `LnFactorial(n)` | the natural logarithm of n! as a float64. |
| `Digamma(a)` / `Trigamma(a)` | the digamma ψ(x) and the trigamma ψ′(x) of each element. |
| `Beta(x, y)` | the Euler beta function `B(x, y) = Γ(x)Γ(y)/Γ(x+y)`, the two arrays of one shape. |
| `Erf(a)` / `Erfc(a)` | the error function and the complementary error function. |
| `BesselJ(n, x)` / `BesselY(n, x)` | the Bessel functions of the first and second kind of integer order n at one real point; Y is defined for `x > 0` and refuses a non-positive argument. |
| `BesselJRealOrder(nu, x)` | the Bessel function of the first kind of real order ν at one positive real point; series below the crossover, above it the order's fractional pair is seeded from the expansion and the recurrence runs in its stable direction. Orders within 1e-8 of a non-negative integer are served by the exact integer algorithm; a negative order or a non-positive argument is an error. |
| `BesselI0(a)` / `BesselI1(a)` / `BesselIn(n, a)` | the modified Bessel function of the first kind, of order zero, one, and integer order n. |
| `BesselK0(a)` / `BesselK1(a)` / `BesselKn(n, a)` | the modified Bessel function of the second kind; any NaN or non-positive element is an error naming it, never a silent NaN. |
| `Airy(a)` | the Airy functions of the first and second kind, returned in that order; outside `\|x\| ≤ 8` the answer is NaN rather than a silently wrong value. |
| `ExpIntegralE1(a)` | the exponential integral `E1(x)`, defined for `x > 0`. |
| `ExpIntegralEi(a)` | the exponential integral `Ei(x)` for real x ≠ 0, the negative side through `E1`. |
| `FresnelC(a)` / `FresnelS(a)` | the Fresnel cosine and sine integrals. |
| `Legendre(l, x)` | the Legendre polynomial `P_l(x)` by the Bonnet recurrence, `P_0 = 1`, `P_1 = x`, no extra scaling. |
| `LegendreAssociated(l, m, x)` | the associated Legendre function `P_l^m(x)` with the Condon-Shortley phase folded in and no extra normalisation. |
| `Hermite(n, x)` | the physicists' Hermite polynomial `H_n(x)`. |
| `Laguerre(n, alpha, x)` | the generalised Laguerre polynomial `L_n^α(x)`; the degree must be at least 0. |
| `ChebyshevT(n, x)` / `ChebyshevU(n, x)` | the Chebyshev polynomials of the first and second kind. |
| `SphericalHarmonic(l, m, theta, phi)` | the complex spherical harmonic `Y_l^m(θ, φ)` with the Condon-Shortley phase and the orthonormal convention; theta and phi must share a shape. |
| `SphericalHarmonicReal(l, m, theta, phi)` | the real spherical harmonic built from the complex one under the standard branch convention. |
| `SphericalBesselJ(l, x)` / `SphericalBesselY(l, x)` | the spherical Bessel functions of the first and second kind; every `y_l` diverges to -Inf at x = 0. |
| `EllipticK(m)` / `EllipticE(m)` / `EllipticPi(n, m)` | the complete elliptic integrals of the first, second and third kind in the parameter convention `m = k²`. |
| `EllipticKScalar(m)` / `EllipticFScalar(phi, m)` | the same first-kind integral at one point, complete and incomplete, where the incomplete form is the amplitude view behind the Jacobi functions. |
| `JacobiSN(u, m)` / `JacobiCN(u, m)` / `JacobiDN(u, m)` | the Jacobi elliptic functions of the parameter m, shared across the u array. |
| `JacobiCDScalar(u, m)` | `cd(u, m) = cn(u, m)/dn(u, m)` at one point. |
| `Hypergeometric2F1(a, b, c, x)` | the Gauss hypergeometric function `₂F₁(a, b; c; x)` element-wise over x with scalar parameters; a non-positive integer c is an error. |
#### Interpolation
| Call | What it does |
|---|---|
| `Interpolate(xs, ys, query)` | the piecewise-linear interpolation of the points `(xs[i], ys[i])` at each query; xs need only be non-decreasing, a query outside the range clamps to the boundary, and a NaN query or a non-finite knot is refused. |
| `InterpolateMonotone(xs, ys, query)` | the monotone piecewise cubic through the samples, passing through every knot with a slope that never exceeds twice the neighbouring secants; xs must be strictly increasing. |
| `Interpolate2D(grid, xs, ys, x0, y0, dx, dy)` | the bilinear interpolation of a regular rows × cols grid at a set of query points, exact on any field that is bilinear within a cell; a query outside the rectangle is an error, never a silent clamp, and either sign of dx or dy works. |
| `InterpolateGrid(grid, origins, steps, queries)` | multilinear interpolation on a grid of any rank, queries being an (m × rank) matrix of coordinates; a query outside the grid clamps to the boundary and a rank above 12 is an error. |
#### Quasirandom sequences
| Call | What it does |
|---|---|
| `HaltonPoints(n, dim, skip)` | the first n Halton points of the given dimension as an (n, dim) float64 array, skipping the leading skip points; dim must lie in `[1, 32]`, beyond which the available small primes run out. |
| `SobolPoints(n, dim, skip)` | the same for the base-2 digital Sobol sequence; dim must lie in `[1, 40]`, the width of the direction-number table. |
Both drop the index-zero origin before the skip is applied, because it carries
no information, and both refuse a negative n or skip and require `n + skip`
below 2^32, the index budget past which the arithmetic would wrap back to the
origin.
#### Random numbers
| Call | What it does |
|---|---|
| `NewGenerator(seed)` | seeds a fresh generator; any int64 seed is valid, and the stream is xoshiro256++ seeded through splitmix64, stable across Go releases. |
| `Generator.Next()` | advances the generator and returns the raw 64-bit value. |
| `Generator.Unit()` | draws one uniform float in `[0, 1)` with 53-bit resolution. |
| `Generator.NormalUnit()` | draws one standard normal value by the polar Box-Muller method. |
| `Floats(g, n)` | n uniform floats in `[0, 1)` with 53-bit resolution. |
| `Float32s(g, n)` | n uniform float32 values in `[0, 1)` with 24-bit resolution. |
| `Ints(g, n, min, max)` | n uniform ints in `[min, max)`, drawn without modulo bias; min must be below max. |
| `Normal(g, n, mean, std)` | n Gaussian draws of the given mean and standard deviation, bit-stable across Go releases; a negative or NaN std is an error. |
| `TruncatedNormal(g, shape, mean, std)` | an array of the given shape drawn from a normal truncated to ±2σ, as float32; an invalid shape yields a nil array. |
| `Permutation(g, n)` | a uniform permutation of `0..n-1`. |
| `Shuffle(g, a)` | a shuffled copy of a. |
| `Splitmix64(state)` | advances the splitmix64 stream one step, returning the advanced state and the mixed output; the mixer is a bijection on uint64, so callers seeding their own streams can build on it. |
| `Substream(seed, index)` | the index-th member of the stream family one seed carries: the index is mixed through splitmix64 before it meets the seed, and both mixings are bijections, so distinct indices give provably distinct initial states. The index starts at zero; a negative one is an error. |
Every draw of a given seed and call sequence is reproducible, which is what the
examples rely on.
#### Execution policy
| Call | What it does |
|---|---|
| `SetNumCPU(n)` | sets the number of goroutines the parallel kernels may use and returns the previous value; a value below 1 resets to `runtime.NumCPU()`, and a running kernel finishes with its old worker count. |
| `NumWorkers()` | returns the current worker count. |
The default is `runtime.NumCPU()`, the logical CPUs available to the process.
The heavy loops of the library, matrix products, convolutions, element-wise
maps, axis reductions, scans and the FFT, run in parallel across this count and
reduce in a fixed order, so a given element order gives bit-identical results
run to run.
#### Payload and element access
| Call | What it does |
|---|---|
| `Array.RawFloats()` | returns the float64 payload directly: element i of the array sits at payload index i, views included, because the package never sets strides. Treat it as read-only; only an array the caller owns is safe to write through. |
| `Array.RawFloat32s()` | the float32 payload, same contract. |
| `Array.RawInts()` | the int64 payload, same contract. |
| `Array.RawHalves()` | the float16 payload, the raw IEEE 754 binary16 bit patterns, same contract. |
| `Array.RawComplexes()` | the complex128 payload, same contract. |
| `Array.Elements[E]()` | the flat payload converted to the caller's element type; the ladder runs int64 ← float16 ← float32 ← float64 ← complex128, so a wider E converts and a narrower one is an error naming both dtypes. The slice returned is a copy. |
| `Array.ComplexValues(name)` | the elements as complex values, sharing the payload as a read-only alias for a contiguous complex array and copied out otherwise. |
| `FloatAt(a, index...)` | the element at the given index as a float64; the array must be float. |
| `IntAt(a, index...)` | the element at the given index as an int64; the array must be int. |
| `ComplexAt(a, index...)` | the element at the given index as a complex128; the array must be complex. |
| `Item(a)` | the single element of a 1-element array as a float64, the real part for a complex array. |
| `Array.FloatAt(i)` | the numeric read primitive the derivative packages build on. |
| `Array.ComplexAt(i)` | element i as a complex128, converting a real element. |
| `Array.SetFloatAt(i, v)` | sets element i from v, converting to the array's dtype; the numeric write primitive complementing `FloatAt`. |
| `WithInt(a, v, index...)` | a new int array with v at the given index; the receiver is unchanged. |
| `WithFloat(a, v, index...)` | a new float array with v at the given index. |
| `WithComplex(a, v, index...)` | a new complex array with v at the given index. |
The `Raw*` accessors are for kernels that must touch the payload directly; every
other path through the library reads through the accessors, so a write through a
raw slice is the caller's responsibility.
#### The fluent chain
| Call | What it does |
|---|---|
| `Pipe(a)` | starts the fluent chain from a, returning a `*Pipeline` that holds the current array and the first error encountered during the chain. |
| `Pipeline.Result()` | ends the chain, returning the array and that first error. |
Every other `Pipeline` method is one of the core operations, eager and returning
the pipeline itself, so the methods are the package-level calls without the
intermediate error checks. The chain is defined in `linalg` and re-exported
here, so its full method list belongs to [Package `linalg`](#package-linalg).
#### Domain re-exports
Every symbol of every domain package is also a root symbol, unchanged. Each
package below has its own section further down this document:
| Package | Reachable here as |
|---|---|
| `linalg` | `Solve`, `SVD`, `Eigen`, `SpEigen`, `Pipe` and the rest, plus `ArrayFromFloatsSafe`. See [Package `linalg`](#package-linalg). |
| `signal` | `FFT`, `DWT`, `CWT`, `Conv2D`, `KalmanFilter`, the window functions and the filter designs. See [Package `signal`](#package-signal). |
| `integrate` | `IntegrateODE`, `IntegrateHeat1D`, `IntegrateND`, `IntegrateFilon`, the FEM meshes and solvers. See [Package `integrate`](#package-integrate). |
| `stats` | `LinearRegression`, `PCA`, `KMeans`, `Histogram`, the distributions and the hypothesis tests. See [Package `stats`](#package-stats). |
Each package's options and result types are re-exported the same way, so
`tensor.ODEOptions`, `tensor.LBFGSOptions` and `tensor.HessianOptions` are the
types the corresponding root calls take.
#### Options and results
The core owns two exported structs, and both are plain option and data records
with no methods beyond those of their fields.
| Field | Type | Default | Effect |
|---|---|---|---|
| `SparseCOO.Indices` | `*Array` | required | the coordinates, shape (nnz, ndim) and dtype int. |
| `SparseCOO.Values` | `*Array` | required | the stored values, shape (nnz,) and the element dtype of the array. |
| `SparseCOO.Shape` | `[]int` | required | the dense shape the coordinates index into. |
| `JacobianOptions.Step` | `float64` | zero, meaning the per-column default | the absolute difference step applied to every coordinate. Zero or negative selects `sqrt(ε)·max(1, abs(x_j))` per column, the largest step whose central-difference truncation error still sits below the rounding floor. |
#### Errors
Every error the library returns carries the `tensor: ` prefix, whatever package
raised it.
- Two operands of a binary element-wise operation whose shapes disagree: an
error naming both shapes; nothing is computed.
- A dimension index outside the array's rank, in any axis reduction, scan,
`MoveAxis`, `Squeeze`, `Unsqueeze`, `Concat`, `Stack`, `Diff` or
`InterpolateGrid`: an error naming the dimension and the shape.
- A reduced dimension of size zero in `CumSum` or `CumProd`: an error naming the
dimension.
- A payload length that does not exactly fill the declared shape in any `From…`
constructor: an error naming the count and the shape.
- A shape list that is empty, holds a negative dimension, or holds more elements
than fit in an index: an error, raised before any allocation.
- A dtype constant that is not one of the five: an error from `Zeros`, `Ones`
and the `Full*` family, and a nil array from `New`.
- An element read or write whose array has another dtype: `IntAt`, `FloatAt`,
`ComplexAt`, `WithInt`, `WithFloat` and `WithComplex` each name the dtype they
found.
-`Quo` or `QuoI` on a non-int array, or with a zero divisor: an error.
-`Pow` or `PowI` with a negative exponent on an int array: an error.
- A negative `n` in `Floats`, `Float32s`, `Ints`, `Normal` or `Permutation`; a
`min` at or above `max` in `Ints`; a negative or NaN `std` in `Normal`: an
error. `TruncatedNormal` is the exception, answering a nil array.
- A `Slice` range outside the dimension's extent, or a dimension outside the
rank: an error naming the range or the dimension.
-`RangeBy` with a zero step: an error.
-`HaltonPoints` with dim outside `[1, 32]`, `SobolPoints` with dim outside
`[1, 40]`, either with a negative n or skip, or either with `n + skip` at or
above 2^32: an error.
-`Take` with a negative index, `CopyRows` with an index outside the leading
dimension, `OneHot` with a code outside `[0, classes)`: an error.
- A complex array in a call that needs an ordering, among them `Sort`,
`ArgMin` and `ArgMax`: an error, because a complex lattice has no ordering.
- A complex array in `Mean`, `MeanAxis`, `Prod` or `Norm`: an error, because
there is no real-valued answer.
- An empty array in `Mean`, `Min`, `Max`, `ArgMin` or `ArgMax`: an error.
- Two operands of different length in `Dot`, or `Dot` on anything but 1-D
arrays: an error naming the shapes and the lengths.
- A float16 operand in `MatMul2D` or `Einsum`: an error naming `Astype` as the
conversion.
-`Interpolate2D` with a grid that is not rank 2 or has an extent below 2, a
zero or non-finite spacing or origin, or a query outside the grid: an error.
-`Interpolate` with a non-finite knot or a NaN query, `InterpolateMonotone`
with knots that are not strictly increasing: an error.
#### Workflow
```go
// Build a flat payload, reshape it, slice it, reduce it, and hand the
// result to a domain entry point.
vals:=make([]float64,16)
fori:=rangevals{
vals[i]=float64(i+1)
}
flat,err:=tensor.FromFloats(vals,16)
iferr!=nil{
returnerr
}
m,err:=tensor.Reshape(flat,4,4)
iferr!=nil{
returnerr
}
// Whole rows of a 2-D array: a read-only view sharing the storage.
rows,err:=tensor.Slice(m,0,1,4)
iferr!=nil{
returnerr
}
// A partial column range: copied, because only a contiguous
// selection is a view.
sq,err:=tensor.Slice(rows,1,0,3)
iferr!=nil{
returnerr
}
// Reduce the block to one value per column.
rhs,err:=tensor.MeanAxis(sq,0)
iferr!=nil{
returnerr
}
// The domain packages take over from here; Solve reads the core
// array and returns one.
x,err:=tensor.Solve(sq,rhs)
iferr!=nil{
returnerr
}
fmt.Println(sq.Shape(),x.Shape())
```
### Package `linalg`
Dense and sparse linear algebra: factorisations and their solves, the
spectral decompositions, matrix functions, polynomial fitting and
root finding, cubic splines, the compressed sparse views, and the
direct and Krylov methods that run on them. Every symbol is
re-exported by the root package, so `linalg.Solve` and `tensor.Solve`
are one function; the arrays it reads and writes are the shared core
array, re-exported by the root package as `tensor.Array`.
The package does not choose an algorithm for the caller. Dense or
sparse, symmetric or general, direct or iterative is the decision each
call makes, and the names say which route they take. Complex data is
supported across the dense surface and on four named sparse entry
points; every other sparse routine refuses it rather than promoting
it. The `Pipeline` is eager sugar over the package-level calls, with
no lazy graph and no autograd.
#### Constructing an input
| Call | What it does |
|---|---|
| `ArrayFromFloatsSafe(v, n)` | builds a float vector of length n from v, copying the values so the caller keeps ownership of the slice. |
`ArrayFromFloatsSafe` is the constructor for a caller that imports
this package on its own, without the root facade: no general array
constructors are exported here, so this one exists to build the input
to a call. The general constructors belong to the root package, where
`tensor.FromFloats`, `tensor.Zeros`, `tensor.Identity` and their
neighbours are the way in.
#### Dense factorisations and solves
| Call | What it does |
|---|---|
| `Solve(a, b)` | returns x with a·x = b for a square a and b a vector of length n or a matrix with n rows; one LU with partial pivoting, complex promotion when either operand is complex. |
| `Inv(a)` | returns the inverse of a square matrix, through the same LU kernel. |
| `Det(a)` | returns the determinant of a square real matrix; a singular matrix gives 0, not an error. |
| `DetComplex(a)` | the same for a square complex matrix, as a `complex128`. |
| `Cholesky(a)` | returns the lower factor L with a = L·Lᵀ for a symmetric positive definite a; a non-positive pivot and a non-finite entry are refused. |
| `CholeskyUpdate(l, x)` | returns the lower factor of A + x·xᵀ from the factor of A, by orthogonal rotations. |
| `CholeskyDowndate(l, x)` | returns the lower factor of A − x·xᵀ, by hyperbolic rotations; leaving the positive definite cone is an error. |
| `QR(a)` | returns q (m×m orthogonal) and r (m×n upper triangular) with a = q·r, for m ≥ n. |
| `LeastSquares(a, b)` | solves A·x = b in the least-squares sense for m×n a with m ≥ n and b of m rows or m×k; a rank-deficient system is refused. |
| `SolveTridiagonal(a, b, c, d)` | solves the tridiagonal system by the Thomas algorithm: a the lower diagonal of length n−1, b the main diagonal, c the upper diagonal, d the right-hand side; a zero pivot is refused. |
| `SolveCyclicTridiagonal(a, b, c, d)` | the same for the periodic system, where `a[0]` is the corner A[0][n−1] and `c[n−1]` the corner A[n−1][0], by Sherman-Morrison on the Thomas elimination. |
| `Eigen(a)` | returns the eigenvalues of a real symmetric matrix, ascending, and the orthonormal eigenvectors as columns; asymmetry beyond a scale-relative 1e-12 and a non-finite entry are refused. |
| `EigenComplex(a)` | the same for a complex Hermitian matrix; values are real, vectors complex, the same 1e-12 Hermitian tolerance applies, and a non-finite entry is refused. |
| `EigenGeneral(a)` | the eigenvalues and eigenvectors of a square matrix of any dtype; real and int inputs promote to `complex128`, values descend by magnitude, and a real matrix may carry conjugate pairs. |
| `EigenGeneralised(a, b)` | solves A·v = λ·B·v for symmetric a and symmetric positive definite b, through the Cholesky factor of b; values ascend, eigenvectors are B-orthonormal columns. |
| `SVD(a)` | the thin decomposition a = U·Σ·Vᵀ for m ≥ n: U is m×n with orthonormal columns, Σ a length-n vector descending, Vᵀ n×n orthogonal; a wide matrix is transposed first and the factors are swapped back. |
| `SVDComplex(a)` | the same shapes for a complex matrix, A = U·diag(Σ)·Vᴴ. |
| `SchurComplex(a)` | the complex Schur decomposition t·q with a = q·t·qᴴ, t upper triangular and q unitary; the diagonal of t carries the eigenvalues. |
| `Pinverse(a, eps)` | the Moore-Penrose pseudoinverse, built from the SVD by inverting singular values strictly above eps; eps ≤ 0 uses max(m, n)·max(Σ)·ε. |
| `MatrixRank(a, eps)` | the count of singular values strictly above eps, with the same default when eps ≤ 0. |
| `Cond(a, eps)` | the 2-norm condition number σmax/σmin; a singular value at or below a positive eps, or exactly zero, gives +Inf. |
Both `SVD` routes take the singular values from the eigenvalues of a
squared matrix, BᵀB or Aᴴ·A. Their accuracy on very small singular
values is therefore that of a squared condition number: exact enough
for a rank decision, weaker for resolving near-null directions. The
same caveat applies to the rank and condition answers above, which
are read off that spectrum.
#### Rank-revealing QR
| Call | What it does |
|---|---|
| `RRQR(a)` | returns q, r, the column permutation `perm` and the numerical rank of an m×n matrix with m ≥ n, from A·P = Q·R with column pivoting; the rank counts \|R[i,i]\| above n·ε·max\|R\|. |
| `RRQRRank(a)` | the same rank count without forming the orthogonal factor. |
| `SolveRRQR(a, b)` | solves min ‖A·x − b‖₂ through the pivoted factorisation; on rank-deficient input it returns the minimum-norm least-squares solution. |
#### Regularised and truncated solves
| Call | What it does |
|---|---|
| `SolveTikhonov(a, b, lambda)` | solves min ‖A·x − b‖² + λ‖x‖² with the identity prior, scaling every singular direction by σ/(σ²+λ); a non-positive λ is an error. |
| `SolveTruncated(a, b, rank)` | keeps the `rank` largest singular values and discards the rest, the truncated pseudoinverse; a singular value that vanishes below the requested rank is an error. |
#### Matrix functions
| Call | What it does |
|---|---|
| `MatrixExp(a)` | returns exp(A) of a square matrix by scaling and squaring over a diagonal Padé approximant; the zero matrix gives the identity. |
| `MatrixSqrt(a)` | the principal square root of a symmetric positive semi-definite matrix by diagonalisation, with small negative eigenvalues clamped to zero and a genuinely indefinite spectrum refused; a nonsymmetric matrix runs through the complex Schur route and is refused when the principal root leaves the reals. |
| `MatrixLog(a)` | the principal logarithm of a real symmetric positive definite matrix by the same diagonalisation route; a non-positive eigenvalue is refused, and a nonsymmetric matrix takes the Schur-Parlett route. |
#### Fitting, roots and splines
| Call | What it does |
|---|---|
| `FitPolynomial(x, y, degree)` | returns the coefficients, lowest power first, of the degree-th polynomial through the samples, by QR least squares over the Vandermonde matrix; n < degree+1 or mismatched lengths are errors. |
| `PolynomialRoots(coeffs)` | returns the roots of the polynomial whose coefficients are lowest power first, as a complex vector descending by magnitude, through the companion matrix; trailing zeros are stripped, the zero polynomial is an error, and a nonzero constant gives an empty vector. |
| `NewCubicSpline(xs, ys)` | builds the natural cubic spline through the points; the abscissae must be strictly increasing and at least 3 points are required. |
| `CubicSpline.At(x)` | evaluates the spline at one point; outside the knot range the answer is NaN. |
| `CubicSpline.Evaluate(x)` | maps an array of query points element-wise, refusing a complex query array. |
#### Iterative solves over an operator
| Call | What it does |
|---|---|
| `GMRES(op, b, restart, maxIter, tol)` | solves A·x = b by restarted GMRES, with A given as the function `op` that maps a vector to A·v; restart ≤ 0 or above n means n, maxIter ≤ 0 means 20 cycles, tol ≤ 0 means 1e-10 relative residual, an exhausted budget is an error naming the best residual. `op` is handed a read-only vector the solver refills for each call, so it must not retain or modify it, and it may hand back a buffer it reuses. | |
#### Sparse storage
| Call | What it does |
|---|---|
| `CSRFromCOO(s)` | converts a COO matrix to compressed sparse row, summing duplicate coordinates, dropping explicit zeros and sorting each row; complex values are refused. |
| `CSCFromCOO(s)` | the same canonicalisation into compressed sparse column form. |
| `SparseCSR.ToCSC()` | converts the same matrix to the column view. |
| `SparseCSC.ToCSR()` | converts the same matrix to the row view. |
| `SparseCSR.Transpose()` | returns the transpose, in CSR form. |
| `SparseCSR.MatVec(x)` | computes A·x for a dense vector of length Cols; output rows are independent and split across workers. |
| `SparseCSC.MatVec(x)` | the same product over the column view, with a fixed scatter order. |
| `SparseCSR.MatMulDense(x)` | computes A·x for a dense matrix of shape (Cols, k), streaming the non-zeros once. |
| `SparseCSR.MatMulSparse(o)` | returns the sparse product A·B where A.Cols equals B.Rows, storing only what survives. |
| `SparseCSR.NNZ()` | the count of stored non-zeros. |
| `SparseCSC.NNZ()` | the same for the column view. |
#### Sparse direct factorisations
| Call | What it does |
|---|---|
| `NewSparseCholesky(a, ordering)` | factors a symmetric positive definite matrix into L with P·A·Pᵀ = L·Lᵀ; the lower triangle defines the matrix, and a stored upper entry without its equal lower counterpart is refused. One factorisation solves any number of right-hand sides. |
| `SparseCholesky.Solve(b)` | computes A⁻¹·b for a dense vector: permute, forward substitution, backward substitution, undo. |
| `SparseCholesky.Update(x)` | applies A ← A + x·xᵀ to the factor in place on the stored pattern, refusing an update that would need fill the pattern does not hold. |
| `SparseCholesky.Downdate(x)` | applies A ← A − x·xᵀ the same way, refusing a matrix that leaves the positive definite cone. |
| `SparseCholesky.Permutation()` | the elimination order, position k holding the original index factored k-th; a copy. |
| `SparseCholesky.NNZ()` | the count of stored non-zeros in the factor, diagonal included. |
| `NewSparseLU(a)` | factors a square matrix with partial pivoting into P·A = L·U; complex, rectangular and non-finite inputs are refused, and a zero pivot column means a singular matrix, which is reported. |
| `SparseLU.Solve(b)` | computes A⁻¹·b for a dense vector through L and U. |
| `SparseLU.Permutation()` | the row elimination order, position k holding the original index of the row factored k-th; a copy. |
| `SparseLU.NNZ()` | the count of stored non-zeros: L's strict columns, U's strict rows and U's diagonal. |
| `NewSparseILU(a)` | builds the ILU(0) factorisation of a square matrix in its CSR pattern, as the Krylov preconditioner; a missing diagonal entry or a zero pivot is refused. |
| `SparseILU.Apply(r)` | solves (L·U)·x = r over the stored pattern, approximating A⁻¹·r to the accuracy the dropped fill allows. |
The fill-reducing permutation is chosen with `SparseOrdering`. It has
three values: `SparseOrderingNatural`, which eliminates in stored
order and is the reference point every ordering is measured against;
`SparseOrderingReverseCuthillMcKee`, which orders every component in
reverse breadth-first order from a pseudo-peripheral start and is the
classic choice for mesh-shaped patterns; and
`SparseOrderingMinimumDegree`, which eliminates the vertex with the
fewest remaining neighbours at each step and is the stronger choice on
irregular patterns.
#### Sparse iterative solves
| Call | What it does |
|---|---|
| `SpSolve(a, b, tol, maxIter, precond...)` | solves A·x = b for a real symmetric positive definite sparse A by preconditioned conjugate gradient; the default preconditioner is the Jacobi diagonal and an ILU(0) from `NewSparseILU` may replace it. |
| `SpSolveBiCGSTAB(a, b, tol, maxIter, precond...)` | the same for a general real square sparse A, by BiCGSTAB, with the same preconditioner choice. |
| `SpSolveComplexCG(a, b, tol, maxIter)` | the Hermitian positive definite complex case, by conjugate gradient with a complex Jacobi preconditioner. |
| `SpSolveComplexBiCGSTAB(a, b, tol, maxIter)` | the general non-Hermitian complex case, by BiCGSTAB. |
All four stop on the relative residual ‖b − A·x‖₂ ≤ tol·‖b‖₂ with
tol ≤ 0 meaning 1e-10 and maxIter ≤ 0 meaning n steps. An
unconverged solve is an error naming the residual achieved, never a
silent approximation. A zero or missing diagonal entry is refused,
since the Jacobi preconditioner divides by it.
#### Sparse least squares
| Call | What it does |
|---|---|
| `SpLSQR(a, b, tol, maxIter, conlim)` | minimises ‖A·x − b‖₂ over a sparse overdetermined A by the Golub-Kahan recursion of Paige and Saunders, returning the solution and a `LeastSquaresInfo`. |
| `SpLSMR(a, b, tol, maxIter, conlim)` | minimises ‖Aᵀ(b − A·x)‖₂ by Fong and Saunders' LSMR, whose normal-equations residual moves monotonically; the answers agree on a consistent rank-deficient system, where both give the minimum-norm solution. |
tol ≤ 0 means 1e-10 and feeds both the residual and the
normal-equations test; maxIter ≤ 0 means 2n steps; conlim ≤ 0 means
1e8, and cond(A) passing it stops the iteration without claiming
convergence. Running out of steps with every tolerance unmet is an
error naming the residual achieved.
#### Sparse eigensolvers and the exponential action
| Call | What it does |
|---|---|
| `SpEigen(s, k, gen)` | the k eigenvalues of largest magnitude of a real symmetric sparse matrix, each with its unit eigenvector, by Lanczos, values descending by magnitude. |
| `SpEigenComplex(s, k, gen)` | the same for a Hermitian sparse matrix with complex entries; a non-Hermitian matrix is refused. |
| `SpEigenGeneral(s, k, gen)` | the k eigenvalues of largest magnitude of a general real sparse matrix, as a `complex128` vector with the matching eigenvectors, by Arnoldi; symmetric input gets a cheaper answer from `SpEigen`. |
| `SpEigenGeneralComplex(s, k, gen)` | the general complex case, non-Hermitian operators included. |
| `SpExpApply(a, v, steps)` | returns exp(A)·v for a real symmetric sparse A and a vector v, by Krylov projection; steps ≤ 0 means min(n, 40), and steps ≥ n decomposes the whole space so the answer is exact. |
The eigensolvers take a generator (`tensor.Generator`) for their start
vector; passing nil uses a fixed seed, so an unseeded call is
reproducible. The Ritz pairs are approximations whose accuracy
improves with the iteration budget, unlike the exact answers `Eigen`
computes.
#### The pipeline
| Call | What it does |
|---|---|
| `Pipe(a)` | starts a pipeline from a. |
| `Pipeline.Result()` | returns the current array and the first error seen during the chain, or nil. |
| `Pipeline.Tanh()`, `Sigmoid()` | the activations. |
| `Pipeline.SumAxis(dim)`, `MeanAxis(dim)` | reductions along one axis. |
| `Pipeline.ArgMaxAxis(dim)`, `ArgMinAxis(dim)` | the index of the extremum along one axis. |
| `Pipeline.TopK(k, dim)` | the top-k values along dim, discarding the matching indices; the package-level `TopK` is the call when the indices matter. |
| `Pipeline.Transpose()`, `TransposeAxes(dims...)` | the transpose and the axis permutation. |
| `Pipeline.MatMul2D(b)` | the matrix product. |
| `Pipeline.Inv()` | the inverse of the current square matrix. |
| `Pipeline.Solve(b)` | the solve of the current square matrix against b. |
Every step returns the pipeline, so the chain reads as one
expression. A step that fails records its error and the steps after
it become no-ops; `Result` reports the first one.
#### Options and results
**`LeastSquaresInfo`**: what a sparse least-squares iteration
achieved and which stopping test ended it. Returned by `SpLSQR` and
`SpLSMR`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Iterations` | `int` | 0 | the number of Golub-Kahan steps folded into the answer. |
| `Criterion` | `string` | `""` | the test that ended the iteration: `LeastSquaresResidual`, `LeastSquaresNormal` or `LeastSquaresCondition`; empty when the exact answer x = 0 was returned without a step. |
| `ResidualNorm` | `float64` | 0 | the achieved ‖b − A·x‖₂, recomputed from the returned x. |
| `NormalResidual` | `float64` | 0 | the achieved ‖Aᵀ(b − A·x)‖₂, recomputed the same way. |
| `MatrixNorm` | `float64` | 0 | the iteration's running estimate of ‖A‖. |
| `Condition` | `float64` | 0 | the iteration's running estimate of cond(A). |
| `Converged` | `bool` | `false` | true when a residual or normal-equations test fired; a condition stop leaves it false, so a caller must treat that answer as a warning rather than a solution. |
The three criterion names are the exported constants
The same calls exist in the root package under one import:
`tensor.Solve`, `tensor.Cholesky`, `tensor.SpSolve` and the rest.
### Package `signal`
Transforms, spectra, filters and stencils. The package covers the Fourier, cosine,
sine and wavelet transforms, the spectral estimators, IIR filter design and
application, sample-rate conversion, the Hilbert envelope, convolution and pooling,
rank filters, spatial stencils, state-space estimation and time-series models.
Every call takes whole arrays and returns whole arrays, and an array is an immutable
value, so no call modifies its input. The package holds no state between calls: a
design returns the direct-form coefficients `b` and `a`, and the caller hands those
to `FilterApply` for one pass or to `Filtfilt` for a zero-phase forward and backward
sweep. There is no streaming filter object, no transform plan to reuse, and no
batched or multi-channel entry point: `WelchPSD`, `STFT`, `Spectrogram`, the
resamplers, the filter application and the wavelet transforms take one rank-1
signal per call, so a stack of channels is looped by the caller. The estimators and
resamplers also refuse a complex array; the Fourier transforms are the complex
path. The spectral estimators take `fs`, a sample rate in hertz, and so does every
filter design, whose cutoff or band edges must lie strictly inside `(0, fs/2)`. A
spectral estimate is one-sided unless the call says otherwise, and a wavelet
transform packs its coefficients as `[A_levels, D_levels, …, D_1]`, the deepest
approximation first and the finest detail last.
#### Fourier transforms
| Call | What it does |
|---|---|
| `FFT(a)` | Returns the forward DFT of a rank-1 array as a complex array of the same length, reading real, integer and complex input alike; refuses an empty array and any rank above 1. |
| `IFFT(a)` | The inverse of `FFT`, scaled by `1/n`; refuses an empty array and any rank above 1. |
| `FFT2(a)` | Returns the 2-D DFT of an `(H, W)` array as an `(H, W)` complex array, each row transformed then each column; refuses an empty array or a rank other than 2. |
| `IFFT2(a)` | The inverse 2-D DFT, scaled by `1/(H·W)`. |
| `FFT3(a)` | Returns the 3-D DFT over shape `(D, H, W)`; refuses a rank other than 3. |
| `IFFT3(a)` | The inverse 3-D DFT, scaled by `1/(D·H·W)`. |
| `FFTN(a, dims)` | Returns the N-D DFT along the dimensions in `dims`, or along every dimension when `dims` is empty; a dimension listed twice is transformed twice. Refuses out-of-range or zero-length dimensions. |
| `IFFTN(a, dims)` | The inverse N-D DFT over the same `dims`, dividing by the product of the transformed extents. |
| `RFFT(a)` | The real-input DFT: a rank-1 real array in, the non-redundant `n/2+1` complex half-spectrum out; refuses a complex array and an empty one. |
| `IRFFT(a, n)` | The inverse of `RFFT`: the half-spectrum back to a real signal of length `n`, where `n = 0` means `2·(len−1)` (or 1 for a lone DC bin). Refuses a real input, a spectrum that is not rank-1, and a length that does not match the spectrum. |
| `FFTFreq(n, d)` | Returns the `n` DFT sample frequencies for spacing `d` in the standard FFT order, `[0, 1/n, …, −1/2, …, −1/n]/d`, with `d = 0` read as 1 and a non-positive `n` answering an empty array. |
#### Cosine and sine transforms
The orthogonal transforms of types I to IV, all orthonormal, so
`IDCT(DCT(x, k), k)` and `IDST(DST(x, k), k)` restore `x`.
| Call | What it does |
|---|---|
| `DCT(x, kind)` | Returns the orthonormal discrete cosine transform of type `kind` (1 to 4) of a rank-1 vector; refuses a kind outside 1 to 4, a complex or non-vector input, an empty vector, and a type I of fewer than two points. |
| `IDCT(x, kind)` | The inverse orthonormal DCT, the transpose partner of the forward transform of the same kind; refuses a kind outside 1 to 4 and the same input checks. |
| `DST(x, kind)` | Returns the orthonormal discrete sine transform of type `kind` (1 to 4) of a rank-1 vector, under the `DCT` input checks. |
| `IDST(x, kind)` | The inverse orthonormal DST of the same kind. |
#### Non-uniform transform
| Call | What it does |
|---|---|
| `NUFFTType1(x, c, n)` | Computes `f_k = Σ_j c_j·e^{2πi·k·x_j}` for `k = 0…n−1` by Gaussian gridding, so the answer carries the gridding error of a few digits rather than the exactness of the direct sum. `x` holds the non-uniform coordinates in `[−1/2, 1/2)` and `c` the complex values; refuses an out-of-range or NaN coordinate, mismatched lengths, a non-positive output size and non-real coordinates. |
#### Spectral estimation
| Call | What it does |
|---|---|
| `STFT(x, opts)` | Returns the complex frames of the short-time Fourier transform as a `(frames × segment)` array, row `t` holding the spectrum of `x[t·hop : t·hop+segment]` under the window, `hop = segment − overlap`; refuses a segment outside `[2, n]`, an overlap outside `[0, segment)`, a complex signal and an unknown window name. |
| `Spectrogram(x, fs, opts)` | Returns the one-sided power spectrogram as a `(frames × segment/2+1)` array in units of `x²/Hz`, each frame the periodogram of its windowed segment under the same doubling and window-power normalisation Welch's estimate uses, so averaging the frames reproduces `WelchPSD` on the same geometry; refuses a non-positive or infinite `fs` on top of the `STFT` checks. |
| `WelchPSD(x, fs, segment, overlap, window)` | Returns the frequency grid and the averaged one-sided power spectral density of a rank-1 real signal: `segment/2+1` bins from the `(n−overlap)/(segment−overlap)` segments the signal fills, the doubling applied away from DC and Nyquist, the window's power normalising the scale, so white noise of variance `σ²` estimates `σ²` across the band. Refuses a segment outside `[2, n]`, an overlap outside `[0, segment)`, a non-positive or infinite `fs`, a complex signal and an unknown window name. |
| `LombScargle(times, values, minFreq, maxFreq, nFreq)` | Returns the frequency grid and the normalised Lomb-Scargle periodogram of unevenly sampled observations over `nFreq` frequencies evenly spaced from `minFreq` to `maxFreq` inclusive, with the classical normalisation that peaks near `A²·n/(4·var(values))` for a pure sinusoid of amplitude `A`. Refuses a time base shorter than three points, a length mismatch, an all-equal time base, a non-positive variance, a complex array and a range that does not satisfy `0 < minFreq ≤ maxFreq`. |
#### Poisson solvers
| Call | What it does |
|---|---|
| `SolvePoissonPeriodic(f, lx, ly)` | Solves `−Δu = f` on the period square `[0, Lx] × [0, Ly]` on the grid carried by the shape of `f`, returning a float64 array of the same shape with the zero Fourier mode set to zero. Refuses a non-float64 `f`, a rank other than 2, a dimension below 2, a non-positive side and a nonzero mean. |
| `SolvePoissonDirichlet(f, lx, ly)` | Solves `−Δu = f` with `u = 0` on the whole boundary, over the interior of the grid; the boundary entries of `f` play no role. Refuses a non-float dtype, a grid under 3×3 and a non-positive side length. |
| `SolvePoissonNeumann(f, lx, ly)` | Solves `−Δu = f` with zero normal derivative on the whole boundary, every grid sample an unknown and the constant mode fixed to zero. Refuses a non-float dtype, a grid under 3×3, a non-positive side and a source whose trapezoidal-weighted sum does not vanish, the operator's own compatibility condition. |
#### Filter design
Each design returns the direct-form coefficients `b` (numerator) and `a`
(denominator, `a[0] = 1`) at a sample rate `fs`, with the passband edge or the
band edges prewarped to the bilinear axis and the answer exact at the mapped
frequencies. All of them refuse an order below 1, a non-positive or infinite `fs`,
and an edge outside `(0, fs/2)`; the band forms additionally require
`0 < edge1 < edge2 < fs/2`.
| Call | What it does |
|---|---|
| `ButterworthLowPass(order, fs, cutoff)` | The maximally flat low-pass: −3 dB at `cutoff`, unity at DC. |
| `ButterworthHighPass(order, fs, cutoff)` | The high-pass mirror, sharing the low-pass poles with its zeros at `z = 1`: −3 dB at the same cutoff, unity at Nyquist. |
| `ButterworthBandPass(order, fs, edge1, edge2)` | The maximally flat band-pass spanning `edge1` to `edge2`; the prototype's order doubles through the band move. |
| `ButterworthBandStop(order, fs, edge1, edge2)` | The maximally flat band-stop over the same band. |
| `ChebyshevLowPass(order, fs, cutoff, rippleDB)` | The type I equiripple low-pass: the passband oscillates between 0 and `−rippleDB`, the edge is the last touch of `−rippleDB`; refuses a non-positive `rippleDB`. |
| `ChebyshevHighPass(order, fs, cutoff, rippleDB)` | The type I mirror above the edge. |
| `ChebyshevBandPass(order, fs, edge1, edge2, rippleDB)` | The type I band-pass; the order doubles through the band move. |
| `ChebyshevBandStop(order, fs, edge1, edge2, rippleDB)` | The type I band-stop. |
| `InverseChebyshevLowPass(order, fs, cutoff, stopbandDB)` | The type II low-pass: flat through the edge, the stopband bottoming out at `−stopbandDB` and equiripple beyond it; refuses a non-positive `stopbandDB`. |
| `InverseChebyshevHighPass(order, fs, cutoff, stopbandDB)` | The type II mirror above the edge. |
| `InverseChebyshevBandPass(order, fs, edge1, edge2, stopbandDB)` | The type II band-pass. |
| `InverseChebyshevBandStop(order, fs, edge1, edge2, stopbandDB)` | The type II band-stop. |
| `CauerLowPass(order, fs, cutoff, rippleDB, stopbandDB)` | The elliptic low-pass: equiripple within `rippleDB` in the passband and not above `−stopbandDB` in the stopband, with the narrowest transition of any design at the order and its zeros finite and on the unit circle. Refuses a `rippleDB` that is not positive or a `stopbandDB` not above it. |
| `CauerHighPass(order, fs, cutoff, rippleDB, stopbandDB)` | The elliptic mirror above the edge. |
The designs hand back direct-form coefficients, and direct-form filtering loses
digits as the order climbs; past roughly order eight the caller is expected to
split the design into second-order sections.
#### Filtering a signal
| Call | What it does |
|---|---|
| `FilterApply(b, a, x)` | Runs the direct-form-II-transposed recursion `y[n] = Σ b_m·x[n−m] − Σ a_m·y[n−m]` over a rank-1 real signal, the output as long as the input. The coefficient lists may differ in length (the shorter is zero-padded), `a[0]` must be non-zero and is normalised away, float32 and float64 keep their dtype and other real dtypes widen to float64. Refuses a complex or higher-rank signal, an empty coefficient list and a zero `a[0]`. |
| `Filtfilt(b, a, x)` | Filters the rank-1 real signal forwards and backwards with the same transfer function and returns a result the length of `x` whose magnitude response is the square of the one-pass filter's and whose phase is zero, so a passband sinusoid comes out aligned with its input. Each end is extended by an even reflection of `pad = 3·(nfilt−1)` samples, the edge sample not repeated, and both pad regions are cropped away afterwards. Refuses a signal no longer than the pad, an empty coefficient list and a zero `a[0]`. |
#### Windows
Nine tapers, each in the symmetric (`periodic = false`) and the periodic
(`periodic = true`) convention: the symmetric form divides its argument by `n−1`
so the first and last samples coincide, the periodic form divides by `n` so the
sequence is one exact period of its underlying shape. Every builder returns a
fresh `n`-sample `[]float64`, every one refuses `n` below 1, and a one-sample
window is the single value 1 in both conventions. `WindowKaiser` additionally
refuses a `beta` that is negative, NaN or infinite.
| Call | What it does |
|---|---|
| `WindowHann(n, periodic)` | The raised cosine `0.5 − 0.5·cos(2πx)`, zero at the edges in both conventions, −6 dB per octave sidelobe roll-off. |
| `WindowHamming(n, periodic)` | The raised cosine on a pedestal, `0.54 − 0.46·cos(2πx)`: the pedestal cancels Hann's first sidelobe at the cost of a floor the outer sidelobes never drop below. |
| `WindowBlackman(n, periodic)` | The exact Blackman window `0.42 − 0.5·cos(2πx) + 0.08·cos(4πx)`: sidelobes below −58 dB, a main lobe twice Hann's. |
| `WindowBlackmanHarris(n, periodic)` | The four-term Blackman-Harris window: sidelobes below −92 dB, a main lobe three Hann lobes wide, the choice when dynamic range matters more than resolution. |
| `WindowBartlett(n, periodic)` | The triangle `1 − \|2x − 1\|`, the Fejér kernel of the box, non-negative everywhere and zero at both edges. |
| `WindowKaiser(n, beta, periodic)` | The modified Bessel taper `I0(beta·sqrt(1 − r²))/I0(beta)` over `r = 2x − 1`, the adjustable compromise between main lobe width and sidelobe height; `beta` 0 is the box, near 5 the sidelobes sit around −30 dB, near 9 around −60 dB. |
| `WindowFlatTop(n, periodic)` | The five-term generalised cosine whose main lobe is flat to within a hundredth of a decibel, so a spectral line's amplitude reads true wherever it falls between bins; its edge samples are slightly negative, so it is for amplitude metrology, not for filtering. |
| `WindowCosine(n, periodic)` | The cosine (sine) window `sin(πx)`, one positive half-period. |
| `WindowBox(n, periodic)` | The untapered box: `n` ones. The `periodic` flag changes nothing here and exists only for signature uniformity. |
`STFT` and `Spectrogram` read an empty window name as `"hann"`; `WelchPSD` has no
default, so an empty name is an error there. All three accept only `"hann"`,
`"hamming"` and `"box"`, resolved through the periodic forms of the catalogue.
#### Generators
| Call | What it does |
|---|---|
| `Chirp(n, f0, f1, rate)` | `n` samples of a linear frequency sweep from `f0` through `f1` at `rate` samples per unit of time, reaching `f1` exactly at the last sample. Every phase comes from the closed form at that sample's own time, never from a recursive oscillator, so no drift accumulates and any single sample stands alone. Both sweep edges must stay strictly below the Nyquist frequency `rate/2`, magnitudes counted for negative edges. Refuses `n` below 1, a non-positive or non-finite rate and a non-finite edge; the one-sample chirp is the single zero. |
#### Resampling and the envelope
| Call | What it does |
|---|---|
| `Decimate(data, factor, taps)` | Reduces the sample rate by the integer `factor` behind a Kaiser tapered FIR whose passband ends at nine tenths of the new Nyquist and whose stopband floor of about 80 dB is reached before it, compensating the filter's group delay and keeping every `factor`-th sample. `taps` sets the filter length, a non-positive value meaning `32·factor+1`; the result holds about `(n − taps)/factor` samples and is empty rather than read past the end when the tap count leaves no sample with full context. Refuses a `factor` below 2, an empty series and a tap count at or above the length. |
| `Resample(data, up, down, taps)` | Converts the rate by the rational factor `up/down`, filtering on the up-sampled grid at the tighter Nyquist with the up gain folded in and keeping every `down`-th compensated sample. `taps` is the kernel length on the up-sampled grid, a non-positive value meaning `32·max(up, down)+1`. Refuses the identity `1/1`, a factor below 1, an empty series and a tap count above `up·n`. |
| `ResampleFourier(data, size)` | Resamples to exactly `size` samples by the Fourier (band-limited) definition: the spectrum's bins are kept and zero-padded or truncated at the fold, scaled so the amplitudes carry over. Exact for series band-limited below the new Nyquist and treats the input as one period, so energy past the new Nyquist is lost. Refuses a non-vector or empty series, a complex one, and a target size below 1. |
| `AnalyticSignal(data)` | Builds the analytic signal `z = x + i·H(x)`: negative frequencies removed, positive ones doubled, the DC and Nyquist bins left alone. The Fourier definition treats the series as one period, so it is exact for an integer number of tones. Refuses a complex or empty rank-1 signal. |
| `Envelope(data)` | The instantaneous amplitude of a series, the modulus of its analytic signal: for a narrowband series this traces the curve a peak detector would find, without the smoothing lag. |
#### Wavelets
The discrete transforms pack `[A_levels, D_levels, …, D_1]` and the Haar pair
conserves energy exactly.
| Call | What it does |
|---|---|
| `DWT(x, levels)` | Returns the Haar transform of a rank-1 real signal over `levels` scales with the periodic boundary; `levels` must be at least 1 and at most `log2(n)`, and Parseval holds for the orthonormal Haar basis. |
| `IDWT(coef, levels)` | Inverts `DWT` over the same level count and layout, widening the coefficients through the float accessor, so every real dtype `DWT` accepts inverts here as well. |
| `DaubechiesDWT(x, family, levels, mode)` | Returns the `dbN` transform over `levels` scales in the same packed layout. `DWTPeriodic` refuses a length that does not leave every live block a multiple of the `2N`-tap filter; `DWTZeroPad` pads the tail to the next such length first, so any length transforms. The periodic transform conserves energy exactly, a zero-padded one conserves the energy of the padded signal. `levels` must be at least 1. |
| `DaubechiesIDWT(coef, family, levels, mode)` | Inverts `DaubechiesDWT` over the same family, level count and mode, undoing the packed layout deepest band first. The coefficient vector must satisfy the length contract the forward transform produced; the mode argument gates exactly that contract, since the inverse bank itself is the periodic one. |
| `CWT(x, wavelet, scales, dt)` | Returns the continuous wavelet transform of a rank-1 real signal sampled at spacing `dt` as a `(len(scales), n)` complex array, row `k` the transform at `scales[k]`. The convolution runs through the FFT zero-padded to `2n` and the wavelet is L1-normalised per scale, so amplitudes stay comparable across scales. Morlet yields the full complex transform, MexicanHat a real result with zero imaginary part. Refuses a signal that is not rank-1 real or is empty, a `dt` that is not positive and finite, an empty scale list, a scale that is not positive and finite, and a `CWTWavelet` other than the two constants. |
#### Correlation and time series
| Call | What it does |
|---|---|
| `Autocorrelate(x, maxLag)` | Returns the sample autocorrelation at lags `0…maxLag` with the mean removed and every value normalised by the lag-zero sum, the biased estimator the Durbin-Levinson recursion and the Bartlett-band theory are written for. `maxLag` must lie in `[0, n−1]`; the result starts at 1 unless the signal is constant, whose zero power makes every lag 0, lag zero included. |
| `CrossCorrelate(x, y)` | Returns the raw cross-correlation of two equal-length real signals at every lag as `2n−1` entries, index `i` carrying lag `i−(n−1)` and the value `Σ_t x[t+lag]·y[t]` over the overlapping `t`. No mean removal and no normalisation: correlation as the inner product of shifted copies. |
| `PartialAutocorrelate(x, maxLag)` | Returns the partial autocorrelation at lags `1…maxLag` by the Durbin-Levinson recursion over the biased autocorrelation, `pacf[k]` being the last coefficient of the order-`k` AR fit. `maxLag` must lie in `[1, n−2]`. |
| `EstimateAR(x, order)` | Fits the order-`p` autoregression `x_t − μ = Σ_j φ_j·(x_{t−j} − μ) + e_t` by the Yule-Walker equations over the biased autocovariance, solved by Durbin-Levinson. The result carries the coefficients, the innovation variance, the concentrated Gaussian likelihood over the whole series and both information criteria. Refuses an order below 1, a series too short for the lag, non-finite or complex data, and autocovariances that do not describe a stationary process. |
| `EstimateARMA(x, p, q, opts)` | Fits `ARMA(p, q)` by the Hannan-Rissanen innovations method: an order-`m` proxy autoregression whose residuals stand in for the unobserved innovations, then one least-squares regression of the demeaned series on its own lags and the lagged residuals. A `q` of 0 is routed to `EstimateAR`, which solves the pure AR case exactly. The estimates carry more sampling noise than a maximum-likelihood fit would, so tolerances set against them should be looser. Refuses negative orders, `p + q = 0`, a proxy order below `p+q+1`, a criterion that is neither `"aic"` nor `"bic"` and a series too short to leave a regression window worth fitting. |
| `SelectARMA(x, maxAR, maxMA, opts)` | Searches the order grid `0…maxAR × 0…maxMA` for the cell the chosen criterion ranks best, fitting every cell with `EstimateARMA`, skipping the `(0, 0)` cell and any cell whose fit fails, and reporting the last failure when nothing on the grid could be fitted. Refuses negative grid bounds and a grid that holds no candidate. |
| `ARMASpectrum(res, nFreq)` | Returns the fitted model's theoretical one-sided spectrum `σ²·\|Θ(e^{−2πif})\|² / \|Φ(e^{−2πif})\|²` at `nFreq` frequencies evenly spaced from 0 to the Nyquist frequency 0.5 inclusive, on the same convention `WelchPSD` prints, so model and data line up bin for bin at `fs = 1` without a scale fudge. Refuses fewer than two frequencies, a nil model, a non-positive innovation variance or a non-finite coefficient, and names the frequency of a pole of `Φ` that sits on the unit circle instead of answering infinities. |
#### State-space estimation
| Call | What it does |
|---|---|
| `KalmanFilter(z, transition, observation, opts)` | Runs the linear Kalman filter over the measurement stack `z` under `x_{t+1} = F·x_t + w_t`, `z_t = H·x_t + v_t`, predicting with `F` and correcting with a Joseph-form update, and accumulating the exact Gaussian log-likelihood of the innovations. A rank-1 `z` holds `n` scalar observations, a rank-2 `z` holds `n` rows of `m` channels. Refuses a non-square transition, a shape mismatch, an asymmetric noise covariance, a singular measurement noise, a non-finite value anywhere and an innovation covariance that loses positive definiteness, naming the step. |
| `ExtendedKalmanFilter(z, transition, observation, opts)` | The same recursion on the nonlinear model `x_{t+1} = f(x_t) + w_t`, `z_t = h(x_t) + v_t`: the mean propagates through `f`, the covariance through the linearisation `F = ∂f/∂x`, and the correction uses `H = ∂h/∂x`. The Jacobians come from the options when supplied and from central differences otherwise. Being the linear filter on local linear models, it is blind to the curvature of `f` and `h`, so a strongly bent observation map wants the unscented filter. Refuses a state dimension it cannot fix from the options and reports a failing callback or Jacobian together with the step it failed at. |
| `UnscentedKalmanFilter(z, transition, observation, opts)` | Carries the state distribution through `f` and `h` to second order by the deterministic sigma-point set `x̂ ± sqrt(d+λ)·L[:, i]`, `L` the Cholesky factor of `P`, whose weighted moments reconstruct the predicted mean and covariance. The update carries no Joseph form, so `P` leaves it as `P⁻ − K·S·Kᵀ` mirrored into its symmetric average, and the next predict's Cholesky factorisation is what enforces positive definiteness, naming the step when it fails. The log-likelihood accumulates exactly as in the linear filter, and on a linear model the sigma transforms are exact, so the filter degenerates to the Kalman answer to rounding. |
#### Rank filters and smoothing
| Call | What it does |
|---|---|
| `MedianFilter(x, window)` | Returns the running median of a rank-1 signal over an odd window, removing isolated spikes whole while holding monotone ramps and edges still. The window must be odd, at least 3 and no longer than the signal, and a NaN in a window propagates into that output sample. |
| `MedianFilter2D(img, window)` | The same over a square odd window of a rank-2 image, the standard impulse-noise cleaner: salt-and-pepper dots vanish while steps between regions keep their corners. The window must be odd, at least 3 and fit both dimensions. |
| `RankFilter(x, window, k)` | Returns the `k`-th order statistic (ascending, 0-based) of each window of a rank-1 signal: rank 0 is the running minimum, `window−1` the running maximum, the middle rank the median `MedianFilter` takes. Windows near a boundary are truncated to the samples that exist, so the output is complete without padding, and the requested rank scales to the truncation. The window must be odd, at least 3, no longer than the signal, and `k` must lie in `[0, window)`. |
| `RankFilter2D(img, window, k)` | The same over a square window of a rank-2 image: rank 0 is erosion, `window²−1` is dilation, the middle rank the median. The window must be odd and at least 3, must fit both dimensions, and `k` must lie in `[0, window²)`. |
| `SavitzkyGolay(data, window, order)` | Smooths a rank-1 signal with a Savitzky-Golay polynomial filter, `window` the odd number of samples per fit and `order` the polynomial degree; a polynomial of degree at most `order` passes through unchanged. Every edge point owns a truncated window fitted at the sample's own position, so the result is as long as the input without padding. Refuses a negative order, an order above `window/2` (the truncated edge fits would be underdetermined), a window that is not odd or is below 3, a window longer than the signal, a complex signal and weights that overflow. |
#### Stencils
| Call | What it does |
|---|---|
| `Gradient1D(y, dx)` | Returns the central-difference derivative of a rank-1 uniform grid signal of spacing `dx`, interior points on the second-order stencil and the two endpoints on the first-order one-sided stencil, so the result is as long as the input. Refuses a rank other than 1, fewer than two points, a zero spacing and a complex signal. |
| `Laplacian(a, spacings…)` | Returns the second-derivative Laplacian of a grid signal: one spacing for rank 1, two (`dx`, `dy`) for a row-major rank-2 grid on the 5-point stencil, three for rank 3 on the 7-point stencil. Boundary points copy their nearest interior value, the boundary condition being the caller's. Refuses a rank outside 1 to 3, the wrong spacing count, a zero spacing and a degenerate extent (every axis at least 2 points, every axis of a 2-D or 3-D grid at least 3). |
#### Convolutions
| Call | What it does |
|---|---|
| `Conv1D(input, kernel, bias, stride, padding, dilation)` | The 1-D forward pass: `(N, C_in, L)` input, `(C_out, C_in, kL)` kernel, `(N, C_out, L_out)` output, NCL layout, `bias` optional and applied per output channel. Refuses a complex input or kernel, a channel mismatch, a rank other than 3, a non-positive stride, a negative padding, a kernel that does not fit, an empty output and a dilation other than 1, which is not implemented. |
| `Conv2D(input, kernel, bias, stride, padding)` | The 2-D forward pass: `(N, C_in, H, W)` input, `(C_out, C_in, kH, kW)` kernel, `(N, C_out, H_out, W_out)` output. The call is `Conv2DGroups` with `groups = 1`, under the same refusals. |
| `Conv2DGroups(input, kernel, bias, stride, padding, groups)` | The same pass with `groups`: a grouped convolution for `groups > 1` and a depthwise one when `groups == C_in`, the kernel's in-channels being `C_in/groups` per group. Refuses a group count below 1, an input or output channel count not divisible by it, a kernel in-channel count that does not match `C_in/groups`, a complex input or kernel, a rank other than 4, a non-positive stride, a negative padding, a kernel that does not fit and an empty output. |
| `Conv3D(input, kernel, bias, stride, padding, dilation)` | The 3-D forward pass: `(N, C_in, D, H, W)` input, `(C_out, C_in, kD, kH, kW)` kernel, `(N, C_out, D_out, H_out, W_out)` output, NCDHW layout. `padding` and `dilation` are per-axis triples; a dilation other than 1 is refused, not implemented. |
| `ConvTranspose2D(input, kernel, bias, stride, padding)` | The transposed convolution: `(N, C_in, H, W)` input, `(C_in, C_out, kH, kW)` kernel, `(N, C_out, H_out, W_out)` output with `H_out = (H−1)·stride − 2·padding + kH` and the same for `W`. Refuses a complex input, a rank other than 4, a kernel in-channel count that does not match the input, a non-positive stride, a negative padding and an empty output. |
#### Pooling
The maxima propagate a NaN in a window; the averages divide by the full kernel
size when `countIncludePad` is true and by the number of non-padded elements
otherwise. Padding is refused at or above the kernel, where a window would hold
no data.
| Call | What it does |
|---|---|
| `MaxPool1D(input, kernel, stride, padding)` | The maximum over each window of an `(N, C, L)` tensor. |
| `MaxPool2D(input, kernel, stride, padding)` | The maximum over each window of an `(N, C, H, W)` tensor. |
| `MaxPool3D(input, kernel, stride, padding)` | The same over a `(N, C, D, H, W)` tensor, `kernel`, `stride` and `padding` being per-axis triples. |
| `AvgPool1D(input, kernel, stride, padding, countIncludePad)` | The average over each window of an `(N, C, L)` tensor. |
| `AvgPool2D(input, kernel, stride, padding, countIncludePad)` | The average over each window of an `(N, C, H, W)` tensor. |
| `AvgPool3D(input, kernel, stride, padding, countIncludePad)` | The same over a `(N, C, D, H, W)` tensor with per-axis triples. |
| `AdaptiveMaxPool1D(input, outputL)` | Pools an `(N, C, L)` tensor to `outputL` by taking the maximum over the window from `floor(o·L_in/L_out)` to `ceil((o+1)·L_in/L_out)`, so every input sample lands in some window. |
| `AdaptiveMaxPool2D(input, outputH, outputW)` | The same floor-start, ceil-end convention on an `(N, C, H, W)` tensor; both output sizes must be at least 1. |
| `AdaptiveMaxPool3D(input, outputD, outputH, outputW)` | The same on a `(N, C, D, H, W)` tensor. |
| `AdaptiveAvgPool1D(input, outputL)` | The average over the same windows of an `(N, C, L)` tensor. |
| `AdaptiveAvgPool2D(input, outputH, outputW)` | The average over the same windows of an `(N, C, H, W)` tensor. |
| `AdaptiveAvgPool3D(input, outputD, outputH, outputW)` | The same on a `(N, C, D, H, W)` tensor. |
| `GlobalMaxPool1D(input)` | Reduces an `(N, C, L)` tensor to `(N, C, 1)`. |
| `GlobalMaxPool2D(input)` | Reduces an `(N, C, H, W)` tensor to `(N, C, 1, 1)`, the global maximum of a feature map. |
| `GlobalMaxPool3D(input)` | Reduces a `(N, C, D, H, W)` tensor to `(N, C, 1, 1, 1)`. |
| `GlobalAvgPool1D(input)` | Reduces an `(N, C, L)` tensor to `(N, C, 1)`. |
| `GlobalAvgPool2D(input)` | `AdaptiveAvgPool2D` reduced to `(1, 1)`, the global average pooling of modern CNNs. |
| `GlobalAvgPool3D(input)` | Reduces a `(N, C, D, H, W)` tensor to `(N, C, 1, 1, 1)`. |
Every one of them refuses a complex array, the rank that does not match its
dimensionality, an empty spatial dimension, a kernel or stride below 1, a negative
padding, a padding at or above the kernel, a window that does not fit the extent
and an output of zero extent; the two adaptive families additionally refuse an
output size below 1.
#### Accumulation
| Call | What it does |
|---|---|
| `SumKahan(a)` | Returns the sum of all elements by Kahan's compensated summation, which carries more of the small terms than a plain left-to-right accumulation when the magnitudes are mixed. Refuses a complex array. |
#### Options and results
**`STFTOptions`** tunes `STFT` and `Spectrogram`. The frame count follows from
the geometry: `(n − overlap)/(segment − overlap)`, at least one.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Segment` | `int` | required, must lie in `[2, n]` | The length of one frame in samples. A value outside that range is an error. |
| `Overlap` | `int` | `0` | The samples two neighbouring frames share; `segment/2` is the usual choice. Must lie in `[0, segment)`. |
| `Window` | `string` | `"hann"` for `""` | The taper: `"hann"`, `"hamming"` or `"box"`; any other name is an error. |
**`ARMAOptions`** tunes the Hannan-Rissanen estimation and the `SelectARMA`
grid search.
| Field | Type | Default | Effect |
|---|---|---|---|
| `HighAROrder` | `int` | `0` means `max(16, p+q+8)`, bounded by the data length | The order of the proxy autoregression whose residuals supply the MA stage; below `p+q+1` it is an error. |
| `Criterion` | `string` | `""` means `"aic"` | The information criterion `SelectARMA` minimises: `"aic"` or `"bic"`. Any other value is an error. |
**`ARMAResult`** is one fitted time-series model, in the convention
`x_t − μ = Σ_j φ_j·(x_{t−j} − μ) + e_t + Σ_k θ_k·e_{t−k}`, the innovations white
with variance `InnovationVariance`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `AR` | `[]float64` | empty only for a pure MA model | The coefficients `φ_1…φ_P`. |
| `MA` | `[]float64` | empty only for a pure AR model | The coefficients `θ_1…θ_Q`. |
| `InnovationVariance` | `float64` | set by the fit | The estimated variance `σ²` of `e_t`. A fit whose innovation variance does not come out positive is refused rather than returned. |
| `Mean` | `float64` | set by the fit | The sample mean the fit removed and reports back. |
| `LogLikelihood` | `float64` | set by the fit | The concentrated Gaussian likelihood of the innovations over the whole series, `−n/2·(log 2πσ² + 1)`, so the criteria of different models on one series sit on a common footing. |
| `AIC` | `float64` | set by the fit | `−2·LogLikelihood + 2k` with `k = P + Q + 1`, the variance counted as a parameter. |
| `BIC` | `float64` | set by the fit | `−2·LogLikelihood + k·log n`, the same `k` against the innovation count's logarithm. |
| `P`, `Q` | `int` | set by the fit | The orders the result carries. |
**`KalmanOptions`** carries the initial condition, the noise levels and the
filter-specific knobs. An unset array field takes its default; the extended and
unscented filters cannot infer the state dimension from their callbacks, so at
least one of `InitialState` and `InitialCovariance` must be set for them, and the
initial covariance must be symmetric positive definite.
| Field | Type | Default | Effect |
|---|---|---|---|
| `InitialState` | `*core.Array` | nil means a zero state of the inferred dimension | The initial mean `x̂_0`; must be a vector of one fixed length, finite. |
| `InitialCovariance` | `*core.Array` | nil means the identity | The initial covariance `P_0`, a symmetric positive-definite `d×d` matrix. |
| `ProcessNoise` | `*core.Array` | nil means zeros | The process noise covariance `Q`, a finite symmetric `d×d` matrix. |
| `MeasurementNoise` | `*core.Array` | nil means the identity | The measurement noise covariance `R`, a finite symmetric `m×m` matrix; it is factored every step, so a singular one is refused. |
| `TransitionJacobian` | `JacobianFunc` | nil means central differences, two evaluations per partial per step | The analytic `∂f/∂x` of the extended filter's transition. |
| `ObservationJacobian` | `JacobianFunc` | nil means central differences | The analytic `∂h/∂x` of the extended filter's observation. |
| `SigmaAlpha` | `float64` | `0` means `0.001` | The unscented spread `α`, read by `UnscentedKalmanFilter` only; a negative or NaN value, or a combination with `SigmaKappa` that leaves no positive scale, is an error. |
| `SigmaBeta` | `float64` | `0` means `2` | The unscented prior correction `β`, the standard 2 for a Gaussian prior; a negative or NaN value is an error. |
| `SigmaKappa` | `float64` | `0` | The unscented secondary scaling `κ`; NaN is an error. |
**`KalmanResult`** is one filtering pass over the measurement stack, `n`
measurements of `m` channels and a state of dimension `d`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `States` | `*core.Array` | set by the pass | The `(n × d)` stack of filtered means `x̂_{t|t}`, one row per measurement. |
| `Covariances` | `*core.Array` | set by the pass | The `(n × d × d)` stack of filtered covariances `P_{t|t}`, one symmetric positive-definite block per measurement. |
| `Innovations` | `*core.Array` | set by the pass | The `(n × m)` stack of one-step prediction errors `z_t − h(x̂_{t|t−1})`. |
| `InnovationCovariances` | `*core.Array` | set by the pass | The `(n × m × m)` stack of the innovation covariances `S_t` the likelihood reads. |
| `LogLikelihood` | `float64` | set by the pass | `Σ_t log N(z_t; h(x̂_{t|t−1}), S_t)`, the exact Gaussian likelihood of the measurement sequence under the model and the quantity noise and parameter estimation maximises. |
**`CWTWavelet`** names the analysing wavelet of `CWT`. The zero value names no
wavelet; pass one of the two constants.
| Constant | Value | Meaning |
|---|---|---|
| `Morlet` | `"morlet"` | The complex Morlet with `ω₀ = 5`, the time-frequency standard. |
| `MexicanHat` | `"mexicanhat"` | The real Ricker wavelet, the zero-mean second derivative of a Gaussian. |
**`DWTMode`** picks the boundary treatment of `DaubechiesDWT` and
`DaubechiesIDWT`. The zero value is `DWTPeriodic`; a value that is neither
constant is an error.
| Constant | Value | Meaning |
|---|---|---|
| `DWTPeriodic` | `0` | Treats the signal as one period of a periodic sequence. Every block keeps its exact energy, and the length must offer every level a multiple of the filter length to work on. |
| `DWTZeroPad` | `1` | Extends the signal with zeros at the tail to the next length the level tree needs, so any length transforms; the coefficients past the signal's own span carry the response of the step to zero at the seam. |
**`Daubechies`** names a member of the Daubechies wavelet family for
`DaubechiesDWT` and `DaubechiesIDWT`; `dbN` carries `N` vanishing moments and a
`2N`-tap filter pair. Haar is the `db1` case and keeps its own exact transform in
`DWT` and `IDWT`. Any other value is an error.
| Constant | Value | Meaning |
|---|---|---|
| `DB2` | `"db2"` | The 4-tap Daubechies wavelet with 2 vanishing moments. |
| `DB3` | `"db3"` | The 6-tap wavelet with 3 vanishing moments. |
| `DB4` | `"db4"` | The 8-tap wavelet with 4 vanishing moments. |
| `DB5` | `"db5"` | The 10-tap wavelet with 5 vanishing moments. |
| `DB6` | `"db6"` | The 12-tap wavelet with 6 vanishing moments. |
| `DB7` | `"db7"` | The 14-tap wavelet with 7 vanishing moments. |
| `DB8` | `"db8"` | The 16-tap wavelet with 8 vanishing moments. |
**`StateFunc`** is the type `func(x *core.Array) (*core.Array, error)`, the shape
of a model callback: the `f` of `x_{t+1} = f(x_t) + w_t` or the `h` of
`z_t = h(x_t) + v_t`. The input array is private to the call and may be kept
until the call returns; the output must be a real rank-1 array of one fixed
length.
**`JacobianFunc`** is the type `func(x *core.Array) (*core.Array, error)`,
returning the Jacobian of a `StateFunc` at `x` as an `(m × n)` float array, row
`i` holding the partials of output `i`. It is the type of
`KalmanOptions.TransitionJacobian` and `KalmanOptions.ObservationJacobian`; an
analytic Jacobian is always the better instrument, and a nil one is replaced by
central differences.
#### Errors
Every error carries the library's `tensor: ` prefix and names the call.
- A rank or shape the call does not take: refused with the shape it received
(`needs a 1-D array, got shape (2, 3)`, `input must be 4-D (N, C_in, H, W)`,
`the signal must be a vector`).
- An empty input where a transform needs samples: refused (`an empty array has no
FFT`, `the input must not be empty`, `the signal must not be empty`).
- A complex array where the call reads real values: refused by the estimators,
the resamplers, the filter application, the pooling and convolution kernels and
the Kalman filters.
- A transform parameter outside its range: an order below 1, a `fs` that is not
positive and finite, an edge at or beyond `fs/2`, a band whose second edge does
not exceed its first, a non-positive `rippleDB` or `stopbandDB`, a `stopbandDB`
not above `rippleDB`, a DCT or DST kind outside 1 to 4.
- A window parameter that cannot be honoured: a `segment` outside `[2, n]`, an
`overlap` outside `[0, segment)`, a window name that is not `"hann"`,
`"hamming"` or `"box"`, an odd-window filter given an even, below-3 or
oversized window, a rank outside `[0, window)` (or `[0, window²)`).
- A filter that cannot run: an empty coefficient list or `a[0] = 0` in
`FilterApply` and `Filtfilt`, a complex or non-vector signal, and a signal no
longer than `3·(nfilt−1)` in `Filtfilt`, which leaves nothing to return once
both transient regions are excluded.
- A resampling that cannot stand: a `factor` below 2 in `Decimate`, an identity
`up/down` in `Resample`, and a tap count that leaves nothing after the filter
delay.
- A wavelet length the mode cannot serve: `DWTPeriodic` refuses a length that does
not leave every live block a multiple of the `2N`-tap filter, `DWT` and
`DaubechiesDWT` refuse a `levels` below 1, and `DWT` refuses one above
`log2(n)`.
- A solve that has no solution: a nonzero mean in `SolvePoissonPeriodic`, a
nonzero trapezoidal mean in `SolvePoissonNeumann`.
- A time-series fit that carries no information: an order below 1, an order above
what the series can support, a non-positive innovation variance, a series too
short for the Hannan-Rissanen regression window, a criterion that is neither
`"aic"` nor `"bic"`, and a grid where no model could be fitted (the last
failure is reported).
- A Kalman pass that cannot continue: a non-square transition, a shape mismatch,
an asymmetric noise covariance, a singular measurement noise, an innovation
covariance that loses positive definiteness (naming the step), a failing model
callback or Jacobian (naming the step) and a state dimension the options do not
fix.
A numeric overflow in the Savitzky-Golay normal equations, a pole of a fitted
ARMA model's `Φ` on the unit circle in `ARMASpectrum`, and a coordinate outside
`[−1/2, 1/2)` in `NUFFTType1` are refused the same way, each naming the value.
#### Workflow
Design a low-pass, filter a two-tone series both ways for a zero-phase result, and
read the spectrum of the answer back out.
```go
package main
import (
"fmt"
"log"
"math"
"sourcedock.dev/petrbalvin/tensor"
"sourcedock.dev/petrbalvin/tensor/signal"
)
// A 5 Hz tone a design must pass, a 45 Hz tone it must attenuate: one
// filter pass lags the tone, the forward-and-backward sweep does not.
fmt.Printf("peak of the filtered spectrum: %.0f Hz over %d bins\n",
freqs.FloatAt(peak), psd.Len())
}
```
### Package `integrate`
Differential equations, quadrature, PDE evolution and finite elements.
The package keeps no state between calls: every solver takes the problem as
arguments and returns the answer.
It deliberately stops at the point where a solver would have to guess. It
offers no dense-output object (an event time is narrowed by re-integrating
the accepted step, and `IntegrateODEPath` and `IntegrateODESteps` return
exactly the states they name), no adaptive step size in the symplectic
family (adaptivity would destroy the property those methods exist for), no
projection of an inconsistent start onto a DAE's constraint manifold and no
order above one there, and no element order above P1 or mesh that is not
conforming. The gradient of a trajectory with respect to its parameters is
the `grad` package's to compute.
An ordinary differential equation is `y' = f(t, y)` with `f` returning the
derivative of the state. The state is rank 1, and the ODE family widens its
elements to `float64`, so an `int` or `float32` state integrates there; the
symplectic family accepts `float64` and `float32` positions and momenta
only, and a complex state is refused everywhere. Returned trajectories are
freshly allocated `float64` arrays, and inputs are never written to.
#### Initial value problems
| Call | What it does |
|---|---|
| `IntegrateODE(f, t0, t1, y0, opts)` | Integrates to `t1` with the adaptive Dormand-Prince 4(5) pair and returns `y(t1)`; the default route for a non-stiff problem. |
| `IntegrateRK4(f, t0, t1, y0, steps)` | The classical fixed-step fourth-order Runge-Kutta scheme over `steps` equal steps; returns `y(t1)`. No options, no adaptivity. |
| `IntegrateBackwardEuler(f, t0, t1, y0, steps, opts)` | Fully implicit Euler over `steps` equal steps, each solved by Newton over a numerical Jacobian and the library's LU solver; the entry-level stiff scheme. |
| `IntegrateBDF2(f, t0, t1, y0, opts)` | Variable-step BDF2; second order with adaptive step control, for stiff problems where an explicit pair is pinned by the fast mode. |
| `IntegrateBDFVar(f, t0, t1, y0, opts)` | Variable-step, variable-order BDF of orders one through five, with the run's counters reported through `BDFVarOptions.Stats`; the stiff workhorse. |
| `IntegrateROS4(f, t0, t1, y0, opts)` | The four-stage L-stable Rosenbrock-Wanner scheme ROS4, with the Jacobian taken by central differences once per step. The fourth order holds for autonomous systems: a genuinely time-dependent `f` loses the second-order local terms the tableau's time-derivative weights would carry and can degrade to first order globally, while the adaptive controller still holds its tolerance at the cost of more steps. |
| `IntegrateODEPath(f, t0, t1, y0, nSamples, opts)` | Returns the trajectory sampled at `nSamples` evenly spaced times, endpoints included; each interval is integrated on its own, so the step control never has to align with the sampling grid. |
| `IntegrateODESteps(f, t0, t1, y0, opts)` | Returns the trajectory at every accepted solver step, starting at `(t0, y0)` and ending at `(t1, y(t1))`; those nodes are where the local error was judged within tolerance, which is what post-processing and adjoint passes want. |
Every solver in this group accepts `t1 < t0` and integrates in the negative
direction, the step carrying the sign of the span. None of them returns a
truncated or silently wrong trajectory: an exhausted step budget, a collapsed
step size or an `f` that returns an array of the wrong shape is an error
naming the call, and the fixed-step `IntegrateRK4` additionally refuses a
non-finite derivative, having no step control to catch one.
#### Events along a trajectory
| Call | What it does |
|---|---|
| `IntegrateODEEvents(f, t0, t1, y0, watches, opts)` | Integrates exactly like `IntegrateODE` and, alongside the final state, returns every zero crossing of the watches, sorted by time, as `ODEEventHit` values. |
A watch is an `ODEWatch`: a scalar function of `(t, y)` and a `Direction`
filter. Direction `0` records both crossings, `+1` only a rising one (the
watch going from negative to non-negative) and `-1` only a falling one. The
watch is evaluated at the boundaries of every accepted step, and the first
accepted step is seeded with the watch value at its start state, so a
crossing inside it is detected like any other; the crossing itself is then
narrowed by bisection that re-integrates that step's interval. Watches are
compared only across accepted-step boundaries, so a watch that touches zero
and returns to its sign inside one step goes unnoticed, and a sign change is
searched strictly after `t0`.
#### Differential-algebraic equations
| Call | What it does |
|---|---|
| `IntegrateDAE(f, m, t0, t1, y0, steps, opts)` | Integrates the mass-matrix system `M·y' = f(t, y)` over `steps` equal implicit Euler steps and returns `y(t1)`. |
The mass matrix must be square and singular, with its rank deficiency
carried by whole zero rows matched by an equal count of whole zero columns:
the zero rows are the algebraic constraints, the zero columns the algebraic
variables. The scheme is first order at a fixed step, and consistent initial
values are the caller's contract: the solver verifies the initial residual on
the algebraic rows and refuses when it sits beyond the tolerance, but it does
not project a general start onto the constraint manifold. The index is
certified at `t0` by factoring the Jacobian of the algebraic rows against
the algebraic variables, which refuses an index-3 system such as the
Cartesian pendulum with multipliers.
#### Boundary value problems
| Call | What it does |
|---|---|
| `IntegrateBoundary(f, t0, t1, y0, bc, nSamples, opts)` | Solves `y' = f(t, y)` under `bc` by shooting and returns the trajectory at `nSamples` evenly spaced times; `states[0]` carries the initial state with the shooting unknowns replaced by the values that satisfy the end conditions. |
| `SolveBoundaryCollocation(f, t0, t1, y0, bc, opts)` | Solves the same problem by three-point Lobatto IIIA collocation on an adaptively refined mesh, returning a `CollocationSolution` with the mesh, the nodal states and the nodal slopes. |
`BoundaryConditions` states which components are prescribed where:
`len(Start) + len(End)` must equal the state length, the `Start` values are
read from `y0`, the `End` values come from `EndValues`, and a component may
carry a condition at both ends. The remaining components are the shooting
unknowns. The shooting root find is local: a start whose basin holds no
matching trajectory, or a trial that blows up on the way to `t1`, reports
the failure. Backward integration works.
#### Symplectic integrators
| Call | What it does |
|---|---|
| `IntegrateVerlet(accel, t0, t1, q0, p0, steps)` | Integrates a separable Hamiltonian system with unit masses by velocity Verlet (kick-drift-kick) over `steps` equal steps, returning the positions and momenta at `t0 + s·h`. |
| `IntegrateYoshida4(accel, t0, t1, q0, p0, steps)` | The same contract at fourth order, by Yoshida's composition of three leapfrog sub-steps per step. |
| `IntegrateMidpoint(gradH, t0, t1, q0, p0, steps, opts)` | Integrates the general Hamiltonian flow `dz/dt = J·∇H(z)`, `z = (q, p)`, by the implicit midpoint rule, each step's implicit stage solved by `optim.FindRootSystem`. |
`accel` returns the acceleration `-∂V/∂q` at a position and `gradH` returns
the stacked gradient `(∂H/∂q, ∂H/∂p)`. The step size stays fixed by design;
`positions[0]` is `q0` and `momenta[0]` is `p0`.
#### Quadrature and cubature
| Call | What it does |
|---|---|
| `IntegrateFunction(f, a, b, opts)` | Returns the definite integral of a scalar `f` over `[a, b]` and an estimate of the absolute error. Infinite bounds are accepted under a rational substitution, and a reversed interval (`a > b`) integrates in the negative direction. |
| `IntegrateFilon(f, a, b, k, opts)` | Returns `∫ f(x)·cos(kx) dx` and `∫ f(x)·sin(kx) dx` over `[a, b]` by a Filon-type scheme: the amplitude is interpolated through Gauss-Legendre nodes on each panel and the product with the carrier is carried exactly through per-panel weights, so the error tracks the smoothness of `f` alone and the cost does not grow with the frequency. A reversed interval negates both parts; `k = 0` degenerates to the plain integral with a zero sine part. |
| `GaussLegendreNodes(n)` | Returns the nodes (ascending) and weights of the `n`-point Gauss-Legendre rule over `[-1, 1]`, exact for polynomials up to degree `2n-1`; `n` must be between 1 and 128. |
| `IntegrateND(f, lower, upper, opts)` | Returns the integral of `f` over the hyperrectangle `[lower, upper]` element-wise, by globally adaptive bisection with product Gauss-Legendre rules (orders 3 and 5 per axis), always bisecting the worst box along its longest edge; no error estimate comes back, only the value. |
The slices `GaussLegendreNodes` returns are a shared cache and must be
treated as read-only, because a write would poison every later quadrature run
on the same node count. Every sampled scheme has one blind spot: a feature
entirely inside the gaps of the first rule's nodes, say a peak far narrower
than `(b-a)/n`, produces small values everywhere it samples and is missed
with a small error estimate, so known sharp features belong in their own
`IntegrateFunction` calls.
#### PDE evolution in one dimension
| Call | What it does |
|---|---|
| `IntegrateHeat1D(u0, kappa, dx, tFinal, dt, samples, boundL, boundR)` | Evolves `u_t = κ·u_xx` over the interior grid of `u0` (`n = u0.Len()`, `dx = L/(n+1)`) with the Dirichlet ends `boundL` and `boundR`, by Crank-Nicolson in steps of at most `dt`; returns the `(samples, n)` array of interior states evenly spaced in time, endpoints included. |
| `IntegrateWave1D(u0, v0, c, dx, tFinal, dt, samples)` | Evolves `u_tt = c²·u_xx` with zero Dirichlet ends and the initial velocity `v0`, by velocity Verlet at fixed step `dt`; same return contract as `IntegrateHeat1D`. |
| `IntegrateUpwindAdvection1D(u0, a, dx, tFinal, dt, samples, boundL, boundR)` | Evolves `u_t + a·u_x = 0` with the plain first-order upwind flux: monotone under CFL ≤ 1 and diffuse, the baseline the limited scheme is measured against. |
| `IntegrateAdvection1D(u0, a, dx, tFinal, dt, samples, boundL, boundR)` | The same equation with the Koren-limited upwind flux: total variation diminishing under CFL ≤ 1, third order at smooth faces and first order next to the inflow boundary. |
| `IntegrateAdvectionDiffusion1D(u0, a, kappa, dx, tFinal, dt, samples, boundL, boundR)` | Evolves `u_t + a·u_x = κ·u_xx`: the limited advection flux advanced explicitly over the Crank-Nicolson diffusion step, first order in time and second in space. With `a = 0` it reduces exactly to `IntegrateHeat1D`. |
Crank-Nicolson is stable for any `dt`, but accuracy wants `dt` of a few
`dx²/κ`; the wave and the advection solvers have genuine explicit CFL
budgets (`|c·dt/dx| ≤ 1` and `|a·dt/dx| ≤ 1`), which are enforced as errors
because the explicit stencils have no honest answer past them.
#### PDE evolution on a rectangle
| Call | What it does |
|---|---|
| `IntegrateHeat2D(u0, kappa, dx, dy, tFinal, dt, samples, boundBottom, boundTop, boundLeft, boundRight)` | Evolves `u_t = κ·Δu` on the rank-2 grid of `u0` by Peaceman-Rachford alternating direction implicit steps, unconditionally stable and second order in space and time; returns a `(samples, rows, cols)` array with the final state forced into the last sample. |
| `IntegrateWave2D(u0, v0, c, dx, dy, tFinal, dt, samples)` | Evolves `u_tt = c²·Δu` with the boundary ring held at zero, by the explicit central-difference stencil, with the CFL budget `c·dt·sqrt(1/dx² + 1/dy²) ≤ 1` enforced as an error; same return contract as `IntegrateHeat2D`. |
The grid is the rank-2 shape of the initial state: row `r` samples
`y = r·dy` and column `c` samples `x = c·dx`, the boundary ring is held
fixed and the interior carries the dynamics. The grid must be at least 3×3
to hold interior points.
#### Meshes
| Call | What it does |
|---|---|
| `GridTriangleMesh2D(x0, y0, width, height, m, n)` | Builds the structured triangulation of the axis-aligned rectangle with `m` by `n` cells, two triangles each; `m` and `n` must both be positive. |
| `NewTriangleMesh2D(vertices, triangles)` | Builds a mesh from a vertex table with two columns and a triangle table with three columns of vertex indices; an out-of-range index or a degenerate (collinear) triangle is an error. |
| `BoxTetraMesh3D(x0, y0, z0, width, height, depth, m, n, p)` | Builds the structured tetrahedralisation of the box with `m` by `n` by `p` cells, six positively oriented tetrahedra per cell (the Kuhn subdivision), conforming across cell faces. |
| `NewTetraMesh3D(vertices, tetrahedra)` | Builds a mesh from a vertex table with three columns and a tetrahedron table with four columns; a zero-volume or negatively oriented tetrahedron is an error naming the element and its vertices. |
| Method | What it does |
|---|---|
| `mesh.Vertices2()` | The vertex count of a `TriangleMesh2D`. |
| `mesh.Triangles3()` | The triangle count of a `TriangleMesh2D`. |
| `mesh.BoundaryEdges()` | The boundary edges as flat pairs of vertex indices, sorted; an edge is on the boundary when exactly one triangle carries it. |
| `mesh.Vertices3()` | The vertex count of a `TetraMesh3D`. |
| `mesh.Tetrahedra4()` | The tetrahedron count of a `TetraMesh3D`. |
| `mesh.BoundaryFaces()` | The boundary faces as flat triples of vertex indices, sorted lexicographically; a face is on the boundary when exactly one tetrahedron carries it. |
A triangle's orientation does not matter; a tetrahedron's does, because the
signed volume has to be positive.
#### Finite element Poisson solvers
| Call | What it does |
|---|---|
| `SolvePoissonFEM2D(mesh, f, opts)` | Solves `-∇·(κ∇u) = f` on the triangular mesh with P1 elements and returns the vertex values; `f` may be nil for the homogeneous equation. |
| `SolvePoissonFEM3D(mesh, f, opts)` | The tetrahedral counterpart of the same problem, on P1 elements over a `TetraMesh3D`. |
Both assemble the stiffness matrix per element (the conductivity evaluated at
the centroids when it varies), integrate Neumann fluxes on the prescribed
boundary edges or faces, eliminate Dirichlet values by lifting, and hand the
reduced system to the sparse Cholesky factorisation in `linalg`. The 2-D load
is lumped at the vertices from `f` at the centroids; the 3-D load is
integrated per tetrahedron with the 3×3×3 collapsed Gauss rule, exact through
degree 5. At least one Dirichlet node is required, because a purely Neumann
problem has no unique solution.
#### Options and results
**`ODEOptions`**: tunes the ODE drivers that take it (`IntegrateODE`,
`IntegrateODEPath`, `IntegrateODESteps`, `IntegrateODEEvents` and
`IntegrateBoundary`); the defaults are applied inside the solver when a field
is not positive.
| Field | Type | Default | Effect |
|---|---|---|---|
| `RelTol` | `float64` | `1e-6` | Relative part of the local error tolerance. Values `≤ 0` mean the default. |
| `AbsTol` | `float64` | `1e-9` | Absolute part of the local error tolerance. Values `≤ 0` mean the default. |
| `MaxSteps` | `int` | `100000` | Cap on attempted steps (a rejected step spends the budget like an accepted one) before the run is refused. Values `≤ 0` mean the default. |
**`ODEWatch`**: one scalar quantity to watch along a trajectory, passed to
`IntegrateODEEvents`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Function` | `func(t float64, y *tensor.Array) (float64, error)` | none, and a nil function is an error | The scalar `g(t, y)` whose zero crossings are reported. |
| `RelTol` | `float64` | `1e-6` | Together with `AbsTol`, scales the mesh-refinement estimate and floors the Newton convergence, an order of magnitude below it. Values `≤ 0` mean the default. |
| `AbsTol` | `float64` | `1e-9` | The absolute half of the same pair. Values `≤ 0` mean the default. |
| `InitialNodes` | `int` | `10` | Interval count of the uniform starting mesh. Values `≤ 0` mean the default. |
| `MaxNodes` | `int` | `256` | Cap on the refined mesh; the Newton matrix is factored by the dense LU, so the cap also bounds the per-round cost. Values `≤ 0` mean the default. |
| `MaxIterations` | `int` | `40` | Cap on the damped Newton rounds on each mesh. Values `≤ 0` mean the default. |
**`CollocationSolution`**: the solved problem, returned by
`SolveBoundaryCollocation`. The piecewise cubic Hermite through
`(Mesh, Values, Slopes)` is the collocation solution itself, so interpolating
between the nodes on that data is exact to the solver's tolerance.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Mesh` | `[]float64` | set by the solver | The node times. |
| `Values` | `[]*tensor.Array` | set by the solver | `Values[k]` is the state at `Mesh[k]`. |
| `Slopes` | `[]*tensor.Array` | set by the solver | `Slopes[k]` is the derivative `y' = f(t, y)` at `Mesh[k]`. |
| `RelTol` | `float64` | `1e-10` | Relative part of the target for the summed error estimate. Values `≤ 0` mean the default. |
| `AbsTol` | `float64` | `1e-12` | Absolute part of the same target. Values `≤ 0` mean the default. |
| `MaxIntervals` | `int` | `256` | Cap on subintervals; reaching it with the tolerance unmet is an error. Values `≤ 0` mean the default. |
**`FilonOptions`**: tunes `IntegrateFilon`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Panels` | `int` | `≤ 0` means automatic | The number of equal panels the interval splits into. Automatic keeps each panel at most about `Nodes` half-wavelengths of the carrier, the range the weights are built exact in. A forced count whose panels carry more than 4096 half-wavelengths is refused. |
| `Nodes` | `int` | `≤ 0` means `16` | The Gauss-Legendre node count per panel; the amplitude interpolant's degree is `Nodes−1`. Values outside `[2, 32]` are refused. |
**`CubatureOptions`**: tunes `IntegrateND`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Tolerance` | `float64` | `1e-10` | Bounds the global sum of box error estimates. Values `≤ 0` mean the default. |
| `MaxEvals` | `int` | `2000000` | Bounds the function evaluations; an exhausted budget is an error naming the achieved estimate. Values `≤ 0` mean the default. |
**`MidpointOptions`**: tunes the per-step implicit stage of
`IntegrateMidpoint`, which is a root find.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Tolerance` | `float64` | `1e-13` | Convergence tolerance of the stage solve, deliberately tight because the energy band wants it. Values `≤ 0` mean the default. |
| `MaxIterations` | `int` | `100` | Cap on the root find's iterations. Values `≤ 0` mean the default. |
**`FEMPoissonOptions`**: everything `SolvePoissonFEM2D` needs beside the
mesh and the source.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Kappa` | `float64` | none, and it must be positive when `KappaFunc` is nil | The constant conductivity used when `KappaFunc` is nil; a non-finite value is refused either way. |
| `KappaFunc` | `func(x, y float64) float64` | `nil` | The conductivity at a point, evaluated at the triangle centroids; a non-positive or non-finite value names the triangle. |
| `DirichletNodes` | `[]int` | none, and an empty slice is an error | The vertices with prescribed values. |
| `DirichletValues` | `[]float64` | none | The prescribed values, parallel to `DirichletNodes`. |
| `NeumannEdges` | `[]int` | none | Boundary edges as flat pairs of vertex indices; each receives half of `length·flux` at its midpoint into both endpoints. |
| `NeumannFlux` | `func(x, y float64) float64` | `nil`, which means zero flux | The flux `κ∂u/∂n` along each edge's outward normal. |
| `Ordering` | `linalg.SparseOrdering` | zero value, the natural order | Fill-reducing permutation for the sparse Cholesky factorisation; meshes usually want `SparseOrderingReverseCuthillMcKee`. |
**`FEMPoisson3DOptions`**: the same for `SolvePoissonFEM3D`, with faces
instead of edges.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Kappa` | `float64` | none, and it must be positive when `KappaFunc` is nil | The constant conductivity used when `KappaFunc` is nil; a non-finite value is refused either way. |
| `KappaFunc` | `func(x, y, z float64) float64` | `nil` | The conductivity at a point, evaluated at the tetrahedron centroids; a non-positive or non-finite value names the element. |
| `DirichletNodes` | `[]int` | none, and an empty slice is an error | The vertices with prescribed values. |
| `DirichletValues` | `[]float64` | none | The prescribed values, parallel to `DirichletNodes`. |
| `NeumannFaces` | `[]int` | none | Boundary faces as flat triples of vertex indices; each face's integral comes from the degree-2 edge-midpoint rule. |
| `NeumannFlux` | `func(x, y, z float64) float64` | `nil`, which means zero flux | The flux `κ∂u/∂n` along each face's outward normal. |
| `Ordering` | `linalg.SparseOrdering` | zero value, the natural order | Fill-reducing permutation for the sparse Cholesky factorisation. |
**`TriangleMesh2D`**: a conforming triangular mesh, built by
`GridTriangleMesh2D` or `NewTriangleMesh2D` and consumed by
`SolvePoissonFEM2D`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Vertices` | `[]float64` | none, filled by the constructor | The vertex coordinates as x,y pairs, two entries per vertex. |
| `Triangles` | `[]int64` | none, filled by the constructor | Three vertex indices per triangle. |
**`TetraMesh3D`**: a conforming tetrahedral mesh, built by
`BoxTetraMesh3D` or `NewTetraMesh3D` and consumed by `SolvePoissonFEM3D`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Vertices` | `[]float64` | none, filled by the constructor | The vertex coordinates as x,y,z triples, three entries per vertex. |
| `Tetrahedra` | `[]int64` | none, filled by the constructor | Four vertex indices per tetrahedron, in positive orientation. |
#### Errors
The package exports no error values and no error types: every failure comes
back as a plain non-nil error carrying the library's `tensor: ` prefix and,
in almost every case, the name of the call that refused. The conditions, by
family:
- **Any ODE solver**: a state that is not a rank-1 non-empty array, or is
complex; an `f` that returns an array of the wrong shape; an exhausted
`MaxSteps`; a step size that has collapsed below the resolution of `t`.
Each piece of that program is also a runnable example in the package's
test file, with the printed output checked by `go test`.
### Package `stats`
Distributions, descriptive summaries, classical inference and the statistical models that fit a response to a design. The distribution surface covers the normal, exponential, gamma, chi-square, Student t, Poisson, binomial, negative binomial, Weibull, lognormal and Pareto laws, the Dirichlet, the multivariate normal, and the noncentral chi-square, F and t families. Each univariate law is carried as far as the law goes: a density where one exists, a CDF and a quantile always, and a generator for the laws the library draws from. On that foundation sit the descriptives, the hypothesis tests, the contingency table analyses, the linear, generalised linear, regularised, robust and quantile regressions, the linear mixed model, principal components, clustering, hidden Markov models, kernel density estimation and Gaussian-process regression.
The package stops where the estimator ends. Nothing here is Bayesian, and every draw takes an explicit generator: no entry point reads a global source, so a fit is reproducible from its seed alone. The one search it deliberately will not run is the Gaussian-process hyperparameter fit: `MarginalLogLikelihood` is exposed as the objective, and the caller drives it from outside with the house minimiser, because the package has no edge to `optim` in the dependency graph. Complex-valued input and non-finite observations are refused rather than propagated, and a sample beyond the exactness contract of `TheilSenRegression` is refused rather than approximated.
#### Distribution foundations
| Call | What it does |
|---|---|
| `GammaLower(a, x)` | The regularised lower incomplete gamma `P(a, x)`, the CDF of a Gamma(shape `a`, rate 1) draw. Refuses `a ≤ 0` or `x < 0`, and errors when the power series or the continued fraction has not converged inside its budget of `1000 + 20·√a` rounds. |
| `GammaUpper(a, x)` | The regularised upper incomplete gamma `Q(a, x) = 1 - P(a, x)`, on the same foundation and with the same refusals as `GammaLower`. |
| `BetaIncomplete(x, a, b)` | The regularised incomplete beta `I_x(a, b)`, the CDF of a Beta(`a`, `b`) draw, by continued fraction with the symmetry switch at `x > (a+1)/(a+b+2)`. Refuses `a ≤ 0`, `b ≤ 0` or `x` outside `[0, 1]`. |
#### Normal and multivariate normal
| Call | What it does |
|---|---|
| `NormalCDF(x)` | Φ(x), the standard normal CDF, through one `Erfc`. Returns a plain `float64`: no error, for any `x`. |
| `NormalQuantile(q)` | The q-quantile of the standard normal, the inverse of `NormalCDF`, by a bracketed Newton walk through the density, with a reflected-tail bisection route below `2⁻⁵³`. Refuses `q` outside `[0, 1]`, NaN included, and answers an error at `q = 0` and `q = 1`, which have no finite quantile. |
| `MultivariateNormalLogDensity(mean, cov, x)` | The log density of N(`mean`, `cov`) at one point, through the Cholesky factor. `mean` and `x` rank 1, `cov` rank 2 symmetric positive definite. Refuses complex input, every non-finite entry, a mirror pair of the covariance that disagrees beyond a relative `1e-12`, and a non-positive pivot, naming the row. |
| `MultivariateNormalDraws(g, n, mean, cov)` | `n` draws from N(`mean`, `cov`) as an (n × d) array, one draw per row, from standard normals coloured by the Cholesky factor. Deterministic for a given generator state. Refuses a nil generator, `n < 1`, a shape or dimension mismatch, non-finite input, an asymmetric covariance and a non-positive pivot. |
#### Exponential
| Call | What it does |
|---|---|
| `ExponentialCDF(x, rate)` | `P(X ≤ x)` for X ~ Exponential(`rate`), evaluated through `Expm1` so the left tail keeps its digits. Refuses `rate ≤ 0` and a NaN `x`; `x ≤ 0` answers 0. |
| `ExponentialQuantile(q, rate)` | The q-quantile of Exponential(`rate`), by a bracketed Newton walk through the density. Refuses `q` outside `[0, 1]`, the open ends `q = 0` and `q = 1`, and a non-positive rate. |
| `ExponentialDraws(g, n, rate)` | `n` draws from Exponential(`rate`), mean 1/`rate`, by inverse CDF. Refuses `n < 1` or `rate ≤ 0`. |
#### Gamma
| Call | What it does |
|---|---|
| `GammaCDF(x, shape, rate)` | `P(X ≤ x)` for X ~ Gamma(`shape`, `rate`), the same parametrisation `GammaDraws` samples, through `GammaLower`. Refuses `shape ≤ 0` or `rate ≤ 0` and a negative `x`. |
| `GammaQuantile(q, shape, rate)` | The q-quantile of Gamma(`shape`, `rate`), by a bracketed Newton walk through the density, seeded at the mean `shape/rate`. Refuses the parameter contract of `GammaCDF` and the q contract of every quantile. |
| `GammaDraws(g, n, alpha, beta)` | `n` draws from Gamma(shape α, rate β) by Marsaglia-Tsang for α ≥ 1 and a boost with the exponential for α < 1. Refuses `n < 1` or a non-positive shape or rate. |
#### Chi-square
| Call | What it does |
|---|---|
| `ChiSquareCDF(x, df)` | `P(X ≤ x)` for X ~ χ²(`df`). Refuses `df < 1`. |
| `ChiSquareQuantile(q, df)` | The q-quantile of χ²(`df`), the critical value tables quote. Refuses `df < 1` and the q contract. |
| `ChiSquareDraws(g, n, df)` | `n` draws from χ²(`df`), the gamma(`df`/2, 2) law. Refuses `df < 1`, and `n < 1` through `GammaDraws`. |
#### Student t
| Call | What it does |
|---|---|
| `StudentTCDF(t, df)` | `P(T ≤ t)` for T ~ Student t(`df`), in closed form through the incomplete beta. Refuses `df < 1`. |
| `StudentTQuantile(q, df)` | The q-quantile of Student t(`df`) on the signed axis, with the same reflected-tail route the normal quantile takes. Refuses `df < 1`, `q` outside `[0, 1]`, and the open ends. |
| `StudentTDraws(g, n, df)` | `n` draws from Student t(`df`) as N(0,1) over the square root of χ²(`df`)/`df`; a χ² draw that underflowed to zero becomes a signed infinity rather than a NaN. Refuses `df < 1`. |
#### Poisson
| Call | What it does |
|---|---|
| `PoissonCDF(k, lambda)` | `P(N ≤ k)` for N ~ Poisson(`lambda`), through `ΓUpper(k+1, λ)`. Refuses `lambda ≤ 0`; `k < 0` answers 0. |
| `PoissonQuantile(q, lambda)` | The smallest `k` with `P(N ≤ k) ≥ q`, by doubling the bound then bisecting the integer grid. Refuses `lambda ≤ 0`, `q` outside `[0, 1]` and a bracket that never reaches `q`. `q = 0` answers 0. |
| `PoissonDraws(g, n, lambda)` | `n` draws from Poisson(`lambda`): the Knuth multiplication method for λ < 30, the normal approximation above. Refuses `n < 1` or `lambda < 0`; λ = 0 answers an array of zeros. |
#### Binomial
| Call | What it does |
|---|---|
| `BinomialCDF(k, trials, p)` | `P(X ≤ k)` for X ~ Binomial(`trials`, `p`), through `I_{1-p}(n-k, k+1)`. Refuses `trials < 1` or `p` outside `(0, 1)`; `k < 0` answers 0 and `k ≥ trials` answers 1. |
| `BinomialQuantile(q, p, trials)` | The smallest `k` with `P(X ≤ k) ≥ q`. Refuses `p` outside `(0, 1)` and the shared q contract. |
| `BinomialDraws(g, n, trials, p)` | `n` draws from Binomial(`trials`, `p`) by the exact per-trial uniform loop, so it costs O(`trials`) uniforms per draw. Refuses `n < 1`, `trials < 1` or `p` outside `[0, 1]`, the closed ends included. |
#### Negative binomial
| Call | What it does |
|---|---|
| `NegativeBinomialPMF(k, r, p)` | `P(X = k)` for the number of failures `X` before the `r`-th success, assembled in log space with `lgamma`. Refuses `r < 1` or `p` outside `(0, 1)`; `k < 0` answers 0. |
| `NegativeBinomialCDF(k, r, p)` | `P(X ≤ k)` by direct summation of the PMF terms under their multiplicative recurrence, so the sum carries no cancellation. Same refusals as the PMF. |
| `NegativeBinomialQuantile(q, p, r)` | The smallest `k` with `P(X ≤ k) ≥ q`, through the discrete bracketed search. Refuses `r < 1`, `p` outside `(0, 1)` and the shared q contract. |
#### Weibull
| Call | What it does |
|---|---|
| `WeibullDensity(x, k, lambda)` | The Weibull(k, λ) density, `(k/λ)(x/λ)^{k-1}e^{-(x/λ)^k}`, at `x ≥ 0`, and 0 below the support and at +∞. Refuses a shape or scale that is not finite and positive, and a NaN `x`. At `x = 0` the formula speaks: 0 for k > 1, 1/λ for k = 1, +∞ for k < 1. |
| `WeibullCDF(x, k, lambda)` | `P(X ≤ x)` for X ~ Weibull(k, λ), the closed form `1 - e^{-(x/λ)^k}` through `Expm1`. Same parameter refusals; `x ≤ 0` answers 0. |
| `WeibullQuantile(q, k, lambda)` | The q-quantile of Weibull(k, λ), the closed form `λ(-ln(1-q))^{1/k}`. Refuses the parameter contract and the open ends of the q range. |
#### Lognormal
| Call | What it does |
|---|---|
| `LognormalDensity(x, mu, sigma)` | The lognormal density with location μ and log-scale σ at `x > 0`, assembled in log space so a subnormal `x` still answers 0 instead of a NaN. Refuses a non-finite μ, a σ that is not finite and positive, and a NaN `x`; 0 at `x ≤ 0` and at +∞. |
| `LognormalCDF(x, mu, sigma)` | `P(X ≤ x)` for X ~ lognormal(μ, σ), the normal CDF at `(ln x - μ)/σ`. Same refusals; `x ≤ 0` answers 0. |
| `LognormalQuantile(q, mu, sigma)` | The q-quantile of lognormal(μ, σ) through the normal quantile, `e^{μ + σ·Φ⁻¹(q)}`. Refuses the location and scale contract and the q contract of `NormalQuantile`. |
#### Pareto
| Call | What it does |
|---|---|
| `ParetoDensity(x, xm, alpha)` | The Pareto density `α·x_m^α/x^{α+1}` at `x ≥ x_m`, and 0 below the support and at +∞. Refuses a scale or tail index that is not finite and positive, and a NaN `x`. |
| `ParetoCDF(x, xm, alpha)` | `P(X ≤ x)` for X ~ Pareto(x_m, α), the closed form `1 - (x_m/x)^α` through `Expm1`, so the answers just above the support keep their digits. Same parameter refusals; `x < x_m` answers 0. |
| `ParetoQuantile(q, xm, alpha)` | The q-quantile of Pareto(x_m, α), `x_m(1-q)^{-1/α}`. Refuses the parameter contract and the open ends of the q range. |
#### Dirichlet
| Call | What it does |
|---|---|
| `DirichletDensity(alpha, x)` | The Dirichlet density at the simplex point `x`, `Π x_i^{α_i-1}/B(α)`. Refuses fewer than two components, mismatched lengths, a concentration that is not finite and positive, a non-finite or negative `x`, and a point that does not sum to 1 within `1e-9`. A boundary `x_i = 0` answers +∞ below α_i = 1, contributes 1 at α_i = 1 and 0 above. |
| `DirichletMean(alpha)` | The mean vector `α_i/α₀`. Refuses fewer than two components and a concentration entry that is not finite and positive. |
| `DirichletMode(alpha)` | The interior mode `(α_i-1)/(α₀-k)`. Refuses the concentration contract and any `α_i ≤ 1`, which pushes the mode onto the boundary. |
| `DirichletDraws(g, n, alpha)` | `n` draws as an (n, k) array whose rows sum to one, each row scaling the independent gamma(α_i, 1) draws `GammaDraws` uses. Refuses `n < 1`, fewer than two components and the concentration contract. A row whose every gamma draw underflowed falls back to the uniform row. |
#### Noncentral chi-square, F and t
| Call | What it does |
|---|---|
| `NoncentralChiSquareCDF(x, df, lambda)` | `P(X ≤ x)` for X ~ χ²(ν, λ), the Poisson(λ/2) mixture of central χ²(ν + 2i) CDFs. Refuses `df < 1`, a negative or non-finite λ, a NaN `x`, and a noncentrality whose Poisson weight peak sits past the term budget (the mixture answers up to roughly 2·10⁵). λ = 0 answers through `ChiSquareCDF` exactly. |
| `NoncentralChiSquareDensity(x, df, lambda)` | The χ²(ν, λ) density, the same mixture with central densities. Refuses `df < 1`, a negative or non-finite λ, a NaN `x`, and the term budget. 0 below `x = 0`; at `x = 0` it is +∞ for `df = 1`, `e^{-λ/2}/2` for `df = 2` and 0 past that. |
| `NoncentralChiSquareQuantile(q, df, lambda)` | The q-quantile of χ²(ν, λ) by bisection, seeded near the mean ν + λ. Refuses `df < 1`, a negative or non-finite λ, and the shared q contract. |
| `NoncentralFCDF(x, df1, df2, lambda)` | `P(X ≤ x)` for X ~ F(ν₁, ν₂, λ), the Poisson(λ/2) mixture of the scaled central pieces, summed through `BetaIncomplete`. Refuses `df1 < 1` or `df2 < 1`, a negative or non-finite λ, a NaN `x`, and the term budget. λ = 0 is the central F exactly. |
| `NoncentralFQuantile(q, df1, df2, lambda)` | The q-quantile of F(ν₁, ν₂, λ) by bisection, seeded at 1. Refuses `df1 < 1` or `df2 < 1`, a negative or non-finite λ, and the shared q contract. |
| `NoncentralTCDF(t, df, delta)` | `P(T ≤ t)` for T ~ t(ν, δ), through Lenth's even and odd series. Refuses `df < 1`, a non-finite δ, and a series that misses its term budget (the walk answers δ up to about 440). δ = 0 answers through `StudentTCDF` and `t = 0` through Φ(-δ). |
| `NoncentralTQuantile(q, df, delta)` | The q-quantile of t(ν, δ) by bisection on the signed axis, the bracket growing both ways from the seed. Refuses `df < 1`, a non-finite δ and the shared q contract. |
#### Descriptives
| Call | What it does |
|---|---|
| `Median(a)` | The median as a `float64`, averaging the two middle values on even length (in integer arithmetic for an int sample, so the exact answer survives past 2⁵³). Refuses a complex or empty array and any non-finite sample. |
| `Std(a)` | The population standard deviation, ddof = 0. Refuses a complex or empty array. |
| `Var(a)` | The population variance, ddof = 0. Refuses a complex or empty array. |
| `VarSample(a)` | The unbiased sample variance, ddof = 1. Refuses a complex array and fewer than two elements. |
| `MedianAbsoluteDeviation(a)` | The median of `|x - median(x)|`, the robust scale that breaks down only when nearly half the sample is wild. Multiply by 1.4826 to read it as a standard deviation on Gaussian data. Refuses whatever `Median` refuses. |
| `TrimmedMean(a, fraction)` | The mean after dropping `fraction` of the samples from each tail, floored to whole samples. Refuses a fraction outside `[0, 0.5)`, a complex or empty sample, a non-finite sample, and a trim that leaves nothing. |
| `Quantile(a, qs)` | The quantiles in `qs`, each in `[0, 1]`, by linear interpolation on the sorted values (on the exact integer difference for an int sample). Refuses a complex or empty array, a non-finite sample, and any `q` outside `[0, 1]`. |
| `Histogram(a, bins)` | The counts and the edges of `bins` equal-width bins over `[min, max]`: an int count array of length `bins` and a float edge array of length `bins + 1`. The top bin absorbs the maximum; an all-equal sample widens to `[v-0.5, v+0.5]`. Refuses a complex or empty array, `bins < 1`, more than 1048576 bins, a non-finite sample, and a sample spanning more than the float64 range. |
| `BinCounts(a, bins)` | The count array of `Histogram` alone, with the same refusals. |
| `Histogram2D(x, y, xBins, yBins)` | The (xBins × yBins) count matrix and the two edge vectors of the paired samples. Bins are closed on the left and the last bin absorbs the maximum, exactly as `Histogram`'s are. Refuses unequal lengths, empty samples, complex input, a bin count below 1, a product above 1048576, and a non-finite sample. |
| `RollingMean(a, window)` | The mean of every window of the series: `n - window + 1` elements, element `i` summarising samples `[i, i+window)`. Refuses a non-vector or complex series and a window outside `[1, n]`. |
| `RollingSum(a, window)` | The total of every window, with the shape and refusals of `RollingMean`. |
| `RollingMin(a, window)` | The smallest sample of every window. A NaN never wins a comparison and an all-NaN window answers NaN. |
| `RollingMax(a, window)` | The largest sample of every window, with the same NaN rule as `RollingMin`. |
#### Inference
| Call | What it does |
|---|---|
| `CovarianceMatrix(a)` | The sample covariance matrix of an (n, p) observation array, with the `1/(n-1)` normalisation. Refuses a non-2-D array, fewer than two observations, complex observations and a non-finite observation. |
| `CorrelationMatrix(a)` | The Pearson correlation matrix, the covariance normalised by each column's sample standard deviation, with the diagonal exactly 1. Adds a refusal of a zero-variance column to the covariance contract. |
| `WelchTTest(a, b)` | Welch's t-test on two independent samples: the statistic, the Welch-Satterthwaite degrees of freedom (generally fractional) and the two-sided p-value from the closed-form t tail. Needs at least two observations per sample, real and finite, and refuses two samples of zero variance. |
| `ANOVAOneWay(groups)` | The one-way analysis of variance: the F statistic and the upper tail of F on (k-1, N-k) degrees of freedom. Needs at least two real, non-empty, finite groups with N > k, and refuses groups with no within-group variance or observations that all share one value. Distinct means with no within-group noise answer +∞ with p = 0. |
| `MannWhitneyU(a, b)` | The rank-based Mann-Whitney U test: U and the two-sided p-value from the normal approximation with the continuity correction and the tie-corrected variance. Refuses an empty, complex or non-finite sample, and data in which every observation is tied. |
| `KolmogorovSmirnovTest(a, b)` | The largest vertical distance between two empirical distribution functions and the asymptotic Kolmogorov p-value, accurate from a few dozen observations up. Refuses an empty, complex or non-finite sample. |
| `ChiSquareGoodnessOfFit(observed, expected)` | Pearson's test of an observed frequency table against expected ones: the statistic, the degrees of freedom (bins minus one) and the χ² upper tail. Needs equal lengths and at least two bins, every expected entry positive, and refuses non-finite input. |
| `BootstrapCI(data, statistic, level, resamples, seed)` | The percentile bootstrap of a statistic: the `alpha/2` and `1-alpha/2` quantiles of the bootstrap distribution, `alpha = 1 - level`, with the resampling on a generator seeded by `seed`. The statistic receives a fresh array per resample and may return its own error. Refuses empty or complex data, a level outside `(0, 1)` and fewer than two resamples. |
| `SpearmanRho(x, y)` | Spearman's rank correlation, computed as the Pearson correlation of the mid-ranks, which is exactly the tie-corrected form. Needs equal-length, real, finite pairs, at least two of them, and refuses a sample whose ranks all agree. |
| `KendallTau(x, y)` | Kendall's τ-b, the tie-corrected rank correlation, `±1` on every perfectly monotone pairing. Same input contract as `SpearmanRho`, and refuses a constant sample, which leaves the denominator zero. |
#### Contingency tables
| Call | What it does |
|---|---|
| `FisherExactTest(table, alternative)` | Fisher's exact test on a 2×2 table of counts, the answer for a cross-classification too sparse for the χ² approximation. Conditions on the margins and sums the hypergeometric probabilities of the tables at least as extreme as the observed one, exactly and in log space; the two-sided sum collects every table whose probability does not exceed the observed one's. Returns the p-value and the sample odds ratio (`+Inf` where a zero cell sits against a full one, `NaN` with p = 1 where a zero margin leaves only one table). The alternative is `TwoSided`, `Less` or `Greater`. Refuses a table that is not 2×2, complex input, a non-finite, negative or fractional count, a count past 2^51 where float64 no longer holds the integers stepwise, and margins spanning more than 4000000 support points, for which `ChiSquareIndependence` is the honest test. |
| `ChiSquareIndependence(table)` | Pearson's χ² test of independence on an r×c table: the expected count is the row total times the column total over the grand total, the statistic is Σ(O−E)²/E and the p-value its tail on (r−1)(c−1) degrees of freedom. Refuses fewer than two rows or columns, complex input, a non-finite, negative or fractional count, a zero row or column total, and an all-zero table. |
| `McNemarTest(table)` | The exact McNemar test on paired counts: under the null the two off-diagonal disagreements split evenly, so the smaller one follows the binomial law at p = ½, and the two-sided p-value doubles the smaller tail through the incomplete beta, costing the same for millions of pairs as for a dozen. No discordant pair answers 1. The input contract is `FisherExactTest`'s own. |
| `CramersV(table)` | Cramér's V, the χ² statistic rescaled into [0, 1] by the sample size and the smaller margin: √(χ²/(n·(min(r,c)−1))). Zero means the counts sit exactly on independence. The input contract is `ChiSquareIndependence`'s own. |
#### Multiple testing
| Call | What it does |
|---|---|
| `Bonferroni(p)` | The Bonferroni-adjusted p-values, each scaled by the vector length and clamped at 1. Refuses an empty vector, a non-finite entry and an entry outside `[0, 1]`. |
| `Holm(p)` | The Holm step-down adjusted p-values, with the running maximum enforcing the non-decreasing order. Same refusals as `Bonferroni`. |
| `BenjaminiHochberg(p)` | The Benjamini-Hochberg step-up adjusted p-values, the q-values of the false discovery rate literature, with the running minimum enforcing the order. Same refusals as `Bonferroni`. |
#### Linear and generalised linear models
| Call | What it does |
|---|---|
| `LinearRegression(x, y)` | Ordinary least squares `y = X·β` with the full classical inference in a `LinearRegressionResult`. The intercept is supplied by the caller as a constant column. Refuses a design that is not rank 2, a response that is not rank 1, a length mismatch, complex or non-finite input, `n ≤ p`, and a rank-deficient or near-collinear design. |
| `WeightedLinearRegression(x, y, w)` | Weighted least squares with the positive weight `w[i]` on observation `i`: the normal equations run on the sqrt-weighted system, so every statistic is the weighted-theory one while `Fitted` and `Residuals` stay in the original units. Refuses a weight that is not finite and positive, then validates as `LinearRegression` does. |
| `LogisticRegression(x, y)` | The binary response `y = Bernoulli(sigmoid(X·β))` by maximum likelihood: Newton-Raphson to a coefficient movement below `1e-10`, at most 100 steps, with Wald inference from the inverse Fisher information. `y` must hold only 0 and 1. Perfectly separable data has no finite optimum and is reported as an error, as is a singular Fisher information or a near-collinear design. |
| `PoissonRegression(x, y)` | The count response `y = Poisson(exp(X·β))` by maximum likelihood on the log link, Newton-Raphson with steps halved while the likelihood does not rise, to the same tolerance and budget. `y` must hold non-negative integers. A singular Fisher information, a near-collinear design, non-finite or negative or fractional responses, and an exhausted iteration budget are all errors. |
| `QuantileRegression(x, y, tau)` | The tau-th conditional quantile by the Frisch-Newton interior-point method on the dual of the check-loss program, started from the least squares fit, at most 100 iterations with the barrier parameter shrinking by `0.25` per iteration down to a floor of `1e-16` and a coefficient tolerance of `1e-14`. Refuses `tau` outside the open interval `(0, 1)`, and validates the design as `LinearRegression` does. |
#### Regularised and robust models
| Call | What it does |
|---|---|
| `Lasso(x, y, lambda)` | The pure lasso at one `lambda`: `ElasticNet` with alpha = 1. The slopes and only the slopes are penalised. |
| `ElasticNet(x, y, lambda, alpha)` | The elastic net, `(1/2n)·Σ(y - β₀ - x·β)² + λ·(α·Σ|β| + (1-α)/2·Σβ²)`, by coordinate descent on the design standardised to unit population standard deviation, at most 10000 cycles to a coefficient tolerance of `1e-8`, with the standardisation inverted before the result returns. Refuses a negative or NaN `lambda`, an `alpha` outside `[0, 1]`, fewer than two observations, a design column with no standard deviation to divide by, and complex or non-finite input. A rank-deficient design and more columns than rows are legitimate here. |
| `LassoPath(x, y, alpha)` | The whole regularisation path at the given mixing, warm-started along 100 log-spaced lambdas from the largest penalty that zeroes every slope down to its thousandth. Refuses an `alpha` outside `[0, 1]` and the same input contract as `ElasticNet`. |
| `HuberRegression(x, y)` | The Huber M-estimate of the linear model at the default tuning constant `DefaultHuberTuning`. |
| `HuberRegressionTuned(x, y, tuning)` | The Huber M-estimate at the given tuning constant: a quadratic loss inside the band `|r| ≤ tuning·σ` and a linear one outside it, fitted by iteratively reweighted least squares, at most 100 rounds to a coefficient tolerance of `1e-10`, with the robust scale σ re-estimated each round as 1.4826 times the median absolute deviation of the residuals. Refuses a tuning constant that is not finite and positive, a design that is not `n > p` or full rank, and complex or non-finite input. A robust scale that collapses to zero stops the iteration as an exact fit. |
| `TheilSenRegression(x, y)` | The Theil-Sen estimate of the simple model `y = a + b·x`: the median of the pairwise slopes over all pairs with distinct predictors, then the median of `y_i - b·x_i` at that slope. Needs at least three observations with at least two distinct predictors, all finite and real. Refuses more than `TheilSenMaxObservations` observations with the cost named, since the median is taken over all n(n-1)/2 slopes. |
#### Linear mixed models
| Call | What it does |
|---|---|
| `LinearMixedModel(y, x, z, groups)` | The Gaussian linear mixed model `y = X·β + Z·b + ε`: a fixed-effect design shared by every row plus a random-effect design whose coefficients vary by group, each group's `b_g` drawn from one shared unstructured q×q covariance Σ, the residual from N(0, σ²I). Σ and σ² are estimated by residual maximum likelihood through expectation maximisation over the random-effect posterior, with the fixed effects' own posterior covariance folded into the M step, so the fixed point is the REML optimum and not the ML one; β̂ follows by generalised least squares at the fitted components and carries standard errors from (XᵀV⁻¹X)⁻¹. The starting point is the data's own least squares, so no generator enters and the fit is deterministic. Convergence is the REML log likelihood settling under `1e-10` relative, within 500 sweeps; `Converged` names which happened. Refuses complex or non-finite input, a response shorter than two rows, a design of fewer than one column, a row count mismatch, at least as many fixed coefficients as observations, a negative group label, a group whose marginal covariance fails to factor, a singular fixed design, and a design whose REML criterion has no interior optimum (a random design that spans the fixed one under an unstructured covariance drives the components up a ridge without a summit; the fit refuses with the condition named). |
#### Principal components
| Call | What it does |
|---|---|
| `PCA(a)` | The decomposition of an (n, p) observation array onto its principal components, by the cyclic Jacobi eigensolver over the package's own covariance matrix, into a `PCAResult`. Needs at least two real, finite observations, and refuses a sample of no variance at all and a covariance that decomposed to a negative eigenvalue beyond the rounding scale. A rank-deficient covariance decomposes normally; only the whitening transforms are withheld. |
| `(r *PCAResult) Whiten(x)` | The unit-covariance representation of an (n, p) array on the fit's own variables: the centred rows expressed on the components and scaled by each component's standard deviation. Refuses a nil fit, a rank-deficient fit, a rank or width mismatch, and complex or non-finite input. |
| `(r *PCAResult) Unwhiten(z)` | The inverse of `Whiten`, recovering the observations in their own coordinates to rounding. Same refusals as `Whiten`. |
#### Clustering
| Call | What it does |
|---|---|
| `KMeans(g, x, k)` | `k` clusters over the rows of an (n, d) sample by Lloyd's iteration, seeded by k-means++ over the house generator, so the fit is deterministic for a generator state. Convergence is declared once no centre moves by more than `1e-10` scaled by the largest absolute coordinate in the sample, and at most 300 sweeps are run; `Converged` names which happened. An empty cluster takes the sample farthest from its centre, and the run is an error if the sample holds fewer distinct points than `k`. Refuses a nil generator, a non-2-D or complex or non-finite sample, `k < 1` and `k > n`. |
| `GaussianMixture(g, x, components)` | A mixture of multivariate normals over the rows of a sample by expectation maximisation, with the component densities through the Cholesky factors of their covariances, initialised from the k-means partitions of the same generator. The E step runs in log space with a max-guarded log-sum-exp normalisation, and each M-step covariance is floored by `1e-6` of the sample's mean per-dimension variance, so a component that collapsed onto one sample keeps a factorable covariance. Convergence is the log likelihood settling under `1e-9` relative, within 200 sweeps. Refuses a nil generator, fewer than two samples, a non-2-D or complex or non-finite sample, and a component count outside `[1, n]`. |
| `GaussianMixtureBIC(g, x, maxComponents)` | Fits the mixtures of 1 to `maxComponents` components and keeps the one with the lowest BIC, `-2·logL + p·ln n` with p the free parameters of the mixture. The grid travels in `BICGrid` and the winner in `Components`; a tie resolves to the smaller model. Refuses a largest component count outside `[1, n]` and the sample contract of `GaussianMixture`. |
| `HierarchicalClustering(x, method)` | The agglomerative dendrogram of the sample's rows over Euclidean distances. Every row starts as its own cluster and the closest pair merges repeatedly, the merged distances rewriting through the linkage's Lance-Williams update; the naive sweep costs O(n³) time and O(n²) memory and is deterministic, ties resolving toward the lowest indices. The method is `SingleLinkage`, `CompleteLinkage`, `AverageLinkage`, `CentroidLinkage` or `WardLinkage`; the centroid and Ward updates run on squared distances with the heights rooted, and the centroid rule is not monotone, so its heights may invert. Refuses a non-rank-2 or complex or non-finite sample, fewer than two rows, more than `HierarchicalMaxObservations` rows, and an unknown linkage. |
| `(d *Dendrogram) Cut(k)` | The flat partition into `k` clusters left by undoing the last k−1 merges, labelling every row 0 to k−1 by each cluster's smallest row, so the sample's first row always lands in cluster 0. Refuses a nil dendrogram and a `k` outside `[1, n]`. |
| `(d *Dendrogram) CutHeight(height)` | The partition left by applying merges in order while they sit at or below `height`: below the first merge the singletons, at or above the last one cluster. Labels as `Cut` does. Refuses a nil dendrogram and a non-finite height. |
#### Hidden Markov models
| Call | What it does |
|---|---|
| `NewHiddenMarkovModel(initial, transition, emission)` | Validates and copies a discrete hidden Markov model: `initial` the state distribution at the first step, `transition` the states×states one-step conditionals row-major, `emission` the states×symbols observation conditionals row-major. Every entry must be finite and in [0, 1] and every row must sum to 1 within 1e-9, so a model value is always safe to evaluate. Refuses an empty state set, a transition or emission matrix whose shape does not fit, and any row that fails those checks. |
| `(m *HiddenMarkovModel) Forward(observations)` | The scaled forward recursion: the filtered state posteriors, one row per step, and the sequence's log likelihood P(observations | model). The per-step scaling keeps a thousand-step sequence from underflowing. Refuses a nil model, an empty sequence and any observation outside the model's symbol set. |
| `(m *HiddenMarkovModel) Smooth(observations)` | The forward-backward smoothed posteriors P(state at t | all observations), one row per step, with the sequence's log likelihood. The refusals are `Forward`'s own. |
| `(m *HiddenMarkovModel) Viterbi(observations)` | The most likely state path through the sequence, decoded in log space with ties broken toward the lowest state index, with its log probability log P(path, observations | model). The refusals are `Forward`'s own. |
| `FitHiddenMarkovModel(g, observations, states, symbols)` | Baum-Welch expectation maximisation of a model over the given state and symbol counts: every starting row drawn from the flat Dirichlet through the house generator, so the fit is deterministic for the generator state, though expectation maximisation only climbs to a local maximum and a different state may land elsewhere. The re-estimation floors every parameter at 1e-12 and renormalises the rows, so no symbol or transition is silenced by one sweep. Convergence is the log likelihood settling under `1e-6` relative, within 500 sweeps, the tolerance stopping the crawl along the flat ridge the objective leaves rather than waiting for the parameters to stop moving. Refuses a nil generator, a count below one, an empty sequence and an out-of-range observation. |
#### Density estimation and Gaussian processes
| Call | What it does |
|---|---|
| `KernelDensity(sample, bandwidth, points)` | The Gaussian-kernel density estimate of the sample at every point, each sample contributing a unit-variance normal of width `bandwidth` averaged over the sample. A non-positive `bandwidth` asks for Silverman's rule, `0.9·min(σ, IQR/1.34)·n^{-1/5}`, with the σ fallback when the interquartile range is degenerate. Refuses a non-vector, complex or non-finite sample or points, a sample of fewer than two points, and a bandwidth that resolved to a non-positive or NaN width. |
| `Kernel` | The covariance function of a Gaussian process, one method: `Covariance(x, y)` returns the prior covariance `k(x, y)` of two points of equal length. Every house kernel carries unit amplitude, `k(x, x) = 1`, and its constructor enforces the parameter contract, so a `Kernel` value is always safe to evaluate. |
| `SquaredExponentialKernel(lengthScale)` | The squared-exponential (RBF) kernel `exp(-r²/(2·lengthScale²))` over the Euclidean distance, the smooth prior. Refuses a length scale that is not finite and positive. |
| `Matern32Kernel(lengthScale)` | The Matérn kernel with ν = 3/2, `(1 + √3·r/ℓ)·exp(-√3·r/ℓ)`, once differentiable. Refuses a length scale that is not finite and positive. |
| `Matern52Kernel(lengthScale)` | The Matérn kernel with ν = 5/2, twice differentiable. Refuses a length scale that is not finite and positive. |
| `PeriodicKernel(lengthScale, period)` | The periodic kernel `exp(-2·sin²(π·r/period)/lengthScale²)`, the prior over functions that repeat exactly with the period. Refuses a length scale or a period that is not finite and positive. |
| `GaussianProcessRegression(kernel, trainX, trainY, noiseVariance, testX)` | The Gaussian-process posterior at the test points: the posterior mean, the full posterior covariance between them and its diagonal in a `GaussianProcessResult`, conditioning on the training rows through the Cholesky factor of `K = k(X, X) + noiseVariance·I`. A zero noise variance is a legitimate noiseless fit and interpolates the training data exactly; duplicated training rows are then a singular Gram matrix and are refused. The inputs must be real and finite, the training and test designs of equal width, the response of the training length, and the noise variance finite and non-negative. |
| `MarginalLogLikelihood(kernel, trainX, trainY, noiseVariance)` | The log marginal likelihood of the observations under the prior the kernel defines, `-½·yᵀK⁻¹y - Σ ln L_ii - (n/2)·ln 2π`, the evidence of the hyperparameters. It is the objective a hyperparameter fit maximises; the package has no edge to `optim`, so the house minimiser drives this function from outside over the kernel parameters and the noise variance. Refuses a nil kernel, a negative or non-finite noise variance, and the training contract of `GaussianProcessRegression`. |
#### Constants
| Constant | Value | Meaning |
|---|---|---|
| `DefaultHuberTuning` | `1.345` | The tuning constant `HuberRegression` passes to `HuberRegressionTuned`: the literature's standard choice, 95 percent asymptotic efficiency at the Gaussian with the influence of an outlier bounded at 1.345 times a residual inside the band. |
| `TheilSenMaxObservations` | `4096` | The exactness contract of `TheilSenRegression`: the largest sample whose pairwise slopes are all medianed exactly. Beyond the cap the estimator refuses with the cost named rather than approximate. |
| `HierarchicalMaxObservations` | `4096` | The sample cap of `HierarchicalClustering`: the working distance matrix is quadratic in the sample, and past the cap the refusal names the cost rather than handing gigabytes to the allocator. |
#### Options and results
The package carries no options structs; every entry point takes its parameters as arguments. The result types below are the whole of its exported state.
**`LinearRegressionResult`** : the least-squares fit and its inference, returned by `LinearRegression` and `WeightedLinearRegression`. Each coefficient slice is indexed by column of the design, in order.
| Field | Type | Meaning |
|---|---|---|
| `Coefficients` | `[]float64` | The estimates β̂. |
| `StandardErrors` | `[]float64` | The estimated standard deviations of the coefficient estimators, σ̂²(XᵀX)⁻¹ on the diagonal. |
| `TStatistics` | `[]float64` | β̂/SE per coefficient. |
| `PValues` | `[]float64` | The two-sided p-values of the t-tests. |
| `Iterations` | `int` | The Newton steps taken. |
| `Converged` | `bool` | Whether the coefficient update fell under the tolerance. |
**`PoissonRegressionResult`** : the fit of a count response, returned by `PoissonRegression`.
| Field | Type | Meaning |
|---|---|---|
| `Coefficients` | `[]float64` | The maximum-likelihood estimates β̂ on the log scale. |
| `StandardErrors` | `[]float64` | The Wald standard errors from the inverse Fisher information at the optimum. |
| `ZStatistics` | `[]float64` | β̂/SE per coefficient. |
| `PValues` | `[]float64` | The two-sided normal-tail probabilities. |
| `Fitted` | `[]float64` | The predicted mean count per sample, clamped into `[1e-12, 1e300]` exactly as the fitting loop clamps it. |
| `LogLikelihood` | `float64` | The maximised Poisson log likelihood, evaluated on the clamped `Fitted` values. |
| `Iterations` | `int` | The Newton steps taken. |
| `Converged` | `bool` | Whether the coefficient update fell under the tolerance. |
**`ElasticNetResult`** : one regularised fit at a single lambda, returned by `Lasso` and `ElasticNet`.
| Field | Type | Meaning |
|---|---|---|
| `Intercept` | `float64` | The intercept on the original scale of the design as supplied, the standardisation inverted. |
| `Coefficients` | `[]float64` | One slope per design column, in order. |
| `Fitted` | `[]float64` | The fitted value of every design row. |
| `Residuals` | `[]float64` | The residual of every row, aligned with the design. |
| `ColumnMeans` | `[]float64` | The column means the standardisation subtracted, recorded so the fit can be reproduced. |
| `ColumnScales` | `[]float64` | The column population standard deviations it divided by. |
| `Lambda` | `float64` | The penalty the fit ran at. |
| `Alpha` | `float64` | The elastic net mixing it ran with. |
| `Iterations` | `int` | The full coordinate-descent cycles taken. |
| `Converged` | `bool` | Whether no slope moved more than the tolerance in the last cycle. An exhausted budget returns the fit found so far with `Converged` false: coordinate descent on this convex objective cannot diverge. |
**`LassoPathResult`** : the warm-started regularisation path, returned by `LassoPath`.
| Field | Type | Meaning |
|---|---|---|
| `Alpha` | `float64` | The mixing the path ran with. |
| `Lambdas` | `[]float64` | The penalty values in descending order: 100 log-spaced values from the largest penalty that zeroes every slope down to its thousandth. For alpha = 0 the pure-lasso grid defines the same path. |
| `Intercepts` | `[]float64` | One intercept per lambda, on the original scale, in the order of `Lambdas`. |
| `Coefficients` | `[][]float64` | One slope vector per lambda, in the same order. |
| `Iterations` | `[]int` | The coordinate-descent cycles each lambda needed, the evidence the warm start earns its keep. |
| `Converged` | `bool` | Whether every fit on the path converged within the iteration budget. |
**`HuberRegressionResult`** : the Huber M-estimate of the linear model, returned by `HuberRegression` and `HuberRegressionTuned`.
| Field | Type | Meaning |
|---|---|---|
| `Coefficients` | `[]float64` | The M-estimates β̂, one per design column, in the design's order. |
| `StandardErrors` | `[]float64` | The asymptotic standard errors from σ²·(XᵀWX)⁻¹ with the final weights and the robust scale σ in place of the residual standard deviation. |
| `Weights` | `[]float64` | The final IRLS weights, one per observation: exactly 1 inside the band and tapering as `band/|r|` outside it. The contaminated observations sit at the bottom of the list. |
| `Scale` | `float64` | The final robust scale σ, 1.4826 times the median absolute deviation of the residuals. |
| `Fitted` | `[]float64` | The fitted value of every design row. |
| `Residuals` | `[]float64` | The residual of every row, aligned with the design. |
| `Iterations` | `int` | The reweighting steps taken. |
| `Converged` | `bool` | Whether the coefficient updates fell under the tolerance. |
**`QuantileRegressionResult`** : a quantile regression fit, returned by `QuantileRegression`.
| Field | Type | Meaning |
|---|---|---|
| `Coefficients` | `[]float64` | The quantile estimates β̂, one per design column; an intercept column is estimated like any other coefficient. |
| `Fitted` | `[]float64` | The fitted value of every design row. |
| `Residuals` | `[]float64` | The residual of every row, aligned with the design. |
| `Tau` | `float64` | The quantile the fit minimises the check loss for. |
| `CheckLoss` | `float64` | The minimised check loss `Σ ρ_τ(r)` at the fit. |
| `Objective` | `[]float64` | The best check loss seen after every interior-point iteration, from the least squares start on. Monotone non-increasing by construction. |
| `Iterations` | `int` | The interior-point iterations taken. |
| `Converged` | `bool` | Whether the run settled by its own stopping rules. |
**`PCAResult`** : the decomposition of an observation array, returned by `PCA`.
| Field | Type | Meaning |
|---|---|---|
| `Mean` | `[]float64` | The column means of the observations the fit ran on. |
| `Loadings` | `*tensor.Array` | The (p, p) rotation: entry (j, k) is the loading of variable j on component k, columns ordered by falling explained variance and orthonormal as columns. Every column's largest-magnitude loading is positive, the first index winning a tie, so two runs on the same data agree sign for sign. |
| `Scores` | `*tensor.Array` | The (n, p) coordinates of the observations on the components: the centred observations times the loadings. |
| `ExplainedVariance` | `[]float64` | Each component's eigenvalue of the covariance, in the loadings' order. |
| `ExplainedVarianceRatio` | `[]float64` | `ExplainedVariance` divided by the total variance, so the ratios sum to one. |
| `Whitening` | `*tensor.Array` | The (p, p) transform taking a centred row to the unit-covariance representation. Nil when the covariance is rank deficient, where no such transform exists. |
| `Unwhitening` | `*tensor.Array` | The (p, p) inverse of `Whitening`. Nil on a rank-deficient fit. |
**`KMeansResult`** : the fit of k-means over a sample, returned by `KMeans`.
| Field | Type | Meaning |
|---|---|---|
| `Centres` | `[][]float64` | The k fitted centroids, one row of d coordinates each. |
| `Labels` | `[]int` | The cluster of every sample row, 0 to k-1. |
| `Inertia` | `float64` | The within-cluster sum of squared distances to the centres, the objective the Lloyd loop minimises. |
| `Iterations` | `int` | The Lloyd sweeps taken. |
| `Converged` | `bool` | Whether the centre movement fell under the tolerance before the iteration budget ran out. |
**`GaussianMixtureResult`** : the fit of a Gaussian mixture, returned by `GaussianMixture` and `GaussianMixtureBIC`.
| Field | Type | Meaning |
|---|---|---|
| `Components` | `int` | The fitted component count. |
| `Weights` | `[]float64` | The mixture weights, in component order, summing to 1. |
| `Means` | `[][]float64` | One mean vector per component. |
| `Covariances` | `[][]float64` | One d-by-d covariance per component, row-major, in component order. |
| `Responsibilities` | `[]float64` | The final E-step posteriors, n rows of `Components` entries each, row-major: the posterior probability of component j given sample i. |
| `BIC` | `float64` | `-2·LogLikelihood + p·ln n` at the fitted parameters, p the count of free parameters. |
| `Iterations` | `int` | The EM sweeps taken. |
| `Converged` | `bool` | Whether the log likelihood settled under the tolerance before the budget. |
| `BICGrid` | `[]float64` | Filled by `GaussianMixtureBIC` only: the BIC of every fit on the component grid 1 to `len(BICGrid)`, in grid order. The plain fit leaves it nil. |
**`GaussianProcessResult`** : the posterior of a Gaussian process at the test points, returned by `GaussianProcessRegression`.
| Field | Type | Meaning |
|---|---|---|
| `Mean` | `[]float64` | The posterior mean function at the test points. |
| `Covariance` | `[]float64` | The posterior covariance between the test points, m-by-m row-major in the order the test points were given. |
| `Variance` | `[]float64` | The diagonal of `Covariance`, the marginal posterior variance per test point, clamped at zero. |
| `LogLikelihood` | `float64` | The log marginal likelihood of the training observations under the prior. |
**`LinearMixedModelResult`** : the fit of a linear mixed model, returned by `LinearMixedModel`.
| Field | Type | Meaning |
|---|---|---|
| `Coefficients` | `[]float64` | The fitted fixed effects β̂, one per column of the fixed design. |
| `StandardErrors` | `[]float64` | Their estimated standard deviations, the square roots of the diagonal of the GLS covariance (XᵀV⁻¹X)⁻¹ at the fitted components. |
| `RandomEffects` | `[][]float64` | The posterior mean b̂_g per group, each the length of a row of the random design, in `GroupLabels` order. |
| `GroupLabels` | `[]int` | The distinct group labels in the order the fit met them. |
| `RandomCovariance` | `[]float64` | The fitted between-group covariance Σ̂ of the random effects, q×q row-major. |
| `ResidualVariance` | `float64` | The fitted σ̂². |
| `Fitted` | `[]float64` | The conditional fit X·β̂ + Z·b̂ per row. |
| `Residuals` | `[]float64` | The response less `Fitted`, aligned with the rows. |
| `Iterations` | `int` | The EM sweeps taken. |
| `Converged` | `bool` | Whether the log likelihood settled under the tolerance before the budget. |
**`HiddenMarkovFitResult`** : the Baum-Welch fit of a hidden Markov model, returned by `FitHiddenMarkovModel`; the fitted `HiddenMarkovModel` carries `Initial` (states), `Transition` (states×states) and `Emission` (states×symbols), all row-major distributions.
| Field | Type | Meaning |
|---|---|---|
| `Model` | `*HiddenMarkovModel` | The fitted model. |
| `LogLikelihood` | `float64` | The training sequence's log likelihood under the fitted model. |
| `Iterations` | `int` | The Baum-Welch sweeps taken. |
| `Converged` | `bool` | Whether the log likelihood settled under the tolerance before the budget. |
**`Dendrogram`** : the merge record of an agglomerative clustering, returned by `HierarchicalClustering`.
| Field | Type | Meaning |
|---|---|---|
| `Left` | `[]int` | The smaller cluster id of each merge; leaves are the sample's rows and the merge at step t creates cluster n+t. |
| `Right` | `[]int` | The larger cluster id of each merge. |
| `Heights` | `[]float64` | The merge distances in merge order, non-decreasing except under `CentroidLinkage`, where an inversion is legitimate. |
| `Sizes` | `[]int` | The row count of each merge's cluster. |
#### Errors
Every entry point returns its value with an error, the sole exception being `NormalCDF`, which returns a bare `float64`. Every error carries the library's `tensor: ` prefix and names the entry point that raised it.
- An empty or otherwise unusable sample: an error naming what is missing, for example `Quantile: empty array has no quantiles`.
- A complex array where a real one is required: an error naming the entry point, for example `Median: complex arrays have no median`.
- A non-finite observation, NaN or ±Inf: an error naming the value, for example `Histogram: sample 3 is not finite (NaN)`. The estimation entries check this before any arithmetic, so a NaN never reaches a result.
- A length, rank or shape mismatch: an error naming both counts or the offending shape, for example `LinearRegression: the design has 6 rows but the response 5`.
- A parameter outside its documented domain, such as a non-positive rate or shape, a probability outside `(0, 1)`, a `q` outside `[0, 1]`, an `alpha` outside `[0, 1]` or a non-positive bandwidth: an error naming the parameter and the value received.
- A quantile at `q = 0` or `q = 1` of a continuous law: an error, since neither has a finite quantile.
- A design that is rank deficient, near-collinear or not `n > p`: an error naming the condition, for example `LinearRegression: the design is rank deficient`.
- A fit that would not settle: `LogisticRegression` reports a perfectly separable response, `PoissonRegression` and `HuberRegression` report an exhausted iteration budget, and the incomplete gamma and beta functions report an iteration that missed its convergence budget.
- An out-of-range search: a discrete quantile whose bracket never reaches `q`, and a sample larger than `TheilSenMaxObservations`, both of which name the cost rather than answer approximately.
#### Workflow
The flagship sequence: build the design, fit it, and quote an interval using the package's own distribution quantile.
```go
// y on the design, the intercept carried as the constant first column.
design, _ := tensor.FromFloats([]float64{
1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5,
}, 6, 2)
y, _ := tensor.FromFloats([]float64{4.1, 7.0, 9.9, 13.2, 15.9, 19.1}, 6)
fit, err := stats.LinearRegression(design, y)
if err != nil {
return err
}
// The two-sided 95 percent critical value on the residual degrees of
The same shape carries every model of the package: `LinearRegression`, `LogisticRegression`, `PoissonRegression`, `ElasticNet`, `HuberRegression` and `QuantileRegression` all take the design first with the intercept as a constant column, return a result struct with the coefficients and their uncertainty, and leave the caller to choose a test or an interval from the distribution functions.
### Package `optim`
Fitting, minimisation, programming and root finding: Levenberg-Marquardt
nonlinear least squares, the Nelder-Mead simplex and limited-memory BFGS for
local minima, the augmented Lagrangian for constrained problems, the two-phase
revised simplex and a primal active-set method for linear and quadratic
programs, three derivative-free global searchers, and scalar and vector root
finders. Every entry point hands the caller's function the candidate point as a
rank-1 `*Array` and returns a fresh array the caller owns; an objective,
residual or gradient callback receives a copy, never a view of a reused
buffer.
The package is real-valued: a complex starting point, cost, right-hand side,
bound, constraint matrix or callback payload is refused with an error rather
than read through a nil payload. It also leaves the modelling to the caller.
`MinimiseLinear` requires the standard form `A·x = b`, `x ≥ 0` exactly and
`MinimiseLinearRows` is the wrapper that converts the house two-sided rows into
it; `MinimiseDifferentialEvolution` clamps to its box and requires one, while
`MinimiseCMAES` has no bounds at all; a local minimum is the minimum of the
basin the solver started in, and multistart or a global searcher is what finds
the others.
#### Curve fitting
| Call | What it does |
|---|---|
| `LevenbergMarquardt(residual, p0, opts)` | Minimises `‖r(p)‖²` over the parameter vector by LM damping of the Gauss-Newton step, returning the parameters and the residual sum of squares. Refuses an underdetermined problem, a residual whose length changes mid-fit and a damping that collapses without meeting the tolerance; a singular solve and an exhausted budget keep the historical error contract here. |
| `LevenbergMarquardtFit(residual, p0, opts)` | The same fit with the full report: a `FitResult` carrying the parameters, the (weighted) χ², the `FitStatus` (`FitConverged`, `FitStalled`, `FitBudget`) and, when requested, the parameter covariance. A singular solve and a collapsed damping come back as `FitStalled` on the best point reached and a spent budget as `FitBudget`, never as an error; the errors here are the model's own fault and, with `RequestCovariance`, a rank-deficient Jacobian at the answer. The `GradTol` and `StepTol` options converge the fit on the gradient norm and on the step size, the exits that reach the flat optimum the χ² tolerance alone never leaves. |
#### Local minimisation
| Call | What it does |
|---|---|
| `Minimise(f, x0, opts)` | Returns the point and value of a local minimum of `f` near `x0` by the Nelder-Mead simplex, which needs no derivatives. |
| `MinimiseLBFGS(f, grad, x0, opts)` | Returns the point and value of a local minimum by limited-memory BFGS with a backtracking Armijo line search; `grad` may be nil, and the box walls in `opts` project the iterate, so the objective is never evaluated outside them. Refuses a vanished or non-descent search direction, a stalled line search and an exhausted budget. |
#### Constrained minimisation
| Call | What it does |
|---|---|
| `MinimiseConstrained(f, grad, x0, cons, opts)` | Returns the point and value of a local minimum of `f` subject to the box walls carried by `opts` and the rows `l ≤ A·x ≤ u` of `cons`, each outer round minimising the augmented Lagrangian and then ascending the row multipliers. A start outside the feasible set is fine; failure to reach feasibility is an error naming the worst remaining violation. |
| `MinimiseNonlinearConstrained(f, grad, x0, cons, opts)` | Returns the point, the value of `f` and the row multipliers of a local minimum subject to the functional rows of `cons` (equalities `g(x) = 0` first, then inequalities `h(x) ≤ 0`, in declaration order). With both slices empty it delegates to `MinimiseLBFGS` and returns nil multipliers. |
#### Linear and quadratic programming
| Call | What it does |
|---|---|
| `MinimiseLinear(c, a, b, opts)` | Returns the point and value of the minimum of `c·x` over the standard-form polytope `A·x = b`, `x ≥ 0` by the two-phase revised simplex under Bland's rule. Refuses an infeasible problem with the phase-1 evidence, an unbounded objective with the profitable column, and an exhausted pivot budget. |
| `MinimiseLinearRows(c, cons, opts)` | The same, over the two-sided rows `l ≤ A·x ≤ u` of `cons`, converting them to the standard form mechanically (each variable splits into two non-negative columns, each finite row side gains a slack). Refuses exactly as `MinimiseLinear` does. |
| `MinimiseQP(h, c, cons, x0, opts)` | Returns the point, the value `½xᵀHx + c·x` and one multiplier per row of the minimum of the strictly convex quadratic over the two-sided rows. Refuses a non-symmetric or non-positive-definite `H` at entry, naming the failed pivot, and an infeasible `x0`. |
#### Global minimisation
| Call | What it does |
|---|---|
| `MinimiseDifferentialEvolution(f, lower, upper, opts)` | Returns the best point and value of the global minimum over the box `[lower, upper]` by rand/1/bin differential evolution with clamping to the bounds. Refuses mismatched or degenerate bounds and a population below four. The generation budget is a tuning parameter, so running it out returns the best point found without an error. |
| `MinimiseCMAES(f, x0, opts)` | Returns the best point and value the covariance matrix adaptation strategy found, one run without restarts. No bounds: the caller who needs a box reparametrises. An exhausted generation budget is an error unless `AllowBudgetExit` is set. |
| `MinimiseSimulatedAnnealing(f, x0, opts)` | Returns the best point and value a Metropolis walk with a Gaussian proposal and geometric cooling found. Finds basins, not minima to full precision; running `MinimiseLBFGS` from the returned point is the standard composition. A schedule that ended while the best value was still improving is an error unless `AllowBudgetExit` is set. |
#### Scalar root finding
| Call | What it does |
|---|---|
| `FindRoot(f, a, b, tol)` | Returns a root of `f` in the bracket `[a, b]` by Brent's method; `f(a)` and `f(b)` must be finite with opposite signs. The budget is fixed at 200 iterations. |
| `FindRootBrent(f, a, b, opts)` | The same method with the tolerance and the budget under the caller's control, in the vocabulary of `RootSystemOptions`: the tolerance thresholds `|f|` at the returned point, and a run costs at most `MaxIterations + 2` evaluations. An exhausted budget is an error, never a silent guess. |
| `FindRootNewton(f, df, x0, tol, maxIter)` | Returns a root near `x0` by Newton's iteration with the supplied derivative. A vanishing derivative or an exhausted budget is an error. |
#### Systems of equations
| Call | What it does |
|---|---|
| `FindRootSystem(f, x0, opts)` | Solves `r(x) = 0` for a vector function `r` of an `n`-vector, returning the solution and the residual infinity norm at it. The residual must be a vector of the same length as `x0`. A singular Jacobian falls back to the steepest-descent direction of the residual norm; a residual that cannot be reduced by damping, and an exhausted iteration budget, are errors. |
#### Options and results
**`LMOptions`**: tunes `LevenbergMarquardt` and `LevenbergMarquardtFit`. The
damping factor is scaled by 0.3 after every accepted step and by 10 after every
rejected one; a damping that passes 1e20 ends the run as a collapse. The
tolerance is the relative χ² improvement threshold.
| Field | Type | Default | Effect |
|---|---|---|---|
| `MaxIterations` | `int` | `≤ 0` means `200` | The number of Gauss-Newton steps the fit may take. |
| `Tolerance` | `float64` | `≤ 0` means `1e-10` | A step is accepted as converged when the χ² improvement falls below `Tolerance·(1 + χ²)`. |
| `Lambda` | `float64` | `≤ 0` means `1e-3` | The initial damping factor. |
| `Jacobian` | `func(p *core.Array) (*core.Array, error)` | nil means central differences, at two residual evaluations per parameter per iteration | The analytic Jacobian of the residual, an observations × parameters matrix with row `i` holding `∂r_i/∂p_j`. A matrix of the wrong shape is refused. |
| `AllowBudgetExit` | `bool` | `false` | Reports the last point with a nil error when the iteration budget runs out instead of refusing it. |
| `ParallelJacobian` | `bool` | `false` | Lets the central-difference Jacobian sweep its columns on several goroutines. Setting it is the caller's consent that the residual callback may run concurrently from more than one goroutine; the default keeps every evaluation on the caller's goroutine. The columns are independent, so the fit is bit-identical either way. No effect while `Jacobian` supplies the analytic matrix. |
| `GradTol` | `float64` | `≤ 0` disables | Converges the fit once the gradient norm `‖Jᵀr‖∞` falls to it, the test that reaches the flat optimum where χ² still falls in slivers while the step directions carry no information. |
| `StepTol` | `float64` | `≤ 0` disables | Converges the fit once an accepted step's infinity norm falls to `StepTol·(‖p‖∞ + StepTol)`, the relative test that stops a fit whose parameters have stopped moving meaningfully. |
| `Sigma` | `*core.Array` | nil | The measurement covariance: a vector of one positive variance per residual, or an exactly symmetric positive definite `nR×nR` matrix. The fit whitens the residuals and the Jacobian through the factor once, χ² becomes `rᵀC⁻¹r` and a requested covariance becomes `(JᵀC⁻¹J)⁻¹`. |
| `RequestCovariance` | `bool` | `false` | Fills `FitResult.Covariance` with `(JᵀJ)⁻¹`, or `(JᵀC⁻¹J)⁻¹` under `Sigma`, at the returned point, at the cost of one more Jacobian there. A rank-deficient Jacobian at the answer has no covariance to report and the run fails naming it. |
**`MinimiseOptions`**: tunes `Minimise`. Both convergence tests are absolute
in the objective's own scale: the value spread is compared against
`Tolerance·max(1, |f|)` and the simplex diameter against
`Tolerance·max(1, |x|)`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `MaxIterations` | `int` | `≤ 0` means `2000` | The number of simplex rounds. |
| `Tolerance` | `float64` | `≤ 0` means `1e-10` | The threshold on both the value spread and the simplex diameter, which must be met together for the run to count as converged. |
| `InitialStep` | `float64` | `≤ 0` means `1` | The offset of each simplex vertex from `x0`, scaled by `max(1, |x_i|)`. |
| `AllowBudgetExit` | `bool` | `false` | Reports the best vertex with a nil error when the budget runs out instead of refusing it. |
**`LBFGSOptions`**: tunes `MinimiseLBFGS` and the inner solves of
`MinimiseConstrained` and `MinimiseNonlinearConstrained`. The tolerance is the
L∞ norm of the projected gradient, which is the KKT residual of the box
problem, and it is absolute in the gradient's own scale.
| Field | Type | Default | Effect |
|---|---|---|---|
| `MaxIterations` | `int` | `≤ 0` means `10000` | The number of quasi-Newton steps. |
| `Tolerance` | `float64` | `≤ 0` means `1e-8` | The threshold on the projected gradient's infinity norm. |
| `Memory` | `int` | `≤ 0` means `10` | The number of correction pairs kept; capped at the number of variables. |
| `Lower` | `[]float64` | nil opens every lower side | Coordinate-wise lower walls, one entry per variable; an infinite entry opens that side. |
| `Upper` | `[]float64` | nil opens every upper side | Coordinate-wise upper walls, one entry per variable. A NaN wall or a crossed pair is an error; `x0` is projected onto the box rather than refused. |
| `AllowBudgetExit` | `bool` | `false` | Reports the best point with a nil error when the budget runs out instead of refusing it. `MinimiseConstrained` sets it for its inner solves. |
**`LinearConstraints`**: carries the rows of `l ≤ A·x ≤ u` for
`MinimiseConstrained`, `MinimiseLinearRows` and `MinimiseQP`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `A` | `*core.Array` | required | The `r×n` constraint matrix over the `n` variables. A nil matrix, a complex one, a rank other than 2, a second dimension other than `n` and a non-finite coefficient are all errors. |
| `Lower` | `[]float64` | required, one entry per row | The lower side of each row; an infinite entry opens that side. A NaN entry or a pair with `Lower > Upper` is an error. |
| `Upper` | `[]float64` | required, one entry per row | The upper side of each row. A row with `Lower = Upper` is an equality constraint. |
**`NonlinearConstraints`**: carries the functional rows for
`MinimiseNonlinearConstrained`. Each callback receives the candidate point as a
rank-1 array and must return a finite value; an error it returns is fatal for
the run.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Equalities` | `[]func(*core.Array) (float64, error)` | empty | The rows `g(x) = 0`. Their signed multipliers come first in the returned slice. |
| `Inequalities` | `[]func(*core.Array) (float64, error)` | empty | The rows `h(x) ≤ 0`. Their non-negative multipliers follow the equality ones. A row that is slack at the answer has an estimate that decays to zero. With both slices empty the call delegates to `MinimiseLBFGS` and returns nil multipliers. |
**`LinearProgramOptions`**: tunes `MinimiseLinear` and `MinimiseLinearRows`.
The tolerance prices reduced costs and separates ratio-test ties, and it is
absolute in the scale the caller's costs and rows carry.
| Field | Type | Default | Effect |
|---|---|---|---|
| `MaxIterations` | `int` | `≤ 0` means `10000` | The number of simplex pivots. |
| `Tolerance` | `float64` | `≤ 0` means `1e-9` | The threshold on reduced costs and on the ratio-test ties. |
**`QPOptions`**: tunes `MinimiseQP`. The tolerance is the threshold on the
KKT step below which the iterate is stationary on its working set, on the
multiplier that releases a row, and on the symmetry of `H`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `MaxIterations` | `int` | `≤ 0` means `1000` | The number of active-set rounds. |
| `Tolerance` | `float64` | `≤ 0` means `1e-10` | The KKT step, multiplier-release and symmetry threshold. |
| `Population` | `int` | `≤ 0` means `15·d`, at least `4` | The number of population members. A resolved value below 4 is an error, because the scheme draws three distinct others besides the target. |
| `F` | `float64` | `≤ 0` means `0.7` | The differential weight of the mutant vector. |
| `CR` | `float64` | `≤ 0` means `0.9` | The binomial crossover probability. |
| `Generations` | `int` | `≤ 0` means `1000` | The generation budget. Running it out returns the best point found, with no error. |
| `Seed` | `int64` | `0` is replaced by `42` | The xoshiro stream seed. Any other value, negatives included, seeds the stream directly. |
**`CMAESOptions`**: tunes `MinimiseCMAES`. The tolerance ends the run when
either the largest principal axis of the search distribution,
`sigma·sqrt(max C_ii)`, has fallen to `Tolerance·max(1, ‖mean‖∞)`, or the
objective spread over one generation has fallen to `Tolerance·max(1, |best|)`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Sigma0` | `float64` | `≤ 0` means `0.3` | The initial step size, the tutorial's typical value for problems scaled to O(1). |
| `Generations` | `int` | `≤ 0` means `500` | The generation budget. |
| `Tolerance` | `float64` | `≤ 0` means `1e-12` | The collapse and flat-landscape threshold. |
| `Seed` | `int64` | `0` is replaced by `42` | The xoshiro stream seed, as in `MinimiseDifferentialEvolution`. |
| `AllowBudgetExit` | `bool` | `false` | Reports the best point with a nil error when the generation budget runs out instead of refusing it. |
**`SimulatedAnnealingOptions`**: tunes `MinimiseSimulatedAnnealing`. The
schedule is the algorithm: the temperature runs from `Temperature0` down by
the factor `CoolingRate` at every proposal.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Steps` | `int` | `≤ 0` means `20000` | The number of proposals. |
| `Temperature0` | `float64` | `≤ 0` means `1` | The starting temperature. |
| `CoolingRate` | `float64` | `≤ 0` means `0.9995`, and a value above `1` is an error | The geometric factor per proposal. |
| `StepScale` | `float64` | `≤ 0` means `0.1` | The relative Gaussian proposal scale: coordinate `i` moves by `StepScale·max(1, |x_i|)` standard normals. |
| `Seed` | `int64` | `0` is replaced by `42` | The xoshiro stream seed, as in `MinimiseDifferentialEvolution`. |
| `Tolerance` | `float64` | `≤ 0` means `1e-6` | The convergence test on the frozen tail: the best value may not improve by more than `Tolerance·max(1, |best|)` over the final quarter of the schedule. |
| `AllowBudgetExit` | `bool` | `false` | Reports the best point when the schedule ended while the value was still improving, instead of refusing it. |
**`BrentOptions`**: tunes `FindRootBrent`, in the vocabulary of
`RootSystemOptions`. The tolerance is a threshold on `|f|` at the returned
point, the scalar counterpart of the residual infinity norm.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Tolerance` | `float64` | `≤ 0` means `1e-10` | The accepted `|f|` at the returned point. |
| `MaxIterations` | `int` | `≤ 0` means `100` | The iteration budget; a run costs at most `MaxIterations + 2` evaluations of `f`. An exhausted budget is an error. |
**`RootSystemOptions`**: tunes `FindRootSystem`. The tolerance is an
infinity-norm threshold on both the residual and the scaled step.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Tolerance` | `float64` | `≤ 0` means `1e-10` | The threshold the residual and the scaled step must both meet. |
| `MaxIterations` | `int` | `≤ 0` means `100` | The number of damped Newton rounds. |
| `UseBroyden` | `bool` | `false` | Builds the central-difference Jacobian once and carries its inverse between steps by the rank-one Broyden update, with a numerical rebuild whenever the update degrades. The default leaves the per-step Jacobian and the iteration's results exactly as they are. |
| `ParallelJacobian` | `bool` | `false` | Lets the central-difference Jacobian sweep its columns on several goroutines, the initial build and every Broyden rebuild included. Setting it is the caller's consent that the residual callback may run concurrently from more than one goroutine; the default keeps every evaluation on the caller's goroutine. The columns are independent, so the run is bit-identical either way. |
#### Budget policy
An iteration budget is a refusal, not an answer. `Minimise`, `MinimiseLBFGS`,
`MinimiseLinear`, `MinimiseLinearRows`, `FindRootBrent`, `FindRootNewton` and
`FindRootSystem` each return an error when the budget runs out before the
tolerance is met, naming the figure they reached and the tolerance they fell
short of, so a budget stop is never mistaken for a converged answer. Setting
`AllowBudgetExit` on the corresponding options reports the best point reached
instead, with a nil error; the default is `false` everywhere, and
`MinimiseConstrained` and `MinimiseNonlinearConstrained` set it only for their
inner solves, whose accuracy the outer loop's feasibility check judges.
`LevenbergMarquardtFit` needs no flag either: its budget stop is reported as
`FitBudget` on the last point.
`MinimiseDifferentialEvolution` needs no flag: its generation budget tunes the
search rather than deciding convergence, so running it out returns the best
point found. `FindRoot` has a fixed budget of 200 iterations and no options
struct at all.
#### Errors
Every error carries the library's `tensor: ` prefix.
- A complex starting point, cost, right-hand side, bound or callback payload: refused by the entry points that read the value directly (`complex starting points are not supported`, `complex costs are not supported`, `complex constraint matrices are not supported`, and so on).
- A non-finite entry in a cost, right-hand side, bound, constraint coefficient or Hessian, and a NaN or crossed pair of walls: refused at entry, naming the row or the variable.
- A callback that returns a non-finite objective, residual, constraint value or gradient: an error naming the value it saw, never a run that quietly reads as converged.
- A callback whose array has the wrong shape or length (a gradient for `n` variables, a Jacobian of `nR×nP`, a residual of the same length as `x0`, an `r×n` constraint matrix): refused with the shape it received.
- An underdetermined least-squares problem (`nR < nP`), a residual whose length changes mid-fit, a damping that collapses, and a vanished or non-descent search direction: refused with the diagnosis. The `LevenbergMarquardtFit` surface reports the singular solve and the collapse as `FitStalled` on the best point reached instead of refusing them.
- A `Sigma` that is not a vector of positive variances or an exactly symmetric positive definite matrix: refused at entry, naming the offending element or pair.
- A bracket that does not change sign, or one that evaluates to a non-finite value: refused by `FindRoot` and `FindRootBrent`.
- An infeasible linear program: refused with the phase-1 infeasibility and the row that carries the worst of it; an unbounded one with the column that prices out as a profitable ray.
- A non-symmetric or non-positive-definite `H` in `MinimiseQP`: refused at entry with the failed pivot named; an `x0` that violates a row by more than 1e-9 is refused with the worst violation.
- An exhausted iteration budget in any solver whose `AllowBudgetExit` is `false`: refused, as described above.
- A failure to reach feasibility in 40 augmented-Lagrangian rounds: refused with the worst remaining row violation. Feasibility itself is judged against a fixed absolute threshold of `1e-10`, independent of the inner solver's tolerance.
#### Workflow
```go
package main
import (
"fmt"
"math"
"sourcedock.dev/petrbalvin/tensor"
"sourcedock.dev/petrbalvin/tensor/optim"
)
// Fit y = a·exp(−b·t) to measurements, then report the parameters and
fmt.Printf("x = %.4f, f = %.3e\n", x.FloatAt(0), f)
}
```
### Package `io`
Reading and writing the formats scientific data arrives in: comma-separated
text, FITS images and tables, HDF5, NetCDF classic and native-endian memory
maps. Every loader returns the library's own `Array`, so a file read is an
ordinary value the rest of the library operates on, and every writer takes one.
Each format is covered by a documented subset, and what lies outside it is
refused with an error naming the feature rather than half-read or guessed at.
The subset, and every refusal, is written down under [Format
support](#format-support).
#### CSV
| Call | What it does |
|---|---|
| `LoadCSV(path, skipHeader)` | Reads a 2-D float64 array from a CSV file. Every row must have the same number of fields; a header row is data unless `skipHeader` is true. An empty file gives a zero-shaped array. |
| `LoadCSVReader(r, skipHeader)` | Reads the same from any `io.Reader`. A leading UTF-8 byte order mark is skipped. A field that is not a number is refused with its row and column. |
| `SaveCSV(path, a)` | Writes a 2-D array to `path` as comma-separated values. The close error is part of the write. |
| `SaveCSVWriter(w, a)` | Writes a 2-D array as CSV to `w`. Complex arrays are refused, as is an array with no columns, whose CSV form would read back as a zero-shaped array. |
Values go out with the shortest text that round-trips the float64.
#### FITS images
| Call | What it does |
|---|---|
| `SaveFITS(path, a, headers)` | Writes a float64 or float32 array as a FITS primary image with the given header entries. Keywords are uppercased and must be 1 to 8 characters of `A-Z`, `0-9`, `-` and `_`; the reserved ones are refused. Values go out as FITS strings of at most 68 characters after quote escaping. |
| `LoadFITS(path)` | Reads a FITS primary image into a float64 (BITPIX -64) or float32 (BITPIX -32) array and returns every non-structural header entry with it. `NAXIS = 0` gives an empty array. |
the keywords differ from the identity; float32 values are computed in float64
and rounded once. `SaveFITS` refuses those two because it writes physical
values, and a scaling card would make a conforming reader scale them a second
time.
#### FITS tables
| Call | What it does |
|---|---|
| `SaveFITSTable(path, ascii, cols, headers)` | Writes a zero-axis primary HDU followed by one table extension: a binary table by default, an ASCII table when `ascii` is set. The headers land in the extension's header beside the column cards. |
| `LoadFITSTable(path)` | Reads the first table extension (`XTENSION` `BINTABLE` or `TABLE`), skipping the primary HDU and any images before it. Numeric columns come back as arrays, character columns as string slices. |
A binary column form is `D` (float64), `E` (float32), `K` (int64), `L`
(logical), `B` (unsigned byte), `I` (16-bit) or `J` (32-bit), each with a
repeat of one, or `nA` for a character string of n characters. The writer
stores `D`, `E`, `K`, `L` and `nA`; the reader decodes all of them and
truncates a character field at its trailing spaces. An integer column scaled
by `TSCALn`/`TZEROn` keeps the int dtype while the map stays integral and
promotes to float64 otherwise.
The ASCII forms are `nA` (or `A`), `Iw`, `Fw.d`, `Ew.d` and `Dw.d`, where w is
the column width in characters. Cells are separated by one space and written
with `TBCOLn` column starts. A value that does not fit its declared width is
refused at write time. On read, a blank cell is skipped; the Fortran-specific
`Dw.d` exponent and the exponent-less `1.5+03` form are accepted.
#### HDF5
| Call | What it does |
|---|---|
| `LoadHDF5(path)` | Reads every dataset of a file, in path order, as numeric arrays with their paths, shapes and attributes. |
| `SaveHDF5(path, datasets, groupAttrs, opts)` | Writes numeric datasets as an HDF5 file: the mirror of `LoadHDF5`. The paths build the group tree, so the file reads back with the same paths, shapes, dtypes and values. |
| `SaveHDF5Text(path, texts, opts)` | Writes fixed-length string datasets, the string side of the datatype message the reader refuses for data but accepts for attributes. These files are for other readers of the format. |
The paths are absolute (`/scan/temperature`), each written once, and an
intermediate group is created as needed. A dataset's `Attrs` are written on
the dataset itself; the attributes of the root and of the groups come from
`groupAttrs`, keyed by group path with the root keyed `/`. Attribute values
are parsed back into typed attributes: a whole number becomes an int64
attribute, a decimal a float64 one, a bracketed list an int64 or float64
array, and anything else a fixed-length string. The written file is
deterministic: children are laid out in sorted name order.
#### NetCDF classic
| Call | What it does |
|---|---|
| `LoadNetCDF(path)` | Reads a NetCDF classic file (CDF-1 and CDF-2) into its dimensions, its variables and its global attributes. Each variable lands the core dtype its classic type code carries: `NC_BYTE` as int8 (signed in the classic model), `NC_CHAR` as uint8 raw bytes, `NC_SHORT` as int16, `NC_INT` as int32, and `NC_FLOAT` and `NC_DOUBLE` as float64. A type code beyond the classic six is refused by name. |
| `SaveNetCDF(path, dims, vars, attrs)` | Writes a NetCDF classic (CDF-1) file: dimensions, variables and text attributes. |
Variables carry their own attributes; only the global attributes come back in
the map. Attribute keys are written in sorted order so the same inputs give
the same bytes. Names must follow the traditional grammar: the first
character alphanumeric or `_`, the rest alphanumeric or one of `_.@+-`.
#### Memory mapping
| Call | What it does |
|---|---|
| `MapFloats(path, offset, n)` | Maps n float64 values of `path`, starting at byte `offset`, into a read-only one-dimensional array. |
| `MapFloat32s(path, offset, n)` | Maps n float32 values, with the same contract. |
| `MapInts(path, offset, n)` | Maps n int64 values, with the same contract. |
| `SaveNativeFloats(path, values)` | Writes float64 values to `path` in the machine's native byte order, the format `MapFloats` reads back. |
The mapped array is a live view of the file's pages: `release` unmaps it and
any use of the array afterwards is a use-after-free, so `release` comes
strictly last. The values must have been written in the machine's native byte
order (`binary.NativeEndian`); the offset must be a multiple of the element
size, which is 8 for `MapFloats` and `MapInts` and 4 for `MapFloat32s`.
#### Options and results
**`FITSTable`**: a parsed table extension. `Names`, `Units`, `Columns` and
`Text` run parallel to the file's column list: a numeric column holds its
values in `Columns` and nil in `Text`, a character column holds its strings in
`Text` and nil in `Columns`.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Kind` | `string` | from the file | `BINTABLE` or `TABLE`. |
| `Names` | `[]string` | from the file | The `TTYPEn` of each column. |
| `Units` | `[]string` | from the file | The `TUNITn` of each column, empty when the card is absent. |
| `Columns` | `[]*core.Array` | from the file | One array per column, nil for a character column. |
| `Text` | `[][]string` | from the file | One string slice per column, nil for a numeric column. |
| `Rows` | `int` | from the file | The row count, `NAXIS2`. |
| `Headers` | `map[string]string` | from the file | Every other header card of the extension. |
**`FITSTableColumn`**: one column of a table to write.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Name` | `string` | required | The column name, written as `TTYPEn`. It must be 1 to 68 characters. |
| `Unit` | `string` | `""` | The unit, written as `TUNITn`; an empty unit writes no card. |
| `Form` | `string` | required | The TFORM descriptor, uppercased on write. See [FITS tables](#fits-tables) for the accepted forms. |
| `Data` | `*core.Array` | `nil` | The values of a numeric column, a vector of the dtype its form requires, one element per row. |
| `Text` | `[]string` | `nil` | The strings of a character column, one per row. A numeric column must carry `Data`, and a `Text` on it is ignored; a character column must carry `Text` and must not carry `Data`. |
**`HDF5Dataset`**: one dataset of a file: its path from the root, its shape
(row-major, as the file stores it), its values and its attributes. The
attribute map also carries the attributes of the groups the dataset sits in,
the nearest one winning. On read, `Shape` and `Values` are filled. On write,
the shape is taken from `Values`; a non-nil `Shape` that disagrees with them
is refused.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Path` | `string` | required | The absolute path from the root, `/scan/temperature`. |
| `Shape` | `[]int` | `nil` | The shape to write; nil means the shape of `Values`. |
| `Values` | `*core.Array` | required | The values, int64, float32 or float64. A complex array is refused. |
| `Attrs` | `map[string]string` | `nil` | The attributes of the dataset, written on it. |
**`HDF5TextDataset`**: one fixed-length string dataset for `SaveHDF5Text`:
`Text` holds the elements in row-major order, each padded to the longest
element in the file.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Path` | `string` | required | The absolute path from the root. |
| `Shape` | `[]int` | required | The shape of the dataset; the element count must equal `len(Text)`. |
| `Text` | `[]string` | required | The elements in row-major order. A NUL byte cannot be carried by a fixed-length element and is refused. |
**`HDF5WriteOptions`**: tunes `SaveHDF5` and `SaveHDF5Text`. The zero value
writes the classic file layout with contiguous datasets. When several option
values are passed, the last one wins.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Latest` | `bool` | `false` | Writes superblock version 3 with version 2 object headers: groups become link messages and every structure the format checksums carries a lookup3 sum. Latest files hold contiguous datasets only, so combining `Latest` with a filter is refused. |
| `Gzip` | `int` | `0` | Applies the deflate filter at the given level: 0 disables it, -1 is the default level and 1 to 9 are the levels of the format. A level outside that set is refused. A filtered dataset is stored in chunks. |
| `Shuffle` | `bool` | `false` | Applies the shuffle filter before deflate, regrouping the bytes of each element so compression sees the high-order bytes together. Shuffle alone also forces chunks. |
| `ChunkBytes` | `int` | `0` | The target size of one chunk in bytes for filtered datasets; 0 selects 64 KiB. Datasets smaller than the target stay in one chunk. A negative target is refused, and a target so small that the dataset needs more than 4194304 chunks is refused with a hint to raise it. |
**`NetCDFDim`**: one named dimension of a NetCDF classic file. A length of
zero is the record dimension (the unlimited one): only it may be zero, it must
lead the list, and its extent is the number of records, which a record
variable carries on its first axis. Reading a file and writing it back
preserves the record dimension.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Name` | `string` | required | The dimension name, under the traditional name grammar. A duplicate name is refused. |
| `Length` | `int` | `0` | The extent. A negative length is refused; zero declares the record dimension. |
**`NetCDFVar`**: one named variable of a NetCDF classic file. Values are
row-major with the slowest dimension first, exactly as the file stores them,
and `Dims` names the dimensions in that same order.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Name` | `string` | required | The variable name, under the traditional name grammar. A duplicate name is refused. |
| `Dims` | `[]string` | `nil` | The dimension names, slowest first. Every one must be declared; a record dimension in a later position is refused. A variable with no dimensions is a scalar. |
| `Values` | `*core.Array` | required | The values: float64, float32 or int64. The element count must equal the extent of the dimensions; a record variable must hold a whole number of records. |
| `Attrs` | `map[string]string` | `nil` | The variable's attributes, written as text. |
#### Format support
| Format | Reads | Writes | The subset that is implemented |
|---|---|---|---|
| CSV | `LoadCSV`, `LoadCSVReader` | `SaveCSV`, `SaveCSVWriter` | 2-D arrays: the writer formats every numeric dtype the core carries (bool as 0 and 1, the integer classes as exact decimals, float16 through its exact widening). Complex arrays and arrays with no columns are refused on write. |
| FITS image | `LoadFITS` | `SaveFITS` | The primary HDU, BITPIX -64 and -32, any rank with positive axes. |
| FITS table | `LoadFITSTable` | `SaveFITSTable` | The `BINTABLE` and `TABLE` extension kinds, and nothing else. |
| HDF5 | `LoadHDF5` | `SaveHDF5`, `SaveHDF5Text` | See the two lists below. |
| NetCDF classic | `LoadNetCDF` | `SaveNetCDF` | The classic model: CDF-1 and CDF-2 read, CDF-1 written. |
| Native-endian map | `MapFloats`, `MapFloat32s`, `MapInts` | `SaveNativeFloats` | float64, float32 and int64 payloads in the machine's own byte order. |
**HDF5 read.** Superblock generations 0 to 3. Generations 0 and 1 are the
classic layout; generations 2 and 3 carry a lookup3 checksum over the
superblock, which is verified, and name the root group by its object header
address. The address and length widths are 4 or 8 bytes. Refused by name: a
superblock version of 4 or more, a non-zero base address, the superblock
extension.
Object headers of version 1 and version 2, version 2 headers being checksummed
and their continuation blocks with them; a header may chain through at most
512 continuation blocks. Groups are read from symbol tables (version 1 group
B-tree, local heap, symbol table nodes) and from version 1 link messages.
Refused by name: a dense group (the fractal-heap link storage), a link message
of another version, a group B-tree more than 32 levels deep.
Datasets are read from contiguous, compact and chunked storage; a chunked
dataset in a superblock 2 or later is refused, because the reference library
indexes such chunks with the version 2 B-tree. The chunk B-tree is walked at
most 32 levels deep. Filter pipelines of version 1 are read, with the deflate
(1), shuffle (2) and fletcher32 (3) filters; the fletcher32 checksum is
verified, and any other filter identifier is refused by name.
Datatypes: fixed-point values of 1, 2, 4 and 8 bytes land in the dtype of
their own width and sign: 1-byte signed and unsigned read as `Int8` and
`Uint8`, 2-byte as `Int16` and `Uint16`, 4-byte as `Int32` and `Uint32`,
8-byte signed as `Int`; unsigned 64-bit data is refused, because float64
cannot hold every value of it. Floating-point values of 4 and 8 bytes read
as `Float32` and `Float`. A boolean dataset written as an HDF5 enumeration
(a one-byte unsigned base with member values 0 and 1) lands `Bool`; every
other enumeration and every bitfield is refused by class name. A big-endian
element is refused by name. Refused for data: string datasets,
variable-length data, and the remaining datatype classes. Dataspace message
versions 1 and 2 are read; a dataset with a dimension permutation is
refused.
Attributes of an object header are read into a text map: a fixed-length string
verbatim, a variable-length string through the global heap, a numeric value
formatted as decimal, with several values as `[a, b, c]`. An attribute message
the reader cannot decode is left out of the map rather than failing the read.
An object reachable through several hard links is read once, under the first
path the traversal reaches it from, and a soft or external link is skipped,
since it names no object of this file. A hard-link cycle along the current
path and a walk deeper than 512 group levels are refused.
A dataset of more than 2 GiB, and the datasets of a file summing past that
budget, are refused with a hint that larger datasets belong behind mmap.
**HDF5 write.** Superblock version 0 (the default, classic layout) or 3
(`Latest`); object headers version 1 or 2; groups as symbol tables or as link
messages; datasets contiguous, or chunked through a version 1 chunk B-tree
when a filter applies. Every address and length is eight bytes. The datatypes
written are the boolean enumeration (`Bool`), 1-, 2-, 4- and 8-byte
fixed-point at their native widths and signs (`Int8`, `Uint8`, `Int16`,
`Uint16`, `Int32`, `Uint32`, `Int64`), 4-byte and 8-byte floating-point
(`Float32`, `Float`), and fixed-length strings (`SaveHDF5Text`); `Float16`
and `Complex` are refused, because `LoadHDF5` decodes neither. Written files
stay byte-deterministic, and the files the previous releases wrote keep
their exact bytes. A filtered
dataset in a latest-version file is refused, as are the deflate and shuffle
filters for string datasets, which are written contiguously. Bounds: a rank of
at most 32, an object path of at most 4096 bytes, at most 4096 attributes on
one object. A group path in `groupAttrs` that names no group of the file is
refused.
**FITS.** Only the primary HDU is read as an image: a file whose first card is
`XTENSION` is refused, and so is any `BITPIX` other than -64 and -32. The
table loader instead walks the HDUs and returns the first `BINTABLE` or
`TABLE` extension it finds, refusing any other extension kind by name rather
than guessing its size. A binary table column of another repeat count than one
(a `3E` vector) and every variable-length form (`P`, `Q`) are refused by name.
On the image side the header must open with `SIMPLE` and `SIMPLE = F` is
refused, `COMMENT`, `HISTORY` and blank cards carry no value and are skipped,
and a header without an `END` card is an error.
**NetCDF.** The classic model only: CDF-1 and CDF-2 are read (CDF-2 addresses
its offsets with 64-bit words, its record count stays 32-bit), CDF-5 is
refused by version. The writer emits CDF-1 and refuses a file at or past
2 GiB, which a CDF-1 offset cannot address. Types read: `NC_BYTE` lands
`Int8`, `NC_SHORT` lands `Int16`, `NC_INT` lands `Int32` and `NC_CHAR`
lands `Uint8` (a CHAR variable carries raw bytes at the array level, not
text), while `NC_FLOAT` and `NC_DOUBLE` keep their float64 landing; a type
code beyond the classic set is refused by name. Types written: float64 as
`NC_DOUBLE`, float32 as `NC_FLOAT` and int64 as `NC_INT`, the widest
integer of the classic model: a value outside the int32 range refuses by
name rather than truncating, and a variable that landed a narrow dtype
from a file is refused by the writer until it is converted with `Astype`.
Attributes are
written as `NC_CHAR`; on read, a numeric attribute is rendered as decimal
text.
A record dimension (length zero) may be declared first, at most one per file.
A variable whose first dimension is the record dimension is a record variable:
it must hold a whole number of records, every record variable must agree on
that number, and the file interleaves one slab of each per record, padded to
four bytes, the layout the classic model defines. On read, the record
dimension comes back with length zero and each record variable's first axis
carries the record count the file declares. A rank-0 variable comes back as a
one-element vector with no dimension names, since an array always carries at
least one dimension.
#### Errors
- A shape or dtype a writer cannot store (a complex array to CSV or HDF5, an
array that is not 2-D, an int64 value outside the int32 range NetCDF stores):
an error naming the shape, the dtype or the value.
- A refused format feature (an unsupported datatype class, storage layout,
filter, extension kind or NetCDF type): an error naming the feature, never a
partly read result.
- Malformed input (a truncated header, a card without an `END`, a row with the
wrong field count, a chunk outside the file): an error naming the byte
offset, the row or the field.
- A hostile declaration (a dimension or dataset extent larger than the file
can hold, a cycle in the group tree): an error from the bounds check that
runs before the allocation, not a panic and not a truncated read.
- A missing file or an unreadable one: the operating system's error, wrapped
with the name of the call.
- Every error carries the library's `tensor: ` prefix and the name of the
It prints `/scan/temperature [2 2] float degC cruise`: the dataset's own
`units` attribute beside the `title` it inherits from the root group.
### Package `grad`
Reverse-mode automatic differentiation over the shared array surface. A
computation written as ordinary Go calls over `Tensor` values records a
graph, and one call to `Backward` propagates the gradient from the
output back to every leaf that requires it:
```mermaid
sequenceDiagram
participant Caller
participant Ops as the forward ops
participant Graph as the recorded graph
Caller->>Ops: build the pass from leaves
Ops-->>Graph: each call records its node and inputs
Caller->>Graph: loss.Backward()
Graph-->>Graph: reverse sweep, each node applies its adjoint
Graph-->>Caller: every leaf reads its Grad
```
The package deliberately stops at that graph. There is no forward-mode
differentiation, nothing beyond the second derivative, no graph
serialisation and no parameter registry: the caller owns the leaves, the
graph is a transient record of one forward pass, and the operation set is
closed, so a new primitive is a new method here and never a
user-registered op.
#### Building a graph
| Call | What it does |
|---|---|
| `FromFloat64s(vals, requiresGrad, shape...)` | A float64 leaf built from a copy of `vals`; the shape needs at least one dimension and must hold exactly `len(vals)` elements, and anything else is an error. |
| `FromArray(a, requiresGrad)` | Wraps an existing array as a tensor without copying it; `requiresGrad` marks it as a leaf whose gradient `Backward` fills. |
| `Tensor.Data()` | The underlying array. |
| `Tensor.Grad()` | The accumulated gradient, `nil` before the first `Backward`. |
| `Tensor.RequiresGrad()` | Whether the tensor is a trainable leaf. |
| `Tensor.ZeroGrad()` | Discards the accumulated gradient. |
| `Tensor.SetGrad(g)` | Replaces the gradient array outright: the hook for clipping, accumulation resets and test harnesses. |
| `Tensor.ReplaceWith(a)` | Swaps the underlying data array, the one mutable point the optimisers use for parameter updates. A graph built before the swap keeps differentiating against the operands its closures captured. |
Only `Tensor` values that require grad carry a node; the result of an
operation requires grad when any of its inputs does, so `RequiresGrad`
is true for intermediate results as well as for leaves. `FromFloat64s`
and `FromArray` are the only constructors.
#### Running the backward pass
| Call | What it does |
|---|---|
| `Tensor.Backward()` | Seeds the output with ones, sweeps the recorded graph in reverse and accumulates the gradient into every leaf that requires it. It refuses an output that does not require grad, and a complex output, whose seed would not be a real scalar objective. |
To differentiate the graph without touching the leaves, as the
second-order helpers do, the internal reverse pass computes into a local
map and commits nothing; the public `Backward` is the call that writes
the leaves' `Grad`.
#### Arithmetic
| Call | What it does |
|---|---|
| `Tensor.Add(u)` | `t + u`. |
| `Tensor.Sub(u)` | `t - u`. |
| `Tensor.Mul(u)` | Element-wise product `t·u`; the complex adjoint conjugates the other factor. |
| `Tensor.Scale(f)` | Every element times the constant `f`; the backward multiplies by the same factor. |
| `Tensor.Pow(n)` | `xⁿ` for an integer `n ≥ 0`; a negative exponent is an error. The exponent-0 backward is zero everywhere, including at `x = 0`, where `n·xⁿ⁻¹` would be a NaN. |
| `Tensor.Abs()` | The absolute value of each element. The real subgradient is `sign(x)` with 0 at zero; the complex one is `z/(2r)` for the magnitude `r`, also zero at the origin. |
| `Tensor.Abs2()` | The squared magnitude as a real tensor. The complex backward is `dz = g·z`; a real operand is squared in float64 and rounded once, keeping its own width. |
| `Tensor.Sqrt()` | `√x`; the backward is `g/(2√x)` with the denominator floored at `1e-12`. A negative input is not refused: the NaN the forward produces flows into the gradient. |
| `Tensor.Exp()` | `eˣ`, complex included, where the holomorphic adjoint multiplies by the conjugated output. |
| `Tensor.Log()` | The natural logarithm. The domain is the caller's, so a non-positive input reaches the gradient without a report; shift the input inside its domain first. |
| `Tensor.Sigmoid()` | The logistic sigmoid; the backward is `g·σ·(1−σ)`. |
| `Tensor.Tanh()` | The hyperbolic tangent; the backward is `g·(1−tanh²)`. |
| `Tensor.Clip(lo, hi)` | Clamps into `[lo, hi]`; the gradient passes through only where `lo ≤ x ≤ hi`. |
| `Tensor.Floor()` | Rounds down with an all-zero gradient, its derivative being zero almost everywhere. |
The dtype gate is uniform: every method accepts float, float32 and
complex input except where its own row says otherwise, and the exceptions
are exactly these. `Log`, `Sigmoid`, `Tanh`, `Clip`, `Floor`, `Sqrt`,
`MeanAxis`, `L2NormAxis` and `MatMulBatched` are float and float32 only
and refuse a complex tensor with an error naming the dtype they got.
`Imag` and `IRFFT` need a complex tensor, `RFFT` needs a real one, and
both of those name the dtype they got too.
#### Matrix products
| Call | What it does |
|---|---|
| `Tensor.MatMul(u)` | The differentiable matrix product over the shapes `MatMul2D` accepts: 2-D×2-D, 2-D×1-D and 1-D×2-D. The complex adjoint conjugates and transposes, `dA = g·Bᴴ` and `dB = Aᴴ·g`. |
| `Tensor.MatMulBatched(u)` | Stacked 3-D matrices multiplied batch-wise, `(N, M, K)·(N, K, P) → (N, M, P)`; a rank other than 3, a batch mismatch or an inner-dimension mismatch is an error. Float and float32 only. |
#### Reductions
| Call | What it does |
|---|---|
| `Tensor.Sum()` | All elements into a single-element tensor; a complex tensor sums in complex. |
| `Tensor.Mean()` | The mean into a single-element tensor, keeping the operand's dtype; an empty tensor is an error. |
| `Tensor.SumAxis(dim)` | Sums along `dim` and drops it; the backward broadcasts the incoming gradient back over the reduced dimension. |
| `Tensor.MeanAxis(dim)` | Averages along `dim` and drops it; the backward scales by `1/size(dim)` before the broadcast. Float and float32 only. |
| `Tensor.L2NormAxis(dim)` | The L2 norm along `dim`, dropped from the shape. The result is float64 whatever the operand's dtype, and the backward divides each element by its line norm, floored at `1e-12` so a zero line does not divide by zero. |
#### Shape, layout and joining
| Call | What it does |
|---|---|
| `Tensor.Reshape(shape...)` | A view-equivalent reshape; the backward reshapes the incoming gradient back. |
| `Tensor.Squeeze(dim)` | Removes a size-1 dimension; the gradient unsqueezes back. |
| `Tensor.Unsqueeze(dim)` | Inserts a size-1 dimension; the gradient squeezes back. |
| `Tensor.Transpose()` | Reverses the dimensions; the gradient transposes back. |
| `Tensor.TransposeAxes(dims...)` | Reorders the axes by a permutation; the backward applies the inverse permutation. |
| `Tensor.Slice(dim, start, stop)` | A range along one dimension; the backward writes the incoming gradient into the corresponding region of the original shape. |
| `Tensor.Concat(u, dim)` | Joins two tensors along an existing dimension, every other dimension agreeing; the backward routes each side its own span, narrowed to the side's dtype first. |
| `Tensor.BroadcastTo(shape...)` | Expands under broadcasting rules, size-1 dimensions replicating; the backward sums the gradient over every replicated dimension. The shape is validated first, so an impossible target reports the shape mismatch; an int tensor is then refused, because only float, float32 and complex tensors carry a graph. |
#### Complex graphs
Complex tensors differentiate under the Wirtinger convention, the
convention the optimiser ecosystem settled on: the loss must be real,
and the gradient a complex leaf accumulates is `∂L/∂z̄`, the coefficient
`g` of `dL = 2·Re(g·dz)`, which is the direction gradient descent steps
along. The adjoint of a holomorphic `y = f(z)` is therefore
`dz = g·conj(f′(z))`, so every complex backward conjugates exactly where
the calculus puts it, and `Mul`, `Div`, `MatMul`, `Pow`, `Exp` and `Abs2`
follow that rule.
`Backward` enforces the real-loss rule rather than approximating it: a
complex output is rejected with
```text
tensor: Backward: the loss must be real-valued; reduce the complex result with Real, Imag, Abs or Abs2 first
```
| Call | What it does |
|---|---|
| `Tensor.Conj()` | The element-wise conjugate. It is anti-holomorphic, so its adjoint conjugates the incoming gradient, `dz = conj(g)`; on a real tensor it is a copy. |
| `Tensor.Real()` | The real part of each element as a float tensor; the complex backward halves the gradient, `∂Re z/∂z̄ = ½`. |
| `Tensor.Imag()` | The imaginary part of each element as a float tensor; the complex backward scales by `i/2`. A non-complex input is an error. |
| `Tensor.Abs()` | Of a complex tensor, the magnitude as a float tensor, with `dz = g·z/(2r)` for the magnitude `r`. |
A real tensor inside a complex graph narrows the incoming complex
gradient by `2·Re`: for a real variable, `dL/dx = 2·Re(∂L/∂x̄)`. That
factor also cancels the `½` the `Real` and `Imag` backward paths
contribute, so a graph mixing the two dtypes composes exactly.
#### Spectral transforms
| Call | What it does |
|---|---|
| `Tensor.FFT()` | The forward DFT of a rank-1 tensor; the backward multiplies the incoming gradient by `Fᴴ`, which is the inverse transform scaled by `n`. |
| `Tensor.IFFT()` | The inverse transform of a rank-1 tensor; the backward runs the forward transform scaled by `1/n`. |
| `Tensor.FFT2()` | The 2-D forward transform; the backward is the 2-D inverse scaled by `H·W`. |
| `Tensor.IFFT2()` | The 2-D inverse transform; the backward is the 2-D forward scaled by `1/(H·W)`. |
| `Tensor.RFFT()` | The real-input half-spectrum transform of a rank-1 real tensor; the backward folds the half-spectrum gradient into `dx = 2·Re(F_halfᴴ·g)` with one padded forward FFT. A complex input is an error. |
| `Tensor.IRFFT(n)` | The inverse half-spectrum transform, `n/2+1` complex bins into a real signal of length `n`; the backward widens the real gradient to a full forward FFT and halves the self-mirrored DC bin and, for even `n`, the Nyquist bin. The input must be a rank-1 complex tensor. |
Every rank check is an error, so `FFT2` on a vector and `FFT` on a matrix
are refused rather than silently reinterpreted.
#### Second order
| Call | What it does |
|---|---|
| `Hessian(f, x, opts)` | The dense Hessian of the scalar `f` at `x`, an `(n, n)` float64 array, at the cost of `2n` gradient evaluations. Column `j` is the central difference of the analytic gradient along coordinate `j`. |
| `HessianVectorProduct(f, x, v, opts)` | `H·v`, by a central difference along the direction itself with the step normalised so it never depends on `v`'s magnitude. Two gradient evaluations answer for any `n`. A zero `v` returns zeros shaped like `x`; a `v` of a different element count is an error. |
Both call `f` with a tensor that requires grad and expect a single-element
real tensor. A complex point (and for the product, a complex direction) is
an error, as are a non-scalar result and an objective that does not depend
on `x` at all. Both differentiate without committing, so the accumulated
gradients of the tensors `f` closes over are left exactly as they were, on
the success and the error path alike.
#### Newton-CG minimisation
| Call | What it does |
|---|---|
| `MinimiseNewtonCG(f, x0, opts)` | A local minimum of the scalar `f` near `x0`, returned as the point, the objective's value there and an error. Each outer step solves `H·s = −∇f` with truncated conjugate gradients, then an Armijo backtracking line search secures descent. No dense Hessian is ever formed: each CG iteration buys one Hessian-vector product, two reverse passes, so the memory stays that of the point. The converged point is a fresh array the caller owns. |
#### Hamiltonian Monte Carlo
| Call | What it does |
|---|---|
| `SampleHMC(logDensity, q0, opts)` | Draws `opts.Samples` states from the unnormalised density whose logarithm `logDensity` computes, starting at the vector `q0`, and returns them as a `(Samples × dim)` array. Each trajectory integrates the Hamiltonian dynamics of a unit-mass particle with the leapfrog scheme, one gradient evaluation per step, and a Metropolis test on the energy change. A rejected trajectory repeats the current state, as Markov chain sampling does. |
`logDensity` receives a leaf tensor that requires grad and must return a
scalar tensor connected to it. An error it raises at `q0` is fatal; an
error raised inside a proposal marks the state as outside the support and
rejects the trajectory, which is how a constrained density keeps the
chain out of forbidden regions. A nil density, a state that is not a
non-empty real vector, a non-positive `Step`, `Steps` or `Samples`, a
negative `BurnIn`, and a density that does not yield a gradient are
errors.
#### Adjoint ODE sensitivities
| Call | What it does |
|---|---|
| `AdjointODE(f, params, t0, t1, y0, lossGrad, opts)` | Differentiates the solution of `y' = f(t, y)` at `t1` with respect to the initial state and to the parameters `f` closes over. Returns `∂L/∂y0` and, parallel to `params`, each `∂L/∂θk` shaped like its parameter. `lossGrad` is `∂L/∂y(t1)`, the seed the loss itself contributes. |
The forward trajectory is recorded at the adaptive solver's accepted
steps and handed to the backward pass through cubic Hermite
interpolation, fourth-order accurate like the Dormand-Prince pair that
produced it; the augmented adjoint system is then integrated by the same
adaptive solver in reverse, so the cost is one extra solve whatever the
parameter count. Backward-in-time problems (`t1 < t0`) work, and a
zero-length span with `t0 == t1` short-circuits to `lossGrad` for the
state and zeros for the parameters. `opts` is the `integrate` package's
`ODEOptions` (`RelTol` 1e-6, `AbsTol` 1e-9, `MaxSteps` 100000 where the
field is not positive).
#### Options and results
**`Tensor`**: a differentiable n-dimensional array. It carries no
exported fields; its state is reached through `Data`, `Grad`,
`RequiresGrad`, `ReplaceWith`, `SetGrad` and `ZeroGrad`.
**`HessianOptions`**: the stencil width the second-order helpers
perturb by.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Step` | `float64` | `0`; `Hessian` then takes `sqrt(2.22e-16)·max(1, abs(x_j))` per coordinate, about `1.49e-8·max(1, abs(x_j))`, and `HessianVectorProduct` takes an absolute `1e-5` along the normalised direction | The perturbation size. A positive value is used as given and applies in both directions, so the stencil stays central. |
**`HMCOptions`**: the sampler's trajectory and chain settings.
| Field | Type | Default | Effect |
|---|---|---|---|
| `Step` | `float64` | none; must be positive, `0` is an error | The leapfrog step size. |
| `Steps` | `int` | none; must be at least 1, `0` is an error | Leapfrog steps per trajectory, so the trajectory length is `Step·Steps`. |
| `BurnIn` | `int` | `0` | Trajectories discarded before the first sample is kept; negative is an error. |
| `Thin` | `int` | `0` | Every `Thin`-th trajectory after the burn-in contributes one sample; zero or less normalises to `1`. |
| `Samples` | `int` | none; must be at least 1, `0` is an error | Kept states; the result is a `(Samples × dim)` array. |
| `Seed` | `int64` | `0` | Seeds the package's xoshiro generator, so a run is bit-reproducible. |
**`NewtonCGOptions`**: the outer iteration budget, the stopping
tolerance and the inner solve budget.
| Field | Type | Default | Effect |
|---|---|---|---|
| `MaxIterations` | `int` | `100`; zero or less takes the default | The outer Newton step budget. Exhausting it without reaching the tolerance is an error. |
| `Tolerance` | `float64` | `1e-8`; zero or less takes the default | Stops when the Euclidean norm of the gradient falls to it or below. |
| `MaxCGIterations` | `int` | `n`, the problem dimension; zero or less takes the default | The inner conjugate-gradient iterations per outer step. |
The line search halves the step up to 40 times from 1.0 and stops at the
first point satisfying the Armijo condition with constant `1e-4`; no
point satisfying it is an error. `MaxCGIterations` defaults to the
dimension because the conjugate-gradient method terminates in at most `n`
steps in exact arithmetic, and the inner solve stops early when the
residual falls to a tenth of the current gradient norm or when it meets
non-positive curvature, in which case the first iteration falls back to
the steepest descent direction.
#### Errors
- an int tensor in the graph: every differentiable call returns
`tensor: autograd: <Name> needs a float, float32 or complex tensor, got int`; the float-only calls name float and float32 instead;
- `Imag` on a real tensor, `RFFT` on a complex tensor, `IRFFT` on a real one, and `MatMulBatched` on anything but float or float32: an error naming the dtype;
- `Backward` on an output that does not require grad, or on a complex output: an error naming the condition, the complex one naming `Real`, `Imag`, `Abs` and `Abs2` as the reducers;
- `Pow` with a negative exponent: `tensor: Pow: negative exponent has no general real gradient`, the exponent being an integer argument rather than a graph node;
- a shape or range the array core refuses: `Reshape`, `Slice`, `Concat`, `Squeeze`, `Unsqueeze`, `TransposeAxes`, `SumAxis`, `MeanAxis` and `L2NormAxis` return the core's own error, and `Mean` refuses a tensor with no elements;
- `Hessian` and `HessianVectorProduct`: a complex point, a complex direction, a `v` of the wrong length, a non-scalar `f`, and an `f` that does not depend on `x`;
- `MinimiseNewtonCG`: a nil `f`, a nil or empty starting point, a complex starting point, a non-scalar or non-finite objective, a CG direction that does not descend, a line search that finds no descent in 40 halvings, and an exhausted iteration budget (the error names the gradient norm it stopped at);
- `SampleHMC`: a nil density, a nil state, a state that is not a non-empty vector, a complex state, a non-positive `Step`, `Steps` or `Samples`, a negative `BurnIn`, a density returning a non-scalar, and a density that yields no gradient;
- `AdjointODE`: a nil `f`, a state or loss seed that is not a non-empty vector, a complex state, a seed of the wrong length, a parameter that does not require grad or has no elements, an `f` returning the wrong shape, a parameter disconnected from the dynamics, and a trajectory too short to interpolate (fewer than two recorded nodes).
Every message carries the `tensor: ` prefix the library uses throughout.
#### Workflow
The flagship sequence: build the leaves, run the forward pass, call
`Backward` once, read the gradients. The imports are
`tensor "sourcedock.dev/petrbalvin/tensor"` for the array type and
`sourcedock.dev/petrbalvin/tensor/grad` for the graph.
```go
// squaredErrorGradient builds Σ (w·x)² and returns ∂L/∂w for one
// Leaves: the data does not require grad, the parameter does.
x, err := grad.FromFloat64s(xs, false, len(xs))
if err != nil {
return nil, err
}
w, err := grad.FromFloat64s(ws, true, len(ws))
if err != nil {
return nil, err
}
// Forward pass: every call records a node and its inputs.
prod, err := w.Mul(x)
if err != nil {
return nil, err
}
sq, err := prod.Pow(2)
if err != nil {
return nil, err
}
loss, err := sq.Sum()
if err != nil {
return nil, err
}
// Reverse sweep, once, then the gradient is on the leaf.
if err := loss.Backward(); err != nil {
return nil, err
}
return w.Grad(), nil
}
```
The runnable form of this and the other flagship workflows, with the
numbers they produce, is in `grad/example_test.go` and rendered beside
the package on pkg.go.dev.
### Package `plot`
Deterministic SVG line charts for scientific figures: linear axes with
five ticks each, one legend line per series, titles and axis labels,
and nothing else. The output is deterministic by contract, so a figure
in a paper is regenerated and compared exactly like any other computed
number. The series colours are part of that contract: a fixed cycle of
seven samples of the Viridis perceptual-uniform map (Smith, van der
Walt and Firing, CC0), taken over the map's legible-on-white range, so
the same series always wears the same colour. The package is small by
intent; it draws the figures, it does not stage a cinema.
| Member | What it does |
|---|---|
| `Chart` | one figure: title, axis labels, optional size, optional axis ranges, the series list |
| `Series`, `Point` | one named polyline and one data point in axis units |
| `Line(name, xs, ys)` | a `Series` from two rank-1 arrays of equal, non-zero length; any numeric dtype through the promotion ladder, non-finite values refused |
| `(*Chart).WriteSVG(path)` | renders the chart; the same chart always renders byte for byte the same file. Refuses a non-finite point in any series, the contract `Line` enforces on the caller's behalf; an axis range with a zero, inverted or non-finite span falls back to the data's own bounds |
```go
xs, _ := tensor.FromFloats(linspace, 200)
ys, _ := tensor.FromFloats(spectrum, 200)
series, _ := tensor.Line("spectrum", xs, ys)
chart := tensor.Chart{
Title: "Absorption spectrum",
XLabel: "wavelength [nm]", YLabel: "intensity",
Series: []tensor.Series{series},
}
err := chart.WriteSVG("spectrum.svg")
```
The ranges fall back to the data extent when the zero value leaves them
unset, a chart needs at least two points across its series, and every
error is prefixed `tensor: ` like the rest of the library.
### Package `spmd`
An experiment: a new surface carrying a concept that is not fully
verified and remains the subject of research, expected to move as it
settles. Explicit SPMD worlds: one program runs on many ranks, over TCP
between machines (`Listen` at rank 0, `Join` everywhere else) or in
one process over channels (`Launch`), with the same collectives and
the same answers on both transports. The determinism contract is the
package's point: the order of a reduction is a function of the data,
never of the world size, the machine, the worker count or the order
frames arrive in, so a sharded reduction and the single-array
reduction carry the same bits, for one rank or for fifty. Any failure
or deadline fails the whole world, and no collective ever returns a
partial numeric result. The package is imported explicitly; the root
facade does not re-export it.
| Member | What it does |
|---|---|
| `Launch(size, fn)` | runs the same function on `size` ranks of one process, one goroutine per rank; the failing ranks' errors come back joined in rank order |
| `Listen(addr, size, opts)` / `Join(addr, opts)` | builds the networked world: rank 0 listens and assigns ranks in dial order, the other ranks dial; the sharded reductions' results never depend on the assignment, while the same-shaped arrays' fold order is the rank order the program fixes |
| `Options` | `Timeout`, one collective's wait on the network (ten minutes by default), and `MaxMessage`, the frame ceiling a peer cannot talk the world into allocating past |
| `(*World).Rank` / `Size` / `Barrier` | this rank's place, the world's size, and a barrier |
| `Partition(globalN, size, rank)` | the rank's contiguous piece of a global axis, cut on the canonical fold partition's block boundaries; a `Span` names the global length and the piece's bounds; a negative `globalN` or a rank outside `[0, size)` is refused with an error naming the input, and valid arguments never fail |
| `(*World).Broadcast(a, root)` | delivers root's array to every rank, bits included |
| `(*World).Scatter(global, root)` | deals root's array out along the first dimension on the canonical boundaries; returns the rank's piece and its `Span` |
| `(*World).Gather(local, root)` / `AllGather(local)` | raises the pieces back into the whole on the root, or on every rank, joined in rank order |
| `(*World).ReduceShards(local, span, op, root)` / `AllReduceShards(local, span, op)` | reduces the shards of one global array: the answer is the single-array reduction's exact bits at any world size; `Sum`, `Min`, `Max`, `Prod`, and `Any`/`All` on `Bool` |
| `(*World).ReduceNormShards(local, span, p, root)` / `AllReduceNormShards(local, span, p)` | the Lp norm of the shards, the power sums folded through the canonical blocks and closed by the norm's own Sqrt and Pow; finite positive p |
| `(*World).ReduceDotShards(x, y, span, root)` / `AllReduceDotShards(x, y, span)` | the dot product of two equally sharded arrays, each rank folding its own blocks; the two shards carry the same dtype |
| `(*World).ExchangeHalos(local, halos)` | hands the edge rows of the rank's piece to its two neighbours and receives theirs, the ghost cells a domain-decomposed stencil needs; world edges answer nil, empty pieces join with empty edges |
| `(*World).ExchangeHalosOnGrid(local, halos, axis, grid)` | the same neighbour exchange on a process grid: `grid` lays the world's ranks out row-major and must cover the world exactly, the halos travel along `axis` between grid neighbours, and the edge slabs keep the piece's other dimensions |
| `(*World).Reduce(a, op, root)` / `AllReduce(a, op)` | folds the ranks' same-shaped arrays together elementwise in rank index order, the canonical order the program itself fixes; the fold runs chunk by chunk across the world instead of piling on one rank |
| `(*World).ReduceArgShards(local, span, op, root)` / `AllReduceArgShards(local, span, op)` | the global index of the extremum (`Min` or `Max`), ties by the earliest global index, NaNs skipped, the single-array ArgMax and ArgMin answer |
| `(*World).ReduceArgSortShards(local, span, root)` / `AllReduceArgSortShards(local, span)` | the global permutation that sorts the whole array, the single-array ArgSort's own answer with its tie and NaN placement |