69 Output_*
const output,
72 const auto left_NR = left.
nrow();
73 const auto common_dim = left.
ncol();
74 const auto right_NC = right.
ncol();
79 populate_sparse_buffers(
false, right_NC, common_dim, right, right_vbuffers, right_ibuffers, right_ranges, options.
num_threads);
90 for (LeftIndex_ lr = 0; lr < length; ++lr) {
91 const auto lrange = ext->fetch(vbuffer.data(), ibuffer.data());
92 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
93 expanded[lrange.index[x]] = lrange.value[x];
98 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
99 const auto rrange = right_ranges[rc];
102 output[sanisizer::nd_offset<std::size_t>(rc, right_NC, start + lr)] = sparse_dot_product<accumulators_>(
107 static_cast<Output_
>(0)
111 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
112 expanded[lrange.index[x]] = 0;
121 const LeftIndex_ max_block_rows = sanisizer::min(length, options.
block_size);
122 std::vector<std::vector<LeftValue_> > left_vbuffers;
123 std::vector<std::vector<LeftIndex_> > left_ibuffers;
124 std::vector<std::vector<LeftValue_> > expanded;
125 left_vbuffers.reserve(max_block_rows);
126 left_ibuffers.reserve(max_block_rows);
127 expanded.reserve(max_block_rows);
128 for (LeftIndex_ b = 0; b < max_block_rows; ++b) {
134 std::vector<LeftIndex_> left_non_empty;
135 left_non_empty.reserve(max_block_rows);
138 while (lr < length) {
142 left_non_empty.clear();
143 LeftIndex_ lr_num = 0;
144 bool all_non_empty =
true;
148 auto lrange = ext->fetch(left_vbuffers[lr_num].data(), left_ibuffers[lr_num].data());
149 if (lrange.number == 0) {
150 std::fill_n(output + sanisizer::product_unsafe<std::size_t>(start + new_lr, right_NC), right_NC, 0);
151 all_non_empty =
false;
156 left_ranges[lr_num] = std::move(lrange);
157 auto& curex = expanded[lr_num];
158 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
159 curex[lrange.index[x]] = lrange.value[x];
161 left_non_empty.push_back(new_lr);
165 if (sanisizer::is_equal(lr_num, options.
block_size)) {
168 }
while (new_lr < length);
170 auto task = [&](
auto converter) ->
void {
174 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
175 const auto rrange = right_ranges[rc];
176 if (rrange.number == 0) {
177 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
178 output[sanisizer::nd_offset<std::size_t>(rc, right_NC, converter(lr_counter))] = 0;
183 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
185 output[sanisizer::nd_offset<std::size_t>(rc, right_NC, converter(lr_counter))] = sparse_dot_product<accumulators_>(
189 expanded[lr_counter].data(),
190 static_cast<Output_
>(0)
197 task([&](
const LeftIndex_ lr_counter) -> LeftIndex_ {
return start + lr + lr_counter; });
199 for (
auto& lrne : left_non_empty) {
202 task([&](
const LeftIndex_ lr_counter) -> LeftIndex_ {
return left_non_empty[lr_counter]; });
205 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
206 const auto& lrange = left_ranges[lr_counter];
207 auto& curex = expanded[lr_counter];
208 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
209 curex[lrange.index[x]] = 0;
void multiply_sparse_row_with_sparse_column_matrix_to_row_output(const tatami::Matrix< LeftValue_, LeftIndex_ > &left, const tatami::Matrix< RightValue_, RightIndex_ > &right, Output_ *const output, const MultiplySparseRowWithSparseColumnMatrixToRowOutputOptions &options)
Definition column_to_row.hpp:66