windows-nt/Source/XPSP1/NT/base/fs/sis/groveler/meancomp.cpp

301 lines
6.5 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
meancomp.cpp
Abstract:
SIS Groveler mean comparitor
Authors:
John Douceur, 1998
Environment:
User Mode
Revision History:
--*/
#include "all.hxx"
const int MeanComparator::max_sample_table_size = 20;
MeanComparator::PTableDescriptor
MeanComparator::p_list = {-1.0, 0, 0, &p_list, &p_list, 0};
MeanComparator::MeanComparator(
int num_clans,
int sample_group_size,
double acceptance_p_value,
double rejection_p_value,
double tolerance)
{
ASSERT(this != 0);
ASSERT(num_clans > 0);
ASSERT(sample_group_size > 0);
ASSERT(acceptance_p_value >= 0.0);
ASSERT(acceptance_p_value <= 1.0);
ASSERT(rejection_p_value >= 0.0);
ASSERT(rejection_p_value <= 1.0);
ASSERT(tolerance >= 0.0);
ASSERT(tolerance <= 1.0);
this->num_clans = num_clans;
this->sample_group_size = sample_group_size;
this->tolerance = tolerance;
sample_table_size = __min(sample_group_size, max_sample_table_size);
acceptance_table = add_p_value(acceptance_p_value, sample_table_size);
ASSERT(acceptance_table != 0);
rejection_table = add_p_value(rejection_p_value, sample_table_size);
ASSERT(rejection_table != 0);
samples = new Sample[sample_group_size];
compare_values = new double[num_clans];
current_offset = 0;
current_group_size = 0;
}
MeanComparator::~MeanComparator()
{
ASSERT(this != 0);
ASSERT(acceptance_table != 0);
remove_p_value(acceptance_table);
acceptance_table = 0;
ASSERT(rejection_table != 0);
remove_p_value(rejection_table);
rejection_table = 0;
ASSERT(samples != 0);
delete[] samples;
samples = 0;
ASSERT(compare_values != 0);
delete[] compare_values;
compare_values = 0;
}
void
MeanComparator::reset()
{
ASSERT(this != 0);
ASSERT(current_group_size >= 0);
ASSERT(current_group_size <= sample_group_size);
current_group_size = 0;
}
void
MeanComparator::sample(
int clan,
double value)
{
ASSERT(this != 0);
ASSERT(current_group_size >= 0);
ASSERT(current_group_size <= sample_group_size);
ASSERT(current_offset >= 0);
ASSERT(current_offset < sample_group_size);
current_offset--;
if (current_offset < 0)
{
current_offset += sample_group_size;
}
current_group_size = __min(current_group_size + 1, sample_group_size);
ASSERT(current_offset >= 0);
ASSERT(current_offset < sample_group_size);
samples[current_offset].clan = clan;
samples[current_offset].value = value;
}
bool
MeanComparator::within(
double compare_value,
...)
{
ASSERT(this != 0);
ASSERT(num_clans > 0);
ASSERT(current_group_size >= 0);
ASSERT(current_group_size <= sample_group_size);
ASSERT(current_offset >= 0);
ASSERT(current_offset < sample_group_size);
va_list ap;
va_start(ap, compare_value);
compare_values[0] = compare_value;
for (int index = 1; index < num_clans; index++)
{
compare_values[index] = va_arg(ap, double);
}
va_end(ap);
int sample_count = 0;
int below_count = 0;
int *p_table = acceptance_table->p_table;
ASSERT(p_table != 0);
for (index = 0;
index < current_group_size && sample_count < sample_table_size;
index++)
{
int loc = (index + current_offset) % sample_group_size;
int clan = samples[loc].clan;
double value = samples[loc].value;
double compare_value = compare_values[clan];
if (fabs(value - compare_value) > tolerance * compare_value)
{
sample_count++;
if (value < compare_value)
{
below_count++;
if (below_count > p_table[sample_count-1])
{
return true;
}
}
}
}
return false;
}
bool
MeanComparator::exceeds(
double compare_value,
...)
{
ASSERT(this != 0);
ASSERT(num_clans > 0);
ASSERT(current_group_size >= 0);
ASSERT(current_group_size <= sample_group_size);
ASSERT(current_offset >= 0);
ASSERT(current_offset < sample_group_size);
va_list ap;
va_start(ap, compare_value);
compare_values[0] = compare_value;
for (int index = 1; index < num_clans; index++)
{
compare_values[index] = va_arg(ap, double);
}
va_end(ap);
int sample_count = 0;
int above_count = 0;
int *p_table = rejection_table->p_table;
ASSERT(p_table != 0);
for (index = 0;
index < current_group_size && sample_count < sample_table_size;
index++)
{
int loc = (index + current_offset) % sample_group_size;
int clan = samples[loc].clan;
double value = samples[loc].value;
double compare_value = compare_values[clan];
if (fabs(value - compare_value) > tolerance * compare_value)
{
sample_count++;
if (value > compare_value)
{
above_count++;
if (above_count > p_table[sample_count-1])
{
return true;
}
}
}
}
return false;
}
MeanComparator::PTableDescriptor *
MeanComparator::add_p_value(
double p_value,
int sample_table_size)
{
ASSERT(p_list.next != 0);
ASSERT(p_list.prev != 0);
PTableDescriptor *ptd = p_list.next;
while (ptd != &p_list && ptd->p_value < p_value)
{
ASSERT(ptd->next == &p_list || ptd->next->p_value > ptd->p_value);
ptd = ptd->next;
}
ASSERT(ptd != 0);
if (ptd->p_value == p_value)
{
ASSERT(ptd != &p_list);
ASSERT(ptd->table_size > 0);
ASSERT(ptd->table_size <= max_sample_table_size);
if (ptd->table_size >= sample_table_size)
{
ptd->ref_count++;
return ptd;
}
ASSERT(ptd->p_table != 0);
delete[] ptd->p_table;
ptd->p_table = 0;
}
else
{
PTableDescriptor *new_ptd = new PTableDescriptor;
new_ptd->p_value = p_value;
new_ptd->p_table = 0;
new_ptd->next = ptd;
new_ptd->prev = ptd->prev;
ptd->prev->next = new_ptd;
ptd->prev = new_ptd;
new_ptd->ref_count = 0;
ptd = new_ptd;
}
ASSERT(ptd->prev == &p_list || ptd->prev->p_value < p_value);
ASSERT(ptd->next == &p_list || ptd->next->p_value > p_value);
int *p_table = new int[sample_table_size];
ptd->table_size = sample_table_size;
double threshold = p_value;
for (int n = 1; n <= sample_table_size; n++)
{
threshold *= 2.0;
if (1.0 > threshold)
{
p_table[n - 1] = n;
continue;
}
__int64 numerator = 1;
__int64 denominator = 1;
__int64 sum = 1;
for (int r = 1; r <= n; r++)
{
numerator *= n - r + 1;
ASSERT(numerator > 0);
denominator *= r;
ASSERT(denominator > 0);
sum += numerator / denominator;
ASSERT(sum > 0);
if (double(sum) > threshold)
{
break;
}
}
p_table[n - 1] = n - r;
}
ptd->p_table = p_table;
ptd->ref_count++;
return ptd;
}
bool
MeanComparator::remove_p_value(
PTableDescriptor *ptd)
{
ASSERT(ptd != 0);
ptd->ref_count--;
ASSERT(ptd->ref_count >= 0);
if (ptd->ref_count == 0)
{
ASSERT(ptd->p_table != 0);
delete[] ptd->p_table;
ptd->p_table = 0;
ptd->prev->next = ptd->next;
ptd->next->prev = ptd->prev;
delete ptd;
ptd = 0;
}
return true;
}