asum
Sum of absolute values Sum |v_i| (BLAS dasum). Sparse vectors sum over stored entries only.
axpy
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
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
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
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
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
v = alpha * v.
swap
syr
syr2
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.