How can I fill this buffer faster in clojure - opengl

I'm trying to make a function that will take a BufferedImage and return a ByteBuffer I can then use as an OpenGL texture. To do so, I've learnt that I must do some byte-shifting which is not really relevant to my question. It has to do with the BufferedImage values being ARGB and OpenGL wanting RGBA.
The function I'm trying to implement (from java) is this one:
public static ByteBuffer toByteBuffer(BufferedImage img){
byte[] byteArray = new byte[img.getWidth()*img.getHeight()*4];
for(int i = 0; i < img.getWidth()*img.getHeight(); i++){
int value = img.getRGB(i%img.getWidth(), (i-(i%img.getWidth()))/img.getWidth() );
byteArray[i*4] = (byte) ((value<<8)>>24);
byteArray[i*4+1] = (byte) ((value<<16)>>24);
byteArray[i*4+2] = (byte) ((value<<24)>>24);
byteArray[i*4+3] = (byte) (value>>24);
}
return (ByteBuffer) ByteBuffer.allocateDirect(byteArray.length).put(byteArray).flip();
}
And this is my attempt with clojure:
(defn sub-byte [^long b ^long x]
(unchecked-byte (-> x
(bit-shift-left (* 8 b))
(bit-shift-right 24))))
(defn bufferedimage->bytebuffer [^BufferedImage img]
(binding [*unchecked-math* true]
(let [w (.getWidth img)
h (.getHeight img)
^bytes arr (make-array Byte/TYPE (* 4 w h))]
(loop [i 0]
(let [img-i (mod i w)
img-j (quot i w)
value (.getRGB img img-i img-j)]
(aset arr (* i 4) (sub-byte 1 value))
(aset arr (+ 1 (* i 4)) (sub-byte 2 value))
(aset arr (+ 2 (* i 4)) (sub-byte 3 value))
(aset arr (+ 3 (* i 4)) (sub-byte 0 value))
(when (< (+ i 1) (* w h)) (recur (+ i 1)))
))
(cast ByteBuffer (-> (ByteBuffer/allocateDirect (count arr))
(.put arr)
(.flip))))))
This takes 10 seconds to load a 512*512 tileset, which is completely unacceptable. I'm trying to make this run in way less than one second.
Note that the part that's taking all the time is the loop.
I might as well mention that those times are taken using the REPL.
Also, note that I'm well aware I can use java for the performance-critical parts of my code, so this is more of a theoretical question so I can learn how to optimize my clojure code.

The issue with solution using function is revealed when you set *warn-on-reflection* to true:
(set! *warn-on-reflection* true)
When you load your code, the compiler will tell you that your sub-byte function returns Object and it cannot resolve statically a matching method.
Reflection warning, web_app/so.clj:26:11 - call to static method aset on clojure.lang.RT can't be resolved (argument types: [B, int, java.lang.Object).
Unfortunately, you cannot use a type hint for byte return value on your function as only long and double primitives are supported as return types:
(defn sub-byte ^byte [^long b ^long x]
(unchecked-byte (-> x
(bit-shift-left (* 8 b))
(bit-shift-right 24))))
CompilerException java.lang.IllegalArgumentException: Only long and double primitives are supported, compiling:(web_app/so.clj:7:1)
You might try to hint ^long as the return type but then the hinted result type is not what your function body returns (byte):
(defn sub-byte ^long [^long b ^long x]
(unchecked-byte (-> x
(bit-shift-left (* 8 b))
(bit-shift-right 24))))
CompilerException java.lang.IllegalArgumentException: Mismatched primitive return, expected: long, had: byte, compiling:(web_app/so.clj:7:1)
You can however have your function to return long but then you have to wrap it everywhere with unchecked-byte - this way you eliminate all reflections warnings:
(defn sub-byte ^long [^long b ^long x]
(-> x
(bit-shift-left (* 8 b))
(bit-shift-right 24))))
(unchecked-byte (sub-byte ...))
Another solution is to use macro as you already found out which will avoid any issues with function calls and its return types.

