Hong-Phuc Bui
2024-10-16 f8613c9ce2bd4b74b11727d2eae204f49151bcba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/*
 * @author Hong-Phuc Bui
 * @filename dfhi-random-test
 * Initial Date 16.12.19
 */
 
import {expect, test} from "@jest/globals";
import * as Rand from "./dfhi-random.js";
 
const LONGEST_TIMEOUT = 2*5000; // secs
 
test( "uniform distribution with default min = 0", () => {
    let min = 0,
        max = 10;
    let uniformSetupFn = (a,b) => () => Rand.uniform(b);
    testUniformDistribution(min, max, uniformSetupFn);
});
 
test("uniform distribution in a rang [min,max)", () => {
    let max = 10,
        min = 5;
    let uniformSetupFn = (a, b) => () => Rand.uniform(a, b);
    testUniformDistribution(min, max, uniformSetupFn);
});
 
function testUniformDistribution(min, max, uniformSetupFn) {
    let randomCount = 1000,
        dist = {};
    let uniformFn = uniformSetupFn(min, max);
    for (let i = 0; i < randomCount; ++i) {
        let r = uniformFn();
        expect(r < max).toBeTruthy();
        expect(min <= r).toBeTruthy();
        if (dist[r]) {
            dist[r] += 1;
        } else {
            dist[r] = 1;
        }
    }
    let exemplars = max - min; // how many distinct int numbers in [min, max);
    let means = randomCount/exemplars; // Erwartungswert
    let epsilon = 0.5;
    for (let [key, value] of Object.entries(dist) ) {
        let diff = Math.abs((value-means)/value );
        expect(diff < epsilon ).toBeTruthy();
    }
}
 
test ("bad range of uniform", () => {
    let max = 10,
        min = max + 1;
    try{
        Rand.uniform(min, max);
    }catch (error) {
        expect(error.message).toBe('bad range [11, 10)');
    }
});
 
test( "discrete distribution", () => {
    let p = [0.1, 0.3, 0.6];
    testDiscreteDist(p);
}, LONGEST_TIMEOUT);
 
test("discrete random 2", () => {
    let p = [0.1, 0.5]; // same as [0.1, 0.5, 0.5]
    testDiscreteDist(p);
}, LONGEST_TIMEOUT);
 
 
function testDiscreteDist(p) {
    let countRandom = {};
    let iteration = 10000;
    
    for(let count = 0; count < iteration; ++count) {
        let i = Rand.discrete(p);
        if (countRandom[i]) {
            countRandom[i] += 1;
        } else {
            countRandom[i] = 1;
        }
    }
    console.log(p);
    let lastP = 1 - p.reduce( (acc, c) => acc + c );
    let epsilon = 0.1;
    for( let [key,count] of Object.entries(countRandom) ) {
        let testP = p[key] ? p[key] : lastP;
        let cP = count / iteration,
            percentDiff = Math.abs(cP - testP) / testP;
        let msg = `probability of ${key} is ${count} / ${iteration} = ${cP},` +
            `near by ${testP} with relative error less than ${percentDiff*100}%`
        expect(percentDiff < epsilon).toBeTruthy();
    }
}
 
test("discrete bad distribution", () => {
    let p = [0.5, 0.5, 0.5]; // same as [0.1, 0.5, 0.5]
    try {
        Rand.discrete(p);
    } catch (error) {
        expect(error.message).toBe('bad distribution [0.5,0.5,0.5]');
    }
});