add probabilistic tests for the ? and | mini-notation operators

The tests are probabilistic, so it is possible that if the
pseudo-random number generator changes in the future, we might
get results that fail. They work for the current PRNG, though,
and use boundaries for the number of values of different types
such that there should only be about a 1% probability that the
tests would fail by chance assuming that the PRNG returns
evenly distributed values.
This commit is contained in:
Bradford Powell 2022-08-02 16:12:08 -04:00
parent 1227d98904
commit 0a558b963d

View File

@ -6,7 +6,6 @@ This program is free software: you can redistribute it and/or modify it under th
import { strict as assert } from 'assert';
import { mini } from '../mini.mjs';
import '@strudel.cycles/core/euclid.mjs';
describe('mini', () => {
const minV = (v) => mini(v)._firstCycleValues;
@ -55,4 +54,39 @@ describe('mini', () => {
mini('a?').queryArc(0, 20).map(hap => hap.whole.begin),
mini('a').degradeBy(0.5).queryArc(0, 20).map(hap => hap.whole.begin));
});
// testing things that involve pseudo-randomness, so there's a probability we could fail by chance.
// these next few tests work with the current PRNG, and are intended to succeed with p > 0.99 even if the PRNG changes
// (as long as the PRNG has a relatively-uniform distribution of values)
it('supports degradeBy with default of 50%', () => {
const haps = mini('a?').queryArc(0, 1000);
assert(459 <= haps.length && haps.length <= 541, 'Number of elements did not fall in 99% confidence interval for binomial with p=0.5');
});
it('supports degradeBy with an argument', () => {
const haps = mini('a?0.8').queryArc(0, 1000);
assert(haps.length > 0, 'Should have had at least one element when degradeBy was set at 0.8');
assert(haps.length < 230, 'Had too many cycles remaining after degradeBy 0.8');
});
it('supports the random choice operator ("|") with nesting', () => {
const numCycles = 900;
const haps = mini('a | [b | c] | [d | e | f]').queryArc(0, numCycles);
// Should have about 1/3 a, 1/6 each of b | c, and 1/9 each of d | e | f.
// Evaluating this distribution with a chi-squared test.
// Note: this just evaluates the overall distribution, not things like correlation/runs of values
const observed = haps.reduce((acc, hap) => {
acc[hap.value] = (acc[hap.value] || 0) + 1;
return acc;
}, {});
const expected = {
a: numCycles / 3, b: numCycles / 6, c: numCycles / 6,
d: numCycles / 9, e: numCycles / 9, f: numCycles / 9
};
let chisq = -numCycles;
for (let k in expected) {
chisq += observed[k] * observed[k] / expected[k];
}
// 15.086 is the chisq for 5 degrees of freedom at 99%, so for 99% of uniformly-distributed
// PRNG, this test should succeed
assert(chisq <= 15.086,
chisq + ' was expected to be less than 15.086 under chi-squared test');
});
});