22namespace differential_analysis {
41double median (IT start,
size_t n) {
43 std::nth_element(start, start + halfway, start + n);
46 return start[halfway];
49 double med = start[halfway];
50 std::nth_element(start, start + halfway - 1, start + halfway);
51 return (med + start[halfway - 1])/ 2;
54template<
typename Stat>
55void summarize_comparisons(
int ngroups,
const Stat* effects,
int group,
size_t gene, std::vector<std::vector<Stat*> >& output, std::vector<Stat>& buffer) {
56 auto ebegin = buffer.data();
62 for (
int r = 0; r < ngroups; ++r, ++eptr) {
63 if (r == group || std::isnan(*eptr)) {
71 int ncomps = elast - ebegin;
73 for (
size_t i = 0; i < MIN_RANK; ++i) {
74 if (output[i].size()) {
75 output[i][group][gene] = std::numeric_limits<double>::quiet_NaN();
78 }
else if (ncomps == 1) {
79 for (
size_t i = 0; i < MIN_RANK; ++i) {
80 if (output[i].size()) {
81 output[i][group][gene] = *ebegin;
85 if (output[MIN].size()) {
86 output[MIN][group][gene] = *std::min_element(ebegin, elast);
88 if (output[MEAN].size()) {
89 output[MEAN][group][gene] = std::accumulate(ebegin, elast, 0.0) / ncomps;
91 if (output[MEDIAN].size()) {
92 output[MEDIAN][group][gene] = median(ebegin, ncomps);
94 if (output[MAX].size()) {
95 output[MAX][group][gene] = *std::max_element(ebegin, elast);
100template<
typename Stat>
101void summarize_comparisons(
size_t ngenes,
int ngroups,
const Stat* effects, std::vector<std::vector<Stat*> >& output,
int threads) {
102#ifndef SCRAN_CUSTOM_PARALLEL
103 #pragma omp parallel num_threads(threads)
105 std::vector<double> effect_buffer(ngroups);
107 for (
size_t gene = 0; gene < ngenes; ++gene) {
109 SCRAN_CUSTOM_PARALLEL([&](
size_t,
size_t start,
size_t length) ->
void {
110 std::vector<double> effect_buffer(ngroups);
111 for (
size_t gene = start, end = start + length; gene < end; ++gene) {
114 auto base = effects + gene * ngroups * ngroups;
115 for (
int l = 0; l < ngroups; ++l) {
116 summarize_comparisons(ngroups, base + l * ngroups, l, gene, output, effect_buffer);
119#ifndef SCRAN_CUSTOM_PARALLEL
130template<
typename Stat>
131size_t fill_and_sort_rank_buffer(
const Stat* effects,
size_t stride, std::vector<std::pair<Stat, int> >& buffer) {
132 auto bIt = buffer.begin();
133 for (
size_t i = 0, end = buffer.size(); i < end; ++i, effects += stride) {
134 if (!std::isnan(*effects)) {
135 bIt->first = -*effects;
140 std::sort(buffer.begin(), bIt);
141 return bIt - buffer.begin();
144template<
typename Stat,
typename Rank>
145void compute_min_rank_internal(
size_t use,
const std::vector<std::pair<Stat, int> >& buffer, Rank* output) {
147 for (
size_t i = 0; i < use; ++i) {
148 auto& current = output[buffer[i].second];
149 if (counter < current) {
156template<
typename Stat>
157void compute_min_rank(
size_t ngenes,
size_t ngroups,
int group,
const Stat* effects, Stat* output,
int threads) {
159 std::vector<std::vector<int> > assignments(threads);
161 size_t per_thread = std::ceil(
static_cast<double>(ngroups - 1) / threads);
162 auto cur_thread = assignments.begin();
163 for (
size_t counter = 0; counter < ngroups; ++counter) {
164 if (counter == group) {
167 if (cur_thread->size() >= per_thread) {
170 cur_thread->push_back(counter);
174 std::vector<std::vector<int> > stores(threads, std::vector<int>(ngenes, ngenes + 1));
176#ifndef SCRAN_CUSTOM_PARALLEL
177 #pragma omp parallel num_threads(threads)
179 std::vector<std::pair<Stat, int> > buffer(ngenes);
181 for (
int t = 0; t < threads; ++t) {
182 for (
auto g : assignments[t]) {
184 SCRAN_CUSTOM_PARALLEL([&](
size_t,
size_t start,
size_t length) ->
void {
185 std::vector<std::pair<Stat, int> > buffer(ngenes);
186 for (
size_t t = start, end = start + length; t < end; ++t) {
187 for (
auto g : assignments[t]) {
190 auto used = fill_and_sort_rank_buffer(effects + g, ngroups, buffer);
191 compute_min_rank_internal(used, buffer, stores[t].data());
193#ifndef SCRAN_CUSTOM_PARALLEL
200 }, threads, threads);
203 std::fill(output, output + ngenes, ngenes + 1);
204 for (
int t = 0; t < threads; ++t) {
206 for (
auto x : stores[t]) {
215template<
typename Stat>
216void compute_min_rank(
size_t ngenes,
size_t ngroups,
const Stat* effects, std::vector<Stat*>& output,
int threads) {
217 size_t shift = ngroups * ngroups;
219#ifndef SCRAN_CUSTOM_PARALLEL
220 #pragma omp parallel num_threads(threads)
222 std::vector<std::pair<Stat, int> > buffer(ngenes);
224 for (
size_t g = 0; g < ngroups; ++g) {
226 SCRAN_CUSTOM_PARALLEL([&](
size_t,
size_t start,
size_t length) ->
void {
227 std::vector<std::pair<Stat, int> > buffer(ngenes);
228 for (
size_t g = start, end = start + length; g < end; ++g) {
231 auto target = output[g];
232 std::fill(target, target + ngenes, ngenes + 1);
233 auto base = effects + g * ngroups;
235 for (
int g2 = 0; g2 < ngroups; ++g2) {
239 auto used = fill_and_sort_rank_buffer(base + g2, shift, buffer);
240 compute_min_rank_internal(used, buffer, target);
243#ifndef SCRAN_CUSTOM_PARALLEL
248 }, ngroups, threads);