I reduced the time from 10s to 173ms by converting sub-byte into a macro:
(defmacro sub-byte [b x]
`(unchecked-byte (-> ~x
(bit-shift-left (* 8 ~b))
(bit-shift-right 24))))
It appears that the performance issues had to do with all the function calls.
I find it quite intriguing though, I didn't think function calls would be so inefficient in Clojure. Also, I thought the compiler was performing inlining optimizations under the hood for me.
Although I've found out the "what", I'm not aware of the "why", so I'll be accepting an answer that explains what's going on rather than mine.

Related

How do I define a safe sqrt function in clojure?

I am using fungp (a genetic programming tool) to model a complex function and having trouble with sqrt.
Basically, I have to pass a vector of functions and their arity into fungp so that it can compose expressions from them. The expressions will then be evaluated and the best one will be returned. This vector of functions looks like:
(def functions
'[[+ 2]
[- 2]
[* 2]
[fungp.util/abs 1]
[fungp.util/sdiv 2]
[fungp.util/sin 1]
[fungp.util/sqrt 1]
[inc 1]
[dec 1]])
That setup gives me a hundred lines of errors like:
#<ClassCastException java.lang.ClassCastException: java.lang.Double cannot be cast to clojure.lang.IFn>
Which I believe is due to the definition of fungp.util/sqrt:
(defn sqrt [x] (if (x > 0) (Math/sqrt x) 0))
I think the 0 is causing the failure to evaluate, but I'm not sure. I've tried defining my own version of the safe square root, but couldn't get the syntax correct.
So, this is where I'm stuck. I need a version of square root that is safe (returns 0 for negative inputs) and evaluates properly in the fungp expression.
EDIT: For completeness, this is one of the (many) variations I've tried for writing my own square root wrapper:
(defn sqrt-fn [x] `(if (~x > 0) (Math/sqrt ~x) 0))
And the output (the middle bit is the expression that was generated from the functions):
#<ClassCastException java.lang.ClassCastException: clojure.lang.Cons cannot be cast to java.lang.Number>
(let [] (- (dec (- (- (fungp.util/sin (tutorial.tut1/sqrt-fn 8.0)) (fungp.util/sdiv (* x 2.0) (dec 9.0))) (fungp.util/sdiv (tutorial.tut1/sqrt-fn (* x x)) (- (- x 4.0) (+ x x))))) (fungp.util/sdiv (tutorial.tut1/sqrt-fn (fungp.util/sin (
+ (dec x) (inc x)))) (fungp.util/sdiv (* (inc (inc 1.0)) (* (+ x 9.0) (fungp.util/sin 9.0))) (tutorial.tut1/sqrt-fn (- (tutorial.tut1/sqrt-fn x) (fungp.util/abs 3.0)))))))
NullPointerException clojure.lang.Numbers.ops (Numbers.java:942)
I am not writing the expressions, so if there are extra parentheses or missing parentheses, they are coming from the way that I've defined sqrt.
There are a couple of things wrong with this:
(defn sqrt-fn [x] `(if (~x > 0) (Math/sqrt ~x) 0))
First, as hinted at in the comments, (x > 0) is trying to call x (presumably a number) as a function. > is the function, so it must come first, as in (> x 0).
Also, you probably don't want they syntax quote here - that prevents evaluation of the contents, so your function is returning a quoted list of symbols.

Writing the Lp norm function

I'm attempting to write the Lp norm function as to generalize the standard L2 norm (Euclidean distance) used. Here is what I have come up with so far, given how I had written the L2 norm:
(defn foo [a b p]
(reduce + (map (comp (map #(power a %) p) -) a b)))
However I am getting the error ClassCastException whenever I try to implement this function. Part of the interim code is from a previously asked question Raising elements in a vector to a power where the following code was provided:
(defn compute [exp numbers]
(map #(power exp %) numbers))
Consider factoring your code.
First define the p-norm
(defn p-norm [p x]
(if (= p :infinity)
(apply max (for [xi x] (Math/abs xi)))
(Math/pow
(reduce + (for [xi x] (Math/pow xi p)))
(/ 1 p))))
And then use the p-norm to define your p-metric
(defn p-metric [p x y]
(p-norm p (map - x y)))
Example
(p-metric 2 [0 0] [3 4])
;=> 5.0
(p-metric :infinity [0 0] [3 4])
;=> 4
Your inner (map):
(map #(power a %) p)
Returns a sequence and you can't feed that to (comp). 'comp' is for 'Function Composition'.
In the REPL:
(doc comp)
clojure.core/comp
([] [f] [f g] [f g h] [f1 f2 f3 & fs])
Takes a set of functions and returns a fn that is the composition
of those fns. The returned fn takes a variable number of args,
applies the rightmost of fns to the args, the next
fn (right-to-left) to the result, etc.
Start breaking your code into smaller steps. (let) form is quite handy, don't be shy to use it.

How to call one defn function in another defn and how to debugging in Clojure

I am having a problem running my program in Clojure. I just start learning Clojure a couple of weeks ago. So I don't know the quick and easy way to debug a Clojure program. My func2 raises an exception at (adj(a b)) as followed:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn
user/func2.
I don't know what is wrong with it. Can someone point out the problem with my coding?
And in func3, I call func2 recursively, but it throws:
ArityException Wrong number of args (0) passed to: PersistentVector
clojure.lan g.AFn.throwArity (AFn.java:437)
What is wrong with func3? Thank you.
(defn adj [value1 value2]
(def result (+ (/ value1 2) (/ value2 2)))
(if (= (mod result 2) 1)
(+ result 1)
result
)
)
(defn func2 [list]
(let [[a b c d] list]
(inc d)
([(adj c a) (adj a b) (adj b c) d]))
)
(defn func3 [list]
(loop [v list r []]
(if(= (v 0) (v 1) (v 2))
(conj list r)
(func3(func2(list)))
))
)
What's the intended result of these functions? We probably need to see some sample inputs and expected results to really be able to help you.
Here's my attempt at cleaning them up. I've noted the changes I made as comments. func3 has the most serious problem in that it's an infinite recursion - there's no end condition. What should cause it to stop working and return a result?
(defn adj [value1 value2]
;; don't use def within functions, use let
(let [result (+ (/ value1 2) (/ value2 2))]
(if (= (mod result 2) 1)
(+ result 1)
result)))
(defn func2 [list]
(let [[a b c d] list]
;; The extra parens around this vector were causing it
;; to be called as a function, which I don't think is
;; what you intended:
[(adj c a) (adj a b) (adj b c) d]))
;; This needs an end condition - it's an infinite recursion
(defn func3 [list]
(loop [v list r []]
(if (= (v 0) (v 1) (v 2))
(conj list r)
;; Removed extra parens around list
(func3 (func2 list)))))
The reason I say not to use def within functions is that it always creates a global function. For local bindings you want let.
Regarding the extra parens, the difference between [1 2 3] and ([1 2 3]) is that the former returns a vector containing the numbers 1, 2, and 3, whereas the latter tries to call that vector as a function. You had excess parens around the literal vector in func2 and around list in func3, which was causing exceptions.
As a style note, the name list isn't a good choice. For one thing, it's shadowing clojure.core/list, and for another you're probably using vectors rather than lists anyway. It would be more idiomatic to use coll (for collection) or s (for sequence) as the name.
This would suggest at least one other change. In func3 you use a vector-only feature (using the vector as a function to perform lookup by index), so to be more general (accept other data structures) you can convert to a vector with vec:
(defn func3 [coll]
(loop [v (vec coll) r []]
(if (= (v 0) (v 1) (v 2))
(conj v r)
(func3 (func2 v)))))
Oh, there is no need to debug that. I suggest you have a look at LightTable.
The first two functions are easily fixed:
(defn adj [value1 value2]
;(def result (+ (/ value1 2) (/ value2 2))) def creates a global binding in current namespace !!!
(let [result (+ (/ value1 2) (/ value2 2))]
(if
(= (mod result 2) 1)
(inc result)
result)))
(defn func2 [xx]
(let [[a b c d] xx]
[ (adj c a) (adj a b) (adj b c) (inc d)]
))
The third function is not clear to me. I don't read your intent. What I understand is: "Keep applying func2 to itself until the first three elements of its result are equal." But I'm afraid this condition is never met, so I replaced it with a true in order to see just one result without blowing the stack.
(defn func3 [xx]
(loop [ v (func2 xx) ]
(if
;(= (v 0) (v 1) (v 2))
true
v
(recur (func2 v))
)))
Useful link: http://clojure.org/cheatsheet
Cheers -

Why am I getting a cast error when trying to use Simpson's rule in Clojure?

I'm trying to work through some of the exercises in SICP using Clojure, but am getting an error with my current method of executing Simpson's rule (ex. 1-29). Does this have to do with lazy/eager evalution? Any ideas on how to fix this? Error and code are below:
java.lang.ClassCastException: user$simpson$h__1445 cannot be cast to java.lang.Number
at clojure.lang.Numbers.divide (Numbers.java:139)
Here is the code:
(defn simpson [f a b n]
(defn h [] (/ (- b a) n))
(defn simpson-term [k]
(defn y [] (f (+ a (* k h))))
(cond
(= k 0) y
(= k n) y
(even? k) (* 2 y)
:else (* 4 y)))
(* (/ h 3)
(sum simpson-term 0 inc n)))
You define h as a function of no arguments, and then try to use it as though it were a number. I'm also not sure what you're getting at with (sum simpson-term 0 inc n); I'll just assume that sum is some magic you got from SICP and that the arguments you're passing to it are right (I vaguely recall them defining a generic sum of some kind).
The other thing is, it's almost always a terrible idea to have a def or defn nested within a defn. You probably want either let (for something temporary or local) or another top-level defn.
Bearing in mind that I haven't written a simpson function for years, and haven't inspected this one for algorithmic correctness at all, here's a sketch that is closer to the "right shape" than yours:
(defn simpson [f a b n]
(let [h (/ (- b a) n)
simpson-term (fn [k]
(let [y (f (+ a (* k h)))]
(cond
(= k 0) y
(= k n) y
(even? k) (* 2 y)
:else (* 4 y))))]
(* (/ h 3)
(sum simpson-term 0 inc n))))

How to type hint

How would I type hint this to get rid of the remaining reflection calls?
(def B
(amap ^"[[D" A i ^"[[D" B
(amap ^doubles (aget A (int i)) j ^doubles row
(* 2 (aget row (int j))))))
There's two reflection calls left, but I don't know how to get rid of them.
You don't show your complete code or the reflection warnings, but if they are what I think they are, you'll need to:
hint A: (def ^"[[D" A ...) wherever you define it
cast the return value of the innermost expression to double: (double (* 2 ...))
The process to come up with these fixes is to perform macroexpand on the macro, run that version, see what expressions are causing the reflection warnings, fix them, and hope that you can retrofit the hints into the original macro, which in this case is possible. I still recommend the more straightforward solution.
IMHO this is easier to do without the amap macro:
(set! *warn-on-reflection* true)
(def ^"[[D" A (into-array [(double-array [0 1 2]) (double-array [2 3 4])]))
(def ^"[[D" B (into-array (map aclone A))) ; aclone is shallow
(dotimes [i (alength B)]
(let [^doubles row (aget B i)]
(dotimes [j (alength row)]
(aset row j (double (* 2 (aget row j)))))))
(doseq [row B]
(prn (vec row)))
This page (in the end) provides good info about type hinting: http://clojure.org/java_interop. It recommends using e.g. (let [n (int)]) instead of ^Integer etc, which also makes the code much more readable. Note that a lot of the material on the internet seems to be for older versions of Clojure and you need less type hints in 1.2.