21# include "config_auto.h"
44 if (max_bucket_value < min_bucket_value) {
48 rangemin_ = min_bucket_value;
49 rangemax_ = max_bucket_value;
50 buckets_ =
new int32_t[1 + rangemax_ - rangemin_];
60 if (max_bucket_value < min_bucket_value) {
63 if (rangemax_ - rangemin_ != max_bucket_value - min_bucket_value) {
65 buckets_ =
new int32_t[1 + max_bucket_value - min_bucket_value];
67 rangemin_ = min_bucket_value;
68 rangemax_ = max_bucket_value;
80 if (buckets_ !=
nullptr) {
81 memset(buckets_, 0, (1 + rangemax_ - rangemin_) *
sizeof(buckets_[0]));
100 if (buckets_ !=
nullptr) {
103 total_count_ +=
count;
113 if (buckets_ ==
nullptr) {
116 int32_t max = buckets_[0];
117 int32_t maxindex = 0;
118 for (
int index = rangemax_ - rangemin_; index > 0; --index) {
119 if (buckets_[index] > max) {
120 max = buckets_[index];
124 return maxindex + rangemin_;
133 if (buckets_ ==
nullptr || total_count_ <= 0) {
134 return static_cast<double>(rangemin_);
137 for (
int index = rangemax_ - rangemin_; index >= 0; --index) {
138 sum +=
static_cast<int64_t
>(index) * buckets_[index];
140 return static_cast<double>(sum) / total_count_ + rangemin_;
149 if (buckets_ ==
nullptr || total_count_ <= 0) {
154 for (
int index = rangemax_ - rangemin_; index >= 0; --index) {
155 sum +=
static_cast<int64_t
>(index) * buckets_[index];
156 sqsum +=
static_cast<double>(index) * index * buckets_[index];
158 double variance =
static_cast<double>(sum) / total_count_;
159 variance = sqsum / total_count_ - variance * variance;
160 if (variance > 0.0) {
161 return sqrt(variance);
173 if (buckets_ ==
nullptr || total_count_ == 0) {
174 return static_cast<double>(rangemin_);
183 double target = frac * total_count_;
184 target =
ClipToRange(target, 1.0,
static_cast<double>(total_count_));
188 for (index = 0; index <= rangemax_ - rangemin_ && sum < target; sum += buckets_[index++]) {
193 return rangemin_ + index -
static_cast<double>(sum - target) / buckets_[index - 1];
195 return static_cast<double>(rangemin_);
205 if (buckets_ ==
nullptr || total_count_ == 0) {
209 for (min = 0; (min <= rangemax_ - rangemin_) && (buckets_[min] == 0); min++) {
212 return rangemin_ + min;
222 if (buckets_ ==
nullptr || total_count_ == 0) {
226 for (max = rangemax_ - rangemin_; max > 0 && buckets_[max] == 0; max--) {
229 return rangemin_ + max;
242 if (buckets_ ==
nullptr) {
243 return static_cast<double>(rangemin_);
246 int median_pile =
static_cast<int>(floor(
median));
247 if ((total_count_ > 1) && (
pile_count(median_pile) == 0)) {
251 for (min_pile = median_pile;
pile_count(min_pile) == 0; min_pile--) {
255 for (max_pile = median_pile;
pile_count(max_pile) == 0; max_pile++) {
258 median = (min_pile + max_pile) / 2.0;
269 if (buckets_ ==
nullptr) {
273 if (buckets_[
x] == 0) {
277 for (index =
x - 1; index >= 0 && buckets_[index] == buckets_[
x]; --index) {
280 if (index >= 0 && buckets_[index] < buckets_[
x]) {
283 for (index =
x + 1; index <= rangemax_ - rangemin_ && buckets_[index] == buckets_[
x]; ++index) {
286 if (index <= rangemax_ - rangemin_ && buckets_[index] < buckets_[
x]) {
302 if (buckets_ ==
nullptr || factor < 2) {
305 STATS result(rangemin_, rangemax_);
306 int entrycount = 1 + rangemax_ - rangemin_;
307 for (
int entry = 0; entry < entrycount; entry++) {
309 int count = buckets_[entry] * factor;
310 for (
int offset = 1; offset < factor; offset++) {
311 if (entry - offset >= 0) {
312 count += buckets_[entry - offset] * (factor - offset);
314 if (entry + offset < entrycount) {
315 count += buckets_[entry + offset] * (factor - offset);
318 result.
add(entry + rangemin_,
count);
320 total_count_ = result.total_count_;
321 memcpy(buckets_, result.buckets_, entrycount *
sizeof(buckets_[0]));
337 int32_t max_clusters,
343 int32_t best_cluster;
344 int32_t new_centre = 0;
349 int32_t cluster_count;
351 if (buckets_ ==
nullptr || max_clusters < 1) {
354 centres =
new float[max_clusters + 1];
355 for (cluster_count = 1;
356 cluster_count <= max_clusters && clusters[cluster_count].buckets_ !=
nullptr &&
357 clusters[cluster_count].total_count_ > 0;
359 centres[cluster_count] =
static_cast<float>(clusters[cluster_count].
ile(0.5));
360 new_centre = clusters[cluster_count].
mode();
361 for (entry = new_centre - 1; centres[cluster_count] - entry < lower && entry >= rangemin_ &&
366 clusters[cluster_count].
add(entry,
count);
370 for (entry = new_centre + 1; entry - centres[cluster_count] < lower && entry <= rangemax_ &&
375 clusters[cluster_count].
add(entry,
count);
382 if (cluster_count == 0) {
383 clusters[0].
set_range(rangemin_, rangemax_);
388 for (entry = 0; entry <= rangemax_ - rangemin_; entry++) {
389 count = buckets_[entry] - clusters[0].buckets_[entry];
392 min_dist =
static_cast<float>(INT32_MAX);
395 dist = entry + rangemin_ - centres[
cluster];
400 if (dist < min_dist) {
406 && (best_cluster == 0 || entry + rangemin_ > centres[best_cluster] * multiple ||
407 entry + rangemin_ < centres[best_cluster] / multiple)) {
408 if (
count > new_mode) {
410 new_centre = entry + rangemin_;
416 if (new_mode > 0 && cluster_count < max_clusters) {
419 if (!clusters[cluster_count].
set_range(rangemin_, rangemax_)) {
423 centres[cluster_count] =
static_cast<float>(new_centre);
424 clusters[cluster_count].
add(new_centre, new_mode);
425 clusters[0].
add(new_centre, new_mode);
426 for (entry = new_centre - 1; centres[cluster_count] - entry < lower && entry >= rangemin_ &&
431 clusters[cluster_count].
add(entry,
count);
435 for (entry = new_centre + 1; entry - centres[cluster_count] < lower && entry <= rangemax_ &&
440 clusters[cluster_count].
add(entry,
count);
444 centres[cluster_count] =
static_cast<float>(clusters[cluster_count].
ile(0.5));
446 }
while (new_cluster && cluster_count < max_clusters);
448 return cluster_count;
457static bool GatherPeak(
int index,
const int *src_buckets,
int *used_buckets,
int *prev_count,
458 int *total_count,
double *total_value) {
459 int pile_count = src_buckets[index] - used_buckets[index];
460 if (pile_count <= *prev_count && pile_count > 0) {
462 *total_count += pile_count;
463 *total_value += index * pile_count;
465 used_buckets[index] = src_buckets[index];
466 *prev_count = pile_count;
481 if (max_modes <= 0) {
484 int src_count = 1 + rangemax_ - rangemin_;
486 STATS used(rangemin_, rangemax_);
496 for (
int src_index = 0; src_index < src_count; src_index++) {
497 int pile_count = buckets_[src_index] - used.buckets_[src_index];
500 max_index = src_index;
505 used.buckets_[max_index] = max_count;
507 double total_value = max_index * max_count;
508 int total_count = max_count;
509 int prev_pile = max_count;
510 for (
int offset = 1; max_index + offset < src_count; ++offset) {
511 if (!GatherPeak(max_index + offset, buckets_, used.buckets_, &prev_pile, &total_count,
516 prev_pile = buckets_[max_index];
517 for (
int offset = 1; max_index - offset >= 0; ++offset) {
518 if (!GatherPeak(max_index - offset, buckets_, used.buckets_, &prev_pile, &total_count,
523 if (total_count > least_count || modes.size() <
static_cast<size_t>(max_modes)) {
525 if (modes.size() ==
static_cast<size_t>(max_modes)) {
526 modes.resize(max_modes - 1);
528 size_t target_index = 0;
530 while (target_index < modes.size() && modes[target_index].data() >= total_count) {
533 auto peak_mean =
static_cast<float>(total_value / total_count + rangemin_);
535 least_count = modes.back().data();
538 }
while (max_count > 0);
548 if (buckets_ ==
nullptr) {
555 for (
int index = min; index <= max; index++) {
556 if (buckets_[index] != 0) {
557 tprintf(
"%4d:%-3d ", rangemin_ + index, buckets_[index]);
558 if (++num_printed % 8 == 0) {
573 if (buckets_ ==
nullptr) {
578 tprintf(
"Total count=%d\n", total_count_);
579 tprintf(
"Min=%.2f Really=%d\n",
ile(0.0), min);
583 tprintf(
"Max=%.2f Really=%d\n",
ile(1.0), max);
584 tprintf(
"Range=%d\n", max + 1 - min);
595#ifndef GRAPHICS_DISABLED
602 if (buckets_ ==
nullptr) {
607 for (
int index = 0; index <= rangemax_ - rangemin_; index++) {
608 window->
Rectangle(xorigin + xscale * index, yorigin, xorigin + xscale * (index + 1),
609 yorigin + yscale * buckets_[index]);
620#ifndef GRAPHICS_DISABLED
627 if (buckets_ ==
nullptr) {
631 window->
SetCursor(xorigin, yorigin + yscale * buckets_[0]);
632 for (
int index = 0; index <= rangemax_ - rangemin_; index++) {
633 window->
DrawTo(xorigin + xscale * index, yorigin + yscale * buckets_[index]);
void tprintf(const char *format,...)
int IntCastRounded(double x)
T ClipToRange(const T &x, const T &lower_bound, const T &upper_bound)
void print_summary() const
void add(int32_t value, int32_t count)
void plot(ScrollView *window, float xorigin, float yorigin, float xscale, float yscale, ScrollView::Color colour) const
int32_t pile_count(int32_t value) const
int32_t min_bucket() const
int top_n_modes(int max_modes, std::vector< KDPairInc< float, int > > &modes) const
int32_t cluster(float lower, float upper, float multiple, int32_t max_clusters, STATS *clusters)
bool local_min(int32_t x) const
void smooth(int32_t factor)
int32_t max_bucket() const
double ile(double frac) const
void plotline(ScrollView *window, float xorigin, float yorigin, float xscale, float yscale, ScrollView::Color colour) const
bool set_range(int32_t min_bucket_value, int32_t max_bucket_value)
void Rectangle(int x1, int y1, int x2, int y2)
void SetCursor(int x, int y)
void DrawTo(int x, int y)