"The probability of an event, given a sample space of equiprobable outcomes."
P(event, space)=length(intersect(event,space))//length(space);
D = [1, 2, 3, 4, 5, 6];
even = [2, 4, 6]
P(even, D)
"""The probability of an event, given a sample space of equiprobable outcomes.
event can be either a set of outcomes, or a predicate (true for outcomes in the event)."""
function P(event, space)
event_ = such_that(event, space)
length(intersect(event_,space))//length(space)
end
#Making use of Julia's multiple dispatch
"The subset of elements in the collection for which the predicate is true."
function such_that(predicate::Function, collection)
filter(predicate,collection)
end;
"Default return for a collection"
function such_that(event, collection)
event
end;
even_p(n) = (n % 2 == 0)
such_that(even_p, D)
P(even_p, D)
D12 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
such_that(even_p, D12)
P(even_p, D12)
S = ["BG", "BB", "GB", "GG"];
two_boys(outcome)= length(matchall(r"B", outcome)) == 2
older_is_a_boy(outcome)= startswith(outcome,"B");
P(two_boys, such_that(older_is_a_boy, S))
at_least_one_boy(outcome)= 'B' in outcome;
P(two_boys, such_that(at_least_one_boy, S))
such_that(at_least_one_boy, S)
S2b = ["BB/b?", "BB/?b",
"BG/b?", "BG/?g",
"GB/g?", "GB/?b",
"GG/g?", "GG/?g"];
observed_boy(outcome)= 'b' in outcome
such_that(observed_boy, S2b)
P(two_boys, such_that(observed_boy, S2b))
sexesdays = ["$sex$day"
for sex in "GB",
day in "1234567"]
S3 = ["$older$younger"
for older in sexesdays,
younger in sexesdays];
@assert length(S3) == (2*7)^2 == 196
print(sort(vec(S3)))
P(at_least_one_boy, S3)
P(at_least_one_boy, S)
P(two_boys, S3)
P(two_boys, S)
P(two_boys, such_that(at_least_one_boy, S3))
P(two_boys, such_that(at_least_one_boy, S))
at_least_one_boy_tues(outcome)= contains(outcome,"B3");
P(two_boys, such_that(at_least_one_boy_tues, S3))
observed_boy_tues(outcome)= contains(outcome,"b3")
S3b=[]
for children in S3
for i=1:2
first_observed=(i==1) ? lowercase(children)[1:2]*"??":"??"*lowercase(children)[3:4]
push!(S3b,"$children/$first_observed")
end
end
P(two_boys, such_that(observed_boy_tues, S3b))
"""Display sample space in a table, color-coded: green if event and condition is true;
yellow if only condition is true; white otherwise."""
function table(space, n=1, event=two_boys, condition=older_is_a_boy)
# n is the number of characters that make up the older child.
olders = sort(unique([outcome[1:n] for outcome in space]))
html= string("
",
join([row(older, space, event, condition) for older in olders]),
"
",
P(event, such_that(condition, space)))
display("text/html",html)
end
"Display a row where an older child is paired with each of the possible younger children."
function row(older, space, event, condition)
thisrow = sort(filter((x)->startswith(x,older),space))
string("", join([cell(outcome, event, condition) for outcome in thisrow]),"
")
end
"Display outcome in appropriate color."
function cell(outcome, event, condition)
color = (event(outcome) && condition(outcome))? "lightgreen": condition(outcome)? "yellow":"ghostwhite"
return "$outcome | "
end;
# Problem 1
table(S, 1, two_boys, older_is_a_boy)
# Problem 2
table(S, 1, two_boys, at_least_one_boy)
# Problem 2
table(S3, 2, two_boys, at_least_one_boy)
# Problem 3
table(S3, 2, two_boys, at_least_one_boy_tues)
B = ["heads/Monday/interviewed", "heads/Tuesday/sleep",
"tails/Monday/interviewed", "tails/Tuesday/interviewed"];
"Return a predicate that is true of all outcomes that have 'property' as a substring."
T(property)=(outcome)-> contains(outcome,property);
heads = T("heads")
interviewed = T("interviewed")
P(heads, such_that(interviewed, B))
P(heads, B)
M = ["Car1Pick1/Open3",
"Car2Pick1/Open3",
"Car3Pick1/Open2"];
P(T("Car1"), such_that(T("Open3"), M))
P(T("Car2"), such_that(T("Open3"), M))
M2 = ["Car1/Pick1/Open2/Goat", "Car1/Pick1/Open3/Goat",
"Car2/Pick1/Open2/Car", "Car2/Pick1/Open3/Goat",
"Car3/Pick1/Open2/Goat", "Car3/Pick1/Open3/Car"];
P(T("Car1"), such_that(T("Open3/Goat"), M2))
P(T("Car2"), such_that(T("Open3/Goat"), M2))
ProbDist=Dict
"Probability Distribution"
probdist(;entries...)= return normalize(Dict(entries))
"Given a distribution dict, return a version where the values are normalized to sum to 1."
function normalize(dist)
total = sum(values(dist))
return Dict(string(e) => dist[e] / total
for e in keys(dist))
end;
DK = probdist(GG=121801, GB=126840,
BG=127123, BB=135138)
"""The probability of an event, given a sample space of equiprobable outcomes.
event: a collection of outcomes, or a predicate that is true of outcomes in the event.
space: a set of outcomes or a probability distribution of {outcome: frequency} pairs."""
function P(event::Function, space::ProbDist)
event_ = such_that(event, space)
return sum([space[v] for v in collect(filter(e-> event(e), keys(space)))])
end
function P(event, space::ProbDist)
return sum([space[v] for v in collect(filter(e-> e in event, keys(space)))])
end
"""The elements in the space for which the predicate is true.
If space is a set, return a subset {element,...};
if space is a dict, return a sub-dict of {element: frequency,...} pairs;
in both cases only with elements where predicate(element) is true."""
function such_that(predicate::Function, space::ProbDist)
return normalize(Dict(e=>space[e] for e in filter(predicate,keys(space))))
end;
# Problem 1 in S
P(two_boys, such_that(older_is_a_boy, S))
# Problem 2 in S
P(two_boys, such_that(at_least_one_boy, S))
# Problem 1 in DK
P(two_boys, such_that(older_is_a_boy, DK))
# Problem 2 in DK
P(two_boys, such_that(at_least_one_boy, DK))
"""The joint distribution of two independent probability distributions.
Result is all entries of the form {a+b: P(a)*P(b)}"""
joint(A, B)=Dict(a * b => A[a] * B[b] for a in keys(A),b in keys(B));
sexes = probdist(B=51.5, G=48.5) # Probability distribution over sexes
days = probdist(L=1, N=4*365) # Probability distribution over Leap days and Non-leap days
child = joint(sexes, days) # Probability distribution for one child family
S4 = joint(child, child); # Probability distribution for two-child family
child
S4
# Problem 4
boy_on_leap_day = T("BL")
P(two_boys, such_that(boy_on_leap_day, S4))
"""Simulate this sequence of events:
- The host randomly chooses a door for the 'car'
- The contestant randomly makes a 'pick' of one of the doors
- The host randomly selects a valid door to be 'opened.'
- If 'switch' is True, contestant changes 'pick' to the other door
Return true if the pick is the door with the car."""
function monty(switch=true)
doors = [1, 2, 3]
car = rand(doors)
pick = rand(doors)
opened = rand(filter(d->d != car && d != pick,doors))
pick = switch? filter(d->d!=pick && d!=opened,doors)[1]: pick
pick==car
end;
count(_->monty(true),1:100000)/100000
count(_->monty(false),1:100000)/100000
# The board: a list of the names of the 40 squares
board = """GO A1 CC1 A2 T1 R1 B1 CH1 B2 B3
JAIL C1 U1 C2 C3 R2 D1 CC2 D2 D3
FP E1 CH2 E2 E3 R3 F1 F2 U2 F3
G2J G1 G2 CC3 G3 R4 CH3 H1 T2 H2""" |> split
# Lists of 16 community chest and 16 chance cards. See do_card.
CC = append!(["GO", "JAIL"], repeat(["?"],outer=[14]))
CH = append!("GO JAIL C1 E3 H2 R1 R R U -3" |> split, repeat(["?"],outer=[6]))
"""Simulate given number of steps of monopoly game,
yielding the name of the current square after each step."""
function monopoly(steps)
global here
here = 1
CC_deck = shuffle(CC)
CH_deck = shuffle(CH)
doubles = 0
function monopolyTask()
for _=1:steps
d1, d2 = rand(1:6), rand(1:6)
goto(here + d1 + d2)
doubles = (d1 == d2) ? (doubles + 1): 0
if doubles == 3 || board[here] == "G2J"
goto("JAIL")
elseif startswith(board[here],"CC")
do_card(CC_deck)
elseif startswith(board[here],"CH")
do_card(CH_deck)
end
produce(board[here])
end
end
Task(monopolyTask)
end
"Go to destination square (a square number). Update 'here'."
function goto(square::Int)
global here
here = (square-1) % length(board)+1
end
"Go to destination square (a square name). Update 'here'."
function goto(square::AbstractString)
global here
here = findfirst(board,square)
end
"Take the top card from deck and do what it says."
function do_card(deck)
global here
card = pop!(deck) # The top card
unshift!(deck,card) # Move top card to bottom of deck
if card == "R"|| card == "U"
while !startswith(board[here],card)
goto(here + 1) # Advance to next railroad or utility
end
elseif card == "-3"
goto(here - 3) # Go back 3 spaces
elseif card != "?"
goto(card) # Go to destination named on card
end
end;
results = collect(monopoly(10^6));
using PyPlot
figure("hist",figsize=(5,3))
ax=axes()
axis([1 ,40, 0 ,70000])
ax[:hist]([findfirst(board,name) for name in results], bins=40);
# We have to implement most_common here at it is not found Julia libraries
using StatsBase
function most_common(r)
commonList=collect(zip(board,counts([findfirst(board,name)::Int for name in r])))
sort!(commonList,by=x->x[2],rev=true)
end
most_common(results)
type Monopoly
board
CC
CH
here
function Monopoly()
this=new()
this.board= """GO A1 CC1 A2 T1 R1 B1 CH1 B2 B3
JAIL C1 U1 C2 C3 R2 D1 CC2 D2 D3
FP E1 CH2 E2 E3 R3 F1 F2 U2 F3
G2J G1 G2 CC3 G3 R4 CH3 H1 T2 H2""" |> split
this.CC = append!(["GO", "JAIL"], repeat(["?"],outer=[14]))
this.CH = append!("GO JAIL C1 E3 H2 R1 R R U -3" |> split, repeat(["?"],outer=[6]))
shuffle!(this.CC)
shuffle!(this.CH)
this.here=1
return this
end
end
"""Simulate given number of steps of monopoly game, incrementing counter
for current square after each step. Return a list of (square, count) pairs in order."""
function simulate(m::Monopoly,steps)
counter=zeros(Int,40)
doubles = 0
for _=1:steps
d1, d2 = rand(1:6), rand(1:6)
goto(m, m.here + d1 + d2)
doubles = (d1 == d2) ? (doubles + 1): 0
if doubles == 3 || m.board[m.here] == "G2J"
goto(m, "JAIL")
elseif startswith(m.board[m.here],"CC") || startswith(m.board[m.here],"CH")
do_card(m)
end
counter[m.here]+=1
end
commonList=collect(zip(m.board,counter))
sort!(commonList,by=x->x[2],rev=true)
end
"Go to destination square (a square number). Update 'here'."
function goto(m::Monopoly, square::Int)
m.here = (square-1) % length(m.board)+1
end
"Go to destination square (a square name). Update 'here'."
function goto(m::Monopoly,square::AbstractString)
m.here = findfirst(m.board,square)
end
"Take the top card from deck and do what it says."
function do_card(m::Monopoly)
deck= startswith(m.board[m.here],"CC") ? m.CC: m.CH #Which deck based on location
card = pop!(deck) # The top card
unshift!(deck,card) # Move top card to bottom of deck
if card == "R"|| card == "U"
while !startswith(m.board[m.here],card)
goto(m,m.here + 1) # Advance to next railroad or utility
end
elseif card == "-3"
before=m.here
goto(m,m.here - 3) # Go back 3 spaces
if m.here==0
println(before, " ",card)
end
elseif card != "?"
goto(m,card) # Go to destination named on card
end
end
simulate(Monopoly(),10^6)
"Return the probability distribution for the St. Petersburg Paradox with a limited bank."
function st_pete(limit)
P = Dict() # The probability distribution
pot = 2 # Amount of money in the pot
pr = 1/2 # Probability that you end up with the amount in pot
while pot < limit
P[pot] = pr
pot, pr = pot * 2, pr / 2
end
P[limit] = pr * 2 # pr * 2 because you get limit for heads or tails
assert(sum(values(P)) == 1.0)
sort(collect(zip(keys(P),values(P))))
end
StP = st_pete(10^9)
"The expected value of a probability distribution."
EV(P) =sum([v[1] * v[2] for v in P]);
EV(StP)
"The value of money: only half as valuable after you already have enough."
function util(dollars, enough=1000)
if dollars < enough
return dollars
else
return enough + util((dollars-enough)/2., enough*2)
end
end;
for d=2:10
println(lpad(10^d,15)," \$ = ",lpad(round(Int,util(10^d)),10), " util")
end
figure("Value of Money",figsize=(5,3))
plot([util(x) for x=1000:1000:10000000])
println("Y axis is util(x); x axis is in thousands of dollars.")
"The expected utility of a probability distribution, given a utility function."
EU(P, U)= sum([e[2] * U(e[1]) for e in P]);
EU(StP, util)
flip()=rand(["head", "tail"])
"Simulate one round of the St. Petersburg game, and return the payoff."
function simulate_st_pete(limit=10^9)
pot = 2
while flip() == "head"
pot = pot * 2
if pot > limit
return limit
end
end
return pot
end;
srand(1234)
# With Julia to can take a few million samples at get the results instantly
results = sort([(z[1],z[2]) for z in proportionmap([simulate_st_pete() for _=1:100_000])], by=x->x[1])
EU(results, util)
EV(results)
"For each element in the iterable, yield the mean of all elements seen so far."
function running_averages(iterable)
total, n = 0, 0
function run_avg_task()
for x in iterable
total, n = total + x, n + 1
produce(total / n)
end
end
Task(run_avg_task)
end
"Plot the running average of calling the function n times."
function plot_running_averages(fn, n)
plot(collect(running_averages([fn() for _=1:n])))
end;
srand(555)
figure("Running Average",figsize=(5,3))
for i=1:10
plot_running_averages(simulate_st_pete, 100000)
end
axis([1 ,100_000, 2, 140]);