Thanks everyone for the input! I've also got some nice replies on
Stack Overflow – there's some sort of a discussion there as well.

I thought I'd add my voice to the crowd. First off, purely imperative
C is fairly elegant itself. I've made it a simple function (along with
the Python version on the SO post), though I could easily use malloc
or some other way to make ys[] dynamic and not have it required as a
function argument, and I could have zeroed it in the function as well,
but I left that off for simplicity's sake.

http://pastie.org/1048769 for formatted version of:

double convolve(double *xs, double *is, double *ys){
  int i,j;
  for(i=0; i<len(xs); i++){
    for(j=0; j<len(is); j++){
      ys[i+j] = ys[i+j] + (xs[i]*is[j]);
    }
  }
  return ys;
}

As for another Clojure version, this one is short and dare I say a
little bit elegant, but uses a couple utility functions I have around
in my utils.clj file for thie project anyway, and it is impractical
and slow for even 1000 points, though as you can see it's a naive
implementation. http://paste.lisp.org/display/112570#1

(defn convolve-3
  [xs is]
  (reduce #(vec-add %1 (pad-l %2 (inc (count %1))))
         (for [x xs]
           (for [i is]
             (* x i)))))

(defn vec-add
  "Adds vectors
together.

   e.g. (vec-add [1 2 3] [6 4 4]) => [7 6
7]
        (vec-add [1 2] [5 5 5 5]) => [6 7 5
5]
  "
  ([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))))

(defn pad-l
  "Pads 'xs on the left with 'e, to length 'len, if it's less than
'len."
  ([xs len] (pad-l xs len 0))
  ([xs len e]
  (if (<= len (count xs))
    xs
    (recur (cons e xs) len e))))

These and other answers that are more lispy don't quite cut it, but as
someone mentioned above me, I could use pmap and parallelize the
procedure some.

I think my question has been answered: there are ways to do it in
Clojure, but to get efficiency you have to drop down into the almost-
Java level.

It's just a shame, it seems to me, that there is such a nice way to
represent the procedure in Python or even C, yet Clojure (or any Lisp
really) struggles to idiomatically answer this question of
convolution.

Interesting, I think, is the fact that Haskell can more idiomatically
handle convolution; though I can't quite read the examples that are
around the web (I need to get on that…). I wonder if there's something
that could be added to Clojure to do what Haskell does, if it's really
doing anything differently.

Philosophically, it's interesting that a problem like convolution, in
which a signal is being *mutated*, is difficult to express in an
functional manner without some struggle or awkwardness. It is a rare
case where something is actually being changed, mutated if you will,
but not over time so much as *at* the time you look at it. I'm not
sure I'm expressing myself well here, but there seems to be a
distinction between the problem of convolution and that other other,
more conventional and functional problems.

Either way, thank you all again.



-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to