5

Smith–Waterman アルゴリズムを使用して、ローカル アラインメントの問題を解決するコードを書きました。

長さ 10000 の文字列を入力し、妥当なメモリ (RAM 2GB 未満) と妥当な時間 (5 分未満) でこれを行いたいと考えています。

最初はこれにバイオライブラリの組み込み関数を使用していましたが、実行が遅すぎて、殺す前に4GBのRAMを消費しました。

同じアルゴリズムを実装する Java プログラム jAligner は、1GB 未満のメモリと 20 秒未満でこの問題を解決できることに注意してください。

これのボックス化されていないバージョンを書いたとき、プログラムは私に<<loop>>. 配列が完全に構築される前に、配列が配列内の項目にアクセスする必要があるためだと思います。

したがって、この種のより大きな動的プログラミングの問題に対して、同様のパフォーマンスで Haskell コードを書くことさえ可能でしょうか。

module LocalAlign where
--import Data.Array.Unboxed
import Data.Tuple
import Data.Array


localAffineAlignment :: (Char -> Char -> Int)
                                    -> Int
                                    -> Int
                                    -> String
                                    -> String
                                    -> (Int, (String, String, String, String))
localAffineAlignment f g e s' t' = (score, best) where
    n = length s'
    m = length t'
    s= array (0,n-1) $ zip [0..n-1] s'
    t= array (0,m-1) $ zip [0..m-1] t'
    table :: (Array (Int,Int) Int,Array (Int,Int) Int)
    table   = (c,d)
      where --a :: UArray (Int,Int) Int
          a = array ((0,0),(n,m)) [((x,y),a' x y)|x<-[0..n],y<-[0..m]] --s end with gap
          b = array ((0,0),(n,m)) [((x,y),b' x y)|x<-[0..n],y<-[0..m]] --t end with gap
          c = array ((0,0),(n,m)) [((x,y),fst (c' x y))|x<-[0..n],y<-[0..m]] -- best 
          d = array ((0,0),(n,m)) [((x,y),snd (c' x y))|x<-[0..n],y<-[0..m]] -- direction
          a' i j
            | i==0 || j==0  = inf
            | otherwise     = max (a!(i-1,j)-e) (c!(i-1,j)-g-e)
          b' i j
            | i==0 || j==0  = inf
            | otherwise     = max (b!(i,j-1)-e) (c!(i,j-1)-g-e)
          c' i j
            | min i j == 0  = (0,0)
            | otherwise     = maximum [(b!(i,j),3),(a!(i,j),2),(c!(i-1,j-1) + f u v,1),(0,0)]
            where u = s!(i-1)
                  v = t!(j-1)
          inf = -1073741824
    score :: Int
    score = maximum $ elems $ fst table
    best :: (String, String, String, String)
    best = (drop si $ take ei s',drop sj $ take ej t',b1,b2)
      where (a,d') = table
            (si,sj,b1,b2) = build ei ej [] []
            (ei,ej) = snd $ maximum $ map swap $ assocs a
            build x y ss tt
             | o == 0       = (x,y,ss,tt)
             | d == 1       = build (x-1) (y-1) (u:ss) (v:tt) 
             | d == 2       = build (x-1) y     (u:ss) ('-':tt) 
             | otherwise    = build x (y-1)     ('-':ss) (v:tt) 
             where o = a!(x,y)
                   d = d'!(x,y)
                   u = s!(x-1)
                   v = t!(y-1)
4

2 に答える 2

10

この種のより大きな動的プログラミングの問題に対して、同様のパフォーマンスでHaskellコードを書くことさえ可能ですか?

はい、もちろん。同じデータ構造と同じアルゴリズムを使用すると、同じ (または一定の要因により、より良い、またはより悪い) パフォーマンスが得られます。

(中間) リストとボックス化された配列を多用しています。代わりに vector パッケージの使用を検討してください。

于 2012-12-12T20:50:02.253 に答える
2

動的プログラミングをはるかに簡単にするMemoCombinators ライブラリに興味があるかもしれません。基本的に、メモ化せずにアルゴリズムを記述してから、メモ化したい変数に注釈を付けるだけで、コンパイラーはそこからそれを取得します。

于 2012-12-13T04:25:37.207 に答える