Last active
September 3, 2020 18:34
-
-
Save awostenberg/78f08abd9ff602206279cbb7ab47af6f to your computer and use it in GitHub Desktop.
random walk over a unit cube
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Consider an ant taking a random walk over corners of a cube. | |
// What are the average number of steps to arrive at the far corner? | |
// user interface is next line: you can change the sample size | |
let nSamples = 1_000_000 | |
type Direction = X | Y | Z | |
/// walk in the given direction | |
let walk (x,y,z) direction = | |
let step along = if along = 0 then 1 else 0 | |
match direction with | |
| X -> step x,y,z | |
| Y -> x,step y,z | |
| Z -> x,y,step z | |
// test walk | |
let test1 = | |
[ | |
walk (0,0,0) X = (1,0,0) | |
walk (0,0,0) Y = (0,1,0) | |
walk (0,0,0) Z = (0,0,1) | |
walk (0,0,1) Z = (0,0,0) | |
] | |
/// convert integer to direction | |
let toDirection n = if n = 0 then X else if n=1 then Y else Z | |
// test toDirection | |
let test2 = | |
[ | |
toDirection 0 = X | |
toDirection 1 = Y | |
toDirection 2 = Z | |
] | |
/// random direction dispenser. not thread safe. | |
let ranDir seed = | |
let r = System.Random(seed) | |
fun() -> toDirection (r.Next(3)) | |
/// walk from origin to opposite corner using random direction dispenser | |
let simAnt r = | |
let rec simAnt' here r = | |
if here = (1,1,1) then 0 else 1+(simAnt' (walk here (r())) r ) | |
simAnt' (0,0,0) r | |
/// dispense fixed set of directions for testability | |
let fixdir items = | |
let mutable i = 0; | |
fun() -> | |
let result = Array.item i items | |
i <- i+1 | |
result | |
// test simulation using known directions | |
let test3 = [ | |
simAnt (fixdir [|X;Y;Z|]) = 3 // shortest journey | |
simAnt (fixdir [|X;Y;Z;Z;Y|]) = 3 // unused steps | |
simAnt (fixdir [|X;Y;X;Z;X|]) = 5 // longer journey | |
] | |
nSamples |> printf "%A ants walking..." | |
// run many simulations in parallel | |
// using independently seeded random number dispensers to solve | |
// the problem of the system random number generator not being thread safe | |
let randomSeeds = System.Random() | |
let simAntFromSeed = ranDir >> simAnt | |
let results = [|1..nSamples|] |> | |
Array.map (fun _ -> randomSeeds.Next()) |> | |
Array.Parallel.map simAntFromSeed | |
results |> Seq.averageBy float |> printfn "simple average %A" // average | |
// some statistics | |
let median items = (Array.sort items).[items.Length/2] | |
let indexInProportion n p = int (float n * p) | |
type SomeStats = {Samples: int; Avg: float; Min:int; Max:int; Median:int; Percentile90: int} | |
let stats manyResults = | |
let sortedResults = Array.sort manyResults; | |
let n90 = indexInProportion sortedResults.Length 0.90 | |
{Samples=sortedResults.Length | |
Avg=Seq.averageBy float manyResults | |
Min=Seq.min sortedResults | |
Max=Seq.max sortedResults | |
Median=median sortedResults | |
Percentile90=sortedResults.[n90]} | |
stats results |> printfn "%A" | |
// plot the probabilty distribution | |
let histogram = results |> | |
Array.groupBy id |> | |
Array.map (fun (steps,occurances) -> steps,occurances.Length) | |
let byDescendingFrequency = histogram |> Array.sortByDescending snd | |
let topFrequency = byDescendingFrequency.[0] |> snd | |
let total = histogram |> Array.map snd |> Array.reduce (+) | |
let probabilityDistribution = | |
byDescendingFrequency |> Array.map (fun (steps,i) -> steps, (float i)/float(total), (float i) / (float topFrequency)) | |
let stars n = ("".PadRight n).Replace(' ','*') | |
let test4 = stars 4 = "****" | |
let starsInProportionTo fraction max = stars (int (fraction * float max)) | |
let test5 = starsInProportionTo 0.5 10 = "*****" | |
printfn "time p" | |
probabilityDistribution |> | |
Array.take 20 |> | |
Array.iter(fun (steps,p,topmost) -> printfn "%4d %f %s" steps p (starsInProportionTo topmost 60)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment