## Galton

### April 10, 2012

The program decomposes into three pieces: drop one marble, drop a series of marbles, and draw a histogram. Here’s the function to drop one marble, which merely needs to count the number of times the marble moves right, signalled when the random integer is 1:

```(define (drop bins)   (do ((b bins (- b 1))        (z 0 (+ z (randint 2))))       ((= b 1) z)))```

Function `galton` drops a series of marbles:

```(define (galton marbles bins)   (let ((bs (make-vector bins 0)))     (do ((m 0 (+ m 1))) ((= m marbles) bs)       (let ((b (drop bins)))         (vector-set! bs b           (+ (vector-ref bs b) 1))))))```

Then the histogram, which scales itself and is displayed horizontally, using an auxiliary function to draw the row of asterisks:

```(define (stars n)   (do ((n n (- n 1))) ((zero? n) (newline))     (display #\*)))```

```(define (histogram xs)   (let* ((max-x (apply max (vector->list xs)))          (len (vector-length xs))          (n (ceiling (/ max-x len))))     (do ((x 0 (+ x 1))) ((= x len))       (stars (ceiling (/ (vector-ref xs x) n))))))```

Here’s a sample run:

```> (histogram (galton 1000 8)) * ** ****** ******** ******** ***** ** *```

We used `randint` from the Standard Prelude. You can run the program at http://programmingpraxis.codepad.org/HatuCXPz.

Pages: 1 2

### 8 Responses to “Galton”

1. […] today’s Programming Praxis exercise, our goal is to simulate a Galton board and display the frequencies of […]

```import Control.Applicative
import System.Random

marble :: Int -> IO Int
marble bins = sum . take (bins - 1) . randomRs (0, 1) <\$> newStdGen

marbles :: Num a => Int -> Int -> IO [a]
marbles n bins = flip fmap (replicateM n \$ marble bins) (\results ->
map (fromIntegral . length . flip filter results . (==)) [0..bins - 1])

histogram :: RealFrac a => a -> [a] -> IO ()
histogram w cols = mapM_ (\n ->
putStrLn \$ replicate (ceiling \$ n * w / maximum cols) '*') cols

main :: IO ()
main = histogram 20 =<< marbles 1000 8
```
3. uberlazy said
```(defn
directions
[]
(for [_ (range)]
(rand-int 2)))

(defn single-pass [size]
(reduce + 0 (take size (directions))))

(defn galton [size passes]
(apply merge-with +
(for [_ (range passes)]
{(single-pass size) 1})))

(defn histogram
([size passes] (histogram size passes 20))
([size passes scale-factor]
(let [g (galton size passes)]
(doseq [i (range (inc size))
:let [cnt (g i 0)]]
(println (format "%5d %5d %s"
i
cnt
(apply str
(take  (* scale-factor (/ cnt passes))
(repeat "*")))))))))
```
4. Jussi Piitulainen said

In R, after realizing that the sum of 200 Bernoulli trials with p=0.5 (each success means falling to the right at a pin, incrementing the bin number by 1) is a binomial trial with n=200 and p=0.5, one obtains the final result thus.

```plot(table(rbinom(1000, 200, 0.5)))
```

That is a bar plot for 1000 balls through 200 levels of pins on the board, hence 201 bins. The real histogram command of R has also the tabulation of values built-in, but I think the bar plot obtained above looks nice for this.

```hist(rbinom(1000, 200, 0.5))
[/source]
It's equally easy to obtain 200 Bernoulli values and sum them to get the bin number of one ball, but to repeat that for 1000 balls would require some sort of loop, I think.
[sourcecode lang="css"]
sum(rbinom(200, 1, 0.5))
```
5. ardnew said

Perl solution, output scaled to \$MAX_WIDTH characters

