|
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 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