tatami_mult
Multiply tatami matrices
Loading...
Searching...
No Matches
column_to_row.hpp
Go to the documentation of this file.
1#ifndef TATAMI_MULT_SPARSE_MATRIX_DENSE_ROW_COLUMN_TO_ROW_HPP
2#define TATAMI_MULT_SPARSE_MATRIX_DENSE_ROW_COLUMN_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#include "../../sparse_dot_product.hpp"
13
19namespace tatami_mult {
20
21/* See https://github.com/tatami-inc/test-multiplication/tree/master/dense_row/sparse_matrix
22 * for an explanation of the choice of algorithm.
23 */
24
41
63template<std::size_t accumulators_ = 4, typename LeftValue_, typename LeftIndex_, typename RightValue_, typename RightIndex_, typename Output_>
67 Output_* const output,
69) {
70 const auto left_NR = left.nrow();
71 const auto common_dim = left.ncol();
72 const auto right_NC = right.ncol();
73
77 populate_sparse_buffers(false, right_NC, common_dim, right, right_vbuffers, right_ibuffers, right_ranges, options.num_threads);
78
79 if (options.block_size == 1) {
80 tatami::parallelize([&](int, LeftIndex_ start, LeftIndex_ length) -> void {
81 auto ext = tatami::consecutive_extractor<false>(left, true, start, length);
83
84 for (LeftIndex_ lr = 0; lr < length; ++lr) {
85 const auto lptr = ext->fetch(dbuffer.data());
86
87 // No point looping over the non-empty RHS columns, as we still need to zero the output columns corresponding to empty RHS columns.
88 // So, we might as well handle the zeroing in the same loop and save ourselves the trouble.
89 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
90 const auto rrange = right_ranges[rc];
91 output[sanisizer::nd_offset<std::size_t>(rc, right_NC, start + lr)] = sparse_dot_product<accumulators_>(
92 rrange.number, // Implicit cast to size_t is safe, as per the tatami contract.
93 rrange.value,
94 rrange.index,
95 lptr,
96 static_cast<Output_>(0)
97 );
98 }
99 }
100 }, left_NR, options.num_threads);
101
102 } else {
103 tatami::parallelize([&](int, LeftIndex_ start, LeftIndex_ length) -> void {
104 auto ext = tatami::consecutive_extractor<false>(left, true, start, length);
105
106 const LeftIndex_ max_block_rows = sanisizer::min(length, options.block_size);
107 std::vector<std::vector<LeftValue_> > lbuffers;
108 lbuffers.reserve(max_block_rows);
109 for (LeftIndex_ b = 0; b < max_block_rows; ++b) {
110 lbuffers.emplace_back(tatami::cast_Index_to_container_size<std::vector<LeftValue_> >(common_dim));
111 }
113
114 LeftIndex_ lr = 0;
115 while (lr < length) {
116 const LeftIndex_ lr_num = sanisizer::min(options.block_size, length - lr);
117 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
118 lptrs[lr_counter] = ext->fetch(lbuffers[lr_counter].data());
119 }
120
121 // Deliberately iterating over the sparse RHS columns in the outer loop and the dense LHS rows in the inner loop.
122 // This aims to keep the entirety of the dense LHS block in cache across multiple RHS columns, provided common_dim is small.
123 // If we did it the other way around, it would just be the same as the block_size == 1 case, but with more looping overhead.
124 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
125 const auto rrange = right_ranges[rc];
126 if (rrange.number == 0) {
127 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
128 output[sanisizer::nd_offset<std::size_t>(rc, right_NC, start + lr + lr_counter)] = 0;
129 }
130 continue;
131 }
132
133 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
134 output[sanisizer::nd_offset<std::size_t>(rc, right_NC, start + lr + lr_counter)] = sparse_dot_product<accumulators_>(
135 rrange.number, // Implicit cast to size_t is safe, as per the tatami contract.
136 rrange.value,
137 rrange.index,
138 lptrs[lr_counter],
139 static_cast<Output_>(0)
140 );
141 }
142 }
143
144 lr += lr_num;
145 }
146 }, left_NR, options.num_threads);
147 }
148}
149
150}
151
152#endif
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
Multiplication of tatami matrices.
Definition column_to_column.hpp:19
void multiply_dense_row_with_sparse_column_matrix_to_row_output(const tatami::Matrix< LeftValue_, LeftIndex_ > &left, const tatami::Matrix< RightValue_, RightIndex_ > &right, Output_ *const output, const MultiplyDenseRowWithSparseColumnMatrixToRowOutputOptions &options)
Definition column_to_row.hpp:64
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_dense_row_with_sparse_column_matrix_to_row_output().
Definition column_to_row.hpp:28