```use strict;
use warnings;

my \$MAX_WIDTH = 320;
my \$SYMBOL    = '*';

sub drop
{
my (\$nbins, \$nballs, @bins) = @_;
map { ++\$bins[grep { int(rand(2)) } 1 .. \$nbins] } 1 .. \$nballs;
return @bins;
}

die "\nusage:\n\t\$0 <bins> <balls>\n" unless
scalar @ARGV > 1;

printf("%5d: %s\n", \$_, \$SYMBOL x (\$_ * \$MAX_WIDTH / \$ARGV[1]))
foreach (drop(@ARGV));
```
6. Mike said

Here’s a quick and dirty Galton board animation in Python 2.7.

```from collections import defaultdict
from random import choice
from turtle import *

R = 5

def galton(nlevels=11, trace=False, speed=6):
setup(width=500, height=800, startx=0, starty=0)
delay(0)
pen(speed=10, shown=False)
goto(-200, -350)
clear()
goto( 200, -350)
pen(pendown=False)
for n,y in enumerate(range(nlevels*14, -1, -14), 1):
for x in range(-7*n, 7*n+1, 14):
goto(x, y)
dot(3)
pen(speed=speed)

angles = (rads(d) for d in range(0,361,36))
addshape('marble', tuple((R*sin(r),R*cos(r)) for r in angles))
shape('marble')

hist = defaultdict(lambda:-343)
while True:
pen(shown=False, pendown=False)
x,y = 0, nlevels*14
goto(x, y)
pen(shown=True, pendown=trace)
delay(5)

while y > 0:
if y%14:
x += choice((-7,7))
goto(x, y)
y -= 7
goto(x, y)

delay(1)
while y > hist[x]:
y -= 7
goto(x, y)

stamp()
hist[x] += 7

if hist[x] > 0:
break
```

```package main

import (
"fmt"
"time"
"math/rand"
)

func galtonStep(ball, peg chan int) {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
for {
pos := <- ball
switch coin := rng.Float32(); true {
case coin < 0.5:
peg <- pos
case coin >= 0.5:
peg <- pos + 1
}
}
}

func galtonBoard(depth int) (ball, bin chan int) {
c := make(chan int)
ball, bin = c, c

for i := 0; i < depth; i++ {
prev := bin
bin = make(chan int)
go galtonStep(prev, bin)
}

return
}

func galtonSimulate(depth, count int) (bins []int) {
bins = make([]int, depth + 1)

ball, bin := galtonBoard(depth)
for i := 0; i < count; i++ {
ball <- 0
bins[<- bin]++
}

return
}

func max(values []int) int {
r := values[0]
for _, v := range(values) {
if v > r {
r = v
}
}
return r
}

func printHist(cols int, hist []int) {
maxv := max(hist)

for bin, v := range(hist) {
count := cols * v / maxv
fmt.Printf("%02d: ", bin)
for i := 0; i < count; i++ {
fmt.Print("*")
}
fmt.Println()
}
}

func main() {
printHist(65, galtonSimulate(20, 1000))
}
```
8. David said

Forth version, with a RNG developed in an earlier exercise (not included here.)

```include random

9 constant #Bins
25 constant HGRAM_WIDTH

: int-array ( n -- )
create
cells allot
does>
swap cells + ;

#Bins int-array galton-board

: init-galton  ( -- )  \ clear the marbles from the machine
['] galton-board >body  #bins cells  0 fill ;

: .galton
#bins 0 DO  i galton-board ?  LOOP ;

: drop-marble  ( -- )   \ drop a marble into the machine
0
[ #bins 1- ] literal 0 DO  2 random +  LOOP
galton-board ++ ;

: max-galton  ( -- n )
0
#bins 0 DO  i galton-board @ max  LOOP ;

: stars  ( n -- )
0 ?DO  [char] * emit  LOOP ;

: histogram  ( width -- )
max-galton  locals| board-max column-max |
cr ." BIN"

#bins 0 DO
cr
i 3 .r space
i galton-board @  column-max board-max */  stars
LOOP ;

: galton ( marbles )
init-galton
0 DO  drop-marble  LOOP
HGRAM_WIDTH histogram ;
```

Execution:

```100000 galton
BIN
0
1 **
2 *********
3 ********************
4 *************************
5 ********************
6 **********
7 **
8  ok
```