You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
7.8 KiB
300 lines
7.8 KiB
/*++
|
|
|
|
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 cv = compare_values[clan];
|
|
if (fabs(value - cv) > tolerance * cv)
|
|
{
|
|
sample_count++;
|
|
if (value < cv)
|
|
{
|
|
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 cv = compare_values[clan];
|
|
if (fabs(value - cv) > tolerance * cv)
|
|
{
|
|
sample_count++;
|
|
if (value > cv)
|
|
{
|
|
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;
|
|
}
|