1#ifndef TATAMI_STATS_GROUP_RSS_HPP
2#define TATAMI_STATS_GROUP_RSS_HPP
15#include "sanisizer/sanisizer.hpp"
16#include "quickstats/quickstats.hpp"
44template<
typename Output_,
typename Count_>
51 std::vector<Output_*>
mean;
58 std::vector<Output_*>
rss;
70template<
typename Count_,
typename Output_,
typename Index_>
71void group_rss_finish_means(
72 const std::size_t num_groups,
73 const Count_*
const group_size,
74 std::vector<Output_>& means,
76 std::vector<Output_*>& output_means
78 for (std::size_t b = 0; b < num_groups; ++b) {
80 means[b] /= group_size[b];
82 means[b] = std::numeric_limits<Output_>::quiet_NaN();
84 output_means[b][i] = means[b];
88template<
typename Value_,
typename Index_,
typename Group_,
typename Output_,
typename Count_>
92 const Group_*
const group,
93 const std::size_t num_groups,
94 GroupRssBuffers<Output_, Count_>& output,
95 const GroupRssOptions& opt
97 const auto dim = (row ? mat.
nrow() : mat.
ncol());
98 const auto otherdim = (row ? mat.
ncol() : mat.
nrow());
100 std::fill_n(output.count, num_groups, 0);
101 for (Index_ i = 0; i < otherdim; ++i) {
102 output.count[group[i]] += 1;
110 auto cur_means = sanisizer::create<std::vector<Output_> >(num_groups);
111 auto cur_rss = sanisizer::create<std::vector<Output_> >(num_groups);
112 auto cur_non_zeros = sanisizer::create<std::vector<Index_> >(num_groups);
114 for (Index_ x = 0; x < l; ++x) {
115 auto range = ext->fetch(vbuffer.data(), ibuffer.data());
118 for (Index_ i = 0; i <
range.number; ++i) {
119 const auto g = group[
range.index[i]];
120 cur_means[g] +=
range.value[i];
123 group_rss_finish_means(num_groups, output.count, cur_means,
static_cast<Index_
>(s + x), output.mean);
126 for (Index_ i = 0; i <
range.number; ++i) {
127 const auto g = group[
range.index[i]];
128 const auto delta =
range.value[i] - cur_means[g];
129 cur_rss[g] += delta * delta;
131 for (std::size_t g = 0; g < num_groups; ++g) {
132 if (output.count[g] > 0) {
133 const Output_ my_rss = cur_rss[g] + cur_means[g] * cur_means[g] * (output.count[g] - cur_non_zeros[g]);
134 output.rss[g][s + x] = my_rss;
136 output.rss[g][s + x] = 0;
140 std::fill(cur_means.begin(), cur_means.end(), 0);
141 std::fill(cur_rss.begin(), cur_rss.end(), 0);
142 std::fill(cur_non_zeros.begin(), cur_non_zeros.end(), 0);
144 }, dim, opt.num_threads);
150 auto cur_means = sanisizer::create<std::vector<Output_> >(num_groups);
151 auto cur_rss = sanisizer::create<std::vector<Output_> >(num_groups);
153 for (Index_ x = 0; x < l; ++x) {
154 auto ptr = ext->fetch(buffer.data());
157 for (Index_ j = 0; j < otherdim; ++j) {
158 cur_means[group[j]] += ptr[j];
160 group_rss_finish_means(num_groups, output.count, cur_means,
static_cast<Index_
>(s + x), output.mean);
163 for (Index_ j = 0; j < otherdim; ++j) {
164 const auto g = group[j];
165 const auto delta = ptr[j] - cur_means[g];
166 cur_rss[g] += delta * delta;
168 for (std::size_t g = 0; g < num_groups; ++g) {
169 output.rss[g][s + x] = cur_rss[g];
172 std::fill(cur_means.begin(), cur_means.end(), 0);
173 std::fill(cur_rss.begin(), cur_rss.end(), 0);
175 }, dim, opt.num_threads);
179template<
typename Value_,
typename Index_,
typename Group_,
typename Output_,
typename Count_>
180void group_rss_running(
183 const Group_*
const group,
184 const std::size_t num_groups,
185 GroupRssBuffers<Output_, Count_>& output,
186 const GroupRssOptions& opt
188 const auto dim = (row ? mat.
nrow() : mat.
ncol());
189 const auto otherdim = (row ? mat.
ncol() : mat.
nrow());
193 std::fill_n(output.count, num_groups, 0);
194 for (std::size_t g = 0; g < num_groups; ++g) {
195 std::fill_n(output.mean[g], dim, std::numeric_limits<Output_>::quiet_NaN());
196 std::fill_n(output.rss[g], dim, 0);
201 const bool do_parallel = opt.num_threads > 1;
202 std::optional<std::vector<std::optional<std::vector<std::vector<Output_> > > > > all_partial_mean, all_partial_rss;
203 std::optional<std::vector<std::optional<std::vector<Count_> > > > all_partial_count;
206 all_partial_rss.emplace(sanisizer::cast<I<
decltype(all_partial_rss->size())> >(opt.num_threads - 1));
207 all_partial_mean.emplace(sanisizer::cast<I<
decltype(all_partial_mean->size())> >(opt.num_threads));
208 all_partial_count.emplace(sanisizer::cast<I<
decltype(all_partial_count->size())> >(opt.num_threads));
211 for (std::size_t g = 0; g < num_groups; ++g) {
212 std::fill_n(output.mean[g], dim, 0);
213 std::fill_n(output.rss[g], dim, 0);
219 std::optional<std::vector<Output_*> > tmp_mean_ptrs, tmp_rss_ptrs;
220 std::optional<std::vector<std::vector<Output_> > > cur_mean, cur_rss;
222 std::optional<std::vector<Count_> > cur_count;
226 mean_ptrs = output.mean.data();
227 rss_ptrs = output.rss.data();
228 count_ptr = output.count;
232 cur_mean.emplace(sanisizer::cast<I<
decltype(cur_mean->size())> >(num_groups));
233 tmp_mean_ptrs.emplace(sanisizer::cast<I<
decltype(tmp_mean_ptrs->size())> >(num_groups));
234 for (std::size_t g = 0; g < num_groups; ++g) {
236 (*tmp_mean_ptrs)[g] = (*cur_mean)[g].data();
238 mean_ptrs = tmp_mean_ptrs->data();
240 cur_count.emplace(sanisizer::cast<I<
decltype(cur_count->size())> >(num_groups));
241 count_ptr = cur_count->data();
244 rss_ptrs = output.rss.data();
246 cur_rss.emplace(sanisizer::cast<I<
decltype(cur_rss->size())> >(num_groups));
247 tmp_rss_ptrs.emplace(sanisizer::cast<I<
decltype(tmp_rss_ptrs->size())> >(num_groups));
248 for (std::size_t g = 0; g < num_groups; ++g) {
250 (*tmp_rss_ptrs)[g] = (*cur_rss)[g].data();
252 rss_ptrs = tmp_rss_ptrs->data();
261 auto nonzeros = sanisizer::create<std::vector<std::vector<Index_> > >(num_groups);
262 std::vector<quickstats::RssRunningSparse<Index_, Value_, Output_> > runners;
263 sanisizer::reserve(runners, num_groups);
264 for (std::size_t g = 0; g < num_groups; ++g) {
266 runners.emplace_back(dim, mean_ptrs[g], rss_ptrs[g], nonzeros[g].data());
269 for (Index_ x = 0; x < l; ++x) {
270 auto out = ext->fetch(vbuffer.data(), ibuffer.data());
271 runners[group[x + s]].add(out.number, out.value, out.index);
274 for (std::size_t g = 0; g < num_groups; ++g) {
275 count_ptr[g] = runners[g].num_obs();
283 std::vector<quickstats::RssRunningDense<Value_, Output_> > runners;
284 sanisizer::reserve(runners, num_groups);
285 for (std::size_t g = 0; g < num_groups; ++g) {
286 runners.emplace_back(dim, mean_ptrs[g], rss_ptrs[g]);
289 for (Index_ x = 0; x < l; ++x) {
290 auto out = ext->fetch(buffer.data());
291 runners[group[x + s]].add(out);
294 for (std::size_t g = 0; g < num_groups; ++g) {
295 count_ptr[g] = runners[g].num_obs();
301 (*all_partial_count)[thread] = std::move(cur_count);
302 (*all_partial_mean)[thread] = std::move(cur_mean);
304 (*all_partial_rss)[thread - 1] = std::move(cur_rss);
307 }, otherdim, opt.num_threads);
311 const auto& ap_mean = *all_partial_mean;
312 const auto& ap_rss = *all_partial_rss;
313 const auto& ap_count = *all_partial_count;
315 std::fill_n(output.count, num_groups, 0);
316 for (
int u = 0; u < nused; ++u) {
317 const auto& cur_count = *(ap_count[u]);
318 for (std::size_t g = 0; g < num_groups; ++g) {
319 output.count[g] += cur_count[g];
324 for (std::size_t g = 0; g < num_groups; ++g) {
325 const auto cur_output = output.mean[g];
326 const auto cur_global_count = output.count[g];
327 if (cur_global_count == 0) {
328 std::fill_n(cur_output, dim, std::numeric_limits<Output_>::quiet_NaN());
332 for (
int u = 0; u < nused; ++u) {
333 const auto cur_count = (*((*all_partial_count)[u]))[g];
334 if (cur_count == 0) {
338 const auto& cur_mean = (*(ap_mean[u]))[g];
339 const Output_ mult =
static_cast<Output_
>(cur_count) /
static_cast<Output_
>(cur_global_count);
340 for (Index_ d = 0; d < dim; ++d) {
341 cur_output[d] += cur_mean[d] * mult;
347 for (std::size_t g = 0; g < num_groups; ++g) {
348 const auto& cur_global = output.mean[g];
349 const auto cur_output = output.rss[g];
351 for (
int u = 0; u < nused; ++u) {
352 const auto cur_count = (*((*all_partial_count)[u]))[g];
353 if (cur_count == 0) {
357 const auto& cur_mean = (*(ap_mean[u]))[g];
359 for (Index_ d = 0; d < dim; ++d) {
360 cur_output[d] = quickstats::recenter_rss_unsafe(cur_count, cur_output[d], cur_mean[d], cur_global[d]);
363 const auto& cur_rss = (*(ap_rss[u - 1]))[g];
364 for (Index_ d = 0; d < dim; ++d) {
365 cur_output[d] += quickstats::recenter_rss_unsafe(cur_count, cur_rss[d], cur_mean[d], cur_global[d]);
396template<
typename Value_,
typename Index_,
typename Group_,
typename Output_,
typename Count_>
400 const Group_*
const group,
401 const std::size_t num_groups,
405 assert(sanisizer::is_equal(num_groups, output.
mean.size()));
406 assert(sanisizer::is_equal(num_groups, output.
rss.size()));
408 group_rss_direct(row, mat, group, num_groups, output, opt);
410 group_rss_running(row, mat, group, num_groups, output, opt);
421template<
typename Output_,
typename Count_>
428 std::vector<std::vector<Output_> >
mean;
435 std::vector<std::vector<Output_> >
rss;
463template<
typename Output_,
typename Count_,
typename Value_,
typename Index_,
typename Group_>
467 const Group_*
const group,
468 const std::size_t num_groups,
472 sanisizer::resize(output.
mean, num_groups);
473 sanisizer::resize(output.
rss, num_groups);
474 sanisizer::resize(output.
count, num_groups);
477 sanisizer::resize(buffers.
mean, num_groups);
478 sanisizer::resize(buffers.
rss, num_groups);
481 const auto dim = (row ? mat.
nrow() : mat.
ncol());
482 for (std::size_t g = 0; g < num_groups; ++g) {
484#ifdef TATAMI_STATS_TEST_DIRTY
488 buffers.
mean[g] = output.
mean[g].data();
490#ifdef TATAMI_STATS_TEST_DIRTY
494 buffers.
rss[g] = output.
rss[g].data();
497 group_rss(row, mat, group, num_groups, buffers, opt);
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 group_rss(bool row, const tatami::Matrix< Value_, Index_ > &mat, const Group_ *const group, const std::size_t num_groups, GroupRssBuffers< Output_, Count_ > &output, const GroupRssOptions &opt)
Definition group_rss.hpp:397
void resize_container_to_Index_size(Container_ &container, const Index_ x, Args_ &&... args)
int parallelize(Function_ fun, const Index_ tasks, const int workers)
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)