scran_blocks
Blocking utilities for libscran
Loading...
Searching...
No Matches
parallel_means.hpp
Go to the documentation of this file.
1#ifndef SCRAN_BLOCKS_PARALLEL_MEANS_HPP
2#define SCRAN_BLOCKS_PARALLEL_MEANS_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
13#include "utils.hpp"
14
20namespace scran_blocks {
21
25template<bool weighted_, typename Stat_, typename Weight_, typename Output_>
26void parallel_means_internal(const std::size_t n, std::vector<Stat_*> in, const Weight_* const w, Output_* const out, const bool skip_nan) {
27 const auto nblocks = in.size();
28 if (nblocks == 0) {
29 std::fill_n(out, n, std::numeric_limits<Output_>::quiet_NaN());
30 return;
31 } else if (nblocks == 1) {
32 if constexpr(weighted_) {
33 if (w[0] == 0) {
34 std::fill_n(out, n, std::numeric_limits<Output_>::quiet_NaN());
35 return;
36 }
37 }
38 std::copy(in[0], in[0] + n, out);
39 return;
40 }
41
42 if (skip_nan) {
43 for (I<decltype(n)> i = 0; i < n; ++i) {
44 Output_ prod = 0;
45 Output_ denom = 0;
46
47 for (I<decltype(nblocks)> b = 0; b < nblocks; ++b) {
48 const auto val = in[b][i];
49 if (!std::isnan(val)) {
50 if constexpr(weighted_) {
51 const auto curw = w[b];
52 prod += val * curw;
53 denom += curw;
54 } else {
55 prod += val;
56 denom += 1;
57 }
58 }
59 }
60
61 out[i] = prod/denom;
62 }
63
64 } else {
65 std::fill_n(out, n, 0);
66 auto wcopy = w;
67 for (const auto current : in) {
68 if constexpr(weighted_) {
69 const Weight_ weight = *(wcopy++);
70 if (weight != 1) {
71 for (I<decltype(n)> i = 0; i < n; ++i) {
72 out[i] += current[i] * weight;
73 }
74 continue;
75 }
76 }
77 for (I<decltype(n)> i = 0; i < n; ++i) {
78 out[i] += current[i];
79 }
80 }
81
82 const Output_ denom = [&]() {
83 if constexpr(weighted_) {
84 return std::accumulate(w, w + in.size(), static_cast<Output_>(0));
85 } else {
86 return in.size();
87 }
88 }();
89 for (I<decltype(n)> i = 0; i < n; ++i) {
90 out[i] /= denom;
91 }
92 }
93}
113template<typename Stat_, typename Output_>
114void parallel_means(const std::size_t n, std::vector<Stat_*> in, Output_* const out, const bool skip_nan) {
115 parallel_means_internal<false>(n, std::move(in), static_cast<int*>(NULL), out, skip_nan);
116 return;
117}
118
133template<typename Output_ = double, typename Stat_>
134std::vector<Output_> parallel_means(const std::size_t n, std::vector<Stat_*> in, const bool skip_nan) {
135 auto out = sanisizer::create<std::vector<Output_> >(n);
136 parallel_means(n, std::move(in), out.data(), skip_nan);
137 return out;
138}
139
158template<typename Stat_, typename Weight_, typename Output_>
159void parallel_weighted_means(const std::size_t n, std::vector<Stat_*> in, const Weight_* const w, Output_* const out, const bool skip_nan) {
160 if (!in.empty()) {
161 bool same = true;
162 const auto numin = in.size();
163 for (I<decltype(numin)> i = 1; i < numin; ++i) {
164 if (w[i] != w[0]) {
165 same = false;
166 break;
167 }
168 }
169
170 if (same) {
171 if (w[0] == 0) {
172 std::fill_n(out, n, std::numeric_limits<Output_>::quiet_NaN());
173 } else {
174 parallel_means(n, std::move(in), out, skip_nan);
175 }
176 return;
177 }
178 }
179
180 parallel_means_internal<true>(n, std::move(in), w, out, skip_nan);
181 return;
182}
183
201template<typename Output_ = double, typename Stat_, typename Weight_>
202std::vector<Output_> parallel_weighted_means(const std::size_t n, std::vector<Stat_*> in, const Weight_* const w, const bool skip_nan) {
203 auto out = sanisizer::create<std::vector<Output_> >(n);
204 parallel_weighted_means(n, std::move(in), w, out.data(), skip_nan);
205 return out;
206}
207
211// Methods for back-compatibility.
212template<typename Stat_, typename Output_>
213void average_vectors(const std::size_t n, std::vector<Stat_*> in, Output_* const out, const bool skip_nan) {
214 parallel_means(n, in, out, skip_nan);
215}
216
217template<typename Output_ = double, typename Stat_>
218std::vector<Output_> average_vectors(const std::size_t n, std::vector<Stat_*> in, const bool skip_nan) {
219 return parallel_means(n, in, skip_nan);
220}
221
222template<typename Stat_, typename Weight_, typename Output_>
223void average_vectors_weighted(const std::size_t n, std::vector<Stat_*> in, const Weight_* const w, Output_* const out, const bool skip_nan) {
224 parallel_weighted_means(n, in, w, out, skip_nan);
225}
226
227template<typename Output_ = double, typename Stat_, typename Weight_>
228std::vector<Output_> average_vectors_weighted(const std::size_t n, std::vector<Stat_*> in, const Weight_* const w, const bool skip_nan) {
229 return parallel_weighted_means(n, in, w, skip_nan);
230}
235}
236
237#endif
Blocking utilities for libscran.
Definition block_weights.hpp:17
void parallel_weighted_means(const std::size_t n, std::vector< Stat_ * > in, const Weight_ *const w, Output_ *const out, const bool skip_nan)
Definition parallel_means.hpp:159
void parallel_means(const std::size_t n, std::vector< Stat_ * > in, Output_ *const out, const bool skip_nan)
Definition parallel_means.hpp:114