私はいくつかの信号処理ソフトウェアを書いています、そして私は離散畳み込み関数を書き出すことから始めています。
これは最初の1万程度の値のリストでは問題なく機能しますが、値が大きくなると(たとえば、100k)、もちろんStackOverflowエラーが発生し始めます。
残念ながら、私は命令型畳み込みアルゴリズムを、実際に使用するのに十分高速な再帰的で怠惰なバージョンに変換するのに多くの問題を抱えています(少なくとも少しの優雅さもあればいいでしょう)。
また、この機能が完全に正しいかどうかも100%確信していませんが、何かが足りない、または何か間違ったことをしている場合はお知らせください。正しいと思います。
(defn convolve
"
Convolves xs with is.
This is a discrete convolution.
'xs :: list of numbers
'is :: list of numbers
"
[xs is]
(loop [xs xs finalacc () acc ()]
(if (empty? xs)
(concat finalacc acc)
(recur (rest xs)
(if (empty? acc)
()
(concat finalacc [(first acc)]))
(if (empty? acc)
(map #(* (first xs) %) is)
(vec-add
(map #(* (first xs) %) is)
(rest acc)))))))
私はどんな種類の助けも必要です。私はまだClojureで自分の方向性を理解しており、これをエレガントで怠惰なものにしたり、再帰的にしたりするのは素晴らしいことです。
Lispで命令型言語で表現するのが非常に簡単なアルゴリズムを表現するのがどれほど難しいか少し驚いています。しかし、おそらく私はそれを間違っています!
編集: 命令型言語で表現するのがいかに簡単であるかを示し、人々にうまく機能し、読みやすいアルゴリズムを提供するために、ここにPythonバージョンがあります。短く、簡潔で、推論がはるかに簡単であることに加えて、Clojureコードよりも桁違いに高速に実行されます。Java配列を使用する私の必須のClojureコードですら。
from itertools import repeat
def convolve(ns, ms):
y = [i for i in repeat(0, len(ns)+len(ms)-1)]
for n in range(len(ns)):
for m in range(len(ms)):
y[n+m] = y[n+m] + ns[n]*ms[m]
return y
一方、ここに命令型のClojureコードがあります。また、畳み込みから最後の、完全に没頭していない値を削除します。したがって、遅くて醜いことを除けば、100%機能するわけではありません。機能的でもありません。
(defn imp-convolve-1
[xs is]
(let [ys (into-array Double (repeat (dec (+ (count xs) (count is))) 0.0))
xs (vec xs)
is (vec is)]
(map #(first %)
(for [i (range (count xs))]
(for [j (range (count is))]
(aset ys (+ i j)
(+ (* (nth xs i) (nth is j))
(nth ys (+ i j)))))))))
これはとてもがっかりします。誰かが私に何か明らかなことを見逃したことを見せてください。
編集3:
これが昨日私が考えた別のバージョンで、それをどのように表現できるようにしたいかを示しています(他のソリューションは非常にエレガントですが、私は別のソリューションを公開しています!)
(defn convolve-2
[xs is]
(reduce #(vec-add %1 (pad-l %2 (inc (count %1))))
(for [x xs]
(for [i is]
(* x i)))))
このユーティリティ関数を使用しますvec-add
:
(defn vec-add
([xs] (vec-add xs []))
([xs ys]
(let [lxs (count xs)
lys (count ys)
xs (pad-r xs lys)
ys (pad-r ys lxs)]
(vec (map #(+ %1 %2) xs ys))))
([xs ys & more]
(vec (reduce vec-add (vec-add xs ys) more))))
(vec (reduce vec-add (vec-add xs ys) more))))