Update all new Tasks

This commit is contained in:
Ingy döt Net 2015-02-20 09:02:09 -05:00
parent 00a190b0a6
commit 91df62d461
5697 changed files with 93386 additions and 804 deletions

View file

@ -0,0 +1,19 @@
{{Percolation Simulation}}
Given an <math>M \times N</math> rectangular array of cells numbered <math>\mathrm{cell}[0..M-1, 0..N-1]</math>assume <math>M</math> is horizontal and <math>N</math> is downwards.
Assume that the probability of any cell being filled is a constant <math>p</math> where
: <math>0.0 \le p \le 1.0</math>
;The task:
Simulate creating the array of cells with probability <math>p</math> and then
testing if there is a route through adjacent filled cells from any on row <math>0</math> to any on row <math>N</math>, i.e. testing for site percolation.
Given <math>p</math> repeat the percolation <math>t</math> times to estimate the proportion of times that the fluid can percolate to the bottom for any given <math>p</math>.
Show how the probability of percolating through the random grid changes with <math>p</math> going from <math>0.0</math> to <math>1.0</math> in <math>0.1</math> increments and with the number of repetitions to estimate the fraction at any given <math>p</math> as <math>t >= 100</math>.
Use an <math>M=15, N=15</math> grid of cells for all cases.
Optionally depict a percolation through a cell grid graphically.
Show all output on this page.

View file

@ -0,0 +1,2 @@
---
note: Percolation Simulations

View file

@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *cell, *start, *end;
int m, n;
void make_grid(int x, int y, double p)
{
int i, j, thresh = p * RAND_MAX;
m = x, n = y;
end = start = realloc(start, (x+1) * (y+1) + 1);
memset(start, 0, m + 1);
cell = end = start + m + 1;
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++)
*end++ = rand() < thresh ? '+' : '.';
*end++ = '\n';
}
end[-1] = 0;
end -= ++m; // end is the first cell of bottom row
}
int ff(char *p) // flood fill
{
if (*p != '+') return 0;
*p = '#';
return p >= end || ff(p+m) || ff(p+1) || ff(p-1) || ff(p-m);
}
int percolate(void)
{
int i;
for (i = 0; i < m && !ff(cell + i); i++);
return i < m;
}
int main(void)
{
make_grid(15, 15, .5);
percolate();
puts("15x15 grid:");
puts(cell);
puts("\nrunning 10,000 tests for each case:");
double p;
int ip, i, cnt;
for (ip = 0; ip <= 10; ip++) {
p = ip / 10.;
for (cnt = i = 0; i < 10000; i++) {
make_grid(15, 15, p);
cnt += percolate();
}
printf("p=%.1f: %.4f\n", p, cnt / 10000.);
}
return 0;
}

View file

