worked on healthcheck

This commit is contained in:
Bill Cox
2014-10-17 06:24:41 -04:00
parent 9a82cecd34
commit 8d737c5739

View File

@@ -28,31 +28,35 @@ confirmed.
#include <time.h>
#define INM_MIN_SAMPLE_SIZE 100
#define INM_ACCURACY 1.1
static uint8_t inmN;
static uint32_t inmPrevBits;
static uint64_t inmNumBitsCounted, inmNumBitsSampled;
static uint64_t *inmOneCounts, *inmZeroCounts, *inmSameAsLastTimeCounts;
static bool *inmPrevResults;
static uint32_t inmNumBitsCounted, inmNumBitsSampled;
static uint32_t *inmOnes, *inmZeros;
static double inmK, inmExpectedEntropyPerBit;
// The total probability of generating the string of states we did is
// 1/(2^inmNumBitsOfEntropy * inmCurrentProbability).
static uint64_t inmNumBitsOfEntropy;
static uint32_t inmNumBitsOfEntropy;
static double inmCurrentProbability;
// Print the tables of statistics.
static void inmDumpStats(void) {
uint32_t i;
for(i = 0; i < 1 << inmN; i++) {
if(inmOnes[i] > 0 || inmZeros[i] > 0) {
printf("%x ones:%u zeros:%u\n", i, inmOnes[i], inmZeros[i]);
}
}
}
// Free memory used by the health checker.
void inmHealthCheckerStop(void) {
if(inmOneCounts != NULL) {
free(inmOneCounts);
if(inmOnes != NULL) {
free(inmOnes);
}
if(inmZeroCounts != NULL) {
free(inmZeroCounts);
}
if(inmSameAsLastTimeCounts != NULL) {
free(inmSameAsLastTimeCounts);
}
if(inmPrevResults != NULL) {
free(inmPrevResults);
if(inmZeros != NULL) {
free(inmZeros);
}
}
@@ -60,7 +64,7 @@ void inmHealthCheckerStop(void) {
// At least 8 bits must be used, and no more than 30. In general, we should use bits
// large enough so that INM output will be uncorrelated with bits N samples back in time.
bool inmHealthCheckerStart(uint8_t N, double K) {
if(N < 8 || N > 30) {
if(N < 1 || N > 30) {
return false;
}
inmNumBitsOfEntropy = 0;
@@ -70,13 +74,10 @@ bool inmHealthCheckerStart(uint8_t N, double K) {
inmPrevBits = 0;
inmNumBitsCounted = 0;
inmNumBitsSampled = 0;
inmOneCounts = calloc(1u << N, sizeof(uint64_t));
inmZeroCounts = calloc(1u << N, sizeof(uint64_t));
inmSameAsLastTimeCounts = calloc(1u << N, sizeof(uint64_t));
inmPrevResults = calloc(1u << N, sizeof(bool));
inmOnes = calloc(1u << N, sizeof(uint32_t));
inmZeros = calloc(1u << N, sizeof(uint32_t));
inmExpectedEntropyPerBit = log(K)/log(2.0);
if(inmOneCounts == NULL || inmZeroCounts == NULL || inmSameAsLastTimeCounts == NULL
|| inmPrevResults == NULL) {
if(inmOnes == NULL || inmZeros == NULL) {
inmHealthCheckerStop();
return false;
}
@@ -85,7 +86,7 @@ bool inmHealthCheckerStart(uint8_t N, double K) {
// Reset the statistics.
static void resetStats(void) {
printf("Resetting with numSampled=%lu and numCounted=%lu\n", inmNumBitsSampled, inmNumBitsCounted);
printf("Resetting with numSampled=%u and numCounted=%u\n", inmNumBitsSampled, inmNumBitsCounted);
inmNumBitsSampled = 0;
inmNumBitsCounted = 0;
inmCurrentProbability = 1.0;
@@ -94,16 +95,16 @@ static void resetStats(void) {
// This should be called for each bit generated.
bool inmHealthCheckerAddBit(bool bit) {
if(inmOneCounts[inmPrevBits] > INM_MIN_SAMPLE_SIZE ||
inmZeroCounts[inmPrevBits] > INM_MIN_SAMPLE_SIZE) {
uint64_t total = inmZeroCounts[inmPrevBits] + inmOneCounts[inmPrevBits];
if(inmOnes[inmPrevBits] > INM_MIN_SAMPLE_SIZE ||
inmZeros[inmPrevBits] > INM_MIN_SAMPLE_SIZE) {
uint32_t total = inmZeros[inmPrevBits] + inmOnes[inmPrevBits];
if(bit) {
if(inmOneCounts[inmPrevBits] != 0) {
inmCurrentProbability *= (double)inmOneCounts[inmPrevBits]/total;
if(inmOnes[inmPrevBits] != 0) {
inmCurrentProbability *= (double)inmOnes[inmPrevBits]/total;
}
} else {
if(inmZeroCounts[inmPrevBits] != 0) {
inmCurrentProbability *= (double)inmZeroCounts[inmPrevBits]/total;
if(inmZeros[inmPrevBits] != 0) {
inmCurrentProbability *= (double)inmZeros[inmPrevBits]/total;
}
}
while(inmCurrentProbability <= 0.5) {
@@ -115,14 +116,10 @@ bool inmHealthCheckerAddBit(bool bit) {
}
inmNumBitsSampled++;
if(bit) {
inmOneCounts[inmPrevBits]++;
inmOnes[inmPrevBits]++;
} else {
inmZeroCounts[inmPrevBits]++;
inmZeros[inmPrevBits]++;
}
if(bit == inmPrevResults[inmPrevBits]) {
inmSameAsLastTimeCounts[inmPrevBits]++;
}
inmPrevResults[inmPrevBits] = bit;
inmPrevBits = (inmPrevBits << 1) & ((1 << inmN)-1);
if(bit) {
inmPrevBits |= 1;
@@ -138,9 +135,9 @@ bool inmHealthCheckerAddBit(bool bit) {
}
if(inmNumBitsOfEntropy > 10000) {
// Check the entropy is in line with expectations
uint64_t expectedEntropy = inmExpectedEntropyPerBit*inmNumBitsCounted;
if(inmNumBitsOfEntropy > expectedEntropy*1.1 || inmNumBitsOfEntropy < expectedEntropy/1.1) {
printf("entropy:%lu, expected entropy:%lu, num bits counted:%lu, num bits sampled:%lu\n",
uint32_t expectedEntropy = inmExpectedEntropyPerBit*inmNumBitsCounted;
if(inmNumBitsOfEntropy > expectedEntropy*INM_ACCURACY || inmNumBitsOfEntropy < expectedEntropy/INM_ACCURACY) {
printf("entropy:%u, expected entropy:%u, num bits counted:%u, num bits sampled:%u\n",
inmNumBitsOfEntropy, expectedEntropy, inmNumBitsCounted, inmNumBitsSampled);
return false;
}
@@ -158,20 +155,29 @@ double inmHealthCheckerEstimateK(void) {
return pow(2.0, entropyPerBit);
}
// Once we have enough samples, we know that entropyPerBit = log(K)/log(2), so
// K must be 2^entryopPerBit.
double inmHealthCheckerEstimateEntropyPerBit(void) {
if(inmNumBitsOfEntropy <= 10000) {
return inmExpectedEntropyPerBit;
}
return (double)inmNumBitsOfEntropy/inmNumBitsCounted;
}
// Compare the ability to predict with 1 fewer bits and see how much less accurate we are.
static void checkLSBStatsForNBits(uint8_t N) {
uint32_t i, j;
uint64_t totalGuesses = 0;
uint64_t totalRight = 0.0;
uint32_t totalGuesses = 0;
uint32_t totalRight = 0.0;
for(i = 0; i < (1 << N); i++) {
uint64_t total = 0;
uint64_t zeros = 0;
uint64_t ones = 0;
uint32_t total = 0;
uint32_t zeros = 0;
uint32_t ones = 0;
for(j = 0; j < (1 << (inmN - N)); j++) {
uint32_t pos = i + j*(1 << N);
total += inmZeroCounts[pos] + inmOneCounts[pos];
zeros += inmZeroCounts[pos];
ones += inmOneCounts[pos];
total += inmZeros[pos] + inmOnes[pos];
zeros += inmZeros[pos];
ones += inmOnes[pos];
}
if(zeros >= ones) {
totalRight += zeros;
@@ -191,6 +197,30 @@ static void checkLSBStats(void) {
}
}
// If running continuously, it is possible to start overflowing the 32-bit counters for
// zeros and ones. Check for this, and scale the stats if needed.
static void reduceStatsIfNeeded(void) {
uint32_t i;
uint32_t maxValue = 0;
for(i = 0; i < (1 << inmN); i++) {
uint32_t zeros = inmZeros[i];
uint32_t ones = inmOnes[i];
if(zeros >= maxValue) {
maxValue = zeros;
}
if(ones > maxValue) {
maxValue = ones;
}
}
if(maxValue > (1 << 30)) {
printf("Scaling stats...\n");
for(i = 0; i < (1 << inmN); i++) {
inmZeros[i] >>= 1;
inmOnes[i] >>= 1;
}
}
}
/* This could be built with one opamp for the multiplier, a comparator with
rail-to-rail outputs, and switches and caps and resistors.*/
static inline bool updateA(double *A, double K, double noise) {
@@ -217,23 +247,27 @@ static inline bool computeRandBit(double *A, double K, double noiseAmplitude) {
int main() {
//double K = sqrt(2.0);
//double K = 1.82;
double K = 1.9;
inmHealthCheckerStart(16, K);
double K = 1.82;
inmHealthCheckerStart(14, K);
srand(time(NULL));
double A = (double)rand()/RAND_MAX; // Simulating INM
double noiseAmplitude = 1.0/(1 << 12);
while(true) {
uint32_t i;
for(i = 0; i < 1 << 26; i++) {
bool bit = computeRandBit(&A, K, noiseAmplitude);
if(!inmHealthCheckerAddBit(bit)) {
printf("Failed health check!\n");
resetStats();
//return 1;
} else if(inmNumBitsCounted > 0 && (inmNumBitsCounted & 0xfffff) == 0) {
printf("Estimated K: %f\n", inmHealthCheckerEstimateK());
printf("Estimated entropy per bit: %f, estimated K: %f\n", inmHealthCheckerEstimateEntropyPerBit(),
inmHealthCheckerEstimateK());
checkLSBStats();
reduceStatsIfNeeded();
//resetStats();
}
}
inmDumpStats();
inmHealthCheckerStop();
return 0;
}