1#ifndef SCRAN_COMPUTE_MEDIAN_MAD_H
2#define SCRAN_COMPUTE_MEDIAN_MAD_H
4#include "../utils/macros.hpp"
39 static constexpr bool log =
false;
128 template<
typename Block>
130 std::vector<int> starts;
132 for (
size_t i = 0; i < n; ++i) {
133 size_t candidate = block[i] + 1;
134 if (candidate > starts.size()) {
135 starts.resize(candidate);
141 for (
auto& s : starts) {
162 template<
typename Input,
typename Buffer>
163 Results run(
size_t n,
const Input* metrics, Buffer* buffer)
const {
168 for (
size_t i = 0; i < n; ++i) {
169 if (!std::isnan(metrics[i])) {
175 compute(copy - buffer, buffer, output.
medians[0], output.
mads[0]);
189 template<
typename Input>
191 std::vector<double> buffer(n);
192 return run(n, metrics, buffer.data());
213 template<
typename Input,
typename Block,
typename Buffer>
214 Results run_blocked(
size_t n,
const Block* block, std::vector<int> starts,
const Input* metrics, Buffer* buffer)
const {
218 for (
size_t i = 0; i < n; ++i) {
219 if (!std::isnan(metrics[i])) {
220 auto& pos = ends[block[i]];
221 buffer[pos] = metrics[i];
227 size_t nblocks = starts.size();
230 for (
size_t g = 0; g < nblocks; ++g) {
231 compute(ends[g] - starts[g], buffer + starts[g], output.
medians[g], output.
mads[g]);
236 return run(n, metrics, buffer);
254 template<
typename Block,
typename Input>
256 std::vector<double> buffer(n);
261 template<
typename Buffer>
262 void compute(
size_t n, Buffer* ptr,
double& median,
double& mad)
const {
264 median = std::numeric_limits<double>::quiet_NaN();
265 mad = std::numeric_limits<double>::quiet_NaN();
271 for (
size_t i = 0; i < n; ++i, ++copy) {
273 *copy = std::log(*copy);
274 }
else if (*copy == 0) {
275 *copy = -std::numeric_limits<double>::infinity();
277 throw std::runtime_error(
"cannot log-transform negative values");
283 size_t halfway = n / 2;
284 median = compute_median(ptr, halfway, n);
286 if (median_only || std::isnan(median)) {
288 mad = std::numeric_limits<double>::quiet_NaN();
290 }
else if (std::isinf(median)) {
299 for (
size_t i = 0; i < n; ++i, ++copy) {
300 *copy = std::abs(*copy - median);
302 mad = compute_median(ptr, halfway, n);
307 static double compute_median (
double* ptr,
size_t halfway,
size_t n) {
308 std::nth_element(ptr, ptr + halfway, ptr + n);
309 double medtmp = *(ptr + halfway);
312 std::nth_element(ptr, ptr + halfway - 1, ptr + n);
313 double left = *(ptr + halfway - 1);
315 if (std::isinf(left) && std::isinf(medtmp)) {
316 if ((left > 0) != (medtmp > 0)) {
317 return std::numeric_limits<double>::quiet_NaN();
323 medtmp = (medtmp + left)/2;
Functions for single-cell RNA-seq analyses.
Definition AggregateAcrossCells.hpp:18