61 const RightColumns_ right_columns,
62 GetRightRow_ get_right_row,
63 Output_*
const output,
66 const auto left_NR = left.
nrow();
67 const auto common_dim = left.
ncol();
71 std::fill_n(output, sanisizer::product<std::size_t>(left_NR, right_columns), 0);
74 std::optional<std::vector<std::optional<std::vector<Output_> > > > tmp_results;
76 tmp_results.emplace(sanisizer::cast<I<
decltype(tmp_results->size())> >(options.
num_threads - 1));
79 const auto num_used =
tatami::parallelize([&](
int t, LeftIndex_ start, LeftIndex_ length) ->
void {
82 std::optional<std::vector<Output_> > tmp_output;
84 if (!do_parallel || t == 0) {
87 tmp_output.emplace(sanisizer::product<I<
decltype(tmp_output->size())> >(left_NR, right_columns));
88 outptr = tmp_output->data();
94 for (LeftIndex_ cd = 0; cd < length; ++cd) {
95 const auto lrange = left_ext->fetch(vbuffer.data(), ibuffer.data());
96 if (lrange.number == 0) {
99 const auto rptr = get_right_row(start + cd);
100 for (RightColumns_ rc = 0; rc < right_columns; ++rc) {
101 const Output_ mult = rptr[rc];
102 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
103 outptr[sanisizer::nd_offset<std::size_t>(lrange.index[x], left_NR, rc)] += mult *
static_cast<Output_
>(lrange.value[x]);
111 std::vector<std::vector<LeftValue_> > left_vbuffers;
112 std::vector<std::vector<LeftIndex_> > left_ibuffers;
113 std::vector<tatami::SparseRange<LeftValue_, LeftIndex_> > left_ranges;
114 std::vector<LeftIndex_> left_non_empty;
116 const LeftIndex_ max_block_cols = sanisizer::min(length, options.
block_size);
117 left_vbuffers.reserve(max_block_cols);
118 left_ibuffers.reserve(max_block_cols);
119 for (LeftIndex_ cd = 0; cd < max_block_cols; ++cd) {
124 left_non_empty.reserve(max_block_cols);
128 while (cd < length) {
131 LeftIndex_ cd_num = 0, cd_copy = cd;
132 bool left_all_non_empty =
true;
133 left_non_empty.clear();
135 auto lrange = left_ext->fetch(left_vbuffers[cd_num].data(), left_ibuffers[cd_num].data());
136 if (lrange.number == 0) {
138 left_all_non_empty =
false;
142 left_ranges[cd_num] = std::move(lrange);
143 left_non_empty.push_back(cd_copy);
147 if (sanisizer::is_equal(cd_num, options.
block_size)) {
150 }
while (cd_copy < length);
152 if (left_all_non_empty) {
153 for (RightColumns_ rc = 0; rc < right_columns; ++rc) {
154 for (LeftIndex_ cd_counter = 0; cd_counter < cd_num; ++cd_counter) {
155 const auto& currange = left_ranges[cd_counter];
156 const Output_ mult = get_right_row(start + cd + cd_counter)[rc];
157 for (LeftIndex_ x = 0; x < currange.number; ++x) {
158 outptr[sanisizer::nd_offset<std::size_t>(currange.index[x], left_NR, rc)] += mult *
static_cast<Output_
>(currange.value[x]);
163 for (
auto& cdne : left_non_empty) {
166 for (RightColumns_ rc = 0; rc < right_columns; ++rc) {
167 for (LeftIndex_ cd_counter = 0; cd_counter < cd_num; ++cd_counter) {
168 const auto& currange = left_ranges[cd_counter];
169 const Output_ mult = get_right_row(left_non_empty[cd_counter])[rc];
170 for (LeftIndex_ x = 0; x < currange.number; ++x) {
171 outptr[sanisizer::nd_offset<std::size_t>(currange.index[x], left_NR, rc)] += mult *
static_cast<Output_
>(currange.value[x]);
181 if (do_parallel && t > 0) {
182 (*tmp_results)[t - 1] = std::move(tmp_output);
187 for (
int u = 1; u < num_used; ++u) {
188 const auto& tmp = *((*tmp_results)[u - 1]);
189 const auto N = tmp.size();
190 for (I<
decltype(N)> x = 0; x < N; ++x) {
220 Output_*
const output,
223 const auto left_NR = left.
nrow();
224 const auto common_dim = left.
ncol();
225 const auto right_NC = right.
ncol();
226 std::fill_n(output, sanisizer::product<std::size_t>(left_NR, right_NC), 0);
229 std::optional<std::vector<std::optional<std::vector<Output_> > > > tmp_results;
231 tmp_results.emplace(sanisizer::cast<I<
decltype(tmp_results->size())> >(options.
num_threads - 1));
234 const auto num_used =
tatami::parallelize([&](
int t, LeftIndex_ start, LeftIndex_ length) ->
void {
238 std::optional<std::vector<Output_> > tmp_output;
240 if (!do_parallel || t == 0) {
243 tmp_output.emplace(sanisizer::product<I<
decltype(tmp_output->size())> >(left_NR, right_NC));
244 outptr = tmp_output->data();
252 for (LeftIndex_ cd = 0; cd < length; ++cd) {
253 const auto lrange = left_ext->fetch(vbuffer.data(), ibuffer.data());
254 const auto rptr = right_ext->fetch(dbuffer.data());
258 if (lrange.number == 0) {
262 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
263 const Output_ mult = rptr[rc];
264 for (LeftIndex_ x = 0; x < lrange.number; ++x) {
265 outptr[sanisizer::nd_offset<std::size_t>(lrange.index[x], left_NR, rc)] += mult *
static_cast<Output_
>(lrange.value[x]);
273 std::vector<std::vector<LeftValue_> > left_vbuffers;
274 std::vector<std::vector<LeftIndex_> > left_ibuffers;
275 std::vector<tatami::SparseRange<LeftValue_, LeftIndex_> > left_ranges;
276 std::vector<std::vector<RightValue_> > right_dbuffers;
277 std::vector<const RightValue_*> right_ptrs;
279 const LeftIndex_ max_block_cols = sanisizer::min(length, options.
block_size);
280 left_vbuffers.reserve(max_block_cols);
281 left_ibuffers.reserve(max_block_cols);
282 right_dbuffers.reserve(max_block_cols);
283 for (LeftIndex_ cd = 0; cd < max_block_cols; ++cd) {
293 while (cd < length) {
296 LeftIndex_ cd_num = 0;
298 auto lrange = left_ext->fetch(left_vbuffers[cd_num].data(), left_ibuffers[cd_num].data());
299 auto rptr = right_ext->fetch(right_dbuffers[cd_num].data());
302 if (lrange.number == 0) {
307 left_ranges[cd_num] = std::move(lrange);
308 right_ptrs[cd_num] = rptr;
312 if (sanisizer::is_equal(cd_num, options.
block_size)) {
315 }
while (cd < length);
317 for (RightIndex_ rc = 0; rc < right_NC; ++rc) {
318 for (LeftIndex_ cd_counter = 0; cd_counter < cd_num; ++cd_counter) {
319 const auto& currange = left_ranges[cd_counter];
320 const Output_ mult = right_ptrs[cd_counter][rc];
321 for (LeftIndex_ x = 0; x < currange.number; ++x) {
322 outptr[sanisizer::nd_offset<std::size_t>(currange.index[x], left_NR, rc)] += mult *
static_cast<Output_
>(currange.value[x]);
329 if (do_parallel && t > 0) {
330 (*tmp_results)[t - 1] = std::move(tmp_output);
335 for (
int u = 1; u < num_used; ++u) {
336 const auto& tmp = *((*tmp_results)[u - 1]);
337 const auto N = tmp.size();
338 for (I<
decltype(N)> x = 0; x < N; ++x) {