singler_classic_markers
Classic marker detection for SingleR
Loading...
Searching...
No Matches
blocked.hpp
1#ifndef MEDIAN_MARKERS_BLOCKED_HPP
2#define MEDIAN_MARKERS_BLOCKED_HPP
3
4#include <cstddef>
5#include <optional>
6#include <vector>
7#include <limits>
8#include <cmath>
9
10#include "sanisizer/sanisizer.hpp"
11#include "tatami/tatami.hpp"
12#include "tatami_stats/tatami_stats.hpp"
13
14#include "queue.hpp"
15#include "scan.hpp"
16#include "number.hpp"
17
19
28 std::optional<std::size_t> number;
29
35 bool keep_ties = false;
36
42 bool use_minimum = false;
43
48 int num_threads = 1;
49};
50
54template<bool include_stat_, typename Stat_, typename Value_, typename Index_, typename Label_, typename Block_>
55Markers<include_stat_, Index_, Stat_> choose_blocked_raw(
56 const tatami::Matrix<Value_, Index_>& matrix,
57 const Label_* label,
58 const Block_* block,
59 const ChooseBlockedOptions& options
60) {
61 const auto NC = matrix.ncol();
62 const std::size_t ngroups = tatami_stats::total_groups/*<std::size_t>*/(label, NC);
63 const std::size_t nblocks = tatami_stats::total_groups/*<std::size_t>*/(block, NC);
64
65 const auto num_keep = get_num_keep<Index_>(ngroups, options.number);
66 auto pqueues = sanisizer::create<std::vector<std::optional<PairwiseTopQueues<Stat_, Index_> > > >(options.num_threads);
67
68 // Creating the combinations between block and not.
69 const auto ncombos = sanisizer::product<std::size_t>(ngroups, nblocks); // check that all producs below are safe.
70 auto combinations = sanisizer::create<std::vector<std::size_t> >(NC);
71 for (I<decltype(NC)> c = 0; c < NC; ++c) {
72 combinations[c] = sanisizer::nd_offset<std::size_t>(label[c], ngroups, block[c]); // group is the faster changing dimension.
73 }
74 auto combo_sizes = tatami_stats::tabulate_groups(combinations.data(), NC);
75
76 const auto num_used = scan_matrix<Stat_>(
77 matrix,
78 sanisizer::cast<std::size_t>(ncombos),
79 combinations.data(),
80 combo_sizes,
81
82 /* setup = */ [&]() -> PairwiseTopQueues<Stat_, Index_> {
83 PairwiseTopQueues<Stat_, Index_> output;
84 allocate_pairwise_queues(output, num_keep, ngroups, options.keep_ties, /* check_nan = */ false); // we'll check it ourselves.
85 return output;
86 },
87
88 /* fun = */ [&](const Index_ r, const std::vector<Stat_>& medians, PairwiseTopQueues<Stat_, Index_>& curqueues) -> void {
89 for (I<decltype(ngroups)> g1 = 1; g1 < ngroups; ++g1) {
90 for (I<decltype(ngroups)> g2 = 0; g2 < g1; ++g2) {
91
92 if (options.use_minimum) {
93 Stat_ xval = std::numeric_limits<Stat_>::infinity();
94 Stat_ yval = std::numeric_limits<Stat_>::infinity();
95 for (I<decltype(nblocks)> b = 0; b < nblocks; ++b) {
96 const auto delta = medians[sanisizer::nd_offset<std::size_t>(g1, ngroups, b)] - medians[sanisizer::nd_offset<std::size_t>(g2, ngroups, b)];
97 if (!std::isnan(delta)) {
98 xval = std::min(xval, delta);
99 yval = std::min(yval, -delta);
100 }
101 }
102
103 if (std::isfinite(xval)) {
104 curqueues[g1][g2].emplace(xval, r);
105 curqueues[g2][g1].emplace(yval, r);
106 }
107
108 } else {
109 Stat_ val = 0;
110 std::size_t denom = 0;
111 for (I<decltype(nblocks)> b = 0; b < nblocks; ++b) {
112 const auto delta = medians[sanisizer::nd_offset<std::size_t>(g1, ngroups, b)] - medians[sanisizer::nd_offset<std::size_t>(g2, ngroups, b)];
113 if (!std::isnan(delta)) {
114 ++denom;
115 val += delta;
116 }
117 }
118
119 if (denom) {
120 val /= denom;
121 curqueues[g1][g2].emplace(val, r);
122 curqueues[g2][g1].emplace(-val, r);
123 }
124 }
125
126 }
127 }
128 },
129
130 /* finalize = */ [&](const int t, PairwiseTopQueues<Stat_, Index_>& curqueues) -> void {
131 pqueues[t] = std::move(curqueues);
132 },
133
134 options.num_threads
135 );
136
137 pqueues.resize(num_used);
138 Markers<include_stat_, Index_, Stat_> output;
139 report_best_top_queues<include_stat_>(pqueues, ngroups, output);
140 return output;
141}
171template<typename Stat_ = double, typename Value_, typename Index_, typename Label_, typename Block_>
172std::vector<std::vector<std::vector<std::pair<Index_, Stat_> > > > choose_blocked(
173 const tatami::Matrix<Value_, Index_>& matrix,
174 const Label_* label,
175 const Block_* block,
176 const ChooseBlockedOptions& options
177) {
178 return choose_blocked_raw<true, Stat_>(matrix, label, block, options);
179}
180
203template<typename Stat_ = double, typename Value_, typename Index_, typename Label_, typename Block_>
204std::vector<std::vector<std::vector<Index_> > > choose_blocked_index(
205 const tatami::Matrix<Value_, Index_>& matrix,
206 const Label_* label,
207 const Block_* block,
208 const ChooseBlockedOptions& options
209) {
210 return choose_blocked_raw<false, Stat_>(matrix, label, block, options);
211}
212
213}
214
215#endif
virtual Index_ ncol() const=0
Implementation of the classic SingleR marker detection.
Definition choose.hpp:21
std::vector< std::vector< std::vector< std::pair< Index_, Stat_ > > > > choose_blocked(const tatami::Matrix< Value_, Index_ > &matrix, const Label_ *label, const Block_ *block, const ChooseBlockedOptions &options)
Definition blocked.hpp:172
std::vector< std::vector< std::vector< Index_ > > > choose_blocked_index(const tatami::Matrix< Value_, Index_ > &matrix, const Label_ *label, const Block_ *block, const ChooseBlockedOptions &options)
Definition blocked.hpp:204
Options for choose_blocked().
Definition blocked.hpp:23
int num_threads
Definition blocked.hpp:48
std::optional< std::size_t > number
Definition blocked.hpp:28
bool use_minimum
Definition blocked.hpp:42
bool keep_ties
Definition blocked.hpp:35