This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-17
Channels
- # adventofcode (96)
- # beginners (49)
- # boot (3)
- # cider (3)
- # cljs-dev (3)
- # clojure (112)
- # clojure-austin (2)
- # clojure-greece (35)
- # clojure-india (2)
- # clojure-sanfrancisco (1)
- # clojure-spec (1)
- # clojure-sweden (1)
- # clojurescript (27)
- # cursive (4)
- # data-science (1)
- # datomic (33)
- # defnpodcast (1)
- # duct (2)
- # editors (1)
- # emacs (4)
- # events (2)
- # figwheel (4)
- # fulcro (4)
- # hoplon (29)
- # instaparse (1)
- # jobs (1)
- # keechma (4)
- # lein-figwheel (2)
- # om (1)
- # parinfer (4)
- # perun (23)
- # reitit (11)
- # shadow-cljs (8)
- # specter (23)
- # uncomplicate (16)
that absolutely did what i wanted - i added bounds checking and added my desired reversing behavior when row2 < row or col2 < col, and ended up with this, which i haven’t tested thoroughly but seems to be correct so far:
(defn ^:direct-nav grid-values
[x1 y1 x2 y2]
(if (g/cell-is-on-grid x1 y1)
(let [x2 (bound-between x2 0 (dec GRID-WIDTH))
y2 (bound-between y2 0 (dec GRID-HEIGHT))]
(reduce
multi-path
(for [x (if (< x1 x2)
(range x1 (inc x2))
(reverse (range x2 (inc x1))))
y (if (< y1 y2)
(range y1 (inc y2))
(reverse (range y2 (inc y1))))]
(nthpath x y))))
STOP))
final usage ends up looking like this, replacing my reduce from earlier:
(fn [xdir ydir]
(let [values-in-direction (select (grid-values (+ x xdir)
(+ y ydir)
(+ x (* xdir MAX-RUN-LENGTH))
(+ y (* ydir MAX-RUN-LENGTH)))
grid)
run-values (take-while (comp not nil?) values-in-direction)]
[(count run-values) (apply + run-values)]))
seems to be way slower than my previous reduce implementation though, dang - likely some mistake on my end, will profile
ok yeah now my program spends 88% of its time in com.rpl.specter.impl.mk_dynamic_path_maker
the specterized code above is awesome though, i really like it way more than my handrolled reduce from yesterday - it untangles the computation into its component parts (first get a list of up to 5 values in this direction, then drop everything after and including the first nil, then count the values and sum them)
so i remain a big fan of specter and also remain appreciative of your help, but am not sure how to proceed performancewise
if it’s helpful, a screenshot of the profile data: https://www.evernote.com/shard/s11/sh/73bf32be-7f86-414d-adcb-d61279942fd2/b3618565f1ea939f (percentages shown are different because i’ve filtered for com.rpl.specter, i believe)
and the profile itself (55MB): http://jrheard.com/quinto_specter_profile
@jrheard it would be a lot faster as a first-class navigator
implementation would be similar to ALL
, except in two dimensions
it would be easy to also avoid needing to do two nth
per element, since you can do every matching value in a row one after another
interesting, thanks for the tip! i’ll read through the docs and investigate that line of attack
hm, can’t tell if this is a foolish question - would the implementation actually look more like srange
rather than all
? the main difference i see is that srange takes arguments start
and end
, and my thing will also take arguments (`x1`, y1
, x2
, y2
)
also, i notice that ALL
uses doseqres
( https://github.com/nathanmarz/specter/blob/5efafd2d9bc2714fd87ff81b1268ae6f88256a81/src/clj/com/rpl/specter/util_macros.clj#L3 ) - should i figure out what doseqres does, or can i safely ignore it?
@jrheard I mean it's going to be similar in function, navigating to many subvalues of a data structure
implementation-wise it will be very different
i ended up with this, it’s 4-5x faster than the previous specter approach but still roughly (no benchmarks collected, going solely on how the app feels to use) 1.5-2x slower than the reduce approach. it’s also kind of hideous but that’s my fault:
(defnav
grid-values-2
[x1 y1 x2 y2]
(select* [this structure next-fn]
(assert (or (= x1 x2)
(= y1 y2)))
(next-fn
(if (cell-is-on-grid x1 y1)
(let [x2 (bound-between x2 0 (dec GRID-WIDTH))
y2 (bound-between y2 0 (dec GRID-HEIGHT))]
(if (= x1 x2)
(let [column (nth structure x1)]
(if (< y1 y2)
(subvec column y1 (inc y2))
(reverse (subvec column y2 (inc y1)))))
(for [x (if (< x1 x2)
(range x1 (inc x2))
(reverse (range x2 (inc x1))))]
(-> structure
(nth x)
(nth y1)))))
[])))
(transform* [this structure next-fn]
; punting on this for now
(assert false)))