Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You can certainly improve the performance of this operation significantly. The good news is that you don't need to drop into Java for this: Clojure is extremely fast if you optimise it correctly and in most instances can produce the same speed as pure Java.</p> <p>For maximum performance of numerical code in Clojure you will want to use:</p> <ul> <li><strong>arrays</strong>, because you want mutable storage with very fast writes and lookup. Clojure sequences and vectors are beautiful, but they come with overheads that you probably want to avoid for truly performance-critical code</li> <li><strong>double</strong> primitives, because they offer much faster maths.</li> <li><strong>aset / aget / areduce</strong> - these are extremely fast operations designed for arrays and basically give you the same bytecode as pure Java equivalents.</li> <li><strong>imperative style</strong> - although it's unidiomatic in Clojure, it gets the fastest results (mainly because you can avoid overheads from memory allocations, boxing and function calls). An example would be using <a href="http://clojuredocs.org/clojure_core/clojure.core/dotimes" rel="noreferrer">dotimes</a> for a fast imperative loop.</li> <li><strong>(set! *warn-on-reflection* true)</strong> - and eliminate any warnings your code produces, because reflection is a big performance killer.</li> </ul> <p>The following should be along the right lines and will probably get you roughly equivalent performance to Java:</p> <pre><code>(def kernel (double-array [0 1 1 2 3 3 0 0 0 0 0 0])) (def data (double-array [1 5 7 4 8 3 9 5 6 3 2 1 1 7 4 9 3 2 1 8 6 4])) (defn convolve [^doubles kernel-array ^doubles data-array] (let [ks (count kernel-array) ds (count data-array) output (double-array (+ ks ds)) factor (/ 1.0 (areduce kernel-array i ret 0.0 (+ ret (aget kernel-array i))))] (dotimes [i (int ds)] (dotimes [j (int ks)] (let [offset (int (+ i j))] (aset output offset (+ (aget output offset) (* factor (* (aget data-array i) (aget kernel-array j)))))))) output)) (seq (convolve kernel data)) =&gt; (0.0 0.1 0.6 1.4 2.4 4.4 5.5 6.1000000000000005 5.600000000000001 6.200000000000001 5.499999999999999 5.9 4.199999999999999 3.3000000000000003 2.5 2.2 3.3 4.4 5.6000000000000005 4.8 4.8999999999999995 3.1 3.5 4.300000000000001 5.0 3.0 1.2000000000000002 0.0 0.0 0.0 0.0 0.0 0.0 0.0) </code></pre> <p>I've not trimmed the output array or done any bounding so you'll probably need to hack this solution a bit to get exactly the output you want, but hopefully you get the idea.....</p> <p>Some very rough benchmarking:</p> <pre><code>(time (dotimes [i 1000] (seq (convolve kernel data)))) =&gt; "Elapsed time: 8.174109 msecs" </code></pre> <p>i.e. that's about 30ns per kernel / data pair combination - I expect that's pretty much hitting the bounds of cached memory access.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload