koblas

SparseBlas

interface SparseBlas(source)

Sparse Levels 2 and 3 over validated CSC storage, in portable Kotlin.

Structural semantics are the contract, not an implementation detail. A stored zero is a position the matrix holds and participates like any other entry; an absent position is never evaluated, so a product against an infinity in the dense operand stays zero where the sparse operand stores nothing. An operation returning a fresh matrix owns every array it hands back, and its rows ascend strictly within each column.

Every routine that can allocate scratch takes a Workspace to lend it, whether that scratch is the snapshot of an operand overlapping the destination or the dense staging a Level 3 schedule works through. A call that needs none takes nothing from the one it is handed. An operation returning a fresh matrix still allocates that result, which is what it was asked for rather than scratch.

Inheritors

Functions

addScaled

abstract fun addScaled(alpha: Double, a: SparseMatrix, transposeA: Boolean, b: SparseMatrix): SparseMatrix(source)

Fresh CSC alpha · op(A) + B. The structural union is retained, including explicit zeros, cancellations, and A-only positions when alpha is zero. Zero alpha does not read A's values; B values are copied. Output rows are strictly ascending and all arrays are independently owned.

gemm

abstract fun gemm(alpha: Double, a: SparseMatrix, transposeA: Boolean, b: DenseMatrixRegion, transposeB: Boolean, beta: Double, c: DenseMatrixRegion, right: Boolean = false, workspace: Workspace? = null)(source)

C = alpha · op(A) · op(B) + beta · C (Sparse BLAS usmm) for a sparse a against a dense b and c, or C = alpha · op(B) · op(A) + beta · C when right. beta == 0.0 overwrites c without reading it, as gemv does.

A sparse matrix times a dense one stays dense and fills in nowhere, which is what puts this on the sparse half at all: it is gemv over the columns of the dense operand.

right is here for the reason dtrsm has a side and dgemm does not. dgemm needs none because its operands are the same kind and a caller picks which is which; here a is distinguished by being the sparse one and cannot be swapped, so without a side the product of a dense matrix by a sparse one is only reachable by transposing the result. workspace reuses dense staging and transpose scratch.


C = A · B for two sparse operands, into a fresh matrix.

The one routine here that returns its result rather than filling a destination, because the result's pattern is what the multiplication discovers: there is no destination to hand in before it is known, and no meaningful beta · C to accumulate into. transpose is the same shape and returns for the same reason.

A.cols must equal B.rows. An entry the arithmetic cancels to zero is kept, as a structural operation keeps one.


abstract fun gemm(alpha: Double, a: SparseMatrix, transposeA: Boolean, b: SparseMatrix, transposeB: Boolean): SparseMatrix(source)

Fresh CSC alpha · op(A) · op(B). Product support is discovered from stored positions, including explicit zeros, retained cancellations, and underflowed values; rows are sorted within every column and all result arrays are owned. When alpha == 0.0, the same structure is discovered without reading operand values, and every entry of it is zero.


abstract fun gemm(alpha: Double, a: SparseMatrix, transposeA: Boolean, b: SparseMatrix, transposeB: Boolean, beta: Double, c: DenseMatrixRegion, workspace: Workspace? = null)(source)

Direct dense-destination C = alpha · op(A) · op(B) + beta · C for two sparse operands. No sparse intermediate is created and implicit sparse zeros are not evaluated. alpha == 0.0 reads neither sparse operand's values; beta == 0.0 does not read c. Sparse value buffers shared with c are staged using workspace.


gemm with alpha = 1, beta = 0, into a fresh matrix. A.cols must equal B.rows.

gemv

abstract fun gemv(alpha: Double, a: SparseMatrix, x: DoubleArray, beta: Double, y: DoubleArray, transpose: Boolean = false, workspace: Workspace? = null)(source)

In-place y = alpha · op(A) · x + beta · y, where op(A) is Aᵀ when transpose. Per BLAS convention beta == 0.0 overwrites y without reading it, so it may arrive uninitialized, and alpha == 0.0 reads neither a nor x.

Only stored entries are visited, so an implicit zero of a forms no product: a column a does not store leaves y untouched even where x holds an infinity. A stored zero does form its product.

x and a's coefficients may share y's buffer and are snapshotted before y is scaled, with workspace lending the snapshot. A structural array is never a destination, so an aliased sparse operand shares it and only its coefficients are copied.


open fun gemv(a: SparseMatrix, x: DoubleArray, transpose: Boolean = false): DoubleArray(source)

A · x, or Aᵀ · x when transpose, into a fresh result.

symm

abstract fun symm(alpha: Double, a: SparseMatrix, b: DenseMatrixRegion, beta: Double, c: DenseMatrixRegion, lower: Boolean = true, right: Boolean = false, workspace: Workspace? = null)(source)

