The Computer Language
Benchmarks Game

spectral-norm Clojure #6 program

source code

;; The Computer Language Benchmarks Game
;; contributed by Jim Kannampuzha
;; inspired by Jesse Rosenstock
;; modified by Andy Fingerhut (small bug where if input value n was
;;    not a multiple of the number of available processors, the
;;    program would hang.)

(ns spectralnorm

(set! *warn-on-reflection* true)

(defmacro eval-a [ii jj]
  `(let [i# (int ~ii)
         j# (int ~jj)
         n# (unchecked-add i# j#)
         n+1# (unchecked-inc n#)]
     (/ (double 1.0)
        (unchecked-add (bit-shift-right (unchecked-multiply n# n+1#) (int 1))
                       (unchecked-inc i#)))))

(defn multiply-a-v [agent ^doubles v ^doubles av range]
  (let [end (int (second range))]
    (loop [i (int (first range))]
      (if (= i end)
          (aset av i (double (areduce v j sum (double 0)
                                      (+ sum (* (eval-a i j) (aget v j))))))
          (recur (unchecked-inc i)))))))

(defn multiply-at-v [agent ^doubles v ^doubles atv range]
  (let [end (int (second range))]
    (loop [i (int (first range))]
      (if (= i end) nil
            (aset atv i
                  (double (areduce v j sum (double 0)
                   (+ sum (* (eval-a j i) (aget v j))))))
            (recur (unchecked-inc i)))))))

(defn multiply-at-a-v [^doubles v ^doubles tmp ^doubles at-av
                       num-threads workers ranges]
  (dotimes [i num-threads]
    (send (nth workers i) multiply-a-v v tmp (nth ranges i)))
  (apply await workers)
  (dotimes [i num-threads]
    (send (nth workers i) multiply-at-v tmp at-av (nth ranges i)))
  (apply await workers))

(defmacro dot-product [^doubles u ^doubles v]
  `(areduce ~u i# sum# (double 0) (+ sum# (* (aget ~u i#) (aget ~v i#)))))

(defn run-game [size]
  (let [num-threads (int (.availableProcessors (Runtime/getRuntime)))
        workers (vec (repeatedly num-threads #(agent ())))
        chunk-size (int (Math/ceil (/ size num-threads)))
        ranges  (vec (partition 2 1
                                (take (unchecked-inc num-threads)
                                      (iterate #(min (+ chunk-size %) size)
                                               (int 0)))))
        u (double-array size 1.0)
        tmp (double-array size 0.0)
        v (double-array size 0.0)]
    (dotimes [_ 10]
      (multiply-at-a-v u tmp v num-threads workers ranges)
      (multiply-at-a-v v tmp u num-threads workers ranges))
    (let [vbv (dot-product u v)
          vv (dot-product v v)]
      (Math/sqrt (/ vbv vv)))))

(defn -main [& args]
  (let [n (if (empty? args)
            (Integer/valueOf ^String (first args)))]
    (println (format "%.9f" (run-game n)))

notes, command-line, and program output

64-bit Ubuntu quad core
Clojure 1.8.0
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

Sat, 27 Feb 2016 18:15:49 GMT

mv spectralnorm.clojure-6.clojure spectralnorm.clj
/usr/local/src/jdk1.8.0_45/bin/java -Dclojure.compile.path=. -cp .:/usr/local/src/clojure/clojure-1.8.0.jar clojure.lang.Compile spectralnorm
Compiling spectralnorm to .
1.24s to complete and log all make actions

/usr/local/src/jdk1.8.0_45/bin/java -server -XX:+TieredCompilation -XX:+AggressiveOpts -Xmx8m -cp .:/usr/local/src/clojure/clojure-1.8.0.jar spectralnorm 5500