1#ifndef TATAMI_STATS_RANGE_HPP
2#define TATAMI_STATS_RANGE_HPP
40template<
typename Value_>
41constexpr Value_ choose_minimum_placeholder() {
43 if constexpr(std::numeric_limits<Value_>::has_infinity) {
44 return std::numeric_limits<Value_>::infinity();
46 return std::numeric_limits<Value_>::max();
50template<
typename Value_>
51constexpr Value_ choose_maximum_placeholder() {
53 if constexpr(std::numeric_limits<Value_>::has_infinity) {
54 return -std::numeric_limits<Value_>::infinity();
56 return std::numeric_limits<Value_>::lowest();
60template<
typename Value_,
typename Index_>
61Value_ min_direct(
const Value_*
const ptr,
const Index_ num,
bool skip_nan) {
62 return nanable_ifelse_with_value<Value_>(
65 auto current = choose_minimum_placeholder<Value_>();
66 for (Index_ i = 0; i < num; ++i) {
76 return *std::min_element(ptr, ptr + num);
78 return choose_minimum_placeholder<Value_>();
84template<
typename Value_,
typename Index_>
85Value_ max_direct(
const Value_* ptr,
const Index_ num,
bool skip_nan) {
86 return nanable_ifelse_with_value<Value_>(
89 auto current = choose_maximum_placeholder<Value_>();
90 for (Index_ i = 0; i < num; ++i) {
100 return *std::max_element(ptr, ptr + num);
102 return choose_maximum_placeholder<Value_>();
108template<
typename Value_,
typename Index_>
109Value_ min_direct(
const Value_* value,
const Index_ num_nonzero,
const Index_ num_all,
bool skip_nan) {
111 auto candidate = min_direct(value, num_nonzero, skip_nan);
112 if (num_nonzero < num_all) {
118 }
else if (num_all) {
121 return choose_minimum_placeholder<Value_>();
125template<
typename Value_,
typename Index_>
126Value_ max_direct(
const Value_* value,
const Index_ num_nonzero,
const Index_ num_all,
bool skip_nan) {
128 auto candidate = max_direct(value, num_nonzero, skip_nan);
129 if (num_nonzero < num_all) {
135 }
else if (num_all) {
138 return choose_maximum_placeholder<Value_>();
151template<
typename Output_>
169template<
typename Value_,
typename Index_,
typename Output_>
171 const auto dim = (row ? mat.
nrow() : mat.
ncol());
172 const auto otherdim = (row ? mat.
ncol() : mat.
nrow());
180 for (Index_ x = 0; x < l; ++x) {
181 auto out = ext->fetch(vbuffer.data(), NULL);
182 output.
minimum[x + s] = min_direct(out.value, out.number, otherdim, opt.
skip_nan);
183 output.
maximum[x + s] = max_direct(out.value, out.number, otherdim, opt.
skip_nan);
191 for (Index_ x = 0; x < l; ++x) {
192 auto ptr = ext->fetch(buffer.data());
200template<
typename Value_,
typename Index_,
typename Output_>
202 const auto dim = (row ? mat.
nrow() : mat.
ncol());
203 const auto otherdim = (row ? mat.
ncol() : mat.
nrow());
206 const bool do_parallel = opt.num_threads > 1;
207 std::optional<std::vector<std::optional<std::vector<Output_> > > > all_partial_min, all_partial_max;
209 all_partial_min.emplace(sanisizer::cast<I<
decltype(all_partial_min->size())> >(opt.num_threads - 1));
210 all_partial_max.emplace(sanisizer::cast<I<
decltype(all_partial_max->size())> >(opt.num_threads - 1));
213 constexpr auto min_placeholder = choose_minimum_placeholder<Value_>();
214 constexpr auto max_placeholder = choose_maximum_placeholder<Value_>();
215 if (opt.skip_nan || otherdim == 0) {
218 std::fill_n(output.minimum, dim, min_placeholder);
219 std::fill_n(output.maximum, dim, max_placeholder);
225 std::optional<std::vector<Output_> > cur_min, cur_max;
227 min_ptr = output.minimum;
228 max_ptr = output.maximum;
231 min_ptr = output.minimum;
232 max_ptr = output.maximum;
236 min_ptr = cur_min->data();
237 max_ptr = cur_max->data();
249 for (Index_ x = 0; x < l; ++x) {
250 auto out = ext->fetch(vbuffer.data(), ibuffer.data());
255 nanable_ifelse<Value_>(
258 for (Index_ i = 0; i < out.number; ++i) {
259 const auto val = out.value[i];
260 if (!std::isnan(val)) {
261 const auto idx = out.index[i];
270 if (!do_parallel || thread == 0) {
271 std::fill_n(min_ptr, dim, 0);
272 std::fill_n(max_ptr, dim, 0);
274 for (Index_ i = 0; i < out.number; ++i) {
275 const auto val = out.value[i];
276 const auto idx = out.index[i];
285 for (Index_ i = 0; i < out.number; ++i) {
286 const auto val = out.value[i];
287 const auto idx = out.index[i];
288 auto& min_current = min_ptr[idx];
289 if (val < min_current) {
292 auto& max_current = max_ptr[idx];
293 if (val > max_current) {
301 for (Index_ d = 0; d < dim; ++d) {
302 if (l > nonzeros[d]) {
303 auto& min_current = min_ptr[d];
304 if (min_current > 0) {
307 auto& max_current = max_ptr[d];
308 if (max_current < 0) {
318 for (Index_ x = 0; x < l; ++x) {
319 auto ptr = ext->fetch(buffer.data());
324 nanable_ifelse<Value_>(
327 for (Index_ i = 0; i < dim; ++i) {
328 const auto val = ptr[i];
329 if (!std::isnan(val)) {
336 std::copy_n(ptr, dim, min_ptr);
337 std::copy_n(ptr, dim, max_ptr);
342 for (Index_ i = 0; i < dim; ++i) {
343 const auto val = ptr[i];
344 auto& min_current = min_ptr[i];
345 if (val < min_current) {
348 auto& max_current = max_ptr[i];
349 if (val > max_current) {
359 (*all_partial_min)[thread - 1] = std::move(cur_min);
360 (*all_partial_max)[thread - 1] = std::move(cur_max);
363 }, otherdim, opt.num_threads);
366 for (
int u = 1; u < nused; ++u) {
367 const auto& cur_min = *((*all_partial_min)[u - 1]);
368 const auto& cur_max = *((*all_partial_max)[u - 1]);
369 for (Index_ d = 0; d < dim; ++d) {
370 if (output.minimum[d] > cur_min[d]) {
371 output.minimum[d] = cur_min[d];
373 if (output.maximum[d] < cur_max[d]) {
374 output.maximum[d] = cur_max[d];
399template<
typename Value_,
typename Index_,
typename Output_>
402 range_direct(row, mat, output, opt);
404 range_running(row, mat, output, opt);
414template<
typename Output_>
444template<
typename Value_,
typename Index_,
typename Output_ = Value_>
447 const auto dim = (row ? mat.
nrow() : mat.
ncol());
449#ifdef TATAMI_STATS_TEST_DIRTY
454#ifdef TATAMI_STATS_TEST_DIRTY
462 range(row, mat, buffers, opt);
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
virtual bool prefer_rows() const=0
virtual bool is_sparse() 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 resize_container_to_Index_size(Container_ &container, const Index_ x, Args_ &&... args)
int parallelize(Function_ fun, const Index_ tasks, const int workers)
I< decltype(std::declval< Container_ >().size())> cast_Index_to_container_size(const Index_ x)
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)
bool sparse_extract_index
bool sparse_ordered_index
Result buffers for range().
Definition range.hpp:152
Output_ * maximum
Definition range.hpp:163
Output_ * minimum
Definition range.hpp:157
Options for range().
Definition range.hpp:23
bool skip_nan
Definition range.hpp:28
int num_threads
Definition range.hpp:34
Results of range().
Definition range.hpp:415
std::vector< Output_ > maximum
Definition range.hpp:426
std::vector< Output_ > minimum
Definition range.hpp:420