@ -0,0 +1,118 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdbool.h>
#define N_COLS 15
#define N_ROWS 15
// Probability granularity 0.0, 0.1, ... 1.0
#define N_STEPS 11
// Simulation tries
#define N_TRIES 100
typedef unsigned char Cell;
enum { EMPTY_CELL = ' ',
FILLED_CELL = '#',
VISITED_CELL = '.' };
typedef Cell Grid[N_ROWS][N_COLS];
void initialize(Grid grid, const double probability) {
for (size_t r = 0; r < N_ROWS; r++)
for (size_t c = 0; c < N_COLS; c++) {
const double rnd = rand() / (double)RAND_MAX;
grid[r][c] = (rnd < probability) ? EMPTY_CELL : FILLED_CELL;
}
}
void show(Grid grid) {
char line[N_COLS + 3];
memset(&line[0], '-', N_COLS + 2);
line[0] = '+';
line[N_COLS + 1] = '+';
line[N_COLS + 2] = '\0';
printf("%s\n", line);
for (size_t r = 0; r < N_ROWS; r++) {
putchar('|');
for (size_t c = 0; c < N_COLS; c++)
putchar(grid[r][c]);
puts("|");
}
printf("%s\n", line);
}
bool walk(Grid grid, const size_t r, const size_t c) {
const size_t bottom = N_ROWS - 1;
grid[r][c] = VISITED_CELL;
if (r < bottom && grid[r + 1][c] == EMPTY_CELL) { // Down.
if (walk(grid, r + 1, c))
return true;
} else if (r == bottom)
return true;
if (c && grid[r][c - 1] == EMPTY_CELL) // Left.
if (walk(grid, r, c - 1))
return true;
if (c < N_COLS - 1 && grid[r][c + 1] == EMPTY_CELL) // Right.
if (walk(grid, r, c + 1))
return true;
if (r && grid[r - 1][c] == EMPTY_CELL) // Up.
if (walk(grid, r - 1, c))
return true;
return false;
}
bool percolate(Grid grid) {
const size_t startR = 0;
for (size_t c = 0; c < N_COLS; c++)
if (grid[startR][c] == EMPTY_CELL)
if (walk(grid, startR, c))
return true;
return false;
}
typedef struct {
double prob;
size_t count;
} Counter;
int main() {
const double probability_step = 1.0 / (N_STEPS - 1);
Counter counters[N_STEPS];
for (size_t i = 0; i < N_STEPS; i++)
counters[i] = (Counter){ i * probability_step, 0 };
bool sample_shown = false;
static Grid grid;
srand(time(NULL));
for (size_t i = 0; i < N_STEPS; i++) {
for (size_t t = 0; t < N_TRIES; t++) {
initialize(grid, counters[i].prob);
if (percolate(grid)) {
counters[i].count++;
if (!sample_shown) {
printf("Percolating sample (%dx%d,"
" probability =%5.2f):\n",
N_COLS, N_ROWS, counters[i].prob);
show(grid);
sample_shown = true;
}
}
}
}
printf("\nFraction of %d tries that percolate through:\n", N_TRIES);
for (size_t i = 0; i < N_STEPS; i++)
printf("%1.1f %1.3f\n", counters[i].prob,
counters[i].count / (double)N_TRIES);
return 0;
}

View file

@ -0,0 +1,95 @@
import std.stdio, std.random, std.array, std.datetime;
enum size_t nCols = 15,
nRows = 15,
nSteps = 11, // Probability granularity.
nTries = 20_000; // Simulation tries.
enum Cell : char { empty = ' ', filled = '#', visited = '.' }
alias Grid = Cell[nCols][nRows];
void initialize(ref Grid grid, in double probability, ref Xorshift rng) {
foreach (ref row; grid)
foreach (ref cell; row)
cell = (rng.uniform01 < probability) ? Cell.empty : Cell.filled;
}
void show(in ref Grid grid) @safe {
writefln("%(|%(%c%)|\n%)|", grid);
}
bool percolate(ref Grid grid) pure nothrow @safe @nogc {
bool walk(in size_t r, in size_t c) nothrow @safe @nogc {
enum bottom = nRows - 1;
grid[r][c] = Cell.visited;
if (r < bottom && grid[r + 1][c] == Cell.empty) { // Down.
if (walk(r + 1, c))
return true;
} else if (r == bottom)
return true;
if (c && grid[r][c - 1] == Cell.empty) // Left.
if (walk(r, c - 1))
return true;
if (c < nCols - 1 && grid[r][c + 1] == Cell.empty) // Right.
if (walk(r, c + 1))
return true;
if (r && grid[r - 1][c] == Cell.empty) // Up.
if (walk(r - 1, c))
return true;
return false;
}
enum startR = 0;
foreach (immutable c; 0 .. nCols)
if (grid[startR][c] == Cell.empty)
if (walk(startR, c))
return true;
return false;
}
void main() {
static struct Counter {
double prob;
size_t count;
}
StopWatch sw;
sw.start;
enum probabilityStep = 1.0 / (nSteps - 1);
Counter[nSteps] counters;
foreach (immutable i, ref co; counters)
co.prob = i * probabilityStep;
Grid grid;
bool sampleShown = false;
auto rng = Xorshift(unpredictableSeed);
foreach (ref co; counters) {
foreach (immutable _; 0 .. nTries) {
grid.initialize(co.prob, rng);
if (grid.percolate) {
co.count++;
if (!sampleShown) {
writefln("Percolating sample (%dx%d, probability =%5.2f):",
nCols, nRows, co.prob);
grid.show;
sampleShown = true;
}
}
}
}
sw.stop;
writefln("\nFraction of %d tries that percolate through:", nTries);
foreach (const co; counters)
writefln("%1.3f %1.3f", co.prob, co.count / double(nTries));
writefln("\nSimulations and grid printing performed" ~
" in %3.2f seconds.", sw.peek.msecs / 1000.0);
}

View file

@ -0,0 +1,123 @@
! loosely translated from python.
! compilation: gfortran -Wall -std=f2008 thisfile.f08
!$ a=site && gfortran -o $a -g -O0 -Wall -std=f2008 $a.f08 && $a
!100 trials per
!Fill Fraction goal(%) simulated through paths(%)
! 0 0
! 10 0
! 20 0
! 30 0
! 40 0
! 50 6
!
!
! b b b b h j m m m
! b b b b b h h m m m m m
! b b b h h h m
! b h h h h h h h
! b b h h h h h h h h h
! b b b h h h h h h h h h h
! b b @ h h h h h h h
! @ @ h h h h h h h h
! @ @ @ @ h h h h
! @ @ @ @ h h h h h h
! @ @ @ h h h h h h h
! @ @ @ h h h h h h
! @ h h h h h h
! @ h h h h h h h
! @ @ h h h h h h h h h h
! 60 59
! 70 97
! 80 100
! 90 100
! 100 100
program percolation_site
implicit none
integer, parameter :: m=15,n=15,t=100
!integer, parameter :: m=2,n=2,t=8
integer(kind=1), dimension(m, n) :: grid
real :: p
integer :: i, ip, trial, successes
logical :: success, unseen, q
data unseen/.true./
write(6,'(i3,a11)') t,' trials per'
write(6,'(a21,a30)') 'Fill Fraction goal(%)','simulated through paths(%)'
do ip=0, 10
p = ip/10.0
successes = 0
do trial = 1, t
call newgrid(grid, p)
success = .false.
do i=1, m
q = walk(grid, i) ! deliberately compute all paths
success = success .or. q
end do
if ((ip == 6) .and. unseen) then
call display(grid)
unseen = .false.
end if
successes = successes + merge(1, 0, success)
end do
write(6,'(9x,i3,24x,i3)')ip*10,nint(100*real(successes)/real(t))
end do
contains
logical function walk(grid, start)
integer(kind=1), dimension(m,n), intent(inout) :: grid
integer, intent(in) :: start
walk = rwalk(grid, 1, start, int(start+1,1))
end function walk
recursive function rwalk(grid, i, j, k) result(through)
logical :: through
integer(kind=1), dimension(m,n), intent(inout) :: grid
integer, intent(in) :: i, j
integer(kind=1), intent(in) :: k
logical, dimension(4) :: q
!out of bounds
through = .false.
if (i < 1) return
if (m < i) return
if (j < 1) return
if (n < j) return
!visited or non-pore
if (1_1 /= grid(i, j)) return
!update grid and recurse with neighbors. deny 'shortcircuit' evaluation
grid(i, j) = k
q(1) = rwalk(grid,i+0,j+1,k)
q(2) = rwalk(grid,i+0,j-1,k)
q(3) = rwalk(grid,i+1,j+0,k)
q(4) = rwalk(grid,i-1,j+0,k)
!newly discovered outlet
through = (i == m) .or. any(q)
end function rwalk
subroutine newgrid(grid, probability)
implicit none
real :: probability
integer(kind=1), dimension(m,n), intent(out) :: grid
real, dimension(m,n) :: harvest
call random_number(harvest)
grid = merge(1_1, 0_1, harvest < probability)
end subroutine newgrid
subroutine display(grid)
integer(kind=1), dimension(m,n), intent(in) :: grid
integer :: i, j, k, L
character(len=n*2) :: lineout
write(6,'(/)')
lineout = ' '
do i=1,m
do j=1,n
k = j+j
L = grid(i,j)+1
lineout(k:k) = ' @abcdefghijklmnopqrstuvwxyz'(L:L)
end do
write(6,*) lineout
end do
end subroutine display
end program percolation_site

