This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-08-17
Channels
- # announcements (7)
- # babashka (24)
- # beginners (11)
- # boot (16)
- # calva (46)
- # cider (5)
- # clara (3)
- # clj-kondo (2)
- # cljfx (5)
- # clojure (122)
- # clojure-brasil (26)
- # clojure-dev (20)
- # clojure-europe (20)
- # clojure-germany (1)
- # clojure-nl (1)
- # clojure-norway (54)
- # clojure-uk (2)
- # clojurescript (6)
- # core-matrix (23)
- # datomic (85)
- # graalvm (1)
- # honeysql (9)
- # hyperfiddle (31)
- # lsp (3)
- # malli (9)
- # nbb (2)
- # off-topic (15)
- # pathom (15)
- # pedestal (4)
- # polylith (5)
- # re-frame (5)
- # reitit (9)
- # releases (2)
- # shadow-cljs (63)
- # specter (4)
- # xtdb (7)
Hi! Math and matrix noob here. I’m trying out core.matrix for the first time using day 6 of adventofcode 2021, for which I was pointed to a solution in Matlab. My non-matrix solution was O(n), and the Matlab implementation was O(log(n)). With ChatGPT’s help, I’ve managed to implement it and reached O(log(n)) too. Loving the learnings. However, the problem as such involves counting large numbers of fish, so the core.matrix solution quickly just results in nonsense, because of doubles. I take this as being what it is, but wanted to check if I am missing something. I also looked for a way to raise a matrix to an power (exponentiation) but didn’t find it, so rolled my own. Did I not look closely enough? Will post some code in a reply to this thread, to not spoil the problem for anyone who hasn’t done this fun exercise yet.
Here’s my solution. It is insanely much faster than my O(n) one. For the 256 generation case (the actual AOC problem) it is 10 µs, compared to 100 µs, and naturally it gets to be much bigger wins as I try with more generations. This is all ignoring that I get correct answers with my O(n) solutions, and incorrect results with this one. 😄
Thanks! Do you know of any other matrix library, using integers? For the 256 case it almost works. But only if I squint. 😃
(int (apply + (nth-school input 256)))
; Execution error (IllegalArgumentException) at pez.aoc-2021.day-6-matrix/eval24843 (REPL:3126).
; Value out of range for int: 1592778185024
(That’s the correct answer for my input.)Ah, nvm, its not a matrix math problem, just a very big number, out of range for int
The main issue remains, though:
(bigint (apply + (nth-school [3,4,3,1,2] 1000))) => 379589061144698200000000000000000000000N
I don’t know where to type hint n
, actually. core.matrix will coerce to doubles anyway, right?
I’m calling the array function because I wanted to use the :vectorsz
implementation and not the regular persistent vectors. I’m not sure it matters all that much now, but I created a much stupid exponentiation function at first and then it mattered tons.
:vectorz
only uses doubles, as I recall. Maybe you already know this, but if you use core.matrix with (mx/set-current-implementation :persistent-vector)
or`(mx/set-current-implementation :ndarray)` or then you can use Long
s, BigInt
s, clojure.lang.Ratio
s, or whatever you want for the precision you need. These are native clojure matrix implementations, so you can choose whatever clojure datatype you want, and as long as your operations preserve the types. (I think you know that :persistent-vector
matrices are just clojure vectors of vectors, so :ndarray
should be more efficient.)
(At one point I wrote something where I needed precise ratios with no rounding or float slop, and using :ndarray
and :persistent-vector
is what made it possible. A lot of people like Neanderthal--with good reason--but it won't do this.)
Thanks! I think “as long as your operations preserve the types” is key for me. I’m using mmul
on two matrices in my matrix-power
function. Trying with both :ndarray
and :persistent-vector
I get:
(m/mmul 1N 1N) => 1N
(m/mmul [[1N]] 1N) => [[1N]]
(m/mmul [[1N]] [[1N]]) => [[1.0]]
(-> (m/mmul [[1N]] [[1N]]) ffirst type) => java.lang.Double
(m/mmul 1/2 1/1) => 1/2
(m/mmul [[1/2]] 1/1) => [[1/2]]
(m/mmul [[1/2]] [[1/1]]) => [[0.5]]
(m/mmul [[1N]] 1M) => [[1M]]
(m/mmul [[1N]] [[1M]]) => [[1.0]]
Now reread the article that @UK0810AQ2 provided above. 😃
(m/mmul (object-array [[1/2]]) (object-array [[1/1]])) => [[1/2]]
And using a java array for my school of lantern fish I now get:
(do
(m/set-current-implementation :ndarray)
(time
(println (bigint (apply + (nth-school [3,4,3,1,2] 1000)))))
(criterium/quick-bench
(apply + (nth-school [3,4,3,1,2] 1000))))
=>
379589061144698259131825683795505058481N
"Elapsed time: 1.855416 msecs"
Evaluation count : 486 in 6 samples of 81 calls.
Execution time mean : 1.231394 ms
Execution time std-deviation : 11.752512 µs
Execution time lower quantile : 1.217677 ms ( 2.5%)
Execution time upper quantile : 1.244845 ms (97.5%)
Overhead used : 1.907725 ns
nil
clj꞉pez.aoc-2021.day-6-matrix꞉>
Which is 3X slower than my non-matrix wielding implementation. But starts to get much faster with more generations. So at 1,000,000 generations the matrix implementation is 4-5X faster.