Add chi-squared test statistic calculator to random.c
Change-Id: I0a0f8c9aad1530d18c70c962e729e84948a074ee Signed-off-by: Dave Barach <dave@barachs.net>
This commit is contained in:
@ -37,11 +37,56 @@
|
||||
|
||||
#include <vppinfra/random.h>
|
||||
|
||||
/* Default random seed for standalone version of library.
|
||||
/** \file Random number support
|
||||
*/
|
||||
|
||||
/** \brief Default random seed for standalone version of library.
|
||||
Value can be overridden by platform code from e.g.
|
||||
machine's clock count register. */
|
||||
u32 standalone_random_default_seed = 1;
|
||||
|
||||
/**
|
||||
* \brief Compute the X2 test statistic for a vector of counts.
|
||||
* Each value element corresponds to a histogram bucket.
|
||||
*
|
||||
* Typical use-case: test the hypothesis that a set of octets
|
||||
* are uniformly distributed (aka random).
|
||||
*
|
||||
* In a 1-dimensional use-case, the result should be compared
|
||||
* with the critical value from chi square tables with
|
||||
* vec_len(values) - 1 degrees of freedom.
|
||||
*
|
||||
* @param[in] values vector of histogram bucket values
|
||||
* @return d - Pearson's X2 test statistic
|
||||
*/
|
||||
|
||||
f64
|
||||
clib_chisquare (u64 * values)
|
||||
{
|
||||
int i;
|
||||
f64 d, delta_d, actual_frequency, expected_frequency;
|
||||
u64 n_observations = 0;
|
||||
|
||||
ASSERT (vec_len (values));
|
||||
|
||||
for (i = 0; i < vec_len (values); i++)
|
||||
n_observations += values[i];
|
||||
|
||||
expected_frequency = (1.0 / (f64) vec_len (values)) * (f64) n_observations;
|
||||
|
||||
d = 0.0;
|
||||
|
||||
for (i = 0; i < vec_len (values); i++)
|
||||
{
|
||||
actual_frequency = ((f64) values[i]);
|
||||
delta_d = ((actual_frequency - expected_frequency)
|
||||
* (actual_frequency - expected_frequency))
|
||||
/ expected_frequency;
|
||||
d += delta_d;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
|
@ -167,6 +167,8 @@ random_string (u32 * seed, uword len)
|
||||
return s;
|
||||
}
|
||||
|
||||
f64 clib_chisquare (u64 * values);
|
||||
|
||||
#endif /* included_random_h */
|
||||
|
||||
/*
|
||||
|
@ -38,6 +38,42 @@
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/bitmap.h>
|
||||
|
||||
static u32 outcome_frequencies[] = {
|
||||
8, 5, 9, 2, 7, 5,
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
test_chisquare (void)
|
||||
{
|
||||
u64 *values = 0;
|
||||
int i;
|
||||
f64 d, delta_d;
|
||||
|
||||
vec_validate (values, 5);
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
values[i] = (u64) outcome_frequencies[i];
|
||||
|
||||
d = clib_chisquare (values);
|
||||
|
||||
delta_d = d - 5.333;
|
||||
|
||||
if (delta_d < 0.0)
|
||||
delta_d = -delta_d;
|
||||
|
||||
if (delta_d < 0.001)
|
||||
{
|
||||
fformat (stdout, "chisquare OK...\n");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fformat (stdout, "chisquare BAD, d = %.3f\n", d);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 known_random_sequence[] = {
|
||||
0x00000000, 0x3c6ef35f, 0x47502932, 0xd1ccf6e9,
|
||||
0xaaf95334, 0x6252e503, 0x9f2ec686, 0x57fe6c2d,
|
||||
@ -54,6 +90,8 @@ test_random_main (unformat_input_t * input)
|
||||
uword print;
|
||||
u32 seed;
|
||||
u32 *seedp = &seed;
|
||||
u64 *counts = 0;
|
||||
f64 d;
|
||||
|
||||
/* first, check known sequence from Numerical Recipes in C, 2nd ed.
|
||||
page 284 */
|
||||
@ -118,6 +156,28 @@ test_random_main (unformat_input_t * input)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (test_chisquare ())
|
||||
return (-1);
|
||||
|
||||
/* Simple randomness tests based on X2 stats */
|
||||
vec_validate (counts, 255);
|
||||
|
||||
for (i = 0; i < 1000000; i++)
|
||||
{
|
||||
u32 random_index;
|
||||
u32 r = random_u32 (&seed);
|
||||
|
||||
random_index = r & 0xFF;
|
||||
|
||||
counts[random_index]++;
|
||||
}
|
||||
|
||||
d = clib_chisquare (counts);
|
||||
|
||||
fformat (stdout, "%d random octets, chisquare stat d = %.3f\n", i, d);
|
||||
|
||||
vec_free (counts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user