Status: current · checked 2026-10-06
Entry points take a MatrixView: a pointer, shape, leading dimension and batch stride over memory the caller owns. Matrix owns memory and produces views. KernelMatrixView is the struct a kernel captures. The user contract is in the C++ API guide.
Dense storage is column-major, as in LAPACK and the vendor libraries, so view pointers, ld and stride pass to vendor kernels unchanged. The Layout enum only labels host CBLAS/LAPACKE calls. There is no row-major Matrix. Row-major data is converted at the edge (gemm by operand swap, others by to_column_major() / to_row_major() with an explicit row pitch).
Element \((i, j)\) of item \(b\) is at \(\mathtt{data}[\,b \cdot \mathtt{stride} + j \cdot \mathtt{ld} + i\,]\). rows, cols, ld, stride and batch_size are int, but every accessor (including batch_item) evaluates the batch term in int64_t. A 512 x 512 float item has stride == 262144, so the product wraps in int at \(b = 8192\). The in-item offset cannot overflow for an allocatable matrix.
Note: debug asserts must compare in int64_t. An int index has already wrapped, and a negative one converted to size_t passes the check (VectorView::at).
0 means packed:
| Argument | 0 resolves to | Constraint |
|---|---|---|
| ld | rows | resolved ld >= rows |
| stride | resolved ld * cols | Matrix: resolved stride >= ld * cols |
The ld < rows check catches an argument-order trap. The batch is the third argument of Matrix(rows, cols, batch) but the sixth of MatrixView(data, rows, cols, ld, stride, batch), so MatrixView<float> V(p, n, n, batch) means ld = batch and throws when batch < n.
Unchecked on purpose: null data and zero extents (shape-only views are passed to about 37 *_buffer_size queries), and stride >= ld * cols. Two in-repo sites violate the last one, the transposed CGS view in src/ops/ortho/ortho.cc (see known defects) and a sizing dummy in syevx_lobpcg. A throw would break both.
rows_, cols_ and batch_size_ must default-initialise to zero. The USM check reads them to decide whether a null pointer is legal.
Pointer-array vendor calls (cuBLAS *Batched) need one base pointer per item. A Matrix with batch_size > 1 allocates that array; data_ptrs(ctx) refills it from the view and waits. A sliced view inherits its parent's array, which holds the unsliced addresses until data_ptrs(ctx) is called on the slice. Fill it for the view immediately before the call.
KernelMatrixView<T, F> is an aggregate of raw pointers and int extents, built by kernel_view() and passed by value, with no ownership or backend handle.
Per-item active extents (Matrix::set_active_dims, MatrixView::with_active_dims) give item \(b\) a leading active_rows[b] x active_cols[b] block. ld and stride are unchanged. rows() and cols() report capacity; rows(b) and cols(b) report the active extents.
Per item, CSR stores rows + 1 offsets (offset_stride) and values and column indices (matrix_stride).
nnz() is a per-item capacity. convert_to<MatrixFormat::CSR>() sizes the batch by its largest item, so for (k = 0; k < nnz(); ++k) on a heterogeneous batch walks past smaller items. This is deliberate: vendor SpMM descriptors take one count for a strided batch. Use nnz(b) for an item's count and nnz_capacity() for buffer sizes. See the C++ API guide.
Entry \(i\) of item \(b\) is at \(b \cdot \mathtt{stride} + i \cdot \mathtt{inc}\); stride = 0 means size * inc. The span touched is \((\mathtt{batch}-1)\,\mathtt{stride} + (\mathtt{size}-1)\,\mathtt{inc} + 1\) (required_span_length). A matrix row is a VectorView with inc = ld; a column has inc = 1. Vector::view() is needed where template deduction must see a VectorView.
Span<T> is the 1-D argument type (eigenvalues, pivots, tau, info, workspace). Its single-element constructor Span(T&) is explicit: an implicit one let syev(q, A, W[i * n], ...) compile and overrun the caller's array.
UnifiedVector<T> is the owning USM-shared array behind Matrix and Vector. It reallocates on growth, which invalidates earlier spans. resize(n, value) is a no-op unless n exceeds the capacity; resize(n) is not. Global-scope names are using-declarations, which BATCHLAS_NO_GLOBAL_NAMES removes.
Advice calls (set_access_device, prefetch, ...) take a mandatory const Queue&. A default Queue is on Device::default_device(), the wrong device in a multi-GPU process. Span's advice calls default the queue and swallow errors.