|
12 | 12 | (:import
|
13 | 13 | (clojure.lang Associative IFn IObj IMapIterable Seqable))))
|
14 | 14 |
|
15 |
| -(defn no-op |
16 |
| - ([gf args] |
17 |
| - (apply gf args)) |
18 |
| - ([_k gf args] |
19 |
| - (apply gf args))) |
20 |
| - |
21 |
| -(def ^:dynamic *trace* |
22 |
| - "Applies the generative function gf to args. Dynamically rebound by functions |
23 |
| - like `gf/simulate`, `gf/generate`, `trace/update`, etc." |
24 |
| - no-op) |
25 |
| - |
26 |
| -(def ^:dynamic *splice* |
27 |
| - "Applies the generative function gf to args. Dynamically rebound by functions |
28 |
| - like `gf/simulate`, `gf/generate`, `trace/update`, etc." |
29 |
| - no-op) |
30 |
| - |
31 |
| -(defn active-trace |
32 |
| - "Returns the currently-active tracing function, bound to [[*trace*]]. |
33 |
| -
|
34 |
| - NOTE: Prefer `([[active-trace]])` to `[[*trace*]]`, as direct access to |
35 |
| - `[[*trace*]]` won't reflect new bindings when accessed inside of an SCI |
36 |
| - environment." |
37 |
| - [] *trace*) |
38 |
| - |
39 |
| -(defn active-splice |
40 |
| - "Returns the currently-active tracing function, bound to [[*splice*]]. |
41 |
| -
|
42 |
| - NOTE: Prefer `([[active-splice]])` to `[[*splice*]]`, as direct access to |
43 |
| - `[[*splice*]]` won't reflect new bindings when accessed inside of an SCI |
44 |
| - environment." |
45 |
| - [] |
46 |
| - *splice*) |
| 15 | +(defprotocol ITrace |
| 16 | + (-splice [this gf args]) |
| 17 | + (-trace [this addr gf args])) |
| 18 | + |
| 19 | +(defrecord NoOp [] |
| 20 | + ITrace |
| 21 | + (-splice [this gf args] |
| 22 | + [this (apply gf args)]) |
| 23 | + (-trace [this _k gf args] |
| 24 | + [this (apply gf args)])) |
| 25 | + |
| 26 | +(def no-op (NoOp.)) |
| 27 | + |
| 28 | +(def ^:dynamic *active* (atom no-op)) |
| 29 | + |
| 30 | +(defn active [] *active*) |
| 31 | + |
| 32 | +(defn splice! [gf args] |
| 33 | + (let [[new-state ret] (-splice @*active* gf args)] |
| 34 | + (swap! *active* (fn [_] new-state)) |
| 35 | + ret)) |
| 36 | + |
| 37 | +(defn trace! [k gf args] |
| 38 | + (let [[new-state ret] (-trace @*active* k gf args)] |
| 39 | + (swap! *active* (fn [_] new-state)) |
| 40 | + ret)) |
47 | 41 |
|
48 | 42 | (defmacro without-tracing
|
49 | 43 | [& body]
|
50 |
| - `(binding [*trace* no-op |
51 |
| - *splice* no-op] |
| 44 | + `(binding [*active* (atom no-op)] |
52 | 45 | ~@body))
|
53 | 46 |
|
54 |
| -(declare assoc-subtrace update-trace trace =) |
| 47 | +(declare assoc-subtrace merge-subtraces update-trace validate-empty! trace =) |
55 | 48 |
|
56 | 49 | (deftype Trace [gf args subtraces retval]
|
57 | 50 | trace/Args
|
|
79 | 72 | (update [this constraints]
|
80 | 73 | (update-trace this constraints))
|
81 | 74 |
|
| 75 | + ITrace |
| 76 | + (-splice [this gf args] |
| 77 | + (let [subtrace (gf/simulate gf args)] |
| 78 | + [(merge-subtraces this subtrace) |
| 79 | + (trace/retval subtrace)])) |
| 80 | + |
| 81 | + (-trace [this k gf args] |
| 82 | + (validate-empty! this k) |
| 83 | + (let [subtrace (gf/simulate gf args)] |
| 84 | + [(assoc-subtrace this k subtrace) |
| 85 | + (trace/retval subtrace)])) |
| 86 | + |
82 | 87 | #?@(:cljs
|
83 | 88 | [Object
|
84 | 89 | (equiv [this other] (-equiv this other))
|
|
193 | 198 | [^Trace t addr subt]
|
194 | 199 | (validate-empty! t addr)
|
195 | 200 | (->Trace (.-gf t)
|
196 |
| - (.-args t) |
197 |
| - (assoc (.-subtraces t) addr subt) |
198 |
| - (.-retval t))) |
| 201 | + (.-args t) |
| 202 | + (assoc (.-subtraces t) addr subt) |
| 203 | + (.-retval t))) |
199 | 204 |
|
200 | 205 | (defn merge-subtraces
|
201 | 206 | [^Trace t1 ^Trace t2]
|
|
211 | 216 | (update :weight + weight)
|
212 | 217 | (cond-> discard (update :discard assoc k discard))))
|
213 | 218 |
|
| 219 | +;; TODO: this does NOT feel like the right data structure. In fact I think |
| 220 | +;; updates should be able to shuffle over the unused stuff from update to |
| 221 | +;; update, instead of having to do that final update at the very end. |
| 222 | +;; |
| 223 | +;; Then each update step could shuffling from the constraints over to the end. |
| 224 | +(defrecord UpdateMap [this constraints trace weight discard] |
| 225 | + ITrace |
| 226 | + (-splice [_ _ _] |
| 227 | + (throw (ex-info "Not yet implemented." {}))) |
| 228 | + |
| 229 | + (-trace [state k gf args] |
| 230 | + (validate-empty! (:trace state) k) |
| 231 | + (let [k-constraints (get (choice-map/submaps constraints) k) |
| 232 | + {subtrace :trace :as ret} |
| 233 | + (if-let [prev-subtrace (get (.-subtraces ^Trace this) k)] |
| 234 | + (trace/update prev-subtrace k-constraints) |
| 235 | + (gf/generate gf args k-constraints))] |
| 236 | + [(combine state k ret) |
| 237 | + (trace/retval subtrace)]))) |
| 238 | + |
214 | 239 | (defn update-trace [this constraints]
|
215 |
| - (let [gf (trace/gf this) |
216 |
| - state (atom {:trace (trace gf (trace/args this)) |
217 |
| - :weight 0 |
218 |
| - :discard (cm/choice-map)})] |
219 |
| - (binding [*splice* |
220 |
| - (fn [& _] |
221 |
| - (throw (ex-info "Not yet implemented." {}))) |
222 |
| - |
223 |
| - *trace* |
224 |
| - (fn [k gf args] |
225 |
| - (validate-empty! (:trace @state) k) |
226 |
| - (let [k-constraints (get (choice-map/submaps constraints) k) |
227 |
| - {subtrace :trace :as ret} |
228 |
| - (if-let [prev-subtrace (get (.-subtraces this) k)] |
229 |
| - (trace/update prev-subtrace k-constraints) |
230 |
| - (gf/generate gf args k-constraints))] |
231 |
| - (swap! state combine k ret) |
232 |
| - (trace/retval subtrace)))] |
233 |
| - (let [retval (apply (:clojure-fn gf) (trace/args this)) |
234 |
| - {:keys [trace weight discard]} @state |
235 |
| - unvisited (apply dissoc |
236 |
| - (trace/choices this) |
237 |
| - (keys (trace/choices trace)))] |
238 |
| - |
239 |
| - {:trace (with-retval trace retval) |
240 |
| - :weight weight |
241 |
| - :discard (merge discard unvisited)})))) |
| 240 | + (let [gf (trace/gf this) |
| 241 | + !state (atom (->UpdateMap |
| 242 | + this constraints |
| 243 | + (trace gf (trace/args this)) |
| 244 | + 0 |
| 245 | + (cm/choice-map))) |
| 246 | + retval (binding [*active* !state] |
| 247 | + (apply (:clojure-fn gf) (trace/args this))) |
| 248 | + {:keys [trace weight discard]} @!state |
| 249 | + unvisited (apply dissoc |
| 250 | + (trace/choices this) |
| 251 | + (keys (trace/choices trace)))] |
| 252 | + {:trace (with-retval trace retval) |
| 253 | + :weight weight |
| 254 | + :discard (merge discard unvisited)})) |
242 | 255 |
|
243 | 256 | ;; ## Primitive Trace
|
244 | 257 | ;;
|
|
0 commit comments