1#ifndef SCRAN_SCORE_MARKERS_HPP
2#define SCRAN_SCORE_MARKERS_HPP
4#include "scan_matrix.hpp"
6#include "simple_diff.hpp"
8#include "average_group_stats.hpp"
9#include "create_combinations.hpp"
118template<
typename Stat_,
typename Rank_>
141 std::vector<SummaryBuffers<Stat_, Rank_> >
cohens_d;
150 std::vector<SummaryBuffers<Stat_, Rank_> >
auc;
176template<
typename Stat_,
typename Rank_>
182 std::vector<std::vector<Stat_> >
mean;
197 std::vector<SummaryResults<Stat_, Rank_> >
cohens_d;
206 std::vector<SummaryResults<Stat_, Rank_> >
auc;
255template<
typename Stat_>
258 EffectsCacher(
size_t ngenes,
size_t ngroups,
size_t cache_size) :
261 my_cache_size(std::min(cache_size, ngroups * (ngroups - 1) / 2)),
263 my_common_cache(ngenes * my_cache_size),
264 my_staging_cache(ngroups)
266 my_unused_pool.reserve(my_cache_size);
267 auto ptr = my_common_cache.data();
268 for (
size_t c = 0; c < my_cache_size; ++c, ptr += ngenes) {
269 my_unused_pool.push_back(ptr);
276 size_t my_cache_size;
278 std::vector<CacheAction> my_actions;
282 std::vector<Stat_> my_common_cache;
289 std::vector<Stat_*> my_staging_cache;
293 std::vector<Stat_*> my_unused_pool;
297 std::map<std::pair<size_t, size_t>, Stat_*> my_cached;
305 void fill_effects_from_cache(
size_t group, std::vector<double>& full_effects) {
310 for (
size_t other = 0; other < my_ngroups; ++other) {
311 if (other == group) {
312 my_actions[other] = CacheAction::SKIP;
316 if (my_cache_size == 0) {
317 my_actions[other] = CacheAction::COMPUTE;
325 my_actions[other] = CacheAction::CACHE;
333 if (my_cached.empty()) {
334 my_actions[other] = CacheAction::COMPUTE;
338 const auto& front = my_cached.begin()->first;
339 if (front.first > group || front.second > other) {
343 my_actions[other] = CacheAction::COMPUTE;
350 my_actions[other] = CacheAction::SKIP;
351 auto curcache = my_cached.begin()->second;
352 for (
size_t i = 0; i < my_ngenes; ++i) {
353 full_effects[other + my_ngroups * i ] = curcache[i];
356 my_unused_pool.push_back(curcache);
357 my_cached.erase(my_cached.begin());
363 for (
size_t other = 0; other < my_ngroups; ++other) {
364 if (my_actions[other] != CacheAction::CACHE) {
368 std::pair<size_t, size_t> key(other, group);
369 if (my_cached.size() < my_cache_size) {
370 auto ptr = my_unused_pool.back();
371 my_cached[key] = ptr;
372 my_staging_cache[other] = ptr;
373 my_unused_pool.pop_back();
380 auto it = my_cached.end();
382 if ((it->first).first > other) {
383 auto ptr = it->second;
384 my_cached[key] = ptr;
385 my_staging_cache[other] = ptr;
391 my_actions[other] = CacheAction::COMPUTE;
397 CacheAction get_action(
size_t other)
const {
398 return my_actions[other];
401 Stat_* get_cache_location(
size_t other)
const {
402 return my_staging_cache[other];
406template<
typename Stat_,
typename Rank_>
407void process_simple_summary_effects(
412 const std::vector<Stat_>& combo_means,
413 const std::vector<Stat_>& combo_vars,
414 const std::vector<Stat_>& combo_detected,
415 const ScoreMarkersSummaryBuffers<Stat_, Rank_>& output,
416 const std::vector<Stat_>& combo_weights,
423 std::vector<Stat_> total_weights_per_group;
424 const Stat_* total_weights_ptr = combo_weights.data();
426 total_weights_per_group = compute_total_weight_per_group(ngroups, nblocks, combo_weights.data());
427 total_weights_ptr = total_weights_per_group.data();
431 size_t in_offset = ncombos *
static_cast<size_t>(start);
432 const auto* tmp_means = combo_means.data() + in_offset;
433 const auto* tmp_detected = combo_detected.data() + in_offset;
434 for (
size_t gene = start, end = start + length; gene < end; ++gene, tmp_means += ncombos, tmp_detected += ncombos) {
435 average_group_stats(gene, ngroups, nblocks, tmp_means, tmp_detected, combo_weights.data(), total_weights_ptr, output.mean, output.detected);
437 }, ngenes, num_threads);
440 PrecomputedPairwiseWeights<Stat_> preweights(ngroups, nblocks, combo_weights.data());
441 EffectsCacher<Stat_> cache(ngenes, ngroups, cache_size);
442 std::vector<Stat_> full_effects(ngroups * ngenes);
443 std::vector<std::vector<Stat_> > effect_buffers(num_threads);
444 for (
auto& ef : effect_buffers) {
448 if (output.cohens_d.size()) {
450 for (
size_t group = 0; group < ngroups; ++group) {
451 cache.fill_effects_from_cache(group, full_effects);
454 size_t in_offset = ncombos *
static_cast<size_t>(start);
455 auto my_means = combo_means.data() + in_offset;
456 auto my_variances = combo_vars.data() + in_offset;
457 auto store_ptr = full_effects.data() +
static_cast<size_t>(start) * ngroups;
458 auto& effect_buffer = effect_buffers[t];
460 for (
size_t gene = start, end = start + length; gene < end; ++gene, my_means += ncombos, my_variances += ncombos, store_ptr += ngroups) {
461 for (
size_t other = 0; other < ngroups; ++other) {
462 auto cache_action = cache.get_action(other);
463 if (cache_action == internal::CacheAction::COMPUTE) {
464 store_ptr[other] = compute_pairwise_cohens_d_one_sided(group, other, my_means, my_variances, ngroups, nblocks, preweights, threshold);
465 }
else if (cache_action == internal::CacheAction::CACHE) {
466 auto tmp = compute_pairwise_cohens_d_two_sided(group, other, my_means, my_variances, ngroups, nblocks, preweights, threshold);
467 store_ptr[other] = tmp.first;
468 cache.get_cache_location(other)[gene] = tmp.second;
471 summarize_comparisons(ngroups, store_ptr, group, gene, output.cohens_d[group], effect_buffer);
473 }, ngenes, num_threads);
475 auto mr = output.cohens_d[group].min_rank;
477 compute_min_rank_for_group(ngenes, ngroups, group, full_effects.data(), mr, num_threads);
482 if (output.delta_mean.size()) {
484 for (
size_t group = 0; group < ngroups; ++group) {
485 cache.fill_effects_from_cache(group, full_effects);
488 auto my_means = combo_means.data() + ncombos *
static_cast<size_t>(start);
489 auto store_ptr = full_effects.data() +
static_cast<size_t>(start) * ngroups;
490 auto& effect_buffer = effect_buffers[t];
492 for (
size_t gene = start, end = start + length; gene < end; ++gene, my_means += ncombos, store_ptr += ngroups) {
493 for (
size_t other = 0; other < ngroups; ++other) {
494 auto cache_action = cache.get_action(other);
495 if (cache_action != internal::CacheAction::SKIP) {
496 auto val = compute_pairwise_simple_diff(group, other, my_means, ngroups, nblocks, preweights);
497 store_ptr[other] = val;
498 if (cache_action == CacheAction::CACHE) {
499 cache.get_cache_location(other)[gene] = -val;
503 summarize_comparisons(ngroups, store_ptr, group, gene, output.delta_mean[group], effect_buffer);
505 }, ngenes, num_threads);
507 auto mr = output.delta_mean[group].min_rank;
509 compute_min_rank_for_group(ngenes, ngroups, group, full_effects.data(), mr, num_threads);
514 if (output.delta_detected.size()) {
516 for (
size_t group = 0; group < ngroups; ++group) {
517 cache.fill_effects_from_cache(group, full_effects);
520 auto my_detected = combo_detected.data() + ncombos *
static_cast<size_t>(start);
521 auto store_ptr = full_effects.data() +
static_cast<size_t>(start) * ngroups;
522 auto& effect_buffer = effect_buffers[t];
524 for (
size_t gene = start, end = start + length; gene < end; ++gene, my_detected += ncombos, store_ptr += ngroups) {
525 for (
size_t other = 0; other < ngroups; ++other) {
526 auto cache_action = cache.get_action(other);
527 if (cache_action != CacheAction::SKIP) {
528 auto val = compute_pairwise_simple_diff(group, other, my_detected, ngroups, nblocks, preweights);
529 store_ptr[other] = val;
530 if (cache_action == CacheAction::CACHE) {
531 cache.get_cache_location(other)[gene] = -val;
535 summarize_comparisons(ngroups, store_ptr, group, gene, output.delta_detected[group], effect_buffer);
537 }, ngenes, num_threads);
539 auto mr = output.delta_detected[group].min_rank;
541 compute_min_rank_for_group(ngenes, ngroups, group, full_effects.data(), mr, num_threads);
547template<
typename Stat_,
typename Rank_>
548ScoreMarkersSummaryBuffers<Stat_, Rank_> fill_summary_results(
size_t ngenes,
size_t ngroups, ScoreMarkersSummaryResults<Stat_, Rank_>& store,
const ScoreMarkersSummaryOptions& options) {
549 ScoreMarkersSummaryBuffers<Stat_, Rank_> output;
551 internal::fill_average_results(ngenes, ngroups, store.mean, store.detected, output.mean, output.detected);
553 if (options.compute_cohens_d) {
554 output.cohens_d = internal::fill_summary_results(
559 options.compute_mean,
560 options.compute_median,
562 options.compute_min_rank
566 if (options.compute_auc) {
567 output.auc = internal::fill_summary_results(
572 options.compute_mean,
573 options.compute_median,
575 options.compute_min_rank
579 if (options.compute_delta_mean) {
580 output.delta_mean = internal::fill_summary_results(
585 options.compute_mean,
586 options.compute_median,
588 options.compute_min_rank
592 if (options.compute_delta_detected) {
593 output.delta_detected = internal::fill_summary_results(
596 store.delta_detected,
598 options.compute_mean,
599 options.compute_median,
601 options.compute_min_rank
645template<
typename Value_,
typename Index_,
typename Group_,
typename Stat_,
typename Rank_>
673 internal::scan_matrix_by_row<true>(
678 static_cast<int*
>(
NULL),
692 internal::scan_matrix_by_column(
704 internal::process_simple_summary_effects(
752template<
typename Value_,
typename Index_,
typename Group_,
typename Block_,
typename Stat_,
typename Rank_>
782 internal::scan_matrix_by_row<false>(
801 internal::scan_matrix_by_column(
813 internal::process_simple_summary_effects(
850template<
typename Stat_ =
double,
typename Rank_ =
int,
typename Value_,
typename Index_,
typename Group_>
882template<
typename Stat_ =
double,
typename Rank_ =
int,
typename Value_,
typename Index_,
typename Group_,
typename Block_>
Marker detection for single-cell data.
Definition score_markers_pairwise.hpp:23
void score_markers_summary(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *group, const ScoreMarkersSummaryOptions &options, const ScoreMarkersSummaryBuffers< Stat_, Rank_ > &output)
Definition score_markers_summary.hpp:646
void score_markers_summary_blocked(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *group, const Block_ *block, const ScoreMarkersSummaryOptions &options, const ScoreMarkersSummaryBuffers< Stat_, Rank_ > &output)
Definition score_markers_summary.hpp:753
void parallelize(Function_ fun, Index_ tasks, int threads)
Utilities for effect summarization.