C = alpha · A · B + beta · C, or C = alpha · B · A + beta · C when right, interpreting square sparse a as symmetric from exactly its selected lower or upper triangle. alpha == 0.0 reads neither input; beta == 0.0 does not read c. Shared input and destination buffers are staged, with workspace reused when supplied.

Which operand alpha is folded into, and the order the terms of one entry are summed in, are the implementation's, as in every product here.

symv

abstract fun symv(alpha: Double, a: SparseMatrix, x: DoubleArray, beta: Double, y: DoubleArray, lower: Boolean = true, workspace: Workspace? = null)(source)

y = alpha · A · x + beta · y for a square sparse a interpreted as symmetric. Exactly the selected lower or upper stored triangle is read; the other triangle and implicit zeros are ignored. A stored off-diagonal entry contributes to both mirrored positions. alpha == 0.0 reads neither a nor x, and beta == 0.0 overwrites y without reading it. Aliasing x with y, or a's values with y, is supported through the staging gemv describes, which workspace lends.

syrk

abstract fun syrk(alpha: Double, a: SparseMatrix, transpose: Boolean, beta: Double, c: DenseMatrixRegion, lower: Boolean = true, workspace: Workspace? = null)(source)

Dense selected-triangle C = alpha · op(A) · op(A)ᵀ + beta · C. Only the selected lower or upper triangle of c is read or written, and products involving implicit sparse zeros are not evaluated.


abstract fun syrk(a: SparseMatrix, transpose: Boolean = false, lower: Boolean = true): SparseMatrix(source)

Fresh CSC selected triangle of op(A) · op(A)ᵀ. Stored-product support and cancellations are retained, rows are sorted, and result arrays are owned. The opposite triangle is absent rather than implicitly mirrored; consume the result with symv or symm when symmetric meaning is intended.

transpose

Fresh transposed a, still CSC, which makes this the CSC-to-CSR conversion as well. Explicitly stored zeros survive, since the transpose is structural rather than arithmetic.

On the seam rather than beside the other whole-matrix operations because the two directions of gemv leave a caller with no reason to materialize a transpose unless it means to hold it.

trmm

abstract fun trmm(a: SparseMatrix, b: DenseMatrixRegion, lower: Boolean, transpose: Boolean = false, unitDiag: Boolean = false, right: Boolean = false, alpha: Double = 1.0, workspace: Workspace? = null)(source)

B = alpha · op(T) · B in place, or B = alpha · B · op(T) when right (BLAS dtrmm). The triangle flags follow trmv. This is multiplication rather than a solve, so zero or missing diagonal entries participate normally and are never treated as singular. The destination may share a's value buffer.

trmv

abstract fun trmv(a: SparseMatrix, x: DoubleArray, lower: Boolean, transpose: Boolean = false, unitDiag: Boolean = false, workspace: Workspace? = null)(source)

Multiply x = op(T) · x in place (BLAS dtrmv), where op transposes when transpose. Only the lower or upper triangle is read; unitDiag treats its diagonal as one without reading it.

Unlike trsv, this performs no division and therefore has no singularity behavior: a missing diagonal is simply zero. The destination may share a's value buffer, staged as in trsv.

trsm

abstract fun trsm(a: SparseMatrix, b: DenseMatrixRegion, lower: Boolean, transpose: Boolean = false, unitDiag: Boolean = false, right: Boolean = false, alpha: Double = 1.0, workspace: Workspace? = null)(source)

B = alpha · op(T)⁻¹ · B in place, or B = alpha · B · op(T)⁻¹ when right (Sparse BLAS ussm). The triangle flags follow trsv; the right-hand sides are the columns of b from the left and its rows from the right. workspace reuses the diagonal and right-hand-side panel scratch. A missing diagonal entry behaves as zero, and singularity is not reported, as in dense dtrsm.

trsv

abstract fun trsv(a: SparseMatrix, x: DoubleArray, lower: Boolean, transpose: Boolean = false, unitDiag: Boolean = false, workspace: Workspace? = null)(source)

Solve op(T) · x = b in place, op transposing when transpose. x holds the right-hand side on entry and the solution on return. Only the lower or upper triangle of a is read, and unitDiag takes the diagonal as 1 without reading it, as the dense com.eignex.koblas.dense.DenseBlas.trsv does.

A missing diagonal entry represents zero. As in dense dtrsv, no singularity check is performed; singular inputs have no guaranteed numerical result. A right-hand side that is already exactly zero contributes no update, which is what keeps a column of zeros from forming 0 · infinity against a stored coefficient.

The substitution overwrites x as it goes, so coefficients sharing that buffer are snapshotted before the first write and workspace lends the snapshot.