Thanks for the detailed suggestions. Implementing them did bring the execution time down to around 250secs. Though that value is still much longer than 45secs. Could you please verify if I have implemented them correctly?
Code - https://github.com/amithgeorge/reddit-dailyprogrammer-clojure/blob/4ec02600e025d257a59d76fee0ad0eb01f4785ff/src/rdp/214_intermediate_arr.clj project.clj contains the line :jvm-opts ^:replace ["-Xms1024m" "-Xmx1g" "-server"] > 0) Switch to Clojure 1.7.0-beta3 - it's faster and some things below are dependent on it for best performance. And use Java 1.8. Done. > 1) Parse the lines you're reading directly into longs (Clojure focuses on 64-bit primitives - longs and doubles) (defn- read-line-nums ([] (read-line-nums (read-line) #(Long/parseLong %1))) ([input-line parse-fn] (if-let [line input-line] (->> line (#(clojure.string/split %1 #" ")) (map parse-fn))))) > 2) Put the longs first into a data structure that preserves the primitive type. The two best options for that here are records (which can have primitive fields) and arrays. I would create a Canvas defrecord with ^long width and height and a Paper defrecord with all ^long fields for example. (defrecord Paper [^long color ^long x1 ^long y1 ^long x2 ^long y2]) (defrecord Canvas [^long width ^long height]) (defn- make-paper ([^long w ^long h] (make-paper [0 0 0 w h])) ([^longs [color x y w h]] (Paper. color x y (+ x w -1) (+ y h -1)))) I had to make the second arity accept a vector, as it seems impossible to create a function accepting more than 4 primitive arguments. Though I suppose I could grouped the args into a `record` of its own? > 3) Store the papers in a vector (using transient to create it) The `read-input-file` function which creates and stores the papers, it finishes within 20ms. So I didn't bother using a transient. > 4) I suspect visible-color and covered? could probably be tightened up into a reduce over papers or a single loop-recur over papers - can't say I totally get what's happening there. The papers vector represents a sheets of papers that have been stacked on top of each other. ie, the last element in the vector is the canvas, and the first element is the topmost sheet. Each sheet is of different dimensions. Depending on the coordinates where they are placed, they may cover a part of the canvas. Different sheets may overlap in the areas they cover and thus we only want to consider the topmost sheet for that area. The `visible-color` function accepts a canvas coordinate and the stack papers and goes through the stack to find the first sheet that covers said coordinate. That papers color will be visible color for that coordinate. > 5) In visible-color-frequencies, you could use "update" instead of get + transient assoc! on the acc map, but this is never going to be terribly fast. Another option here would be to create an array with the max color (you could track that while reading if it's not a well-known answer) and bash the array. That can retain int or long counters and will be *way* faster. (defn- visible-color-frequencies-arr [{:keys [colors canvas papers]}] (let [colorCounts (long-array (count colors))] (reduce (fn [_ ^longs coord] (if-let [color (visible-color coord papers)] (aset-long colorCounts color (+ 1 (aget colorCounts color))) _)) -1 (for [^long y (range (:height canvas)) ^long x (range (:width canvas))] [x y])) (zipmap (range) colorCounts))) It's a bit messy with me abusing reduce and totally ignoring the accumulator, but the version using arrays is atleast 10 seconds faster than the one using transient maps. That said, even the hashmap version took around 260-270secs. So the bulk of the time savings is caused by some other change. > 6) You can use (set! *unchecked-math* :warn-on-boxed) to get faster math (no overflow checks) and also issue warnings (added in 1.7) if you happened to use boxed math by accident. I added these to both the old code (which didn't use type hints) and the new one. I ran the `-main` function of both from within the repl and using lein run. I didn't see any warnings in any of the executions. How am I supposed to use these? (defn -main ([] (-main "0" "false")) ([index use-arrays] (time (binding [*unchecked-math* :warn-on-boxed *warn-on-reflection* true] (if-not (Boolean/parseBoolean use-arrays) (solve (input-files (Integer/parseInt index))) (solve-arr (input-files (Integer/parseInt index)))))))) > Use: ^:jvm-opts ^:replace ["-server"] In my case there isn't any noticable difference between explicitly using '-server' and not using it. Which brings me to my final question, > The major problem here is that you are using boxed math for everything instead of primitives. >From what I understand of the changes I made, a reduction of almost 250 seconds came about from simply using type hints. Is that normal? The incrementing of color counts in the original code, was that the boxed math you were referring to? In C#, using generic types consistently meant I never had to worry about boxing. I tried using `no.disassemble` to verify if the type hints really changed anything, but I only got more confused. Consider this example code where my-val is supposed to be a long and each of the functions is supposed to accept a long and return a long. (-> my-val (func-a) (func-b) (func-c)) I will have to add typehints to original value as well to each function's input and output, right? Can typehints be added to denote a collection/sequence of longs? What about a collection/sequence of records? Finally, can the performance be improved any more? 250secs still feels too long compared to the C# version. -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.