Last active
January 12, 2022 22:46
-
-
Save ztangent/e8fa4451d251e909f6892da55c223855 to your computer and use it in GitHub Desktop.
Random Blocksworld State Generator
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
""" | |
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