我正试图找到一种更好的方法来管理连续马尔可夫链的当前状态向量.使用的状态向量存储概率为浮点数的(状态,可用性)对.
需要优化的算法部分执行以下操作:
>每次迭代都以当前状态向量开始
>计算向量中每个当前值的可达状态,并将它们全部存储在临时列表中,并将其存储在那里
>对于这个新列表中的每个元素,它通过迭代可能的转换来计算新的状态向量(请注意,可能有许多转换导致相同的状态,但是从不同的源状态找到)
这实际上是通过使用哈希表来完成的,这些哈希表具有状态和值作为概率的值.
因此,基本上为了构建新向量,对于每个转换,计算归一化值,然后使用get检索向量中的状态,添加当前转换的概率,然后将结果存储回来.
到目前为止,这种方法似乎有效,但我正在尝试处理导致非常大的空间向量(500k-1mil状态)的系统,因此,虽然散列表给出了存储和检索的恒定复杂性,但迭代开始减慢很多.
这是因为,例如,我们从具有100k状态的向量开始,对于每一个我们计算可达状态(通常为> 1),以便我们获得100k *的转换列表(平均可达状态).然后,每个过渡都经过计算新的概率向量.
不幸的是,我需要通过整个可达列表来查找规范化值而不实际计算下一个vecto,但无论如何,正如我通过分析看到的,这不是算法的瓶颈.计算每个转换时都会出现瓶颈.
这是用于从当前向量(pi)计算转换列表的函数:
HTable.fold (fun s p l ->
if check s f2 then (0., s, p, [s, 1.0]) :: l
else if not (check s f1) then (0., s, p, [s, 1.0]) :: l
else
let ts = P.rnext s in
if List.length ts = 0 then (0., s, p, [s, 1.0]) :: l
else
let lm = List.fold_left (fun a (s,f) -> f +. a) 0. ts in
(lm, s, p, ts) :: l) pi []
这是通过遍历转换列表并将它们全部归一化来计算新pi的函数:
let update_pi s v =
try
let t = HTable.find pi s in
HTable.replace pi s (v +. t)
with Not_found -> HTable.add pi s v
in
HTable.clear pi;
List.iter (fun (llm, s, p, ts) ->
if llm = 0. then
update_pi s p
else begin
List.iter (fun (ss, pp) ->
update_pi ss (p *. (pp /. lm))
) ts;
if llm < lm then update_pi s (p *. (1. -. (llm /. lm)))
end
) u;
我应该找到一个更适合我正在进行的操作的数据结构,问题是使用当前的方法我必须为每个转换执行get和set,但是通过hashtables执行这么多操作会因为常量而杀死性能成本相当昂贵.
最佳答案 如果ts = [],如果List.length ts = 0,则用常量时间替换线性时间不会有什么坏处,尽管我怀疑这会解决你的性能问题.
您的算法听起来有点像将矩阵乘以向量以获得新的向量.这通常加速到blocking.但是在这里,哈希表中的表示可能会花费你的位置.是否可以一劳永逸地对所有状态进行编号,然后使用数组而不是哈希表?请注意,对于任意转换,目标状态仍然不是本地状态,但它可能是一种改进(如果仅因为访问数组比访问哈希表更直接).