I'm trying to wrap Java Apache Maths 3 into Clojure but I'm facing a problem I do not understand.
Here is the javadoc :
http://commons.apache.org/proper/commons-math/javadocs/api-3.3/index.html
The method addValue
adds a value to the object but returns void. I imagine there is some inner data inside this object.
In Java, I would do :
regression.addValue(1,2);
I defined functions in Clojure to wrap it :
;;----------Simple regression object builder----------
(defn simple-regression []
(SimpleRegression.))
;;----------Add points----------
(defn add-point
([reg [x y]]
(.addData reg (double x) (double y)))
([reg x y]
(.addData reg (double x) (double y))))
(defn add-points
([data reg]
(let [x (data :x)
y (data :y)
d (zipmap x y)]
(map (fn [[k v]] (add-point reg k v)) d)))
([x y reg]
(let [d (zipmap x y)]
(map (fn [[k v]] (add-point reg k v)) d))))
The functions work fine when I use it separately in a repl.
I then defined a full wrapper :
(defn lin-reg
([data & {:keys [type] :or {type "simple"}}]
(let [reg (simple-regression)]
(do (add-points data reg)
(cond (= type "simple")
[(.getSlope reg) (.getIntercept reg)]
(= type "extended")
{:params [(.getSlope reg) (.getIntercept reg)] :r (.getR reg) :r2 (.getRSquare reg) :significance (.getSignificance reg)}
(= type "full")
{:params [(.getSlope reg) (.getIntercept reg)] :r (.getR reg) :r2 (.getRSquare reg) :significance (.getSignificance reg)
:conf-intervals [(.getSlopeConfidenceInterval reg) (.getInterceptConfidenceInterval reg)] :params-sse [(.getSlopeStdErr reg) (.getInterceptStdErr reg)]
:sse (.getSumSquaredErrors reg) :ssto (.getTotalSumSquares reg) :ssm (.getRegressionSumSquares reg) :cross-products-sum (.getSumOfCrossProducts reg)}
:else
(println "regression type can only be : simple, extended or full"))))))
Code does not work (returns [NaN NaN] so that it means that the values have not been added), confirmed when I try (.getN reg) = 0 If I try it separately, I mean first
(def reg (simple-regression))
(add-points {:x [1 2 3] :y [0.1 0.2 0.3]} reg)
[(.getSlope reg) (.getIntercept reg)]
No problem, all works.
But inside the function, no. I tried many versions, one with a
_ (add-points data reg)
I have the impression that inside the functions, points are not added. It is the same if I copy paste the do
.
Is there a more general Java mechanism I am missing like that the object cannot change inside a function ? Thanks
map
and zipmap
are lazy so when you use them in do
and don't ask them to return actual values or force them (using doall
or dorun
) so all the elements are realised and all the side effect happen (e.g. calling .addData
is a side effect changing some state) your function passed into map
won't be called at all. When you use those functions in REPL, the result printing will try to render the result of map
operation and thus realise the lazy seq.
If you don't need the actual result from map
but just want the side effects to be applied, you might want to use doseq
instead.