我正在阅读the cat and mouse Markov model on wikipedia,并决定写一些朱莉娅代码来凭经验确认分析结果:
P = [
0 0 0.5 0 0.5 ;
0 0 1 0 0 ;
0.25 0.25 0 0.25 0.25;
0 0 0.5 0 0.5 ;
0 0 0 0 1
]
prob_states = transpose([0.0, 1, 0, 0, 0])
prob_end = [0.0]
for i in 1:2000
prob_states = prob_states * P
prob_end_new = (1 - sum(prob_end)) * prob_states[end]
push!(prob_end, prob_end_new)
println("Ending probability: ", prob_end_new)
println("Cumulative: ", sum(prob_end))
end
println("Expected lifetime: ", sum(prob_end .* Array(1:2001)))
此处P
是转换矩阵,prob_states
是每次迭代时状态的概率分布,prob_end
是每个步骤终止概率的数组(例如{{1}在步骤3)是终止概率。
根据该脚本的结果,鼠标的预期寿命约为4.3,而分析结果为4.5。这个剧本对我有意义,所以我真的不知道它可能出错的地方。有人可以帮忙吗?
P.S。将迭代次数增加一个数量级几乎不会改变任何变化。
答案 0 :(得分:6)
小鼠存活的概率非常快地接近零。这不仅对于鼠标来说是不幸的,而且对我们来说也是不幸的,因为我们不能使用64位浮点数(Julia默认使用这里)来准确地逼近这些微小的生存时间值。
事实上,在相对较少的迭代次数之后,大多数值prob_end
都是相同的零,但是在分析上评估这些值应该不是非常零。 Float64
类型根本不能代表这么小的正数。
这就是为什么数组的乘法和求和永远不会达到4.5;应该推动接近这个值的总和失败的步骤不能产生贡献,因为它们等于零。我们看到收敛到较低的值。
使用可以表示任意微小正值的其他类型,也许是可能的。有一些建议here但是当你执行这个马尔可夫链模型的几百次迭代时,你可能会发现它们非常慢并且记忆力很大。
另一种解决方案可能是将代码转换为使用log probabilities代替(通常用于克服浮点数的这种限制)。
答案 1 :(得分:3)
如果您只想凭经验确认结果,可以直接模拟模型:
const first_index = 1
const last_index = 5
const cat_start = 2
const mouse_start = 4
function move(i)
if i == first_index
return first_index + 1
elseif i == last_index
return last_index - 1
else
return i + rand([-1,1])
end
end
function step(cat, mouse)
return move(cat), move(mouse)
end
function game(cat, mouse)
i = 1
while cat != mouse
cat, mouse = step(cat, mouse)
i += 1
end
return i
end
function run()
res = [game(cat_start, mouse_start) for i=1:10_000_000]
return mean(res), std(res)/sqrt(length(res))
end
μ,σ = run()
println("Mean lifetime: $μ ± $σ")
示例输出:
Mean lifetime: 4.5004993 ± 0.0009083568998918751