/*++ Copyright (c) 1998 Microsoft Corporation Module Name: peakfind.cpp Abstract: SIS Groveler peak finder Authors: John Douceur, 1998 Environment: User Mode Revision History: --*/ #include "all.hxx" PeakFinder::PeakFinder( double accuracy, double range) { ASSERT(this != 0); ASSERT(accuracy > 0.0); ASSERT(accuracy < 1.0); ASSERT(range > 0.0); base = 1.0 + 2.0 * accuracy / (1.0 - accuracy); ASSERT(base >= 1.0); multiplier = 1.0 / log(base); num_bins = int(multiplier * log(range)) + 1; ASSERT(num_bins > 0); bins = new int[num_bins]; target_sample_size = int(1.0 / (accuracy * accuracy)); ASSERT(target_sample_size > 0); reset(); ASSERT(floor_value >= 0.0); ASSERT(sample_size >= 0); ASSERT(total_weight >= 0); } PeakFinder::~PeakFinder() { ASSERT(this != 0); ASSERT(num_bins > 0); ASSERT(bins != 0); ASSERT(base >= 1.0); ASSERT(target_sample_size > 0); ASSERT(floor_value >= 0.0); ASSERT(sample_size >= 0); ASSERT(total_weight >= 0); delete[] bins; bins = 0; } void PeakFinder::reset() { ASSERT(this != 0); ASSERT(num_bins > 0); ASSERT(bins != 0); ASSERT(base >= 1.0); ASSERT(target_sample_size > 0); floor_exp = int(multiplier * log(DBL_MAX)); floor_value = pow(base, floor_exp); ASSERT(floor_value >= 0.0); sample_size = 0; total_weight = 0; } void PeakFinder::sample( double value, int weight) { ASSERT(this != 0); ASSERT(num_bins > 0); ASSERT(bins != 0); ASSERT(base >= 1.0); ASSERT(target_sample_size > 0); ASSERT(floor_value >= 0.0); ASSERT(sample_size >= 0); ASSERT(total_weight >= 0); ASSERT(value >= 0); ASSERT(weight > 0); if (value <= 0.0) { return; } if (value < floor_value) { int new_exp = int(multiplier * log(value)); double new_floor = pow(base, new_exp); int shift = __min(floor_exp - new_exp, num_bins); for (int index = num_bins - shift - 1; index >= 0; index--) { bins[index + shift] = bins[index]; } for (index = 0; index < shift; index++) { bins[index] = 0; } floor_exp = new_exp; floor_value = new_floor; } int bin_index = __max(int(multiplier * log(value / floor_value)), 0); if (bin_index < num_bins) { bins[bin_index] += weight; } ASSERT(total_weight >= 0); total_weight += weight; sample_size++; } bool PeakFinder::found() const { ASSERT(this != 0); ASSERT(num_bins > 0); ASSERT(bins != 0); ASSERT(base >= 1.0); ASSERT(target_sample_size > 0); ASSERT(floor_value >= 0.0); ASSERT(sample_size >= 0); ASSERT(total_weight >= 0); return sample_size > target_sample_size; } double PeakFinder::mode() const { ASSERT(this != 0); ASSERT(num_bins > 0); ASSERT(bins != 0); ASSERT(base >= 1.0); ASSERT(target_sample_size > 0); ASSERT(floor_value >= 0.0); ASSERT(sample_size >= 0); ASSERT(total_weight >= 0); double bin_width = base - 1.0; int max_index = -1; double max_height = 0.0; for (int index = 0; index < num_bins; index++) { double height = double(bins[index]) / bin_width; if (height > max_height) { max_index = index; max_height = height; } bin_width *= base; } if (max_index < 0) { return 0.0; } else { return 2 * base / (base + 1.0) * floor_value * pow(base, max_index); } } double PeakFinder::median() const { ASSERT(this != 0); ASSERT(num_bins > 0); ASSERT(bins != 0); ASSERT(base >= 1.0); ASSERT(target_sample_size > 0); ASSERT(floor_value >= 0.0); ASSERT(sample_size >= 0); ASSERT(total_weight >= 0); double remaining_weight = 0.5 * double(total_weight); for (int index = 0; index < num_bins; index++) { double current_weight = double(bins[index]); if (current_weight > remaining_weight) { return (1.0 + remaining_weight * (base - 1.0) / current_weight) * floor_value * pow(base, index); } remaining_weight -= current_weight; } return 0.0; }