Dynamic 在OCaml中使用备忘录解决序列对齐问题无法获得正确答案

Dynamic 在OCaml中使用备忘录解决序列对齐问题无法获得正确答案,dynamic,recursion,ocaml,dynamic-programming,memoization,Dynamic,Recursion,Ocaml,Dynamic Programming,Memoization,我使用Hashtbl存储int*string*string,这是问题的答案。然而,当我运行时,答案是不正确的。我认为它跳过了一些值,并且没有计算它们 这是我的代码: let solve_memo (x:string) (y:string) : (int*string*string) = let x_len = String.length x in let y_len = String.length y in let tbl_size = x_len * y_len in

我使用Hashtbl存储int*string*string,这是问题的答案。然而,当我运行时,答案是不正确的。我认为它跳过了一些值,并且没有计算它们

这是我的代码:

let solve_memo (x:string) (y:string) : (int*string*string)  =
    let x_len = String.length x in
    let y_len = String.length y in
    let tbl_size = x_len * y_len in
    let tbl = Hashtbl.create tbl_size in
    let case1 xi yi =
        if x.[xi] = y.[yi] then 1 else -1
    in
    let choose_max (pt1,strxi,stryi) (pt2,strx2,stry2) (pt3,strx3,stry3) =
        if pt1>pt2 then
            if pt1>pt3 then (pt1,strxi,stryi)
            else (pt3,strx3,stry3)
        else 
            if pt2>pt3 then (pt2,strx2,stry2) 
            else (pt3,strx3,stry3)
    in
    let rec aux xi yi (pt,strx,stry) =
    if (xi = x_len && yi = y_len) then (pt,strx,stry)
    else
    if xi = x_len then 
        (
            pt + (-2 * (y_len - yi)),
            String.concat "" [strx; String.make (y_len - yi) ' '],
            String.concat "" [stry; String.sub y (yi) (y_len - yi)]
        )
    else if yi = y_len then
        (pt + (-2 * (x_len - xi)),
        String.concat "" [strx; String.sub x (xi) (x_len - xi)],
        String.concat "" [stry; String.make (x_len - xi) ' ']
        )
    else 
        try
        Hashtbl.find tbl (xi,yi)
        with _ ->
        let r1 = aux (xi+1) (yi+1) (pt+(case1 xi yi), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; Char.escaped y.[yi]]) in
        let r2 = aux (xi+1) yi ((pt-2), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; " "]) in
        let r3 = aux xi (yi+1) ((pt-2), String.concat "" [strx; " "] , String.concat "" [stry; Char.escaped y.[yi]]) in
        let r = choose_max r1 r2 r3 in
        let _ = Hashtbl.add tbl (xi,yi) r in
        r
in aux 0 0 (0,"","")
;;
当我打印hashtbl中的值时,它会重复2-3个可能在迭代开始时创建的值。 多谢各位

加:

这是原始的naivesolve函数,我想添加一个Hashtbl使其更快,但它返回了错误的结果

let solve (x:string) (y:string) : (int*string*string)  =
let x_len = String.length x in
let y_len = String.length y in
let rec aux xi yi (pt,strx,stry) =
let case1 xi yi =
    if x.[xi] = y.[yi] then 1 else -1
    in
    let choose_max (pt1,strxi,stryi) (pt2,strx2,stry2) (pt3,strx3,stry3) =
        if pt1>pt2 then
            if pt1>pt3 then (pt1,strxi,stryi)
            else (pt3,strx3,stry3)
        else 
            if pt2>pt3 then (pt2,strx2,stry2) 
            else (pt3,strx3,stry3)
    in
    if xi = x_len then 
        (
            pt + (-2 * (y_len - yi)),
            String.concat "" [strx; String.make (y_len - yi) ' '],
            String.concat "" [stry; String.sub y (yi) (y_len - yi)]
        )
    else if yi = y_len then
        (pt + (-2 * (String.length x - xi)),
        String.concat "" [strx; String.sub x (xi) (x_len - xi)],
        String.concat "" [stry; String.make (x_len - xi) ' ']
        )
    else
        let r1 = aux (xi+1) (yi+1) (pt+(case1 xi yi), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; Char.escaped y.[yi]]) in
        let r2 = aux (xi+1) yi ((pt-2), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; " "]) in
        let r3 = aux xi (yi+1) ((pt-2), String.concat "" [strx; " "] , String.concat "" [stry; Char.escaped y.[yi]]) in
        choose_max r1 r2 r3
in aux 0 0 (0,"","")
;;

我不认为您能够轻松地修改此函数以获取用于记忆的hashtbl。这是因为你把累加器Pt、Strux、Trices传递到一个细胞席,Yi。累加器代表从三个不同方向上排列的子序列N0。n2,如下图所示。直到它们与序列r0..r2的其余部分对齐,您才确定这三者中的哪一个是最佳的


通过添加备忘录,您只存储了一次此类调用的结果,而不是最佳结果。因此,您的结果取决于之前的单元格,即从n0..n2开始的累加器,以及恢复到序列剩余部分r0..r2的最佳对齐。正因为如此,您无法在不详尽无遗的情况下记录结果。要使备忘录发挥作用,您需要明确的子问题,而这些子问题在这里没有。

我想向您保证,OCaml不会被破坏。我们每天都在测试它,试图重写你的代码,这样它至少是可以理解的。这是解决问题的一种奇怪的方法。您应该考虑每个子字符串都是一个矩阵,并记录每个子字符串的子矩阵对的结果。您在矩阵中向前看,而不是向后看子问题。我建议您对一个单元格进行求解,假设邻居被记忆,然后将结果记忆为hashtbl并返回。根据这一基本直觉,您可以看到您应该查询包含答案x_len,y_len的单元格。此外,存储定义对齐的对将使用足够大的序列来消耗内存。通过矩阵的回溯是按顺序进行的,因此在*n上填充成本和对齐方向不会增加太多复杂性。尽管不是您正在寻找的递归解决方案,回溯算法和成本函数的隔离包含在FullAlign模块中的phylocaml项目github.com/amnh/phylocaml alignment.ml文件中。这是功能化的,因此不会满足您的需求,但会为您寻找的解决方案的简单性提供一些指导。感谢您的评论。我最近才开始学习OCaml和函数式编程。我还有很多东西要学。我添加了一些信息,但我会尝试使用您的建议修复它。非常感谢!导致此问题的原因是通过蓄能器。我原以为我会在以后的输出中使用累加器来存储这些值,但不知怎么的,它把使用Hashtbl搞砸了。我所做的是在辅助递归函数中删除累加器,并稍微更改基本情况和递归调用以适应新函数