The Computer Language
Benchmarks Game

binary-trees Clojure #6 program

source code

;; The Computer Language Benchmarks Game
;; Adapted from the Java -server version
;; contributed by Marko Kocic
;; modified by Kenneth Jonsson, restructured to allow usage of 'pmap'
;; modified by Andy Fingerhut to use faster primitive math ops, and
;; deftype instead of defrecord for smaller tree nodes.
;; modified by Mike Anderson to avoid boxing overheads

(ns binarytrees

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

;; These TreeNode's take up noticeably less memory than a similar one
;; implemented using defrecord.

(deftype TreeNode [left right ^int item])

(defn ^:static bottom-up-tree [^long item ^long depth]
  (let [int-item (int item)
        int-depth (int depth)]
    (if (<= depth 0)
      (TreeNode. nil nil int-item)
       (bottom-up-tree (unchecked-dec (unchecked-multiply (int 2) int-item))
                       (unchecked-dec int-depth))
       (bottom-up-tree (unchecked-multiply (int 2) int-item)
                       (unchecked-dec int-depth))

(defn ^:static item-check ^long [^TreeNode node]
  (let [item (int (.item node))]
	  (if-not (.left node)
           (unchecked-int (item-check (.left node))))
           (unchecked-int (item-check (.right node))))))))

(defn ^:static check-trees [^long i ^long acc ^long d]    
  (if (<= i 0)
    (let [value (unchecked-add 
                  (unchecked-int (item-check (bottom-up-tree i d)))
                  (unchecked-int (item-check (bottom-up-tree (- i) d))))]
      (recur (dec i) (+ acc value) d))))

(defn iterate-trees 
  ([mx mn d]
    (let [iterations (bit-shift-left 1 (int (+ mx mn (- d))))]
      (format "%d\t trees of depth %d\t check: %d" (* 2 iterations) d (check-trees iterations 0 d)))))

(def min-depth 4)

(defn main [max-depth]
  (let [stretch-depth (long (inc max-depth))]
    (let [tree (bottom-up-tree 0 stretch-depth)
          check (item-check tree)]
      (println (format "stretch tree of depth %d\t check: %d" stretch-depth check)))
    (let [long-lived-tree (bottom-up-tree 0 max-depth) ]
      ;; The following line is where Kenneth Jonsson used pmap.  On a
      ;; 1-core machine, I have found significantly less user+system
      ;; CPU time used when it is map, and slightly less elapsed time
      ;; (at the cost of more user+system CPU time) when it is pmap.
      (doseq [trees-nfo (map (fn [d]
                                (iterate-trees max-depth min-depth d))
			      (range min-depth stretch-depth 2)) ]
        (println trees-nfo))
      (println (format "long lived tree of depth %d\t check: %d" max-depth (item-check long-lived-tree))))))

(defn -main [& args]
  (let [n (if (first args) (Integer/parseInt (first args)) 0)
        max-depth (if (> (+ min-depth 2) n) (+ min-depth 2) n)]
    (main max-depth)

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)

Sun, 26 Mar 2017 03:55:28 GMT

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

/usr/local/src/jdk1.8.0_121/bin/java  -cp .:/usr/local/src/clojure/clojure-1.8.0.jar binarytrees 7


< stretch tree of depth 8	 check: -1
< 256	 trees of depth 4	 check: -256
< 64	 trees of depth 6	 check: -64
< long lived tree of depth 7	 check: -1
> stretch tree of depth 8	 check: 511
> 128	 trees of depth 4	 check: 3968
> 32	 trees of depth 6	 check: 4064
> long lived tree of depth 7	 check: 255

stretch tree of depth 8	 check: -1
256	 trees of depth 4	 check: -256
64	 trees of depth 6	 check: -64
long lived tree of depth 7	 check: -1