67 Output_*
const output,
70 const auto left_NR = left.
nrow();
71 const auto common_dim = left.
ncol();
72 const auto right_NC = right.
ncol();
77 populate_sparse_buffers(
false, right_NC, common_dim, right, right_vbuffers, right_ibuffers, right_ranges, options.
num_threads);
80 auto right_non_empty = filter_non_empty_sparse(
82 [&](
const RightIndex_ rc) ->
void {
83 std::fill_n(output + sanisizer::product_unsafe<std::size_t>(left_NR, rc), left_NR, 0);
96 for (LeftIndex_ lr = 0; lr < length; ++lr) {
97 const auto lrange = ext->fetch(vbuffer.data(), ibuffer.data());
98 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
99 expanded[lrange.index[x]] = lrange.value[x];
102 auto loop_body = [&](RightIndex_ rc) ->
void {
103 const auto rrange = right_ranges[rc];
104 output[sanisizer::nd_offset<std::size_t>(start + lr, left_NR, rc)] = sparse_dot_product<accumulators_>(
109 static_cast<Output_
>(0)
113 if (right_non_empty.has_value()) {
114 for (
const auto rc : *right_non_empty) {
118 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
123 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
124 expanded[lrange.index[x]] = 0;
134 const LeftIndex_ max_block_rows = sanisizer::min(length, options.
block_size);
135 std::vector<std::vector<LeftValue_> > lvbuffers;
136 std::vector<std::vector<LeftIndex_> > libuffers;
137 std::vector<std::vector<LeftValue_> > expanded;
138 lvbuffers.reserve(max_block_rows);
139 libuffers.reserve(max_block_rows);
140 expanded.reserve(max_block_rows);
141 for (LeftIndex_ b = 0; b < max_block_rows; ++b) {
149 while (lr < length) {
153 const LeftIndex_ lr_num = sanisizer::min(options.
block_size, length - lr);
154 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
155 auto lrange = ext->fetch(lvbuffers[lr_counter].data(), libuffers[lr_counter].data());
156 auto& curex = expanded[lr_counter];
157 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
158 curex[lrange.index[x]] = lrange.value[x];
160 lranges[lr_counter] = std::move(lrange);
166 auto loop_body = [&](RightIndex_ rc) ->
void {
167 const auto rrange = right_ranges[rc];
168 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
169 const auto val = sparse_dot_product<accumulators_>(
173 expanded[lr_counter].data(),
174 static_cast<Output_
>(0)
176 output[sanisizer::nd_offset<std::size_t>(start + lr + lr_counter, left_NR, rc)] = val;
180 if (right_non_empty.has_value()) {
181 for (
const auto rc : *right_non_empty) {
185 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
190 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
191 const auto& lrange = lranges[lr_counter];
192 auto& curex = expanded[lr_counter];
193 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
194 curex[lrange.index[x]] = 0;
void multiply_sparse_row_with_sparse_column_matrix_to_column_output(const tatami::Matrix< LeftValue_, LeftIndex_ > &left, const tatami::Matrix< RightValue_, RightIndex_ > &right, Output_ *const output, const MultiplySparseRowWithSparseColumnMatrixToColumnOutputOptions &options)
Definition column_to_column.hpp:64