次のコードの効率を改善しようとしています。私は与えられた点の前に(Burrows-Wheeler変換を使ってパターンマッチングの一部として)シンボルのすべての出現を数えたいと思う。どのようにシンボルを数えているかにはいくつかの重複があります。しかし、より効率的なコードでなければならないようなものを実装しようとすると、効率が悪いことが判明しました。私はその怠惰な評価とその貧弱な理解が責任であると仮定しています。リスト処理のためのHaskellの最適化Lazy評価で悩む
カウント機能での私の最初の試みは、次のように行った:マッチング機能自体の本体に続いて
count :: Ord a => [a] -> a -> Int -> Int
count list sym pos = length . filter (== sym) . take pos $ list
:
matching str refCol pattern = match 0 (n - 1) (reverse pattern)
where n = length str
refFstOcc sym = length $ takeWhile (/= sym) refCol
match top bottom [] = bottom - top + 1
match top bottom (sym : syms) =
let topCt = count str sym top
bottomCt = count str sym (bottom + 1)
middleCt = bottomCt - topCt
refCt = refFstOcc sym
in if middleCt > 0
then match (refCt + topCt) (refCt + bottomCt - 1) syms
else 0
(簡潔にするためにストリップダウン - 私が最初にmemoizingよrefCol内のシンボルの出現、および他のいくつかの詳細も同様です)。
編集:サンプルの使用は次のようになります。1(私は何かを間違えていなかったと仮定した場合)されなければならない
matching "AT$TCTAGT" "$AACGTTTT" "TCG"
。
top
ポインタとbottom
の中間にあるすべての情報を再計算しています。これは、文字列に対して4つの可能な選択肢しかない100万文字のDNA文字列を数えたときに加算されます(プロファイリングではこれが大きなボトルネックも、私の時間の48%をbottomCtに、およそ38%をtopCtのために取っています)。参考のために、100万文字列に対してこれを計算し、50パターン(それぞれ1文字と1000文字の間)を一致させようとすると、プログラムの実行には約8.5〜9.5秒かかります。
しかし、私は次の関数を実装しようとした場合:
countBetween :: Ord a => [a] -> a -> Int -> Int -> (Int, Int)
countBetween list sym top bottom =
let (topList, bottomList) = splitAt top list
midList = take (bottom - top) bottomList
getSyms = length . filter (== sym)
in (getSyms topList, getSyms midList)
(補償するマッチング機能に加えられた変更で)、プログラムを実行するために18〜22秒かかります。
以前の呼び出しを追跡できるマップを渡そうとしましたが、実行に約20秒かかってしまい、メモリ使用量が増加します。
同様に、私はfold
に短絡しましたが、foldr
では20秒、foldl
では14-15と短絡しています。
だから、このコードを書き直して最適化するには、適切なHaskellの方法は何でしょうか? (具体的には、事前計算に関係しないものを探しています。文字列をあまり再利用していない可能性があります。なぜこれが起こっているのかを説明します)。
編集:より明確に、私は以下の通りです探しています何:
A)なぜこの動作はHaskellで起こるのでしょうか?怠惰な評価はどのように役割を果たすのですか?コンパイラがcount
とcountBetween
の関数を書き直すためにどのような最適化をしていますか?
b)リストを複数回トラバースしないようにこの問題に対処する簡単なコードの書き換えは何ですか?私は、それを回避する解決策ではなく、その問題に対処するものを特に探しています。最終的な答えがcount
の場合、コードを書くのに最も効率的な方法ですが、それはなぜですか?
サンプルを入力できますか(大幅に縮小しても)? – pdexter
'長さ。フィルター 'をたやすく倍に短縮することができる。 – ThreeFx
'マッチング'の 'str'パラメータの目的は何ですか? 'n'は' length refCol'やそれに類するはずです。 – ErikR