update notes
[propagator.git] / propagator.org
blobdd2c93a6f057e68b583b4c7d9ac178151135a488
1 #+TITLE: Concurrent Propagator System
2 #+OPTIONS: num:nil ^:nil
3 #+LaTeX_CLASS: normal
5 * code
6   :PROPERTIES:
7   :tangle:   src/propagator.clj
8   :END:
9 #+begin_src clojure
10   (ns
11       #^{:author "Eric Schulte",
12          :license "GPLV3",
13          :doc "Simple concurrent propagator system."}
14     propagator
15     (:use clojure.contrib.repl-utils clojure.contrib.math))
16   
17   (defmacro cell "Define a new cell."
18     [name state]
19     `(def ~name (agent ~state)))
20   
21   (defmacro propagator "Define a new propagator."
22     [name in-cells out-cells & body]
23     `(do
24        (defn ~(with-meta name
25                 (assoc (meta name)
26                   :in-cells in-cells :out-cells out-cells))
27          ~in-cells ~@body)
28        (doseq [cell# ~in-cells] (add-neighbor cell# ~name))
29        ~name))
30   
31   (defn set-cell "Set the value of a cell" [cell value]
32     (send cell (fn [_] value)))
33   
34   (defmacro run-propagator
35     "Run a propagator, first collect the most recent values from all
36   cells associated with the propagator, then evaluate."
37     [propagator]
38     `(let [results# (apply ~propagator (map deref (:in-cells ^#'~propagator)))]
39        (doseq [cell# (:out-cells ^#'~propagator)]
40          (when (not (= @cell# results#))
41            (send cell# (fn [_#] results#))))
42        results#))
43   
44   (defmacro add-neighbor "Add a neighbor to the given cell."
45     [cell neighbor]
46     `(add-watcher
47       ~cell :send
48       (agent nil :validator (fn [_#] (do (future (run-propagator ~neighbor)) true)))
49       (fn [_# _#])))
50 #+end_src
51 * usage
52 ** doubling a number -- simplest
53 #+begin_src clojure
54   (cell in 0)
55   (cell out 0)
56   (propagator doubler [in] [out] (* 2 in))
57   ;; then any updates to in
58   (set-cell in 1)
59   ;; will propagate to out
60   @out
61 #+end_src
63 ** square roots -- heron
64 results in errors...
66 #+begin_src clojure
67   (cell guess 1)
68   (cell x 9)
69   (cell done false)
70   (cell margin 0.1)
71   
72   (propagator enough [x guess] [done]
73     (if (< (abs (- (* guess guess) x)) @margin) true false))
74   
75   (propagator heron [x guess] [guess]
76     (if (enough x guess)
77       guess
78       (/ (+ guess (/ x guess)) 2.0)))
79 #+end_src
81 * notes
82 ** look at mutable data stores
83 - http://clojure.org/agents
84 - http://clojure.org/atoms
85 - http://clojure.org/refs
87 most definitely will use agents, functions to set their values are
88 applied to them with send (or send-off if potentially I/O bound), they
89 support validators, and they can be set to run actions (i.e. alert
90 propagators) as part of their update cycle (with add-watcher).
92 ** design to permit distribution across multiple machines
93 it should be possible to wrap these mutable items including
94 - network connections from other machines
95 - hardware (timers, I/O devices, etc...)
97 in cells, so that the propagator system remains "pure"