tatami_mult
Multiply tatami matrices
Loading...
Searching...
No Matches
column_to_column.hpp
Go to the documentation of this file.
1#ifndef TATAMI_MULT_SPARSE_MATRIX_SPARSE_COLUMN_COLUMN_TO_COLUMN_HPP
2#define TATAMI_MULT_SPARSE_MATRIX_SPARSE_COLUMN_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_column/sparse_matrix
22 * for an explanation of the choice of algorithm.
23 */
24
35
55template<typename LeftValue_, typename LeftIndex_, typename RightValue_, typename RightIndex_, typename Output_>
59 Output_* const output,
61) {
62 const auto left_NR = left.nrow();
63 const auto common_dim = left.ncol();
64 const auto right_NC = right.ncol();
65
67 conv_opt.two_pass = false;
68 conv_opt.num_threads = options.num_threads;
70
71 // If there are any empty RHS columns, we only iterate over the non-empty ones and the corresponding RHS rows.
72 auto right_non_empty = filter_non_empty_sparse(
73 rhs_data.index,
74 [&](const RightIndex_) -> void {}
75 );
76
77 const bool do_parallel = options.num_threads > 1;
78 std::optional<std::vector<std::optional<std::vector<Output_> > > > tmp_results;
79 if (do_parallel) {
80 tmp_results.emplace(sanisizer::cast<I<decltype(tmp_results->size())> >(options.num_threads - 1));
81 }
82
83 std::fill_n(output, sanisizer::product_unsafe<std::size_t>(left_NR, right_NC), 0);
84
85 // If we have empty RHS rows, we completely skip the corresponding LHS columns.
86 // Otherwise doing the easier approach of just looping with a counter.
87 const LeftIndex_ cd_total = (right_non_empty.has_value() ? static_cast<LeftIndex_>(right_non_empty->size()) : common_dim);
88 const int num_used = tatami::parallelize([&](int t, LeftIndex_ start, LeftIndex_ length) -> void {
89 std::optional<std::vector<Output_> > tmp_output;
90 Output_* outptr;
91 if (!do_parallel || t == 0) {
92 outptr = output;
93 } else {
94 tmp_output.emplace(sanisizer::product<I<decltype(tmp_output->size())> >(left_NR, right_NC));
95 outptr = tmp_output->data();
96 }
97
100
101 auto task = [&](std::unique_ptr<tatami::OracularSparseExtractor<LeftValue_, LeftIndex_> >& ext, auto converter) -> void {
102 for (LeftIndex_ cd = 0; cd < length; ++cd) {
103 const auto lrange = ext->fetch(vbuffer.data(), ibuffer.data());
104 const auto actual_cd = converter(cd);
105 const auto& right_values = rhs_data.value[actual_cd];
106 const auto& right_indices = rhs_data.index[actual_cd];
107 const RightIndex_ right_nnz = right_values.size();
108 for (RightIndex_ x = 0; x < right_nnz; ++x) {
109 const Output_ mult = right_values[x];
110 const auto idx = right_indices[x];
111 for (LeftIndex_ y = 0; y < lrange.number; ++y) {
112 outptr[sanisizer::nd_offset<std::size_t>(lrange.index[y], left_NR, idx)] += mult * static_cast<Output_>(lrange.value[y]);
113 }
114 }
115 }
116 };
117
118 if (right_non_empty.has_value()) {
119 auto ext = tatami::new_extractor<true, true>(left, false, std::make_shared<tatami::FixedViewOracle<LeftIndex_> >(right_non_empty->data() + start, length));
120 task(
121 ext,
122 [&](const LeftIndex_ cd) -> LeftIndex_ {
123 return (*right_non_empty)[start + cd];
124 }
125 );
126 } else {
127 auto ext = tatami::consecutive_extractor<true>(left, false, start, length);
128 task(
129 ext,
130 [&](const LeftIndex_ cd) -> LeftIndex_ {
131 return cd + start;
132 }
133 );
134 }
135
136 if (do_parallel && t > 0) {
137 (*tmp_results)[t - 1] = std::move(tmp_output);
138 }
139 }, cd_total, options.num_threads);
140
141 if (do_parallel) {
142 for (int u = 1; u < num_used; ++u) {
143 const auto& tmp = *((*tmp_results)[u - 1]);
144 const auto N = tmp.size();
145 for (I<decltype(N)> x = 0; x < N; ++x) {
146 output[x] += tmp[x];
147 }
148 }
149 }
150}
151
152}
153
154#endif
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
Multiplication of tatami matrices.
Definition column_to_column.hpp:19
void multiply_sparse_column_with_sparse_column_matrix_to_column_output(const tatami::Matrix< LeftValue_, LeftIndex_ > &left, const tatami::Matrix< RightValue_, RightIndex_ > &right, Output_ *const output, const MultiplySparseColumnWithSparseColumnMatrixToColumnOutputOptions &options)
Definition column_to_column.hpp:56
auto new_extractor(const Matrix< Value_, Index_ > &matrix, const bool row, MaybeOracle< oracle_, Index_ > oracle, Args_ &&... args)
FragmentedSparseContents< StoredValue_, StoredIndex_ > retrieve_fragmented_sparse_contents(const Matrix< InputValue_, InputIndex_ > &matrix, const bool row, const RetrieveFragmentedSparseContentsOptions &options)
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_column_with_sparse_column_matrix_to_column_output().
Definition column_to_column.hpp:28