tatami_stats
Matrix statistics for tatami
Loading...
Searching...
No Matches
count.hpp
Go to the documentation of this file.
1#ifndef TATAMI_STATS_COUNT_HPP
2#define TATAMI_STATS_COUNT_HPP
3
4#include <vector>
5#include <algorithm>
6#include <cmath>
7#include <type_traits>
8
9#include "tatami/tatami.hpp"
10#include "sanisizer/sanisizer.hpp"
11
12#include "utils.hpp"
13
20namespace tatami_stats {
21
30 int num_threads = 1;
31};
32
36template<typename Value_, typename Index_, typename Output_, class Condition_>
37void count_direct(const bool row, const tatami::Matrix<Value_, Index_>& mat, Output_* const output, Condition_ condition, const CountOptions& opt) {
38 const Index_ dim = (row ? mat.nrow() : mat.ncol());
39 const Index_ otherdim = (row ? mat.ncol() : mat.nrow());
40
41 if (mat.sparse()) {
42 tatami::Options topt;
43 topt.sparse_ordered_index = false;
44 const bool count_zero = condition(0);
45
46 tatami::parallelize([&](int, Index_ start, Index_ len) -> void {
47 auto ext = tatami::consecutive_extractor<true>(mat, row, start, len, topt);
50
51 for (Index_ x = 0; x < len; ++x) {
52 auto range = ext->fetch(xbuffer.data(), ibuffer.data());
53 Output_ target = 0;
54 for (Index_ j = 0; j < range.number; ++j) {
55 target += condition(range.value[j]);
56 }
57 if (count_zero) {
58 target += otherdim - range.number;
59 }
60 output[x + start] = target;
61 }
62 }, dim, opt.num_threads);
63
64 } else {
65 tatami::parallelize([&](int, Index_ start, Index_ len) -> void {
67 auto ext = tatami::consecutive_extractor<false>(mat, row, start, len);
68
69 for (Index_ x = 0; x < len; ++x) {
70 auto ptr = ext->fetch(xbuffer.data());
71 Output_ target = 0;
72 for (Index_ j = 0; j < otherdim; ++j) {
73 target += condition(ptr[j]);
74 }
75 output[x + start] = target;
76 }
77 }, dim, opt.num_threads);
78 }
79}
80
81template<typename Value_, typename Index_, typename Output_, class Condition_>
82void count_running(const bool row, const tatami::Matrix<Value_, Index_>& mat, Output_* const output, Condition_ condition, const CountOptions& opt) {
83 const Index_ dim = (row ? mat.nrow() : mat.ncol());
84 const Index_ otherdim = (row ? mat.ncol() : mat.nrow());
85
86 const bool do_parallel = opt.num_threads > 1;
87 std::optional<std::vector<std::optional<std::vector<Output_> > > > all_partial_count;
88 if (do_parallel) {
89 all_partial_count.emplace(sanisizer::cast<I<decltype(all_partial_count->size())> >(opt.num_threads - 1));
90 }
91
92 // Checking if we should count zeros in the sparse case.
93 const bool is_sparse = mat.is_sparse();
94 const bool count_zero = is_sparse && condition(0);
95
96 std::fill_n(output, dim, 0);
97
98 const int num_used = tatami::parallelize([&](int thread, Index_ start, Index_ len) -> void {
99 Output_* out_ptr;
100 std::optional<std::vector<Output_> > cur_count;
101 if (!do_parallel) {
102 out_ptr = output;
103 } else {
104 // Directly write the result to the output buffer for the first thread to save ourselves an allocation.
105 // Everything else goes into these temporary vectors.
106 if (thread == 0) {
107 out_ptr = output;
108 } else {
109 cur_count.emplace(tatami::cast_Index_to_container_size<std::vector<Output_> >(dim));
110 out_ptr = cur_count->data();
111 }
112 }
113
114 if (is_sparse) {
115 tatami::Options topt;
116 topt.sparse_ordered_index = false;
117 auto ext = tatami::consecutive_extractor<true>(mat, !row, start, len, topt);
121
122 for (Index_ x = 0; x < len; ++x) {
123 auto range = ext->fetch(xbuffer.data(), ibuffer.data());
124 for (Index_ j = 0; j < range.number; ++j) {
125 auto idx = range.index[j];
126 out_ptr[idx] += condition(range.value[j]);
127 ++(nonzeros[idx]);
128 }
129 }
130
131 if (count_zero) {
132 for (Index_ d = 0; d < dim; ++d) {
133 out_ptr[d] += len - nonzeros[d];
134 }
135 }
136
137 } else {
139 auto ext = tatami::consecutive_extractor<false>(mat, !row, start, len);
140
141 for (Index_ x = 0; x < len; ++x) {
142 auto ptr = ext->fetch(xbuffer.data());
143 for (Index_ d = 0; d < dim; ++d) {
144 out_ptr[d] += condition(ptr[d]);
145 }
146 }
147 }
148
149 if (thread) {
150 (*all_partial_count)[thread - 1] = std::move(cur_count);
151 }
152 }, otherdim, opt.num_threads);
153
154 if (do_parallel) {
155 // Skip the first thread as we already put its counts in 'output'.
156 for (int u = 1; u < num_used; ++u) {
157 const auto& curout = *((*all_partial_count)[u - 1]);
158 for (Index_ d = 0; d < dim; ++d) {
159 output[d] += curout[d];
160 }
161 }
162 }
163}
187template<typename Value_, typename Index_, typename Output_, class Condition_>
188void count(const bool row, const tatami::Matrix<Value_, Index_>& mat, Output_* const output, Condition_ condition, const CountOptions& opt) {
189 if (mat.prefer_rows() == row) {
190 count_direct(row, mat, output, std::move(condition), opt);
191 } else {
192 count_running(row, mat, output, std::move(condition), opt);
193 }
194}
195
213template<typename Output_, typename Value_, typename Index_, class Condition_>
214std::vector<Output_> count(const bool row, const tatami::Matrix<Value_, Index_>& mat, Condition_ condition, const CountOptions& opt) {
215 const Index_ dim = (row ? mat.nrow() : mat.ncol());
216 auto output = sanisizer::create<std::vector<Output_> >(dim
217#ifdef TATAMI_STATS_TEST_DIRTY
218 , -1
219#endif
220 );
221 count(row, mat, output.data(), std::move(condition), opt);
222 return output;
223}
224
225}
226
227#endif
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
virtual bool prefer_rows() const=0
virtual bool is_sparse() const=0
virtual std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(bool row, const Options &opt) const=0
Functions to compute statistics from a tatami::Matrix.
Definition count.hpp:20
void range(bool row, const tatami::Matrix< Value_, Index_ > &mat, RangeBuffers< Output_ > &output, const RangeOptions &opt)
Definition range.hpp:400
void count(const bool row, const tatami::Matrix< Value_, Index_ > &mat, Output_ *const output, Condition_ condition, const CountOptions &opt)
Definition count.hpp:188
int parallelize(Function_ fun, const Index_ tasks, const int workers)
I< decltype(std::declval< Container_ >().size())> cast_Index_to_container_size(const Index_ x)
Container_ create_container_of_Index_size(const Index_ x, Args_ &&... args)
auto consecutive_extractor(const Matrix< Value_, Index_ > &matrix, const bool row, const Index_ iter_start, const Index_ iter_length, Args_ &&... args)
bool sparse_ordered_index
Options for count().
Definition count.hpp:25
int num_threads
Definition count.hpp:30