121template<
typename Stat_>
195template<
typename Stat_>
203 std::vector<std::vector<Stat_> >
mean;
255template<
typename Index_,
typename Stat_>
256void process_simple_pairwise_effects(
258 const std::size_t ngroups,
259 const std::size_t nblocks,
260 const std::size_t ncombos,
261 const std::vector<Stat_>& combo_means,
262 const std::vector<Stat_>& combo_vars,
263 const std::vector<Stat_>& combo_detected,
264 const double threshold,
265 const BlockAverageInfo<Stat_>& average_info,
267 const int num_threads
269 const Stat_* total_weights_ptr = NULL;
270 std::optional<std::vector<Stat_> > total_weights_per_group;
271 if (average_info.use_mean()) {
274 total_weights_per_group = compute_total_weight_per_group(ngroups, nblocks, average_info.combo_weights().data());
275 total_weights_ptr = total_weights_per_group->data();
277 total_weights_ptr = average_info.combo_weights().data();
282 std::optional<PrecomputedPairwiseWeights<Stat_> > preweights;
283 if (average_info.use_mean()) {
285 preweights.emplace(ngroups, nblocks, average_info.combo_weights().data());
290 std::optional<std::vector<Stat_> > qbuffer, qrevbuffer;
291 std::optional<quickstats::SingleQuantileVariableNumber<Stat_, std::size_t> > qcalc;
292 if (!average_info.use_mean()) {
294 qrevbuffer.emplace();
295 qcalc.emplace(nblocks, average_info.quantile());
298 for (Index_ gene = start, end = start + length; gene < end; ++gene) {
299 auto in_offset = sanisizer::product_unsafe<std::size_t>(gene, ncombos);
301 if (!output.
mean.empty()) {
302 const auto tmp_means = combo_means.data() + in_offset;
303 if (average_info.use_mean()) {
304 average_group_stats_blockmean(gene, ngroups, nblocks, tmp_means, average_info.combo_weights().data(), total_weights_ptr, output.
mean);
306 average_group_stats_blockquantile(gene, ngroups, nblocks, tmp_means, *qbuffer, *qcalc, output.
mean);
311 const auto tmp_detected = combo_detected.data() + in_offset;
312 if (average_info.use_mean()) {
313 average_group_stats_blockmean(gene, ngroups, nblocks, tmp_detected, average_info.combo_weights().data(), total_weights_ptr, output.
detected);
315 average_group_stats_blockquantile(gene, ngroups, nblocks, tmp_detected, *qbuffer, *qcalc, output.
detected);
320 const auto out_offset = sanisizer::product_unsafe<std::size_t>(gene, ngroups, ngroups);
323 const auto tmp_means = combo_means.data() + in_offset;
324 const auto tmp_variances = combo_vars.data() + in_offset;
325 const auto outptr = output.
cohens_d + out_offset;
326 if (average_info.use_mean()) {
327 compute_pairwise_cohens_d_blockmean(tmp_means, tmp_variances, ngroups, nblocks, threshold, *preweights, outptr);
329 compute_pairwise_cohens_d_blockquantile(tmp_means, tmp_variances, ngroups, nblocks, threshold, *qbuffer, *qrevbuffer, *qcalc, outptr);
334 const auto tmp_detected = combo_detected.data() + in_offset;
336 if (average_info.use_mean()) {
337 compute_pairwise_simple_diff_blockmean(tmp_detected, ngroups, nblocks, *preweights, outptr);
339 compute_pairwise_simple_diff_blockquantile(tmp_detected, ngroups, nblocks, *qbuffer, *qcalc, outptr);
344 const auto tmp_means = combo_means.data() + in_offset;
345 const auto outptr = output.
delta_mean + out_offset;
346 if (average_info.use_mean()) {
347 compute_pairwise_simple_diff_blockmean(tmp_means, ngroups, nblocks, *preweights, outptr);
349 compute_pairwise_simple_diff_blockquantile(tmp_means, ngroups, nblocks, *qbuffer, *qcalc, outptr);
353 }, ngenes, num_threads);
356template<
typename Index_,
typename Stat_>
357ScoreMarkersPairwiseBuffers<Stat_> preallocate_pairwise_results(
359 const std::size_t ngroups,
360 ScoreMarkersPairwiseResults<Stat_>& store,
361 const ScoreMarkersPairwiseOptions& opt
363 ScoreMarkersPairwiseBuffers<Stat_> output;
365 if (opt.compute_group_mean) {
366 preallocate_average_results(ngenes, ngroups, store.mean, output.mean);
368 if (opt.compute_group_detected) {
369 preallocate_average_results(ngenes, ngroups, store.detected, output.detected);
372 const auto num_effect_sizes = sanisizer::product<typename std::vector<Stat_>::size_type>(ngenes, ngroups, ngroups);
374 if (opt.compute_cohens_d) {
375 store.cohens_d.resize(num_effect_sizes
376#ifdef SCRAN_MARKERS_TEST_INIT
377 , SCRAN_MARKERS_TEST_INIT
380 output.cohens_d = store.cohens_d.data();
382 if (opt.compute_auc) {
383 store.auc.resize(num_effect_sizes
384#ifdef SCRAN_MARKERS_TEST_INIT
385 , SCRAN_MARKERS_TEST_INIT
388 output.auc = store.auc.data();
390 if (opt.compute_delta_mean) {
391 store.delta_mean.resize(num_effect_sizes
392#ifdef SCRAN_MARKERS_TEST_INIT
393 , SCRAN_MARKERS_TEST_INIT
396 output.delta_mean = store.delta_mean.data();
398 if (opt.compute_delta_detected) {
399 store.delta_detected.resize(num_effect_sizes
400#ifdef SCRAN_MARKERS_TEST_INIT
401 , SCRAN_MARKERS_TEST_INIT
404 output.delta_detected = store.delta_detected.data();
420 const std::size_t ngroups,
421 const Group_*
const group,
422 const std::size_t nblocks,
423 const Block_*
const block,
424 const std::size_t ncombos,
425 const std::size_t*
const combo,
426 const std::vector<Index_>& combo_sizes,
427 const ScoreMarkersPairwiseOptions& options,
428 const ScoreMarkersPairwiseBuffers<Stat_>& output
430 const auto ngenes = matrix.
nrow();
431 const auto payload_size = sanisizer::product<typename std::vector<Stat_>::size_type>(ngenes, ncombos);
432 std::vector<Stat_> combo_means, combo_vars, combo_detected;
433 if (!output.mean.empty() || output.cohens_d != NULL || output.delta_mean != NULL) {
434 combo_means.resize(payload_size);
436 if (output.cohens_d != NULL) {
437 combo_vars.resize(payload_size);
439 if (!output.detected.empty() || output.delta_detected != NULL) {
440 combo_detected.resize(payload_size);
445 BlockAverageInfo<Stat_> average_info;
446 if (options.block_average_policy == BlockAveragePolicy::MEAN) {
447 average_info = BlockAverageInfo<Stat_>(
450 options.block_weight_policy,
451 options.variable_block_weight_parameters
455 average_info = BlockAverageInfo<Stat_>(options.block_quantile);
459 scan_matrix_by_row_full_auc<single_block_>(
478 scan_matrix_by_column(
481 if constexpr(single_block_) {
488 if constexpr(single_block_) {
502 process_simple_pairwise_effects(
592template<
typename Value_,
typename Index_,
typename Group_,
typename Stat_>
595 const Group_*
const group,
599 const Index_ NC = matrix.
ncol();
600 const auto group_sizes = tatami_stats::tabulate_groups(group, NC);
601 const auto ngroups = sanisizer::cast<std::size_t>(group_sizes.size());
603 internal::score_markers_pairwise<true>(
608 static_cast<int*
>(NULL),
610 static_cast<std::size_t*
>(NULL),
656template<
typename Value_,
typename Index_,
typename Group_,
typename Block_,
typename Stat_>
659 const Group_*
const group,
660 const Block_*
const block,
664 const Index_ NC = matrix.
ncol();
665 const auto ngroups = output.
mean.size();
666 const auto nblocks = tatami_stats::total_groups(block, NC);
668 const auto combinations = internal::create_combinations(ngroups, group, nblocks, block, NC);
669 const auto combo_sizes = internal::tabulate_combinations<Index_>(ngroups, nblocks, combinations);
670 const auto ncombos = combo_sizes.size();
672 internal::score_markers_pairwise<false>(
674 sanisizer::cast<std::size_t>(ngroups),
676 sanisizer::cast<std::size_t>(nblocks),
678 sanisizer::cast<std::size_t>(ncombos),
702template<
typename Stat_ =
double,
typename Value_,
typename Index_,
typename Group_>
704 const auto ngroups = tatami_stats::total_groups(group, matrix.
ncol());
706 auto buffers = internal::preallocate_pairwise_results(matrix.
nrow(), ngroups, res, options);
730template<
typename Stat_ =
double,
typename Value_,
typename Index_,
typename Group_,
typename Block_>
733 const Group_*
const group,
734 const Block_*
const block,
737 const auto ngroups = tatami_stats::total_groups(group, matrix.
ncol());
739 const auto buffers = internal::preallocate_pairwise_results(matrix.
nrow(), ngroups, res, options);