worked on healthcheck
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user