tatami_mult
Multiply tatami matrices
Loading...
Searching...
No Matches
column_to_column.hpp
Go to the documentation of this file.
1#ifndef TATAMI_MULT_DENSE_MATRIX_SPARSE_ROW_COLUMN_TO_COLUMN_HPP
2#define TATAMI_MULT_DENSE_MATRIX_SPARSE_ROW_COLUMN_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#include "../../sparse_dot_product.hpp"
13
19namespace tatami_mult {
20
21/* See https://github.com/tatami-inc/test-multiplication/tree/master/sparse_row/dense_matrix
22 * for an explanation of the choice of algorithm.
23 */
24
41
61template<std::size_t accumulators_ = 4, typename LeftValue_, typename LeftIndex_, typename RightColumns_, class GetRightColumn_, typename Output_>
64 const RightColumns_ right_columns,
65 GetRightColumn_ get_right_column,
66 Output_* const output,
68) {
69 const auto left_NR = left.nrow();
70 const auto common_dim = left.ncol();
71
72 if (options.block_size == 1) {
73 tatami::parallelize([&](int, LeftIndex_ start, LeftIndex_ length) -> void {
74 auto ext = tatami::consecutive_extractor<true>(left, true, start, length);
77
78 for (LeftIndex_ lr = 0; lr < length; ++lr) {
79 const auto range = ext->fetch(vbuffer.data(), ibuffer.data());
80 for (RightColumns_ rc = 0; rc < right_columns; ++rc) {
81 output[sanisizer::nd_offset<std::size_t>(start + lr, left_NR, rc)] = sparse_dot_product<accumulators_>(
82 range.number, // Implicit cast of range.number to size_t is safe, as per the tatami contract.
83 range.value,
84 range.index,
85 get_right_column(rc),
86 static_cast<Output_>(0)
87 );
88 }
89 }
90 }, left_NR, options.num_threads);
91 return;
92 }
93
94 tatami::parallelize([&](int, LeftIndex_ start, LeftIndex_ length) -> void {
95 auto ext = tatami::consecutive_extractor<true>(left, true, start, length);
96
97 std::vector<std::vector<LeftValue_> > left_vbuffers;
98 std::vector<std::vector<LeftIndex_> > left_ibuffers;
99 std::vector<tatami::SparseRange<LeftValue_, LeftIndex_> > left_ranges;
100 {
101 const LeftIndex_ max_block_rows = sanisizer::min(length, options.block_size);
102 left_vbuffers.reserve(max_block_rows);
103 left_ibuffers.reserve(max_block_rows);
104 for (LeftIndex_ lr = 0; lr < max_block_rows; ++lr) {
105 left_vbuffers.emplace_back(tatami::cast_Index_to_container_size<std::vector<LeftValue_> >(common_dim));
106 left_ibuffers.emplace_back(tatami::cast_Index_to_container_size<std::vector<LeftIndex_> >(common_dim));
107 }
108 sanisizer::resize(left_ranges, max_block_rows);
109 }
110
111 LeftIndex_ lr = 0;
112 while (lr < length) {
113 // No point skipping the LHS rows with no structural non-zeros.
114 // We still need to set the corresponding entry of 'output' to zero, so we'd end up having to loop through the LHS rows anyway.
115 // We might as well just let it be set to zero naturally in the existing loop below.
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 left_ranges[lr_counter] = ext->fetch(left_vbuffers[lr_counter].data(), left_ibuffers[lr_counter].data());
119 }
120
121 for (RightColumns_ rc = 0; rc < right_columns; ++rc) {
122 const auto rcol = get_right_column(rc);
123 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
124 const auto& currange = left_ranges[lr_counter];
125 output[sanisizer::nd_offset<std::size_t>(start + lr + lr_counter, left_NR, rc)] = sparse_dot_product<accumulators_>(
126 currange.number, // Implicit cast of range.number to size_t is safe, as per the tatami contract.
127 currange.value,
128 currange.index,
129 rcol,
130 static_cast<Output_>(0)
131 );
132 }
133 }
134
135 lr += lr_num;
136 }
137 }, left_NR, options.num_threads);
138}
139
162template<std::size_t accumulators_ = 4, typename LeftValue_, typename LeftIndex_, typename RightValue_, typename RightIndex_, typename Output_>
166 Output_* const output,
168) {
169 const auto right_NC = right.ncol();
172 const auto common_dim = left.ncol();
173 populate_dense_buffers(false, right_NC, common_dim, right, right_buffers, right_ptrs, options.num_threads);
174
176 left,
177 right_NC,
178 [&](const RightIndex_ rc) -> const RightValue_* {
179 return right_ptrs[rc];
180 },
181 output,
182 options
183 );
184}
185
186
187}
188
189#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_dense_column_matrix_to_column_output(const tatami::Matrix< LeftValue_, LeftIndex_ > &left, const RightColumns_ right_columns, GetRightColumn_ get_right_column, Output_ *const output, const MultiplySparseRowWithDenseColumnMatrixToColumnOutputOptions &options)
Definition column_to_column.hpp:62
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_dense_column_matrix_to_column_output().
Definition column_to_column.hpp:28