View file

@ -0,0 +1,114 @@
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
func main() {
const (
m, n = 15, 15
t = 1e4
minp, maxp, Δp = 0, 1, 0.1
)
rand.Seed(2) // Fixed seed for repeatable example grid
g := NewGrid(.5, m, n)
g.Percolate()
fmt.Println(g)
rand.Seed(time.Now().UnixNano()) // could pick a better seed
for p := float64(minp); p < maxp; p += Δp {
count := 0
for i := 0; i < t; i++ {
g := NewGrid(p, m, n)
if g.Percolate() {
count++
}
}
fmt.Printf("p=%.2f, %.4f\n", p, float64(count)/t)
}
}
const (
full = '.'
used = '#'
empty = ' '
)
type grid struct {
cell [][]byte // row first, i.e. [y][x]
}
func NewGrid(p float64, xsize, ysize int) *grid {
g := &grid{cell: make([][]byte, ysize)}
for y := range g.cell {
g.cell[y] = make([]byte, xsize)
for x := range g.cell[y] {
if rand.Float64() < p {
g.cell[y][x] = full
} else {
g.cell[y][x] = empty
}
}
}
return g
}
func (g *grid) String() string {
var buf bytes.Buffer
// Don't really need to call Grow but it helps avoid multiple
// reallocations if the size is large.
buf.Grow((len(g.cell) + 2) * (len(g.cell[0]) + 3))
buf.WriteByte('+')
for _ = range g.cell[0] {
buf.WriteByte('-')
}
buf.WriteString("+\n")
for y := range g.cell {
buf.WriteByte('|')
buf.Write(g.cell[y])
buf.WriteString("|\n")
}
buf.WriteByte('+')
ly := len(g.cell) - 1
for x := range g.cell[ly] {
if g.cell[ly][x] == used {
buf.WriteByte(used)
} else {
buf.WriteByte('-')
}
}
buf.WriteByte('+')
return buf.String()
}
func (g *grid) Percolate() bool {
for x := range g.cell[0] {
if g.use(x, 0) {
return true
}
}
return false
}
func (g *grid) use(x, y int) bool {
if y < 0 || x < 0 || x >= len(g.cell[0]) || g.cell[y][x] != full {
return false // Off the edges, empty, or used
}
g.cell[y][x] = used
if y+1 == len(g.cell) {
return true // We're on the bottom
}
// Try down, right, left, up in that order.
return g.use(x, y+1) ||
g.use(x+1, y) ||
g.use(x-1, y) ||
g.use(x, y-1)
}

View file

