tatami_mult
Multiply tatami matrices
Loading...
Searching...
No Matches
row_to_row.hpp
Go to the documentation of this file.
1#ifndef TATAMI_MULT_SPARSE_MATRIX_SPARSE_ROW_ROW_TO_ROW_HPP
2#define TATAMI_MULT_SPARSE_MATRIX_SPARSE_ROW_ROW_TO_ROW_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 const bool do_parallel = options.num_threads > 1;
71 if (!do_parallel) {
72 std::fill_n(output, sanisizer::product_unsafe<std::size_t>(left_NR, right_NC), 0);
73 }
74
75 tatami::parallelize([&](int, LeftIndex_ start, LeftIndex_ length) -> void {
76 auto ext = tatami::consecutive_extractor<true>(left, true, start, length);
79
80 std::optional<std::vector<Output_> > tmp_row;
81 if (do_parallel) {
82 tmp_row.emplace(tatami::cast_Index_to_container_size<std::vector<Output_> >(right_NC));
83 }
84
85 for (LeftIndex_ lr = 0; lr < length; ++lr) {
86 const auto lrange = ext->fetch(vbuffer.data(), ibuffer.data());
87 const auto optr = output + sanisizer::product_unsafe<std::size_t>(start + lr, right_NC);
88 const auto tmp_optr = (do_parallel ? tmp_row->data() : optr);
89
90 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
91 const auto rrange = right_ranges[lrange.index[x]];
92 const Output_ mult = lrange.value[x];
93 for (RightIndex_ y = 0; y < rrange.number; ++y) {
94 tmp_optr[rrange.index[y]] += mult * static_cast<Output_>(rrange.value[y]);
95 }
96 };
97
98 if (do_parallel) {
99 std::copy_n(tmp_optr, right_NC, optr);
100
101 // Technically, we only have to reset the positions at which there is at least one non-zero across all RHS rows.
102 // However, the union of all non-zero positions across all RHS rows is probably quite dense.
103 // It'll likely be faster to just zero the entire buffer rather than trying to zero specific positions;
104 // for example, one 64-byte cache line contains 8 doubles, so you'd need a density below ~10% to even avoid loading every cache line.
105 // And that's not even considering further optimizations in the memset call.
106 std::fill_n(tmp_optr, right_NC, 0);
107 }
108 }
109 }, left_NR, options.num_threads);
110}
111
112}
113
114#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_row_output(const tatami::Matrix< LeftValue_, LeftIndex_ > &left, const tatami::Matrix< RightValue_, RightIndex_ > &right, Output_ *const output, const MultiplySparseRowWithSparseRowMatrixToRowOutputOptions &options)
Definition row_to_row.hpp:55
int parallelize(Function_ fun, const Index_ tasks, const int workers)
I< decltype(std::declval< Container_ >().size())> cast_Index_to_container_size(const Index_ x)
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_row_output().
Definition row_to_row.hpp:27