Clojure Video Data Performance Questions - clojure

I'm writing some code to generate and process large amounts of video data. At first I intend only to work with randomized data.
My technique is to treat a pixel as a map of R, G, B, A integer values, to treat a frame of video as a vector of these pixel maps, and to treat video across time as a vector of these vectors of pixel maps. I've written three functions that do this reliably but am running into performance issues when they are scaled.
(defn generateFrameOfRandomVideoData
"Generates a frame of video data which is a vector of maps of pixel values."
[num-pixels-in-frame]
(loop [num-pixels-in-frame num-pixels-in-frame
pixels-added 0
frame '[]]
(if (> num-pixels-in-frame pixels-added)
(recur num-pixels-in-frame
(inc pixels-added)
(conj frame (assoc '{}
:r (rand-int 256)
:g (rand-int 256)
:b (rand-int 256)
:a (rand-int 256))))
frame)))
(defn generateRandomVideoData
"Generates a vector of frames of video data."
[number-of-frames frame-height frame-width]
(loop [number-of-frames number-of-frames
frame-height frame-height
frame-width frame-width
frames '[]]
(if (> number-of-frames (count frames))
(recur number-of-frames
frame-height
frame-width
(conj frames (generateFrameOfRandomVideoData (* frame-height frame-width))))
frames)))
(defn generateRandomizedVideo
"Generates video data based on the specified parameters."
[number-of-frames frame-height frame-width]
(assoc '{}
:number-of-frames number-of-frames
:frame-height frame-height
:frame-width frame-width
:frames (generateRandomVideoData number-of-frames frame-height frame-width)))
Call this to use the functions to generate 60 frames of 1920X1080p video:
(generateRandomizedVideo 60 1920 1080)
When I run this call to generate 10 frames worth of 1920X1080p video the algorithm completes quite quickly. When I call it to produce 60 frames of video it bogs down, does not complete, and generates huge amounts of memory. I watched it take up 16gb worth of memory.
This doesn't really make any sense to me. My algorithm is O(number of frames * (height of frame * width of frame)). Number of frames is O(n) and (height of frame * width of frame is constant at O(height * width). These arguments resolve to O(n).
Now that I've convinced myself and hopefully you that my algorithm isn't simply intractable, I think I have some coherent questions:
How much memory does an integer in Clojure take up in bits? I cant seem to find this information anywhere.
What kind of overhead does storing Integers bound to map keys cause? Is it costlier in terms of memory than just keeping them in a vector?
Why is the algorithm bogging down in terms of time and memory for large numbers of frames? What is Clojure doing to hog so much memory?
Thanks!

How much memory does an integer in Clojure take up in bits?
16 bytes, according to clj-memory-meter:
(mem/measure (rand-int 256))
=> "16 B"
Only 4 bytes are used to represent a 32-bit integer value, but a java.lang.Integer in Clojure is the same as in Java, and there's additional storage "overhead" for every java.lang.Object:
(type (rand-int 256))
=> java.lang.Integer
What kind of overhead does storing Integers bound to map keys cause? Is it costlier in terms of memory than just keeping them in a vector?
Yes, almost twice as much in this case:
(mem/measure [(rand-int 256) (rand-int 256) (rand-int 256) (rand-int 256)])
=> "320 B"
(mem/measure {:r (rand-int 256)
:g (rand-int 256)
:b (rand-int 256)
:a (rand-int 256)})
=> "544 B"
Each frame is going to be quite large:
(mem/measure
(into [] (repeatedly (* 1920 1080)
(fn [] {:r (rand-int 256)
:g (rand-int 256)
:b (rand-int 256)
:a (rand-int 256)}))))
=> "232.2 MB"
Why is the algorithm bogging down in terms of time and memory for large numbers of frames? What is Clojure doing to hog so much memory?
Storing a hash map per pixel is going to add up very quickly, if each 1920x1080 frame is ~232 MB that's ~1 GB every 4 frames. I don't think this is specific to Clojure — this is an expensive storage scheme for any language. I'd consider a few things:
Store the individual pixel values more efficiently e.g. represent each pixel as as four unsigned bytes packed into a single 32-bit integer. An open hash map is probably one of the least space-efficient structures when you have this many data points, all in the same structure.
Since your map shape is well-defined, you could use a record to save space and have map-like semantics:
(defrecord Pixel [r g b a])
(mem/measure (->Pixel (rand-int 256)
(rand-int 256)
(rand-int 256)
(rand-int 256)))
=> "112 B" ;; similar deftype is 96 B
A primitive integer array of four is only slightly larger than a single Integer object:
(mem/measure (int-array (range 4)))
=> "32 B"
A similar vector is 10x larger:
(mem/measure [(int 0) (int 1) (int 2) (int 3)])
=> "320 B"
You could try an array of bytes, but JVM doesn't have unsigned byte primitives:
(mem/measure (byte-array 4))
=> "24 B"
There's a lot of immutable-data-structure-changing happening where each pixel and frame is getting conj'd onto an existing vector, and that doesn't come "for free" with Clojure's persistent data structures. A more efficient way to do this is using transients, but...
Do you need to store all these frames in-memory? If not, you could stream these lazily without holding them all. If you have to build them into a large, realized collection, maybe use transients, JVM arrays, etc.
(defn gen-frame [num-pixels]
(repeatedly num-pixels
#(->Pixel (rand-int 256) (rand-int 256) (rand-int 256) (rand-int 256))))
(defn frame-op [frame] ;; not very interesting for random pixels
(let [num-pixels (count frame)
avg #(double (/ (apply + (map % frame)) num-pixels))]
(->Pixel (avg :r) (avg :g) (avg :b) (avg :a))))
(time
(->> (repeatedly #(gen-frame (* 1920 1080)))
(map frame-op)
(take 60)
(doall)))
"Elapsed time: 240527.803662 msecs"
=>
(#sandbox.core.Pixel{:r 127.4540152391975, :g 127.4542722800926, :b 127.3754962384259, :a 127.4886294367284}
#sandbox.core.Pixel{:r 127.4727488425926, :g 127.4447955246914, :b 127.4472164351852, :a 127.4626080246914}
...
This example is lazily analyzing each frame of an infinite sequence and taking the first 60 results; the analyzed frame/pixel data is getting garbage collected as this runs, so it won't run out of memory (but the GC will be busy).
These arguments resolve to O(n).
Large constants matter, sometimes!

If you need further speedup from what you can get out of #Taylor Wood's answer, consider compressing your storage further.
If you just press 99, Clojure will store that as a java.lang.Long, taking up 64 bytes per number. Using java.lang.Integer will cut that in half, taking up 32 bytes per number.
But we have further room for optimization! You generate numbers between 0 and 255, meaning you need log2(256) = 8 bits for storage per number. We could then fit all three RGB values into a single java.lang.Integer!
I've started out below. Credits for this approach goes to mikera/imagez. If you feel like tweaking more, you can try to avoid my usage of rem and quot and go for bit fiddling instead. The memory will be the same, but the CPU usage will go down.
(defn encodable? [i]
(and (nat-int? i)
(< i 256)))
(defn rgb->int
"Store an RGB value in a single integer!"
[[r g b]]
(do (assert (encodable-int? r))
(assert (encodable-int? g))
(assert (encodable-int? b)))
(int
(+ (* 256 256 r)
(* 256 g)
b)))
(defn int->rbg [i]
[(rem (quot i (* 256 256)) 256)
(rem (quot i 256) 256)
(rem i 256)])
;; Let's try to store 99, 101, 255!
(def c [99 101 255])
(rgb->int c)
;; => 6514175
(type (rgb->int c))
;; => java.lang.Integer
(-> c rgb->int int->rbg)
;; => [99 101 255]

Related

Decrease list values by ratio in Clojure

I have a little programming issue that I'm trying to resolve in Clojure.
Say, I have a list with Integer values (they also include zeros). These values have a sum, which I want to decrease by a certain value. To get to this lower sum, I want to decrease the values in the list by ratio.
Say, I have the following list: [0, 10, 30, 40, 20, 0]. The sum is 100, and I want to decrease the sum to 90. I want to decrease the values by ratio, so the new list will be [0, 9, 27, 36, 18, 0].
However, this gets problematic when the numbers turn into fractions. When you round numbers (either with round, floor or ceil), you can end up with a sum that's off by 1 or 2. I can't seem to find an elegant solution. Everything I get consists of going through all the values once, and then going back to repair the offset. Any ideas?
Edit
To clarify the behaviour I want to see, the way it rounds doesn't really matter to me, as long as the sum is correct and the ratios of the numbers are approximately the same. I don't care care whether the total error is the smallest or that most are rounded down.
Additional requirements are that numbers are only allowed to stay equal or get lower, numbers should be >= 0, and the resulting list of numbers should be integers.
We can specify the function's requirements with clojure.spec. If we want the function to support integers w/arbitrary precision, sequences that sum to zero, empty sequences, etc., we could write this function spec:
(s/def ::natural-integer (s/and integer? (comp not neg?)))
(s/fdef dec-sum-int
:args (s/and (s/cat :new-sum ::natural-integer
:nums (s/coll-of ::natural-integer))
#(<= (:new-sum %) (apply +' (:nums %))))
:ret (s/coll-of ::natural-integer)
:fn (fn [{:keys [args ret]}]
(and (= (count (:nums args)) (count ret))
;; each output <= corresponding input
(every? true? (map <= ret (:nums args)))
(or (empty? ret)
(= (:new-sum args) (apply + ret))))))
Then st/check the original answer below to see failing examples, or see example invocations with s/exercise-fn.
Here's a version that satisfies the spec for your updated requirements. Most of the complexity is to ensure each output <= input when adjusting for rounding error:
(defn dec-sum-int [new-sum nums]
(let [sum (apply +' nums)
ratio (if (zero? sum) 1 (/ new-sum sum))
nums' (map #(bigint (*' % ratio)) nums)
err (- new-sum (apply + nums'))]
(loop [nums nums
nums' nums'
out []
err err]
(cond
(zero? err)
(into out nums')
(seq nums')
(let [[num & more] nums
[num' & more'] nums']
(if (pos? num)
(let [num'' (min num (+ num' err))]
(recur more more'
(conj out num'')
(- err (- num'' num'))))
(recur more more' (conj out num') err)))
:else out))))
(st/summarize-results (st/check `dec-sum-int))
{:sym playground.so/dec-sum-int}
=> {:total 1, :check-passed 1}
Original Answer
Here's a function to multiply each number in a collection by a ratio to reach some desired sum:
(defn adjust-sum [new-sum nums]
(let [sum (apply + nums)]
(map #(* % (/ new-sum sum))
nums)))
(adjust-sum 90 [0 10 30 40 20 0])
=> (0N 9N 27N 36N 18N 0N)
(map int *1)
=> (0 9 27 36 18 0)
For your example the results naturally come out as big integers. This is the only given example, but this problem lends itself well to property-based, generative testing. We can define properties that should hold for all examples and use test.check to test the function against many random examples we may not have imagined:
(tc/quick-check 10000
(prop/for-all [new-sum gen/int
nums (->> (gen/vector gen/int)
;; current approach fails for inputs that sum to zero
(gen/such-that #(not (zero? (apply + %)))))]
(= new-sum (apply + (adjust-sum new-sum nums)))))
=> {:result true, :num-tests 10000, :seed 1552170880184}
See updates above for handling examples with rounding error, or prior edits for handling negative numbers.
I don't think there is way to solve it without going through the list a second time to fix the rounding. Here is one solution using Largest Remainder Method:
(defn adj-seq
[input ratio rounding]
(let [;;
;; function to apply ratio to a number
;;
mul-ratio (partial * ratio)
;;
;; function to apply ratio and rounding to a number
;;
mul-ratio-r (comp rounding mul-ratio)
;;
;; sort oirignal input with largest remainder first
;; then applies ratio and rounding to each number
;;
rounded-list (->> input
(sort-by #(- (mul-ratio-r %)
(mul-ratio %)))
(map mul-ratio-r))
;;
;; sum of original numbers
;;
sum-input (reduce + input)
;;
;; calculate the delta between the expected sum and sum of all rounded numbers
;;
delta (- (mul-ratio-r sum-input) (reduce + rounded-list))]
;;
;; distribute delta to the rounded numbers in largest remainder order
;;
(->> rounded-list
(reductions (fn [[remain _] e]
;; increment number by 1 if remaining delta is >1
(if (pos? remain)
[(dec remain) (inc e)]
;; otherwise returns the rounded number as is
[0 e]))
;; delta is the initial value to feed to the reducing function
[delta])
;;
;; ignore the first output from the reducing function - which is the original delta
;;
rest
;;
;; get the adjusted number: ratio + rounding + delta-adj
;;
(map last))))
And a sample run:
(def input [0 10 30 40 20 0])
(def ratio 0.83)
(def rounding int)
(reduce + input)
;; => 100
(* ratio *1)
;; => 83.0
(adj-seq input ratio rounding)
;; => (25 17 8 33 0 0)
(reduce + *1)
;; => 83
Is this what you need?
(defn scale-vector
"Given `s`, a sequence of numbers, and `t`, a target value for the sum of
the sequence, return a sequence like `s` but with each number scaled
appropriately."
[s t]
(let [ratio (/ (reduce + (filter number? s)) t)]
(map #(if (number? %) (/ % ratio) %) s)))
(scale-vector [10 20 :foo 30 45.3 0 27/3] 21)
=> (1.837270341207349 3.674540682414698 :foo 5.511811023622047 8.32283464566929 0.0 1.6535433070866141)
(reduce + (filter number? (scale-vector [10 20 :foo 30 45.3 0 27/3] 21)))
=> 21.0
What's going on here:
We're assuming that s is a sequence of numbers; but it isn't necessarily an error if some element is not a number. Filtering for numbers allows us to cope gracefully is some elements are non-numeric; I've chosen to preserve non-numeric elements, but you could equally drop them.
I've done nothing special to exclude rational numbers from the output, and I can't see why you'd need to; but if you wanted to do that you could use (map double [1 1/2 22/7]) => (1.0 0.5 3.142857142857143).
But idiomatically, in Clojure, a number is just a number. Any function that accepts numbers should accept numbers. Rational numbers - what you are referring to as 'fractions' - are just numbers like any other numbers. Don't worry about them.

Clojure; Design performant data structure for objects in 2D Space for collision detection

I'm writing a game in clojurescript.
It has a 2D game area for example from 0 to 10000 on the x and y axis.
In this area there can be dots of different sizes.
If the player touches a dot it will be deleted.
There can be up to 2500 dots or even more.
Since the player can move every frame i would have to check all ~2500 dots 60 times per second.
If if where to be having this data structure:
(defonce state (atom {:food [{:center {:x 19 :y 51} :radius 1.78 :area 10}
{:center {:x 12 :y 34} :radius 1.78 :area 10}]}))
i imagine it to be quite slow and inefficient.
In C/C++ i would probably have created an array of 10000 by 10000 and used the indicies as x and y value/keys to a pointer to my object. This way i would only have to figure out how big the player currently is and which points of the play area his body covers. Then i would only have to check at those indicies.
dot dots[10000][10000];
// if player where a square of 5 at the moment at x=123 y=456
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
isDot(dots[123+i][456+j]);
}
}
Is there a similar way with clojure and it's data structures?
I tried to have a "point key" and tried to retrieve its value like this:
(def state (atom {:food { {:x 123 :y 456}{:radius 1.783 :area 9.9}
{:x 321 :y 654}{:radius 1.784 :area 10}}}))
(println (get-in #state [:food {:x 123 :y 456}]))
Is something like this possible? (This does only give me nil to print)
Three options for a lookup table
Your point key is a map where each key is also a map, which does work. The nil that you see in your REPL is in fact what calling println returns as a result. The (get-in #state [:food {:x 123 :y 456}]) part works fine; it returns the value associated with the key {:x 123 :y 456}.
I could think of three options for a lookup table in CLJS that are straight-forward to implement: a plain JS Array, nested ClojureScript vectors, and nested maps. The latter is a variant of your "point key", where first map is indexed by row number, and the inner nested map by column number (or vice versa).
Here's an example of initializing each of the three data structures:
; plain JS Array
(def js-array (reduce (fn [acc _] (do (.push acc (make-array 10000)) acc)) (array) (range 10000)))
; nested CLJS vectors
(def vec-array (->> false (repeat 10000) vec (repeat 10000) vec))
; nested CLJS map
(def map-grid (reduce #(assoc-in % [(rand-int 10000) (rand-int 10000)] {:radius 1.78 :area 10}) {} (range 2500)))
Note how the mutable state of the plain JS Array forces the code to be less idiomatic.
Lookup performance measured
A quick-and-dirty performance test shows that the plain JS Array is (only) slightly more efficient for look ups than the other two. The following code shows performance testing with 100k lookups:
(defn exec-time [get-fn n]
(do (time (reduce (fn [x y] (or x y)) ;; stop compiler from optimizing lookups away :-)
(repeatedly n get-fn)))
nil)) ;; Suppress output
(exec-time #(aget js-array (rand-int 10000) (rand-int 10000))
100000)
(exec-time #(-> (nth vec-array (rand-int 10000))
(nth (rand-int 10000)))
100000)
(exec-time #(get-in map-grid [(rand-int 10000) (rand-int 10000)])
100000)
My results from repeating each series of 100k lookups 10 times in Figwheel REPL:
plain JS Array: avg. 116, min 100, max 156 (msecs)
nested vectors: avg. 141, min 128, max 194
nested maps: avg. 246, min 232, max 305
The performance differences are so small that I would choose your lookup structure just based on convenience. In this case, I would prefer CLJS immutable structures (e.g., vectors) over plain JS. Note also that the performance of cljs data structures compares very favourably to Immutable.js. If you only perform something in the scale of 25 lookups per frame, then there is little lost in using the persistent data structures of Clojure(Script), and a lot to be gained.

How to get one solution of the equation u + v + x + y + z = 100 in Clojure

I've faced a problem that how to write a clojure function to get one solution of the equation u + v + x + y + z = 100, all variables are positive integers.
The function works like this , if we run (fun 100)then we get one solution (such as [1 10 49 3 37]), if we run (fun 100)once more, we got another solution (maybe [29 46 7 12 6])
Josh's answer mentions a smart algorithm that doesn't waste time brute-forcing dead-end paths. This algorithm is quite simple to write, by tracking the outstanding sum and only choosing numbers no larger than what remains.
(defn sums-to [n total]
(case n
1 [[total]]
(for [i (range (inc total))
solution (sums-to (dec n) (- total i))]
(cons i solution))))
It gets the same answers as the brute-force approach, and instead of ten minutes it takes ten seconds to find them:
user> (time (count (sums-to 5 100)))
"Elapsed time: 12734.779787 msecs"
4598126
This can be achieved with the for list comprehension. Given that you have five variables, there are 10B operations that must be performed, and to brute force it takes a bit of time (a few minutes at least on a core i7 machine. Your best bet is to seek a smart algorithm which will say, for example, that when x is 98, y is 1, and z is 1, then there's no use in looping through u and v, as they must be zero. But, here is the brute force approach:
(def solns (for [x (range 101)
y (range 101)
z (range 101)
u (range 101)
v (range 101)
:when (= 100 (+ x y z u v))]
[x y z u v]))
Now, you have a lazy list of all solutions. Be careful with this, as it's very computationally intensive to perform a (count solns) or (rand-nth solns) (it will take maybe 10 minutes on a modern machine), as the whole list will be realized. Once the list is realized though, you can easily get truly random solutions with (rand-nth solns) as the computation is already done. There are 4,598,126 solutions.
Finally I got the answer myself:
(defn fun [total-sum]
(let [init-part-list (repeat 4 1)
sum (atom (- total-sum (apply + init-part-list)))
part-list (map #(let [r (rand-int #sum)]
(reset! sum (- #sum r))
(+ % r))
init-part-list)]
(cons (- total-sum (apply + part-list)) part-list)))
It really works and takes less than 1 msecs to get the result
=> (time (fun 100))
"Elapsed time: 0.070562 msecs"
But the code look a little bit complicated, can anyone show us a more concise solution?

Clojure transients - assoc! causing exception

Here is the function I'm trying to run...
(defn mongean [cards times]
(let [_cards (transient cards)]
(loop [i 0 c (get cards i) _count (count cards) _current (/ _count 2)]
(assoc! _cards _current c)
(if ((rem i 2) = 0)
(def _newcur (- _current (inc i)))
(def _newcur (+ _current (inc i))))
(if (<= i _count)
(recur (inc i) (get cards i) _count _newcur )))
(persistent! _cards)))
It's resulting in this Exception...
Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative
Being new to clojure, I'd also appreciate any constructive criticism of my approach above. The goal is to take a List, and return a re-ordered list.
I assume that you are trying to implement the Mongean shuffle. Your approach is very imperative and you should try to use a more functional approach.
This would be a possible implementation, were we calculate the final order of the cards (as per Wikipedia formula) and then we use the built-in replace function to do the mapping:
(defn mongean [cards]
(let [num-cards (count cards)
final-order (concat (reverse (range 1 num-cards 2)) (range 0 num-cards 2))]
(replace cards final-order)))
user> (mongean [1 2 3 4 5 6 7 8])
(8 6 4 2 1 3 5 7)
How do you call that function? It looks like you're passing a set, so that its transient version will also be a set and hence can't be used with any of the assoc functions, as they work on associative data structures and vectors:
user=> (assoc #{} :a 1)
ClassCastException clojure.lang.PersistentHashSet cannot be cast to clojure.lang.Associative clojure.lang.RT.assoc (RT.java:691)
user=> (assoc! (transient #{}) :a 1)
ClassCastException clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative clojure.core/assoc! (core.clj:2959)
; the following works as it uses maps and vectors
user=> (assoc {} :a 1)
{:a 1}
user=> (assoc! (transient {}) :a 1)
#<TransientArrayMap clojure.lang.PersistentArrayMap$TransientArrayMap#65cd1dff>
user=> (assoc [] 0 :a)
[:a]
Now, let's try to discuss the code itself. It's a bit hard to follow your code and try to understand what the goal really is without some more hints on what you want to achieve, but as general comments:
you have a times input parameter you don't use at all
you are supposed to use the result of a transient mutation, not assume that the transient will mutate in place
avoid transients if you can, they're only meant as a performance optimization
the binding _current (/ _count 2) is probably not what you want, as (/ 5 2) really returns 5/2 and it seems that you want to use it as a position in the result
constants like _count don't need to be part of the loop binding, you can use the outer let so that you don't have to pass them at each and every iteration
use let instead of def for naming things inside a function
(if ((rem 1 2) = 0)) is definitely not what you want
Now, leaving aside the shuffling algorithm, if you need to rearrange a sequence you might just produce a sequence of new positions, map them with the original cards to produce pairs of [position card] and finally reduce them by placing the card at the new position, using the original sequence as the seed:
(defn generate [coll] ; counts down from (count coll) to 0, change to
; implement your shuffling algorithm
(range (dec (count coll)) -1 -1))
(defn mongean [cards times]
(let [positions (generate cards) ; get the new positions
assemble (fn [dest [pos card]] ; assoc the card at the wanted position
(assoc dest pos card))]
(reduce assemble cards (map vector positions cards))))
If you simply want to shuffle:
(defn mongean [cards times] (shuffle cards))

Why isn't this running in constant space (and how do I make it so it does)?

I'm doing Project Euler to learn Clojure.
The purpose of this function is to calculate the lcm of the set of integers from 1 to m.
(lcm 10) returns 2520
This is a rather brute-force way of doing this. In theory, we go through each number from m to infinity and return the first number for which all values 1 through m divide that number evenly.
If I understand what 'lazy' means correctly (and if I am truly being lazy here), then this should run in constant space. There's no need to hold more than the list of numbers from 1 to m and 1 value from the infinite set of numbers that we're looping through.
I am, however, getting a java.lang.OutOfMemoryError: Java heap space at m values greater than 17.
(defn lcm [m]
(let [xs (range 1 (+ m 1))]
(first (for [x (iterate inc m) :when
(empty?
(filter (fn [y] (not (factor-of? y x))) xs))] x))))
Thanks!
As far as I can tell, your code is in fact lazy (also in the sense that it's in no hurry to reach the answer... ;-) -- see below), however it generates piles upon piles upon piles of garbage. Just consider that (lvm 17) amounts to asking for over 1.2 million lazy filtering operations on (range 1 18). I can't reproduce your out-of-memory problem, but I'd tentatively conjecture it might be an issue with your memory & GC settings.
Now although I realise that your question is not actually about algorithms, note that the production of all that garbage, the carrying out of all those filtering operations etc. not only utterly destroy the space complexity of this, but the time complexity as well. Why not use an actual LCM algorithm? Like the one exploiting lcm(X) = gcd(X) / product(X) for X a set of natural numbers. The GCD can be calculated with Euclid's algorithm.
(defn gcd
([x y]
(cond (zero? x) y
(< y x) (recur y x)
:else (recur x (rem y x))))
([x y & zs]
(reduce gcd (gcd x y) zs)))
(defn lcm
([x y] (/ (* x y) (gcd x y)))
([x y & zs]
(reduce lcm (lcm x y) zs)))
With the above in place, (apply lcm (range 1 18)) will give you your answer in short order.
I'm getting the same OutOfMemoryError on Clojure 1.1, but not on 1.2.
I imagine it's a bug in 1.1 where for holds on to more garbage than necessary.
So I suppose the fix is to upgrade Clojure. Or to use Michal's algorithm for an answer in a fraction of the time.
While I accept that this is acknowledged to be brute force, I shiver at the idea. For the set of consecutive numbers that runs up to 50, the lcm is 3099044504245996706400. Do you really want a loop that tests every number up to that point to identify the lcm of the set?
Other schemes would seem far better. For example, factor each member of the sequence, then simply count the maximum number of occurrences of each prime factor. Or, build a simple prime sieve, that simultaneously factors the set of numbers, while allowing you to count factor multiplicities.
These schemes can be written to be highly efficient. Or you can use brute force. The latter seems silly here.
Michal is correct about the problem. A sieve will be a little bit faster, since no gcd calculations are needed:
EDIT: This code is actually horribly wrong. I've left it here to remind myself to check my work twice if I have such a hangover.
(ns euler (:use clojure.contrib.math))
(defn sieve
([m] (sieve m (vec (repeat (+ 1 m) true)) 2))
([m sieve-vector factor]
(if (< factor m)
(if (sieve-vector factor)
(recur m
(reduce #(assoc %1 %2 false)
sieve-vector
(range (* 2 factor) (+ 1 m) factor))
(inc factor))
(recur m sieve-vector (inc factor)))
sieve-vector)))
(defn primes [m] (map key (filter val (seq (zipmap (range 2 m) (subvec (sieve m) 2))))))
(defn prime-Powers-LCM [m] (zipmap (primes m) (map #(quot m %) (primes m))))
(defn LCM [m] (reduce #(* %1 (expt (key %2) (val %2))) 1 (seq (prime-Powers-LCM m))))