tatami_mult
Multiply tatami matrices
Loading...
Searching...
No Matches
row_to_column.hpp
Go to the documentation of this file.
1#ifndef TATAMI_MULT_SPARSE_MATRIX_SPARSE_ROW_ROW_TO_COLUMN_HPP
2#define TATAMI_MULT_SPARSE_MATRIX_SPARSE_ROW_ROW_TO_COLUMN_HPP
3
4#include <cstddef>
5#include <vector>
6
7#include "tatami/tatami.hpp"
8#include "sanisizer/sanisizer.hpp"
9
10#include "../utils.hpp"
11#include "../../utils.hpp"
12
18namespace tatami_mult {
19
20/* See https://github.com/tatami-inc/test-multiplication/tree/master/sparse_row/sparse_matrix
21 * for an explanation of the choice of algorithm.
22 */
23
34
54template<typename LeftValue_, typename LeftIndex_, typename RightValue_, typename RightIndex_, typename Output_>
58 Output_* const output,
60) {
61 const auto left_NR = left.nrow();
62 const auto common_dim = left.ncol();
63 const auto right_NC = right.ncol();
64
68 populate_sparse_buffers(true, common_dim, right_NC, right, right_vbuffers, right_ibuffers, right_ranges, options.num_threads);
69
70 tatami::parallelize([&](int, LeftIndex_ start, LeftIndex_ length) -> void {
71 auto ext = tatami::consecutive_extractor<true>(left, true, start, length);
74
75 // Use a temporary buffer to (i) improve data locality and (ii) avoid false sharing.
77
78 for (LeftIndex_ lr = 0; lr < length; ++lr) {
79 const auto lrange = ext->fetch(vbuffer.data(), ibuffer.data());
80
81 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
82 const Output_ mult = lrange.value[x];
83 const auto rrange = right_ranges[lrange.index[x]];
84 for (RightIndex_ y = 0; y < rrange.number; ++y) {
85 tmp_row[rrange.index[y]] += mult * static_cast<Output_>(rrange.value[y]);
86 }
87 }
88
89 // Technically, we could limit the transposition to only those RHS columns that are not empty.
90 // This avoids unnecessary accesses to non-contiguous memory that will always be zero.
91 // To implement this, we'd need to do another pass through the RHS matrix to find the empty columns and store their IDs.
92 // Such extra complexity is probably not worth it; we're not in the hot loop,
93 // and accessing non-consecutive IDs may be a pessimization if it prevents compiler optimizations and/or strided prefetching.
94 // Ensuring correct zeroing of the output columns also becomes a bit complicated if we skip empty RHS columns.
95 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
96 output[sanisizer::nd_offset<std::size_t>(start + lr, left_NR, rc)] = tmp_row[rc];
97 }
98 std::fill(tmp_row.begin(), tmp_row.end(), 0);
99 }
100 }, left_NR, options.num_threads);
101}
102
103}
104
105#endif
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
Multiplication of tatami matrices.
Definition column_to_column.hpp:19
void multiply_sparse_row_with_sparse_row_matrix_to_column_output(const tatami::Matrix< LeftValue_, LeftIndex_ > &left, const tatami::Matrix< RightValue_, RightIndex_ > &right, Output_ *const output, const MultiplySparseRowWithSparseRowMatrixToColumnOutputOptions &options)
Definition row_to_column.hpp:55
int parallelize(Function_ fun, const Index_ tasks, const int workers)
Container_ create_container_of_Index_size(const Index_ x, Args_ &&... args)
auto consecutive_extractor(const Matrix< Value_, Index_ > &matrix, const bool row, const Index_ iter_start, const Index_ iter_length, Args_ &&... args)
Options for multiply_sparse_row_with_sparse_row_matrix_to_column_output().
Definition row_to_column.hpp:27