C++ · MaxSim

MaxSim

#include <numkong/matrix.hpp>#include <numkong/maxsim.hpp> 8.0.0-rc.1 · b1f866ab

MaxSim is the late-interaction primitive used by systems such as ColBERT. It is not generic matrix multiplication. It packs query and document token vectors into a scoring-specific layout and computes a late-interaction score.

auto [queries, queries_status] = nk::tensor<nk::bf16_t>::full({32, 128}, nk::bf16_t::one());
auto [docs, docs_status] = nk::tensor<nk::bf16_t>::full({192, 128}, nk::bf16_t::one());
if (nk::failed(queries_status) || nk::failed(docs_status)) return nk::failed(queries_status) ? queries_status : docs_status;

auto [q, q_status] = nk::packed_maxsim<nk::bf16_t>::make(queries.as_matrix_view());
auto [d, d_status] = nk::packed_maxsim<nk::bf16_t>::make(docs.as_matrix_view());
if (nk::failed(q_status) || nk::failed(d_status)) return nk::failed(q_status) ? q_status : d_status;
auto score = nk::maxsim(q, d);

packed_maxsim is allocator-aware in the same way as packed_matrix. Its footprint is exposed through size_bytes().

API

Types

packed_maxsimPre-packed vector set for MaxSim — ColBERT late-interaction.
matrix.hpp:541 ↗
template <numeric_dtype value_type_,
          typename allocator_type_ = aligned_allocator<char>>
class packed_maxsim

MaxSim computes Σᵢ minⱼ angular(qᵢ, dⱼ) using quantized i8 screening followed by full-precision refinement. Both queries and documents must be independently packed before calling maxsim().

Supported types: bf16_t, f32_t, f16_t.

Functions

maxsim_pack_sizeEstimates the memory requirements for a maxsim packed vector set.
matrix.hpp:173 ↗
template <numeric_dtype in_type_>
expected<std::size_t> maxsim_pack_size(
    std::size_t vector_count,
    std::size_t depth,
    nk_capability_t capabilities = default_capabilities());

Parameters

vector_countinNumber of vectors to pack.
depthinNumber of dimensions per vector.
capabilitiesinCapabilities to pick from, or zero for the C++ template.

Returns

Size in bytes for the packed buffer, or missing_kernel_k when no capability in capabilities packs in_type_.

maxsim_packPacks vectors into a backend-specific layout for maxsim computation.
matrix.hpp:203 ↗
template <numeric_dtype in_type_>
status_t maxsim_pack(
    typename in_type_::raw_t const *vectors,
    std::size_t vector_count,
    std::size_t depth,
    std::size_t stride,
    void *packed,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr);

Parameters

vectorsinInput vectors in row-major order. Packing fuses no transposition, so depth-major vectors are transposed in a separate pass first.
vector_countinNumber of vectors.
depthinNumber of dimensions per vector.
strideinRow stride in bytes for the input vectors.
packedoutOutput packed buffer from maxsim_pack_size.
capabilitiesinCapabilities to pick from, or zero for the C++ template.
streaminNull on the CPU, or the stream of the device capabilities describes.
maxsim_packedComputes angular distance late-interaction on pre-packed vectors.
maxsim.hpp:40 ↗
template <numeric_dtype in_type_, numeric_dtype result_type_ = typename in_type_::maxsim_result_t>
status_t maxsim_packed(
    void const *query_packed,
    void const *document_packed,
    std::size_t query_count,
    std::size_t document_count,
    std::size_t depth,
    result_type_ *result,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr);

Returns Σᵢ minⱼ angular(qᵢ, dⱼ).

Parameters

query_packedinPacked query vectors.
document_packedinPacked document vectors.
query_countinNumber of query vectors.
document_countinNumber of document vectors.
depthinNumber of dimensions per vector.
resultoutSum of per-query minimum angular distances.
capabilitiesinCapabilities to pick from, or zero for the C++ template, which reads packs of the same zero mask.
streaminNull on the CPU, or the stream of the device capabilities describes.
maxsim_referenceExhaustive angular reference for testing: Σᵢ minⱼ angular(qᵢ, dⱼ).
maxsim.hpp:95 ↗
template <numeric_dtype in_type_, numeric_dtype result_type_ = typename in_type_::angular_result_t>
status_t maxsim_reference(
    typename in_type_::raw_t const *queries,
    std::size_t query_count,
    std::size_t query_stride,
    typename in_type_::raw_t const *documents,
    std::size_t document_count,
    std::size_t document_stride,
    std::size_t depth,
    result_type_ *result,
    nk_capability_t capabilities = default_capabilities());

Computes all pairwise angular distances and picks the minimum per query. Uses f64 accumulator for precision.

Parameters

queriesinQuery vectors in row-major order.
query_countinNumber of query vectors.
query_strideinRow stride in bytes for query vectors.
documentsinDocument vectors in row-major order.
document_countinNumber of document vectors.
document_strideinRow stride in bytes for document vectors.
depthinNumber of dimensions per vector.
resultoutPointer to store the sum of per-query minimum angular distances.
capabilitiesinCapabilities the distances pick from, or zero for the C++ template.
maxsimMaxSim: Σᵢ minⱼ angular(qᵢ, dⱼ) on pre-packed vectors.
maxsim.hpp:134 ↗
template <numeric_dtype value_type_>
value_type_::maxsim_result_t maxsim(
    packed_maxsim<value_type_> const & queries,
    packed_maxsim<value_type_> const & documents) noexcept;