tatami_stats
Matrix statistics for tatami
Loading...
Searching...
No Matches
sum.hpp
Go to the documentation of this file.
1#ifndef TATAMI_STATS_SUM_HPP
2#define TATAMI_STATS_SUM_HPP
3
4#include "utils.hpp"
5
6#include <vector>
7#include <numeric>
8#include <algorithm>
9#include <optional>
10#include <cmath>
11
12#include "tatami/tatami.hpp"
13
20namespace tatami_stats {
21
25struct SumOptions {
30 bool skip_nan = false;
31
36 int num_threads = 1;
37};
38
42template<typename Value_, typename Index_, typename Output_>
43void sum_direct(bool row, const tatami::Matrix<Value_, Index_>& mat, Output_* output, const SumOptions& opt) {
44 const auto dim = (row ? mat.nrow() : mat.ncol());
45 const auto otherdim = (row ? mat.ncol() : mat.nrow());
46
47 if (mat.is_sparse()) {
48 tatami::parallelize([&](int, Index_ s, Index_ l) -> void {
49 tatami::Options topt;
50 topt.sparse_extract_index = false;
51 auto ext = tatami::consecutive_extractor<true>(mat, row, s, l, topt);
53
54 nanable_ifelse<Value_>(
55 opt.skip_nan,
56 [&]() -> void {
57 for (Index_ x = 0; x < l; ++x) {
58 const auto out = ext->fetch(vbuffer.data(), NULL);
59 Output_ sum = 0;
60 for (Index_ i = 0; i < out.number; ++i) {
61 const auto val = out.value[i];
62 if (!std::isnan(val)) {
63 sum += val;
64 }
65 }
66 output[x + s] = sum;
67 }
68 },
69 [&]() -> void {
70 quickstats::PairwiseSumWorkspace<Output_> work;
71 for (Index_ x = 0; x < l; ++x) {
72 const auto out = ext->fetch(vbuffer.data(), NULL);
73 output[x + s] = quickstats::pairwise_sum(out.number, out.value, work); // Index_ -> size_t conversion is safe, as per tatami's contract.
74 }
75 }
76 );
77 }, dim, opt.num_threads);
78
79 } else {
80 tatami::parallelize([&](int, Index_ s, Index_ l) -> void {
81 auto ext = tatami::consecutive_extractor<false>(mat, row, s, l);
83
84 nanable_ifelse<Value_>(
85 opt.skip_nan,
86 [&]() -> void {
87 for (Index_ x = 0; x < l; ++x) {
88 const auto ptr = ext->fetch(buffer.data());
89 Output_ sum = 0;
90 for (Index_ i = 0; i < otherdim; ++i) {
91 const auto val = ptr[i];
92 if (!std::isnan(val)) {
93 sum += val;
94 }
95 }
96 output[x + s] = sum;
97 }
98 },
99 [&]() -> void {
100 quickstats::PairwiseSumWorkspace<Output_> work;
101 for (Index_ x = 0; x < l; ++x) {
102 const auto ptr = ext->fetch(buffer.data());
103 output[x + s] = quickstats::pairwise_sum(otherdim, ptr, work); // Index_ -> size_t conversion is safe, as per tatami's contract.
104 }
105 }
106 );
107 }, dim, opt.num_threads);
108 }
109}
110
111template<typename Value_, typename Index_, typename Output_>
112void sum_running(bool row, const tatami::Matrix<Value_, Index_>& mat, Output_* output, const SumOptions& opt) {
113 const auto dim = (row ? mat.nrow() : mat.ncol());
114 const auto otherdim = (row ? mat.ncol() : mat.nrow());
115
116 const bool do_parallel = (opt.num_threads > 1);
117 std::optional<std::vector<std::optional<std::vector<Output_> > > > all_partial_sum;
118 if (do_parallel) {
119 all_partial_sum.emplace(sanisizer::cast<I<decltype(all_partial_sum->size())> >(opt.num_threads - 1));
120 }
121
122 std::fill_n(output, dim, 0);
123
124 const auto nused = tatami::parallelize([&](int thread, Index_ s, Index_ l) -> void {
125 Output_* sum_ptr;
126 std::optional<std::vector<Output_> > cur_sum;
127 if (!do_parallel) {
128 sum_ptr = output;
129 } else {
130 if (thread == 0) {
131 sum_ptr = output;
132 } else {
133 cur_sum.emplace(tatami::cast_Index_to_container_size<std::vector<Output_> >(dim));
134 sum_ptr = cur_sum->data();
135 }
136 }
137
138 if (mat.is_sparse()) {
139 tatami::Options topt;
140 topt.sparse_ordered_index = false; // ordering doesn't matter.
141 auto ext = tatami::consecutive_extractor<true>(mat, !row, s, l, topt);
144
145 for (Index_ x = 0; x < l; ++x) {
146 const auto out = ext->fetch(vbuffer.data(), ibuffer.data());
147 nanable_ifelse<Value_>(
148 opt.skip_nan,
149 [&]() -> void {
150 for (Index_ i = 0; i < out.number; ++i) {
151 const auto val = out.value[i];
152 if (!std::isnan(val)) {
153 sum_ptr[out.index[i]] += val;
154 }
155 }
156 },
157 [&]() -> void {
158 for (Index_ i = 0; i < out.number; ++i) {
159 sum_ptr[out.index[i]] += out.value[i];
160 }
161 }
162 );
163 }
164
165 } else {
166 auto ext = tatami::consecutive_extractor<false>(mat, !row, s, l);
168
169 for (Index_ x = 0; x < l; ++x) {
170 const auto ptr = ext->fetch(buffer.data());
171 nanable_ifelse<Value_>(
172 opt.skip_nan,
173 [&]() -> void {
174 for (Index_ i = 0; i < dim; ++i) {
175 const auto val = ptr[i];
176 if (!std::isnan(val)) {
177 sum_ptr[i] += val;
178 }
179 }
180 },
181 [&]() -> void {
182 for (Index_ i = 0; i < dim; ++i) {
183 sum_ptr[i] += ptr[i];
184 }
185 }
186 );
187 }
188 }
189
190 if (do_parallel) {
191 if (thread > 0) {
192 (*all_partial_sum)[thread - 1] = std::move(cur_sum);
193 }
194 }
195 }, otherdim, opt.num_threads);
196
197 if (do_parallel) {
198 for (int u = 1; u < nused; ++u) {
199 const auto& cur_sum = *((*all_partial_sum)[u - 1]);
200 for (Index_ d = 0; d < dim; ++d) {
201 output[d] += cur_sum[d];
202 }
203 }
204 }
205}
228template<typename Value_, typename Index_, typename Output_>
229void sum(bool row, const tatami::Matrix<Value_, Index_>& mat, Output_* output, const SumOptions& opt) {
230 if (mat.prefer_rows() == row) {
231 sum_direct(row, mat, output, opt);
232 } else {
233 sum_running(row, mat, output, opt);
234 }
235}
236
253template<typename Output_ = double, typename Value_, typename Index_>
254std::vector<Output_> sum(bool row, const tatami::Matrix<Value_, Index_>& mat, const SumOptions& opt) {
255 const auto dim = (row ? mat.nrow() : mat.ncol());
256 auto output = sanisizer::create<std::vector<Output_> >(dim
257#ifdef TATAMI_STATS_TEST_DIRTY
258 , -1
259#endif
260 );
261 sum(row, mat, output.data(), opt);
262 return output;
263}
264
265}
266
267#endif
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
virtual bool prefer_rows() const=0
virtual bool is_sparse() const=0
Functions to compute statistics from a tatami::Matrix.
Definition count.hpp:20
void sum(bool row, const tatami::Matrix< Value_, Index_ > &mat, Output_ *output, const SumOptions &opt)
Definition sum.hpp:229
int parallelize(Function_ fun, const Index_ tasks, const int workers)
I< decltype(std::declval< Container_ >().size())> cast_Index_to_container_size(const Index_ x)
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)
bool sparse_extract_index
bool sparse_ordered_index
Options for sum().
Definition sum.hpp:25
int num_threads
Definition sum.hpp:36
bool skip_nan
Definition sum.hpp:30