70 const RightColumns_ right_columns,
71 GetRightColumn_ get_right_column,
72 Output_*
const output,
75 const auto left_NR = left.
nrow();
76 const auto common_dim = left.
ncol();
80 std::fill_n(output, sanisizer::product_unsafe<std::size_t>(left_NR, right_columns), 0);
83 std::optional<std::vector<std::optional<std::vector<Output_> > > > tmp_results;
85 tmp_results.emplace(sanisizer::cast<I<
decltype(tmp_results->size())> >(options.
num_threads - 1));
88 const auto num_used =
tatami::parallelize([&](
int t, LeftIndex_ start, LeftIndex_ length) ->
void {
91 std::optional<std::vector<Output_> > tmp_output;
93 if (!do_parallel || t == 0) {
96 tmp_output.emplace(sanisizer::product<I<
decltype(tmp_output->size())> >(left_NR, right_columns));
97 outptr = tmp_output->data();
102 for (LeftIndex_ cd = 0; cd < length; ++cd) {
103 const auto ptr = ext->fetch(buffer.data());
104 for (LeftIndex_ lr = 0; lr < left_NR; ++lr) {
105 const auto mult = ptr[lr];
106 for (RightColumns_ rc = 0; rc < right_columns; ++rc) {
107 outptr[sanisizer::nd_offset<std::size_t>(rc, right_columns, lr)] += mult *
static_cast<Output_
>(get_right_column(rc)[start + cd]);
113 std::vector<std::vector<LeftValue_> > left_buffers;
114 std::vector<const LeftValue_*> left_ptrs;
115 std::vector<Output_> tmp_output;
118 left_buffers.reserve(max_block_cols);
119 for (LeftIndex_ cd = 0; cd < max_block_cols; ++cd) {
122 sanisizer::resize(left_ptrs, max_block_cols);
126 const RightColumns_ max_block_right_cols = sanisizer::min(right_columns, options.
primary_block_size);
128 tmp_output.resize(sanisizer::product<I<
decltype(tmp_output.size())> >(max_block_rows, max_block_right_cols));
132 while (cd < length) {
134 for (LeftIndex_ cd_counter = 0; cd_counter < cd_num; ++cd_counter) {
135 left_ptrs[cd_counter] = ext->fetch(left_buffers[cd_counter].data());
138 RightColumns_ rc = 0;
139 while (rc < right_columns) {
140 const RightColumns_ rc_num = sanisizer::min(options.
primary_block_size, right_columns - rc);
142 while (lr < left_NR) {
145 for (LeftIndex_ cd_counter = 0; cd_counter < cd_num; ++cd_counter) {
146 const auto matcol = left_ptrs[cd_counter];
147 for (RightColumns_ rc_counter = 0; rc_counter < rc_num; ++rc_counter) {
148 const Output_ mult = get_right_column(rc + rc_counter)[start + cd + cd_counter];
149 for (LeftIndex_ lr_counter = 0; lr_counter < lr_num; ++lr_counter) {
150 tmp_output[sanisizer::nd_offset<std::size_t>(lr_counter, lr_num, rc_counter)] += mult *
static_cast<Output_
>(matcol[lr + lr_counter]);
156 RightColumns_ lrt = 0;
157 while (lrt < lr_num) {
158 const LeftIndex_ lrt_end = lrt + sanisizer::min(options.
primary_block_size, lr_num - lrt);
159 for (RightColumns_ rc_counter = 0; rc_counter < rc_num; ++rc_counter) {
160 for (LeftIndex_ lrt_copy = lrt; lrt_copy < lrt_end; ++lrt_copy) {
161 const auto val = tmp_output[sanisizer::nd_offset<std::size_t>(lrt_copy, lr_num, rc_counter)];
162 outptr[sanisizer::nd_offset<std::size_t>(rc + rc_counter, right_columns, lr + lrt_copy)] += val;
167 std::fill_n(tmp_output.begin(), sanisizer::product_unsafe<std::size_t>(rc_num, lr_num), 0);
177 if (do_parallel && t > 0) {
178 (*tmp_results)[t - 1] = std::move(tmp_output);
183 for (
int u = 1; u < num_used; ++u) {
184 const auto& tmp = *((*tmp_results)[u - 1]);
185 const auto N = tmp.size();
186 for (I<
decltype(N)> x = 0; x < N; ++x) {