Galton’s Board - Central Limit Theorem

Asked

Viewed 1,027 times

20

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


I received a video on Whatsapp, where mixed colored balls were separated by colors passing through the pins. Or it was a lot of mechanical technology or fake video. In the end, it was a fake video, where a graphic design played a Board of Galton for a study job.

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

Tabuleiro de Galton


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.

Teorema


Idea:

Starting from the board, I decided to create a matrix, where I have malhas and pinos, forming a line:

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

Pin values:

Like the odds on the balls going down is always bigger from the center to the sides, I created the pins with values, and the bigger, more chances to "continue" there. But also, as the pins are "interspersed" and not vertically aligned, also considered this fact.

Knitting:

// 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:

Consider 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 the fabric:

// 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++;
}

Upshot:

|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 make the mesh in other ways ?

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


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

The idea would be to draw between the pin values below, whereas the odds of it staying ever closer to the higher value pin, that is, a draw with different odds, and thus obtain the result as the "Board of Galton".


Feel free to post your way of doing.

  • Whenever a ball hits a nail/pin, the chance of it falling to the left is 50% and to the right is 50%. This shows that your first figure has an error: it is impossible for the balls to reach the two gaps on the far left or the two on the far right, it would take two more rows of nails/pins for that.

  • So if you have n rows of pins, your approach to the problem becomes much simpler if you simply do n draws of numbers 0 or 1. Better yet, draw a random number, make a % (1 << n) and then count how many bits 1 has in the number produced.

  • So... as I even put more on the end, I could work with 0 and 1, having the probability 50% and 50% as I said, with the idea of her "going" to the side but being able to go back to the center. This way is just simplify the loops that create the matrix. Done this, I would make a rand of 2 number, and if the number is odd, I go to the left of the matrix, and if it is even, I go to the right. With this, the values of arrays would be the "column number" the ball will drop. That’s an idea with 0 and 1. That’s + - what you thought ?

1 answer

13


I did with it:

<?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 is 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 the mt_rand() will generate any random number. This binary number 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) is used so that the result has the amount of bits that interest us, represented by the variable $linhas, which corresponds to the amount of pin lines the ball has to cross, which is the same amount of "left or right" draws, with 50% probability for each side.

With that, the number $sorteio corresponds to a number where each bit describes to which side the ball went. If that number is zero (all bits are zero), then in all draws it went left. If all bits are 1, then in all draws he went right. Note that these two cases are quite rare and unlikely and the highest probabilities 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 exist in it, one discovers in which house the ball fell, where the zero house is that of the extreme left and the house $linhas that of the extreme right.

In the second loop for, make 100000 draws (the variable $bolinhas) with polka dots falling to observe the distribution. Note that the resulting distribution is an approximation of the normal distribution (in fact it is a binomial distribution), and as expected, the center 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.

  • Perfect! I didn’t know the mt_hand() and the operator <<. Then I’ll take a closer look! But at first, what I understood was that you drew 0 or 1, N times (that would be the Qtd of columns) for a ball. So, you added up everything, that is to say the 1, and that gives the value of the column that it fell, correct ?

  • *I say "columns" instead of its variable "rows" because thinking visually on the board, I would stand. So it facilitates the association ! rs

  • 1

    @RBZ In fact, I could have drawn 0 or 1, repeatedly by $linhas times. But instead I simply drew a random number (that’s what the mt_rand() does) and forced it to have the desired number of bits ($linhas) by discarding the other bits with the %. Since a number is composed of zeros and ones, counting how many are bits 1, I can know how many times the ball went to the right (subtracting this from $linhas would be how many times went left).

  • 1

    @RBZ The name of this variable is $linhas because it’s the number of nail/pin lines that the ball has to go down. For each row of nails/pins, the ball can either fall to the right or to the left of the pin. Therefore, the number of lines is the number of draws and also the number of bits of the drawn number. And the number of houses where the ball can fall is equal to the number of pin/nail lines plus 1.

  • Caraca. That was to fall hair ! rs It is this type of "travel" that I like in these challenges and still learned a function and an operator playing ! Thank you very much ! (I’ll leave it open, so if people want to post other ideas)

  • @RBZ THE << is a way of doing exponentiation (but only works based on 2). An expression 1 << a produces as a result 2 high power a.

  • You did it just to make the division mod bigger, correct ?

  • @RBZ Yes, the idea of % is to discard the bits that do not interest me. If I have only 15 rows of pins, then only interest me the last 15 bits that the mt_rand produce, and with the % i discard the surplus. With the number 2 after the %, i have 1 bit. with number 4 after the %, i have 2 bits. With the number 8 after the %, i have 3 bits. With the number 16 after the %, I have 4 bits. That is to have n bits I have to put 2 high to n after the %.

  • I understood... I just didn’t understand what you said in: 2 n after the %. Here (1 << $linhas) would be 1 << 15, that is, 1 to 15 ? In PHP documentation it gets even more confusing: $a << $b (Left scroll) Scroll $a $b bits to the left (each step means "multiply by two")

  • 1

    @RBZ If at each step you multiply by 2, then when performing n steps, you will multiply by 2 high to n. So (a << b) will result in a times 2 to b. The (1 << $linhas) means 1 multiplied by [2 high 15], where $linhas is 15.

  • Ah got it ! sorry ! This PHP documentation complicates even more (http://php.net/manual/en/language.operators.bitwise.php)

Show 6 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.