scran_blocks
Blocking utilities for libscran
Loading...
Searching...
No Matches
average_vectors.hpp
Go to the documentation of this file.
1#ifndef SCRAN_BLOCKS_AVERAGE_VECTORS_HPP
2#define SCRAN_BLOCKS_AVERAGE_VECTORS_HPP
3
4#include <vector>
5#include <limits>
6#include <algorithm>
7#include <cmath>
8#include <numeric>
9
15namespace scran_blocks {
16
20namespace internal {
21
22template<bool weighted_, typename Stat_, typename Weight_, typename Output_>
23void average_vectors(size_t n, std::vector<Stat_*> in, const Weight_* w, Output_* out, bool skip_nan) {
24 if (in.empty()) {
25 std::fill_n(out, n, std::numeric_limits<Output_>::quiet_NaN());
26 return;
27 } else if (in.size() == 1) {
28 if constexpr(weighted_) {
29 if (w[0] == 0) {
30 std::fill_n(out, n, std::numeric_limits<Output_>::quiet_NaN());
31 return;
32 }
33 }
34 std::copy(in[0], in[0] + n, out);
35 return;
36 }
37
38 std::fill_n(out, n, 0);
39 std::vector<Weight_> accumulated(skip_nan ? n : 0);
40
41 auto wcopy = w;
42 for (auto current : in) {
43 auto copy = out;
44
45 if constexpr(weighted_) {
46 // Don't skip if weight = 0, as we need to still compute the product, e.g.,
47 // if the value is Inf, we'd end up with 0 * Inf => NaN that can't be skipped.
48 Weight_ weight = *(wcopy++);
49
50 // Use the other loop and skip an unnecessary multiplication when the weight is 1.
51 if (weight != 1) {
52 if (skip_nan) {
53 for (size_t i = 0; i < n; ++i, ++current, ++copy) {
54 auto x = *current * weight;
55 if (!std::isnan(x)) {
56 *copy += x;
57 accumulated[i] += weight;
58 }
59 }
60 } else {
61 for (size_t i = 0; i < n; ++i, ++current, ++copy) {
62 *copy += *current * weight;
63 }
64 }
65 continue;
66 }
67 }
68
69 if (skip_nan) {
70 for (size_t i = 0; i < n; ++i, ++current, ++copy) {
71 auto x = *current;
72 if (!std::isnan(x)) {
73 *copy += x;
74 ++accumulated[i];
75 }
76 }
77 } else {
78 for (size_t i = 0; i < n; ++i, ++current, ++copy) {
79 *copy += *current;
80 }
81 }
82 }
83
84 if (skip_nan) {
85 for (size_t i = 0; i < n; ++i, ++out) {
86 *out /= accumulated[i];
87 }
88 } else {
89 double denom = 1;
90 if constexpr(weighted_) {
91 denom /= std::accumulate(w, w + in.size(), 0.0);
92 } else {
93 denom /= in.size();
94 }
95 for (size_t i = 0; i < n; ++i, ++out) {
96 *out *= denom;
97 }
98 }
99}
100
101}
120template<typename Stat_, typename Output_>
121void average_vectors(size_t n, std::vector<Stat_*> in, Output_* out, bool skip_nan) {
122 internal::average_vectors<false>(n, std::move(in), static_cast<int*>(NULL), out, skip_nan);
123 return;
124}
125
138template<typename Output_ = double, typename Stat_>
139std::vector<Output_> average_vectors(size_t n, std::vector<Stat_*> in, bool skip_nan) {
140 std::vector<Output_> out(n);
141 average_vectors(n, std::move(in), out.data(), skip_nan);
142 return out;
143}
144
162template<typename Stat_, typename Weight_, typename Output_>
163void average_vectors_weighted(size_t n, std::vector<Stat_*> in, const Weight_* w, Output_* out, bool skip_nan) {
164 if (!in.empty()) {
165 bool same = true;
166 for (size_t i = 1, end = in.size(); i < end; ++i) {
167 if (w[i] != w[0]) {
168 same = false;
169 break;
170 }
171 }
172
173 if (same) {
174 if (w[0] == 0) {
175 std::fill_n(out, n, std::numeric_limits<Output_>::quiet_NaN());
176 } else {
177 average_vectors(n, std::move(in), out, skip_nan);
178 }
179 return;
180 }
181 }
182
183 internal::average_vectors<true>(n, std::move(in), w, out, skip_nan);
184 return;
185}
186
202template<typename Output_ = double, typename Stat_, typename Weight_>
203std::vector<Output_> average_vectors_weighted(size_t n, std::vector<Stat_*> in, const Weight_* w, bool skip_nan) {
204 std::vector<Output_> out(n);
205 average_vectors_weighted(n, std::move(in), w, out.data(), skip_nan);
206 return out;
207}
208
209}
210
211#endif
Blocking utilities for libscran.
Definition average_vectors.hpp:15
void average_vectors_weighted(size_t n, std::vector< Stat_ * > in, const Weight_ *w, Output_ *out, bool skip_nan)
Definition average_vectors.hpp:163
void average_vectors(size_t n, std::vector< Stat_ * > in, Output_ *out, bool skip_nan)
Definition average_vectors.hpp:121