Skip to content

Instantly share code, notes, and snippets.

@ztangent
Last active January 12, 2022 22:46
Show Gist options
  • Save ztangent/e8fa4451d251e909f6892da55c223855 to your computer and use it in GitHub Desktop.
Save ztangent/e8fa4451d251e909f6892da55c223855 to your computer and use it in GitHub Desktop.
Random Blocksworld State Generator
"""
A Julia implementation of the random Blocksworld state generation algorithm presented in Figure 2 of [1].
Note that this implementation fixes a minor bug in the pseudo-code provided by [1].
[1] Slaney, J. and Thiébaux, S., 2001. Blocks World Revisited. Artificial Intelligence, 125(1-2), pp.119-153.
DOI: https://doi.org/10.1016/S0004-3702(00)00079-5
"""
"Number of states with `N` blocks."
function nstates(N::Int)
N < 1 ? 1 : nstates(N-1) + (N-1) * (nclear(N-1) + nstates(N-1))
end
"Number of states with `N` blocks where a particular block is clear."
function nclear(N::Int)
N < 1 ? 1 : nstates(N-1) + (N-1) * nclear(N-1)
end
"Direct implementation of the ratio nclear(N)/nstates(N)."
function pground(N::Int) =
N < 1 ? 1.0 : ((N-1) * pground(N-1) + 1) / ((N-1) * (pground(N-1) + 1) + 1)
end
"Sample a Bernoulli random variable."
bernoulli(p) = rand() < p
"Sample a random Blocksworld state with `N` blocks."
function rand_bw(N::Int)
n_ungrounded = N # Number of ungrounded towers
on = zeros(Int, N) # on[i] = j means i is on j, 0=ungrounded, -1=table
top = collect(1:N) # Top of each block's tower
# Repeat until all towers are grounded
while n_ungrounded > 0
i_tower = rand(findall(==(0), on)) # Select ungrounded tower
prob_ground = pground(n_ungrounded)
if bernoulli(prob_ground) # Place tower on table or another tower
while true # Repeatedly try to ground tower
n_ungrounded -= 1
prob_table = 1 / (1 + n_ungrounded * pground(n_ungrounded))
if bernoulli(prob_table) # Place on table, and break
on[i_tower] = -1
break
else # Place on another ungrounded tower, and loop
others = filter(1:N) do j
j != i_tower && on[j] == 0
end
j_tower = rand(others)
on[i_tower] = top[j_tower]
top[j_tower] = top[i_tower]
i_tower = j_tower
end
end
else # Place tower below another ungrounded tower
n_ungrounded -= 1
others = filter(1:N) do j
j != i_tower && on[j] == 0
end
j_tower = rand(others)
on[j_tower] = top[i_tower]
top[i_tower] = top[j_tower]
end
end
# Identities of which block is on which fully define Blocksworld state
return on
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment