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