197 lines
3.7 KiB
C++
197 lines
3.7 KiB
C++
/*++
|
|
|
|
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;
|
|
}
|