scran_markers
Marker detection for single-cell data
Loading...
Searching...
No Matches
block_averages.hpp
Go to the documentation of this file.
1#ifndef SCRAN_MARKERS_BLOCK_AVERAGES_HPP
2#define SCRAN_MARKERS_BLOCK_AVERAGES_HPP
3
4#include <vector>
5#include <cstddef>
6#include <optional>
7
8#include "sanisizer/sanisizer.hpp"
9
10#include "utils.hpp"
11
17namespace scran_markers {
18
27enum class BlockAveragePolicy : unsigned char { MEAN, QUANTILE };
28
32namespace internal {
33
34template<typename Stat_>
35class PrecomputedPairwiseWeights {
36public:
37 // 'combo_weights' are expected to be 'ngroups * nblocks' arrays where
38 // groups are the faster-changing dimension and the blocks are slower.
39 PrecomputedPairwiseWeights(const std::size_t ngroups, const std::size_t nblocks, const Stat_* const combo_weights) :
40 my_total(sanisizer::product<I<decltype(my_total.size())> >(ngroups, ngroups)),
41 my_by_block(sanisizer::product<I<decltype(my_by_block.size())> >(my_total.size(), nblocks)),
42 my_ngroups(ngroups),
43 my_nblocks(nblocks)
44 {
45 auto blocks_in_use = sanisizer::create<std::vector<std::size_t> >(my_total.size());
46 for (I<decltype(nblocks)> b = 0; b < nblocks; ++b) {
47 for (I<decltype(ngroups)> g1 = 1; g1 < ngroups; ++g1) {
48 const auto w1 = combo_weights[sanisizer::nd_offset<std::size_t>(g1, ngroups, b)];
49 if (w1 == 0) {
50 continue;
51 }
52
53 for (I<decltype(g1)> g2 = 0; g2 < g1; ++g2) {
54 const auto w2 = combo_weights[sanisizer::nd_offset<std::size_t>(g2, ngroups, b)];
55 if (w2 == 0) {
56 continue;
57 }
58
59 // Storing it as a 3D array where the blocks are the fastest changing,
60 // and then the two groups are the next fastest changing.
61 const Stat_ combined = w1 * w2;
62 const auto out_offset1 = sanisizer::nd_offset<std::size_t>(g2, ngroups, g1);
63 my_by_block[sanisizer::nd_offset<std::size_t>(b, nblocks, out_offset1)] = combined;
64 my_by_block[sanisizer::nd_offset<std::size_t>(b, nblocks, g1, ngroups, g2)] = combined;
65 my_total[out_offset1] += combined;
66 blocks_in_use[out_offset1] += (combined > 0);
67 }
68 }
69 }
70
71 // If we have exactly one block that contributes to the weighted mean, the magnitude of the weight doesn't matter.
72 // So, we set the weight to 1 to ensure that the weighted mean calculation is a no-op,
73 // i.e., there won't be any introduction of floating-point errors from a mult/div by the weight.
74 // Zero weights do need to be preserved, though, as mult/div by zero gives NaN.
75 for (I<decltype(ngroups)> g1 = 1; g1 < ngroups; ++g1) {
76 for (I<decltype(g1)> g2 = 0; g2 < g1; ++g2) {
77 const auto out_offset1 = sanisizer::nd_offset<std::size_t>(g2, ngroups, g1);
78 if (blocks_in_use[out_offset1] != 1) {
79 continue;
80 }
81
82 my_total[out_offset1] = 1;
83 for (I<decltype(nblocks)> b = 0; b < nblocks; ++b) {
84 auto& curweight = my_by_block[sanisizer::nd_offset<std::size_t>(b, nblocks, out_offset1)];
85 curweight = (curweight > 0);
86 my_by_block[sanisizer::nd_offset<std::size_t>(b, nblocks, g1, ngroups, g2)] = curweight;
87 }
88 }
89 }
90
91 // Filling the other side of my_totals, for completeness.
92 for (I<decltype(ngroups)> g1 = 1; g1 < ngroups; ++g1) {
93 for (I<decltype(g1)> g2 = 0; g2 < g1; ++g2) {
94 my_total[sanisizer::nd_offset<std::size_t>(g1, ngroups, g2)] = my_total[sanisizer::nd_offset<std::size_t>(g2, ngroups, g1)];
95 }
96 }
97 }
98
99public:
100 std::pair<const Stat_*, Stat_> get(const std::size_t g1, const std::size_t g2) const {
101 const auto offset = sanisizer::nd_offset<std::size_t>(g2, my_ngroups, g1);
102 return std::make_pair(
103 my_by_block.data() + offset * my_nblocks,
104 my_total[offset]
105 );
106 }
107
108private:
109 std::vector<Stat_> my_total;
110 std::vector<Stat_> my_by_block;
111 std::size_t my_ngroups, my_nblocks;
112};
113
114template<typename Stat_>
115class BlockAverageInfo {
116public:
117 BlockAverageInfo() = default;
118 BlockAverageInfo(std::vector<Stat_> combo_weights) : my_combo_weights(std::move(combo_weights)) {}
119 BlockAverageInfo(const double quantile) : my_quantile(quantile) {}
120
121private:
122 std::optional<std::vector<Stat_> > my_combo_weights;
123 double my_quantile = 0;
124
125public:
126 bool use_mean() const {
127 return my_combo_weights.has_value();
128 }
129
130 const std::vector<Stat_>& combo_weights() const {
131 return *my_combo_weights;
132 }
133
134 double quantile() const {
135 return my_quantile;
136 }
137};
138
139}
144}
145
146#endif
Marker detection for single-cell data.
Definition score_markers_pairwise.hpp:26
BlockAveragePolicy
Definition block_averages.hpp:27