Galton Board-Central Limit Theorem

the reason for the question is study / learning. Know / apply programming techniques and concepts, turning something "material" into "application".


I received a video on Whatsapp, where mixed colored balls were separated by Colors passing through the pins. Either it was a lot of Mechanical Technology or fake video. In the end, it was a fake video, where a graphic designer reproduced a Board of Galton for a work of study.

Wanting to know more, I found in Wikipedia, and I would like to turn it into a "program".

Galton Board


The board basically simulates the "central Limit Theorem" (Link): the theorem describes the distribution of the mean of a random sample of a population with finite variance.

Theorem


Idea:

Starting with the board, I solved create a array , where I have malhas and pinos, forming a row:

-------Malha------->
[P1][P2][P3][P4][P5]...

Pin values:

Since the chances in the descent of the balls is always higher from the center to the sides, I created the pins with values, and the higher, the more chances to "continue" there. But also, since the pins are "interleaved" and not vertically aligned, I also considered this fact.

Creating the meshes:

// Definicoes
$qtdMalhas = 15;
$qtdPinos = 15;

// Auxiliares malhas/pinos
$am = $ap = 0;

// Criando as malhas e seus pinos
while ($am <= $qtdMalhas) {

    while ($ap < $qtdPinos) {

        if ($ap < ($qtdPinos/2)) {

            if ($am % 2 == 0) {
                $m[$am][$ap] = $ap;
            } else {
                $m[$am][$ap] = $ap+1;
            }
        } else {

            if ($am % 2 == 0) {
                $m[$am][$ap] = $qtdPinos-$ap-1;
            } else {
                $m[$am][$ap] = $qtdPinos-$ap;
            }
        }

        $ap++;      
    }

    $ap = 0;
    $am++;  
}

Mesh structure:

Considering the Matrix basically in the following format:

$m[0][0]-$m[0][1]-$m[0][2]-$m[0][3]-$m[0][4]...
$m[1][0]-$m[1][1]-$m[1][2]-$m[1][3]-$m[1][4]...
$m[2][0]-$m[2][1]-$m[2][2]-$m[2][3]-$m[2][4]...
$m[3][0]-$m[3][1]-$m[3][2]-$m[3][3]-$m[3][4]...
$m[4][0]-$m[4][1]-$m[4][2]-$m[4][3]-$m[4][4]...
...

Printing mesh:

// Zera auxiliares malhas/pinos
$am = $ap = 0; 

// Imprime a malha
while ($am < $qtdMalhas) {

    echo '<br>|';

    while ($ap < $qtdPinos) {

        echo $m[$am][$ap].'|';

        $ap++;
    }

    $ap = 0;
    $am++;
}

Result:

|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|
|1|2|3|4|5|6|7|8|7|6|5|4|3|2|1|
|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|
|1|2|3|4|5|6|7|8|7|6|5|4|3|2|1|
|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|
|1|2|3|4|5|6|7|8|7|6|5|4|3|2|1|
|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|
|1|2|3|4|5|6|7|8|7|6|5|4|3|2|1|
|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|
|1|2|3|4|5|6|7|8|7|6|5|4|3|2|1|
|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|
|1|2|3|4|5|6|7|8|7|6|5|4|3|2|1|
|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|
|1|2|3|4|5|6|7|8|7|6|5|4|3|2|1|
|0|1|2|3|4|5|6|7|6|5|4|3|2|1|0|

Could you knit in other ways ?

Yes, using zero and one for the pins but I believe I would have more work when drawing according to the probability of each pin. Among other ways.


With mesh ready, how can I" pass the balls between her"?

The idea would be to make draw between the values of the pins below, considering that the chances of it always stay closer to the highest value pin, that is, a draw with different odds, and thus get the result as the "Galton Board".


feel free to post your way of doing it.

 20
Author: rbz, 2018-04-13

1 answers

I did this:

<?php
    function cai_bolinha($linhas) {
        $sorteio = mt_rand() % (1 << $linhas);
        return substr_count(decbin($sorteio), '1');
    }

    $linhas = 15;
    $bolinhas = 100000;

    $casas = [];
    for ($i = 0; $i <= $linhas; $i++) {
        $casas[$i] = 0;
    }

    for ($i = 0; $i < $bolinhas; $i++) {
        $casa_resultante = cai_bolinha($linhas);
        $casas[$casa_resultante]++;
    }

    for ($i = 0; $i <= $linhas; $i++) {
        echo $i . "->" . $casas[$i] . "\n";
    }
?>

Here's the output (may vary, obviously):

0->5
1->35
2->310
3->1459
4->4079
5->9071
6->15089
7->19622
8->19771
9->15366
10->9265
11->4136
12->1409
13->334
14->46
15->3

See here working on ideone.

The trick is that mt_rand() will generate any random number. This number, in binary is represented by zeros and ones, where zero means to fall to the left and one means to fall to the right. The % (1 << $linhas) serves for the result to have the amount of bits that interests us, represented by the variable $linhas, which corresponds to the number of rows of pins the ball has to cross, which is the same amount of "left or right" draws, with 50% probability for each side.

With this, the number $sorteio corresponds to a number where each bit describes which way the ball went. If this number is zero (all bits are zero), then in all draws it went to the left. If all bits are 1, then in all draws it went to the right. Note that these two cases are quite rare and unlikely and the greatest odds are that the resulting number is composed of a mixture of zeros and ones.

After that, having this $sorteio, by counting how many bits 1 there are in it, we find out in which house the ball fell, where the zero House is the one on the far left and the $linhas House on the far right.

In the second loop for, I perform 100000 draws (the variable $bolinhas) with falling balls to observe the distribution. Note that the distribution the result is an approximation of the normal distribution (it is actually a binomial distribution), and as expected, the central houses (7 and 8) are the ones that have accumulated the largest numbers of balls, while the extreme houses (0 and 15) the smallest numbers.

Feel free to try other values for the variables $linhas and $bolinhas.

 13
Author: Victor Stafusa, 2018-04-23 20:04:15