@ -0,0 +1,42 @@
any =: +./
all =: *./
quickCheck =: [: all [: (any"1) 2 *./\ ] NB. a complete path requires connections between all row pairs
percolate =: 15 15&$: : (dyad define) NB. returns 0 iff blocked Use: (N, M) percolate P
NB. make a binary grid
GRID =: y (> ?@($&0)) x
NB. compute the return value
if. -. quickCheck GRID do. 0 return. end.
STARTING_SITES =. 0 ,. ({. GRID) # i. {: x NB. indexes of 1 in head row of GRID
any STARTING_SITES check GRID
)
NB. use local copy of GRID. Too slow.
check =: dyad define"1 2 NB. return 1 iff through path found use: START check GRID
GRID =. y
LOCATION =. x
if. 0 (= #) LOCATION do. 0 return. end. NB. no starting point? 0
if. LOCATION any@:((>: , 0 > [) $) GRID do. 0 return. end. NB. off grid? 0
INDEX =. <LOCATION
if. 1 ~: INDEX { GRID do. 0 return. end. NB. fail. either already looked here or non-path
if. (>: {. LOCATION) = (# GRID) do. 1 return. end. NB. Success! (display GRID here)
G =: GRID =. INDEX (>:@:{)`[`]}GRID
any GRID check~ LOCATION +"1 (, -)0 1,:1 0
)
NB. use global GRID.
check =: dyad define"1 2 NB. return 1 iff through path found use: START check GRID
LOCATION =. x
if. 0 (= #) LOCATION do. 0 return. end. NB. no starting point? 0
if. LOCATION any@:((>: , 0 > [) $) GRID do. 0 return. end. NB. off grid? 0
INDEX =. <LOCATION
if. 1 ~: INDEX { GRID do. 0 return. end. NB. fail. either already looked here or non-path
if. (>: {. LOCATION) = (# GRID) do. 1 return. end. NB. Success! (display GRID here)
GRID =: INDEX (>:@:{)`[`]}GRID
any GRID check~ LOCATION +"1 (, -)0 1,:1 0
)
simulate =: 100&$: : ([ %~ [: +/ [: percolate"0 #) NB. return fraction of connected cases. Use: T simulate P

View file

@ -0,0 +1,71 @@
from random import random
import string
from pprint import pprint as pp
M, N, t = 15, 15, 100
cell2char = ' #' + string.ascii_letters
NOT_VISITED = 1 # filled cell not walked
class PercolatedException(Exception): pass
def newgrid(p):
return [[int(random() < p) for m in range(M)] for n in range(N)] # cell
def pgrid(cell, percolated=None):
for n in range(N):
print( '%i) ' % (n % 10)
+ ' '.join(cell2char[cell[n][m]] for m in range(M)))
if percolated:
where = percolated.args[0][0]
print('!) ' + ' ' * where + cell2char[cell[n][where]])
def check_from_top(cell):
n, walk_index = 0, 1
try:
for m in range(M):
if cell[n][m] == NOT_VISITED:
walk_index += 1
walk_maze(m, n, cell, walk_index)
except PercolatedException as ex:
return ex
return None
def walk_maze(m, n, cell, indx):
# fill cell
cell[n][m] = indx
# down
if n < N - 1 and cell[n+1][m] == NOT_VISITED:
walk_maze(m, n+1, cell, indx)
# THE bottom
elif n == N - 1:
raise PercolatedException((m, indx))
# left
if m and cell[n][m - 1] == NOT_VISITED:
walk_maze(m-1, n, cell, indx)
# right
if m < M - 1 and cell[n][m + 1] == NOT_VISITED:
walk_maze(m+1, n, cell, indx)
# up
if n and cell[n-1][m] == NOT_VISITED:
walk_maze(m, n-1, cell, indx)
if __name__ == '__main__':
sample_printed = False
pcount = {}
for p10 in range(11):
p = p10 / 10.0
pcount[p] = 0
for tries in range(t):
cell = newgrid(p)
percolated = check_from_top(cell)
if percolated:
pcount[p] += 1
if not sample_printed:
print('\nSample percolating %i x %i, p = %5.2f grid\n' % (M, N, p))
pgrid(cell, percolated)
sample_printed = True
print('\n p: Fraction of %i tries that percolate through\n' % t )
pp({p:c/float(t) for p, c in pcount.items()})

View file

@ -0,0 +1 @@
Data source: http://rosettacode.org/wiki/Percolation/Site_percolation

View file

@ -0,0 +1,81 @@
#lang racket
(require racket/require (only-in racket/fixnum for*/fxvector))
(require (filtered-in (lambda (name) (regexp-replace #rx"unsafe-" name ""))
racket/unsafe/ops))
(define cell-empty 0)
(define cell-filled 1)
(define cell-wall 2)
(define cell-visited 3)
(define cell-exit 4)
(define ((percol->generator p)) (if (< (random) p) cell-filled cell-empty))
(define t (make-parameter 1000))
(define ((make-percol-grid M N) p)
(define p->10 (percol->generator p))
(define M+1 (fx+ 1 M))
(define M+2 (fx+ 2 M))
(for*/fxvector
#:length (fx* N M+2)
((n (in-range N)) (m (in-range M+2)))
(cond
[(fx= 0 m) cell-wall]
[(fx= m M+1) cell-wall]
[else (p->10)])))
(define (cell->str c) (substring " #|+*" c (fx+ 1 c)))
(define ((draw-percol-grid M N) g)
(define M+2 (fx+ M 2))
(for ((row N))
(for ((col (in-range M+2)))
(define idx (fx+ (fx* M+2 row) col))
(printf "~a" (cell->str (fxvector-ref g idx))))
(newline)))
(define ((percolate-percol-grid?! M N) g)
(define M+2 (fx+ M 2))
(define N-1 (fx- N 1))
(define max-idx (fx* N M+2))
(define (inner-percolate g idx)
(define row (fxquotient idx M+2))
(cond
((fx< idx 0) #f)
((fx>= idx max-idx) #f)
((fx= N-1 row) (fxvector-set! g idx cell-exit) #t)
((fx= cell-filled (fxvector-ref g idx))
(fxvector-set! g idx cell-visited)
(or
; gravity first (thanks Mr Newton)
(inner-percolate g (fx+ idx M+2))
; stick-to-the-left
(inner-percolate g (fx- idx 1))
(inner-percolate g (fx+ idx 1))
; go uphill only if we have to!
(inner-percolate g (fx- idx M+2))))
(else #f)))
(for/first ((m (in-range 1 M+2)) #:when (inner-percolate g m)) g))
(define make-15x15-grid (make-percol-grid 15 15))
(define draw-15x15-grid (draw-percol-grid 15 15))
(define perc-15x15-grid?! (percolate-percol-grid?! 15 15))
(define (display-sample-percolation p)
(printf "Percolation sample: p=~a~%" p)
(for*/first
((i (in-naturals))
(g (in-value (make-15x15-grid 0.6)))
#:when (perc-15x15-grid?! g))
(draw-15x15-grid g))
(newline))
(display-sample-percolation 0.4)
(for ((p (sequence-map (curry * 1/10) (in-range 0 (add1 10)))))
(define n-percolated-grids
(for/sum
((i (in-range (t))) #:when (perc-15x15-grid?! (make-15x15-grid p))) 1))
(define proportion-percolated (/ n-percolated-grids (t)))
(printf "p=~a\t->\t~a~%" p (real->decimal-string proportion-percolated 4)))

View file

@ -0,0 +1,77 @@
package require Tcl 8.6
oo::class create SitePercolation {
variable cells w h
constructor {width height probability} {
set w $width
set h $height
for {set cells {}} {[llength $cells] < $h} {lappend cells $row} {
for {set row {}} {[llength $row] < $w} {lappend row $cell} {
set cell [expr {rand() < $probability}]
}
}
}
method print {out} {
array set map {0 "#" 1 " " -1 .}
puts "+[string repeat . $w]+"
foreach row $cells {
set s "|"
foreach cell $row {
append s $map($cell)
}
puts [append s "|"]
}
set outline [lrepeat $w "-"]
foreach index $out {
lset outline $index "."
}
puts "+[join $outline {}]+"
}
method percolate {} {
for {set work {}; set i 0} {$i < $w} {incr i} {
if {[lindex $cells 0 $i]} {lappend work 0 $i}
}
try {
my Fill $work
return {}
} trap PERCOLATED x {
return [list $x]
}
}
method Fill {queue} {
while {[llength $queue]} {
set queue [lassign $queue y x]
if {$y >= $h} {throw PERCOLATED $x}
if {$y < 0 || $x < 0 || $x >= $w} continue
if {[lindex $cells $y $x]<1} continue
lset cells $y $x -1
lappend queue [expr {$y+1}] $x [expr {$y-1}] $x
lappend queue $y [expr {$x-1}] $y [expr {$x+1}]
}
}
}
# Demonstrate one run
puts "Sample percolation, 15x15 p=0.6"
SitePercolation create bp 15 15 0.6
bp print [bp percolate]
bp destroy
puts ""
# Collect statistics
apply {{} {
puts "Percentage of tries that percolate, varying p"
set tries 100
for {set pint 0} {$pint <= 10} {incr pint} {
set p [expr {$pint * 0.1}]
set tot 0
for {set i 0} {$i < $tries} {incr i} {
set bp [SitePercolation new 15 15 $p]
if {[$bp percolate] ne ""} {
incr tot
}
$bp destroy
}
puts [format "p=%.2f: %2.1f%%" $p [expr {$tot*100./$tries}]]
}
}}