Hybrid (ELL + COO overflow)#
Hybrid splits each row’s non-zeros between a fixed-width ELL section and an overflow COO tail. The ELL part keeps the regular, coalesced-friendly layout for the common portion of every row, while the COO part absorbs any non-zeros that exceed the ELL width, typically a few long rows in an otherwise short-row matrix. SpMV runs as the sum of an ELL SpMV and a COO SpMV; both kernels still touch the same input and output vectors, but each is well-tuned for the layout it operates on.
Storage layout#
A Hybrid matrix owns two child matrices:
An internal
gko::matrix::Ellof width \(k_\text{ell}\) holding the first \(k_\text{ell}\) non-zeros of every row (padded as usual when a row has fewer).An internal
gko::matrix::Cooholding the remaining non-zeros, only populated for rows whose original non-zero count exceeded \(k_\text{ell}\).
Matrix (4 × 4, one heavy row at the bottom):
[ 1 0 2 0 ] ELL part (k_ell = 2, column-major):
[ 0 3 0 0 ] values = [1, 3, 4, 6, 2, 0, 5, 7]
[ 4 0 5 0 ] col_idxs = [0, 1, 0, 0, 2, *, 2, 1]
[ 6 7 8 9 ]
COO part (overflow from row 3):
row_idxs = [3, 3]
col_idxs = [2, 3]
values = [8, 9]
The ELL part dominates storage on a typical matrix: the COO overflow holds only the entries the ELL split could not accommodate.
Choosing the split: strategies#
The width \(k_\text{ell}\) is the central knob. Pick it too small and the COO tail grows; pick it too large and the ELL padding wastes memory. Hybrid ships five strategies that pick \(k_\text{ell}\) for you at construction time:
Strategy |
What it picks |
|---|---|
|
An |
|
A fixed user-supplied column count. |
|
A \(k\) that keeps at least |
|
Like |
|
An |
The chosen strategy is set on the Hybrid object before reading the data:
auto hybrid = gko::matrix::Hybrid<double, int>::create(
exec,
std::make_shared<
gko::matrix::Hybrid<double, int>::imbalance_limit>(0.8));
hybrid->read(data);
When to use Hybrid#
Heavy-tailed row-length distributions. A handful of long rows would inflate ELL’s \(k_\text{max}\) by orders of magnitude; the COO overflow absorbs them.
GPU SpMV on irregular matrices where neither plain ELL nor Sellp recovers enough of ELL’s coalesced access.
Sparse matrices arising from agglomerated meshes with a few high-degree super-nodes alongside many low-degree regular nodes.
For matrices with uniform row lengths, plain ELL or CSR is simpler and faster; Hybrid’s two-kernel SpMV adds overhead that only pays off when the ELL alone would waste significant memory.
Construction#
// From matrix_data with the default automatic strategy
auto hybrid = gko::matrix::Hybrid<double, int>::create(exec);
hybrid->read(data);
// With an explicit strategy
auto hybrid_limit = gko::matrix::Hybrid<double, int>::create(
exec,
std::make_shared<
gko::matrix::Hybrid<double, int>::column_limit>(/*ell_width=*/ 8));
hybrid_limit->read(data);
// Converted from CSR
auto hybrid_csr = gko::matrix::Hybrid<double, int>::create(exec);
hybrid_csr->copy_from(csr);
The chosen strategy is sticky on the Hybrid instance: any copy_from or
read after construction reuses the same split policy.
Performance characteristics#
The total SpMV cost is the sum of:
An ELL SpMV over a fixed-width \(k_\text{ell}\) block, typically the bulk of the work, executing with full coalescing.
A COO SpMV over the overflow entries: partial sums of the same row are combined with a segmented scan and added to the output vector with atomics.
For matrices well-suited to Hybrid the COO part is a small fraction of the
non-zero count (often < 10 %), so its cost is dominated by the ELL kernel.
For matrices where the COO overflow approaches the ELL workload, Hybrid loses
its advantage; check the split with get_ell_num_stored_elements() and
get_coo_num_stored_elements() after construction.
Conversion behaviour#
Hybrid converts to and from CSR and Dense; COO and ELL are reached through CSR:
// Hybrid → CSR
auto csr = gko::matrix::Csr<double, int>::create(exec);
csr->copy_from(hybrid);
// CSR → Hybrid
auto hybrid2 = gko::matrix::Hybrid<double, int>::create(exec);
hybrid2->copy_from(csr); // uses the default automatic strategy
Conversion preserves all numerical entries: the COO overflow re-merges with the ELL part to produce a flat CSR matrix.
See also
Matrix formats: when to pick Hybrid vs alternatives.
ELL: the dense underlying format when row lengths are uniform.
Sellp: per-slice padding; the natural in-between choice when row lengths vary smoothly rather than in a heavy tail.
COO: the overflow representation used internally.
API reference:
gko::matrix::Hybrid.