koblas

Workspace

Reusable scratch for operations that would otherwise allocate their temporaries on every call.

Buffers are pooled by width: an operation borrows a vector of the length it needs and returns it, and the workspace hands out a different buffer for every borrow that is outstanding at the same time. That is what makes nesting safe without any central registry — a condition estimate borrowing four vectors and then calling a triangular solve that borrows a fifth simply grows that width's pool to five. One workspace can therefore serve several dimensions at once, and no two call sites can collide by accident.

A pool grows on demand and never shrinks, so a loop allocates during its first iterations and nothing afterwards. Use reserve to pay that cost up front instead.

Borrowed contents are undefined: an operation that needs zeros clears what it uses.

Not thread-safe, deliberately. A workspace is caller-owned state, so give each solver instance (or each thread) its own; sharing one across concurrent operations corrupts results. Passing none keeps the allocating behaviour, which is always correct.

val ws = Workspace().apply { reserve(n, count = 5) }
val x = DoubleArray(n)
repeat(iterations) {
    koblas.solveInto(lu, b, x, workspace = ws)
    if (koblas.rcond(lu, anorm, ws) < threshold) koblas.factorInto(a, lu)
}

Constructors

Workspace

constructor()(source)

Functions

release

fun release(buffer: DoubleArray)(source)

Returns a buffer from take to its pool.

reserve

fun reserve(size: Int, count: Int)(source)

Pre-allocates count buffers of size, so a loop does not allocate even on its first pass.

take

fun take(size: Int): DoubleArray(source)

Borrows a vector of size, which must be released. Prefer borrow, which returns it for you. Contents are undefined.

Link copied to clipboard
inline fun <T> Workspace.borrow(size: Int, block: (DoubleArray) -> T): T

Borrows a vector of size for the duration of block, returning it to this afterwards.