I would like to understand why I cannot add a return type annotation to this dot product function in clojure.
(defn dot3
"3d vector dot product"
^double [^doubles [u0 u1 u2]
^doubles [v0 v1 v2]]
(+ (* u0 v0) (* u1 v1) (* u2 v2)))
In the log below you can see that an annotation for a subtract works just fine and if I remove the ^double return type annotation it also works. But, the above code produces an error when called:
user=> (dot3 [4 5 6] [1 2 3])
ClassCastException user$dot3 cannot be cast to clojure.lang.IFn$OOD user/eval3487 (form-init8441686871120943013.clj:1)
Thanks in advance,
--Roger
thunder 13:17:21 clojure> lein version
Leiningen 2.5.0 on Java 1.8.0_25 Java HotSpot(TM) 64-Bit Server VM
thunder 13:17:28 clojure> lein new test123
Generating a project called test123 based on the 'default' template.
The default template is intended for library projects, not applications.
To see other templates (app, plugin, etc), try `lein help new`.
thunder 13:18:09 clojure> cd test123
thunder 13:18:14 test123> lein repl
nREPL server started on port 57240 on host 127.0.0.1 - nrepl://127.0.0.1:57240
REPL-y 0.3.5, nREPL 0.2.6
Clojure 1.6.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_25-b17
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> (defn vsub3
#_=> "3d vector subtraction"
#_=> ^doubles [^doubles [u0 u1 u2]
#_=> ^doubles [v0 v1 v2]]
#_=> [(- u0 v0) (- u1 v1) (- u2 v2)])
#'user/vsub3
user=> (vsub3 [4 5 6] [1 2 3])
[3 3 3]
user=> (defn dot3
#_=> "3d vector dot product"
#_=> ^double [^doubles [u0 u1 u2]
#_=> ^doubles [v0 v1 v2]]
#_=> (+ (* u0 v0) (* u1 v1) (* u2 v2)))
#'user/dot3
user=> (dot3 [4 5 6] [1 2 3])
ClassCastException user$dot3 cannot be cast to clojure.lang.IFn$OOD user/eval3487 (form-init8441686871120943013.clj:1)
user=> (defn dot3
#_=> "3d vector dot product"
#_=> [^doubles [u0 u1 u2]
#_=> ^doubles [v0 v1 v2]]
#_=> (+ (* u0 v0) (* u1 v1) (* u2 v2)))
#'user/dot3
user=> (dot3 [4 5 6] [1 2 3])
32
The type annotation you have provided is incompatible with the way you specify your arguments to the function.
Destructuring is preventing the proper code from being compiled. It turns out that this is a bug in current Clojure versions, but will be fixed with the 1.7 release.
The following version works properly:
(defn dot3
"3d vector dot product"
^double [^doubles u
^doubles v]
(+ (* (aget u 0) (aget v 0))
(* (aget u 1) (aget v 1))
(* (aget u 2) (aget v 2))))
user=> (dot3 (double-array [4.0 5.0 6.0]) (double-array [1.0 2.0 3.0]))
32.0
Related
I am trying to extract two elements of a map with the largest distance. For that, I defined the function for calculating the distance and can obtain the distance between the first element (p1) and other elements of the map. But I need to calculate distances between the second item (p2) and the next ones (p3, p4, p5), the third item (p3) and (p4, p5), the fourth item (p4) and fifth item (p5). Then I need to identify the maximum amount between all distances and return the 2 items with the largest distance and the distance itself. Any help is highly appreciated.
Here is my code:
(defn eclid-dist
[u v]
(Math/sqrt (apply + (map #(* % %) (mapv - u v)))))
(def error
{:p1 [1 2 3]
:p2 [4 5 6]
:p3 [7 8 9]
:p4 [1 2 3]
:p5 [6 5 4]})
(dotimes [i (dec (count error))]
(let [dis (eclid-dist (second (nth (seq error) 0))
(second (nth (seq error) (+ i 1))))
max-error (max dis)]
(println [':dis' dis ':max-error' max-error])))
I tried to save each calculated distance as a vector element separately to prevent overwriting but it was not successful.
You could use the for macro for this. It let's you combine two nested loops to test for all pairs. Then you can use max-key to pick the pair with largest distance:
(defn find-largest-dist-pair [vec-map]
(apply max-key second
(for [[[k0 v0] & r] (iterate rest vec-map)
:while r
[k1 v1] r]
[[k0 k1] (eclid-dist v0 v1)])))
(find-largest-dist-pair error)
;; => [[:p3 :p4] 10.392304845413264]
There is nothing wrong with eclid-dist, you could just use the dedicated Clojure library clojure.math (and ->> thread-last macro for better readability) and rewrite it like this:
(:require [clojure.math :as m])
(defn distance [u v]
(->> (mapv - u v)
(mapv #(m/pow % 2))
(reduce +)
m/sqrt))
Your main problem is, how to create unique pairs of points from your data. You could write a recursive function for this:
(defn unique-pairs [point-seq]
(let [[f & r] point-seq]
(when (seq r)
(concat (map #(vector f %) r)
(unique-pairs r)))))
(def error {:p1 [1 2 3]
:p2 [4 5 6]
:p3 [7 8 9]
:p4 [1 2 3]
:p5 [6 5 4]})
(unique-pairs (vals error))
or use library clojure.math.combinatorics:
Dependency: [org.clojure/math.combinatorics "0.1.6"]
(:require [clojure.math.combinatorics :as combi])
(combi/combinations (vals error) 2)
Note that these functions have slightly different results- it doesn't affect the final result, but if you can, you should use combinations.
Now, you have to compute distance for all these pairs and return the pair with the largest one:
(defn max-distance [point-map]
(->> (combi/combinations (vals point-map) 2)
(map (fn [[u v]] {:u u :v v :distance (distance u v)}))
(apply max-key :distance)))
(max-distance error)
=> {:u [1 2 3], :v [7 8 9], :distance 10.392304845413264}
There is macros. This macro is convenient because it allows you
to see the result of executing the Clojure script.
But often it gives out a result that does not suit me.
I use Babashka for running scripts.
(defn symbol-several
"returns a symbol with the concatenation of the str values of the args"
[& x]
(symbol (apply str x)))
(defmacro ! [& forms]
(cons
`symbol-several
(for [form forms]
`(str '~form " ;-> " ~form "\n"))))
,that outputs:
c:\clj>bb "~#.clj"
(do (def v [3 4]) (def l (quote (1 2))) (clojure.core/sequence (clojure.core/seq (clojure.core/concat (clojure.core/list 0) l v)))) ;-> (0 1 2 3 4)
The ~#.clj file contains the macro "!" and the code:
"(! (do (def v [3 4]) (def l '(1 2)) `(0 ~#l ~#v)))"
How to rewrite a macro so that it outputs the original code, i.e. something like this:
(do (def v [3 4]) (def l '(1 2)) `(0 ~#l ~#v))) ;-> (0 1 2 3 4)
Also, instead of the result (list), the macro outputs LazySeq:
c:\clj>bb map.clj
(apply map vector [[1 2] [3 4]]) ;-> clojure.lang.LazySeq#8041
I use Babashka (bb.exe) for running script.
The map.clj file contains the macro "!" and the code:
(apply map vector [[1 2] [3 4]])
Using pr-str helps printing Clojure data structures properly.
(defn symbol-several
"returns a symbol with the concatenation of the str values of the args"
[& x]
(symbol (apply str x)))
(defmacro ! [& forms]
`(symbol-several
~#(for [form forms]
`(str '~form " ;-> " (pr-str ~form) "\n"))))
(! (apply map vector [[1 2] [3 4]]))
;; => (apply map vector [[1 2] [3 4]]) ;-> ([1 3] [2 4])
Also see https://clojuredocs.org/clojure.core/pr-str
Suppose i want to change a number in a loop to a keyword in order to check an entry in a dict/map:
(def myarray {:p1 "test"})
#'user/myarray
user> (get myarray
(keyword ":p1")
)
nil
user> (get myarray
(symbol ":p1")
)
nil
user>
I am just getting nil returned. What do i miss here?
: is the indicator of keyword according to the Clojure guide, and the keyword function adds : automatically according to the Clojure Docs. So the correct code must be (keyword "p1") instead of (keyword ":p1").
Here is an outline of how you can do it:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(dotest
(let [m1 {:p1 "a"
:p2 "b"}
k1 (keyword (str "p" 1))
k2 (keyword (str "p" 2))
v1 (k1 m1)
v2 (k2 m1)]
(is= [k1 k2] [:p1 :p2])
(is= [v1 v2] ["a" "b"])))
Note though, an integer is a perfectly valid map key:
(dotest
(let [m1 {1 "a"
2 "b"}
k1 1
k2 2
v1 (get m1 k1) ; this doesn't work: (k1 m1 )
v2 (get m1 k2)]
(is= [k1 k2] [1 2])
(is= [v1 v2] ["a" "b"])))
You just have to use the get function (with the map as 1st arg!).
The above code is based on this template project.
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.
I am working through The Joy of Clojure (which I understand was written for Clojure 1.2) and I'm trying to understand something about amap and related functions.
The following code doesn't work in Clojure 1.4 without type hints:
(defn asum-sq [xs]
(let [dbl (amap xs i ret
(* (aget xs i)
(aget xs i)))]
(areduce dbl i ret 0.0
(+ ret (aget dbl i)))))
REPL:
user=> (asum-sq (float-array [1 2 3 4]))
IllegalArgumentException No matching method found: aset clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)
Version with type hints added works:
(defn ^Double asum-sq [^floats xs]
(let [^floats dbl (amap xs i ret
(* (aget xs i)
(aget xs i)))]
(areduce dbl i ret 0.0
(+ ret (aget dbl i)))))
REPL:
user=> (asum-sq (float-array [1 2 3 4]))
30.0
I'm having a hard time finding information on this issue. When exactly was this breaking change introduced? Or am I understanding this wrongly?
The breaking change is that too generic overloads of both RT/aget and RT/aset got removed.
a[gs]et is there for when you want raw speed (otherwise you would seq or vec the array) and lack of proper hinting was causing them to silently takes a sloooow path.