koblas

asum

Sum of absolute values Sum |v_i| (BLAS dasum). Sparse vectors sum over stored entries only.

axpy

fun axpy(y: DenseVector, alpha: Double, x: VectorLike)(source)

y = y + alpha * x. Dense x uses SIMD; sparse x walks stored entries.

copy

dst = src (BLAS dcopy). Dense sources bulk-copy; sparse sources zero-fill then scatter.

dot

infix fun VectorLike.dot(other: VectorLike): Double(source)

aT * b. Dense×dense routes through the active com.eignex.koblas.dense.VectorKernels; a mixed pair walks the sparse side and gathers from the dense one; anything else is read entry by entry.

Every combination involving a sparse operand goes through SparseVectorKernels, where a host sparse BLAS could replace it: usdot against a dense vector, and a single-pass merge of the two ascending index lists when both are sparse.

forEachStored

inline fun VectorLike.forEachStored(block: (i: Int, v: Double) -> Unit)(source)

Visit each stored entry of this as (index, value), in ascending index order for any storage. For DenseVector that's every index in 0 until size; for SparseVector that's the entries present in the parallel index/value arrays (which may include numerical zeros); for any other VectorLike it is every index, read through VectorLike.get.

gemv

Matrix-vector product A · x into a fresh dense result (BLAS dgemv with alpha = 1, beta = 0).

The view-taking overload of Blas.gemv, for the same reason ger has one: a SparseVector operand has no BLAS counterpart, and walking only its stored entries is the point of passing one. Two dense operands dispatch to the backend, so this is a shape adapter rather than a second implementation.

Every combination of the two storages resolves to a loop over stored entries only. That matters most for a SparseMatrix operand: the generic fallback below reads through MatrixView.get, which on CSC is a search per entry, so a sparse matrix taking that path would cost rows × cols searches instead of the nnz the representation exists to deliver.

No transpose flag: for a sparse matrix use com.eignex.koblas.sparse.gemv, which takes one.

ger

Rank-one update A = A + alpha · x · yᵀ (BLAS dger). Subtract by passing alpha = -1.0.

Two dense operands dispatch to the installed backend through LinearAlgebra.ger. A sparse or mixed pair has no BLAS counterpart and stays here, visiting only the rows and columns where x_i · y_j can be non-zero.

iamax

Index of the first entry with maximal |v_i| (BLAS idamax), or -1 for a zero-length vector. "First" is by index for either storage: a SparseVector's stored entries are ascending, so its storage order is index order and the two contracts agree. An all-unstored (zero) vector returns index 0, matching the dense zero vector.

norm1

Matrix 1-norm: the maximum absolute column sum (LAPACK dlange with norm 1). This is the anorm input LinearAlgebra.rcond expects, computed on the matrix before factoring, so a solver that estimates conditioning each refactorization calls both.

Takes no workspace, unlike LinearAlgebra.rcond, because it needs no scratch: a column is contiguous, so each column sum completes before the next begins and one accumulator suffices. Row-major storage forced a running total per column and therefore an n-wide array; that is what the workspace argument used to be for.

norm2

Euclidean norm ||v||₂ (BLAS dnrm2). Sparse vectors sum over stored entries only.

The fast path is a plain sqrt(sum of squares); when that sum overflows or drowns in underflow (components beyond roughly 1e±150), a rescaled two-pass recovers the netlib-accurate result, so any finite input yields the correct norm.

normFro

Frobenius norm: sqrt(Sum a_ij²) (LAPACK dlange with norm F).

One pass over the flat backing, and it reuses the shared rescaling rather than growing a third copy of it — a matrix whose entries square out of range is no less likely than a vector's.

normInf

fun normInf(a: DenseMatrix, workspace: Workspace? = null): Double(source)

Matrix infinity-norm: the maximum absolute row sum (LAPACK dlange with norm I).

The awkward one under column-major storage, and the reason it takes a workspace where norm1 does not. A column is contiguous, so a column sum finishes before the next begins and one accumulator serves; row sums all advance together, so this needs a rows-wide running total. That is exactly the array norm1 itself needed back when the storage was row-major.

rot

fun rot(x: DenseVector, y: DenseVector, rotation: Givens)(source)

Apply a plane rotation to a pair of vectors in place (BLAS drot): each (x_i, y_i) becomes (c·x_i + s·y_i, c·y_i − s·x_i).

Deliberately off the com.eignex.koblas.dense.VectorKernels seam, for now, and the reason is the same one that keeps copy and swap off it: whether a foreign call beats the loop has to be measured, not assumed. A rotation does more arithmetic per element than a copy, so it plausibly clears the bar where copy does not — but "plausibly" is not a threshold, and the machine available when this was written could not resolve a 5 ns operation. Adding it to the seam later is additive; guessing wrong now is not.

rotg

Generate the plane rotation that zeroes b against a (BLAS drotg).

Scales by the larger magnitude before squaring, so a pair whose squares would overflow or vanish still produces the right rotation — the same reason norm2 rescales, and not optional: hypot(1e200, 1e200) is representable while 1e200² is not.

Follows netlib drotg's sign convention rather than inventing one, since a caller reconstructing the factorization depends on it: r takes the sign of whichever input was larger in magnitude. The degenerate all-zero pair yields the identity rotation (c = 1, s = 0, r = 0) rather than a NaN.

Together with rot this is what a factorization update needs — QR or Cholesky update and downdate, and the Forrest-Tomlin basis update a simplex uses. koblas has none of those yet; this is the primitive they all require.

scale

fun scale(v: DenseVector, alpha: Double)(source)

v = alpha * v.

swap

Exchange the contents of a and b (BLAS dswap).

syr

fun syr(alpha: Double, x: VectorLike, a: DenseMatrix, uplo: Uplo = Uplo.FULL)(source)

Symmetric rank-1 update A += alpha · x · xᵀ (BLAS dsyr); see Blas.syr.

The symmetric counterpart of ger, and what accumulating a covariance one observation at a time is.

syr2

fun syr2(alpha: Double, x: VectorLike, y: VectorLike, a: DenseMatrix, uplo: Uplo = Uplo.FULL)(source)

Symmetric rank-2 update A += alpha · (x · yᵀ + y · xᵀ) (BLAS dsyr2); see Blas.syr2.

transpose

Fresh transposed matrix Aᵀ. Always materializes; for products against a transposed operand, prefer the transpose flags on LinearAlgebra.gemv / LinearAlgebra.gemm, which read the original storage without copying.


Fresh transposed matrix Aᵀ, still CSC — which makes this the CSC-to-CSR conversion as well.

Worth more than symmetry with DenseMatrix.transpose: transposing compressed-sparse-column is compressed-sparse-row of the original, so this is what a host library wanting row-major sparse input needs (MKL's inspector-executor in CSR mode, some CHOLMOD paths). Groundwork for a host sparse backend as much as a missing routine.

Two counting passes, no searching: tally the entries per row of this to lay out the result's colPtr, then scatter each entry to its place. O(nnz + rows + cols).

Explicitly stored zeros survive, because equality on SparseMatrix distinguishes them — dropping them here would make transpose().transpose() a different matrix from the original.