From a35502b596b66ab80f48adaef15fd6e94952d5bd Mon Sep 17 00:00:00 2001 From: Eric Schulte Date: Mon, 24 Jan 2011 09:41:37 -0700 Subject: [PATCH] updating main readme for publishing on repo.or.cz - removed superfluous examples - removed tangling code which we're already tracking as pure source --- propagator.org | 362 +++++++++++++++------------------------------------------ 1 file changed, 93 insertions(+), 269 deletions(-) rewrite propagator.org (78%) diff --git a/propagator.org b/propagator.org dissimilarity index 78% index 881463e..757c26d 100644 --- a/propagator.org +++ b/propagator.org @@ -1,269 +1,93 @@ -#+TITLE: Concurrent Propagator in Clojure -#+OPTIONS: num:nil ^:nil toc:2 -#+LaTeX_CLASS: normal - -A concurrent propagator system implemented in [[http://clojure.org][Clojure]]. This simple -project builds on the scheme propagator system from Gerald Sussman's -[[http://dspace.mit.edu/handle/1721.1/44215][The art of the Propagator]]. - -#+begin_quote - We develop a programming model built on the idea that the basic - computational elements are autonomous machines interconnected by - shared cells through which they communicate. Each machine - continuously examines the cells it is interested in, and adds - information to some based on deductions it can make from information - from the others. This model makes it easy to smoothly combine - expression-oriented and constraint-based programming; it also easily - accommodates implicit incremental distributed search in ordinary - programs. This work builds on the original research of Guy Lewis - Steele Jr. and was developed more recently with the help of Chris - Hanson. -#+end_quote - -Major differences between this system and the one implemented in /The -art of the Propagator/ are that, -1) this implementation admits parallel execution through the use of - Clojure's [[http://clojure.org/agents][agents]]. -2) this version does not implement the backtracking system which - breaks the locality of the propagator system - -Source code and documentation are available as a [[http://github.com/technomancy/leiningen][leiningen]] project, -and can be checked out using [[http://git-scm.com/][git]] from [[http://gitweb.adaptive.cs.unm.edu/propagator.git][here]] with -: git clone http://gitweb.adaptive.cs.unm.edu/propagator.git - -(note: this is an exploratory, educational implementation and isn't -suitable for any sort of /production/ application.) - -* code - :PROPERTIES: - :tangle: src/propagator.clj - :END: -tangled to [[file:src/propagator.clj]] - -#+begin_src clojure - (ns - #^{:author "Eric Schulte", - :license "GPLV3", - :doc "Simple concurrent propagator system."} - propagator - (:use clojure.contrib.repl-utils clojure.contrib.math)) - - (defmacro cell "Define a new cell." - [name state] - `(def ~name (agent ~state))) - - (defn set-cell "Set the value of a cell" [cell value] - (send cell (fn [_] value))) - - (defmacro propagator "Define a new propagator." - [name in-cells out-cells & body] - `(do - (defn ~(with-meta name - (assoc (meta name) - :in-cells in-cells :out-cells out-cells)) - ~in-cells ~@body) - (doseq [cell# ~in-cells] (add-neighbor cell# ~name)) - ~name)) - - (defmacro run-propagator - "Run a propagator, first collect the most recent values from all - cells associated with the propagator, then evaluate." - [propagator] - `(let [results# (apply ~propagator (map deref (:in-cells ^#'~propagator)))] - (doseq [cell# (:out-cells ^#'~propagator)] - (when (not (= @cell# results#)) - (send cell# (fn [_#] results#)))) - results#)) - - (defmacro add-neighbor "Add a neighbor to the given cell." - [cell neighbor] - `(add-watcher - ~cell :send - (agent nil :validator (fn [_#] (do (future (run-propagator ~neighbor)) true))) - (fn [_# _#]))) -#+end_src -* extension: graphing the propagator network -Draw a graph of a propagator network in a JFrame, tangles to -[[file:src/graphs.clj]]. - -#+begin_src clojure :tangle src/graphs.clj - (in-ns 'propagator) - (use 'vijual) - (import '(javax.swing JFrame JPanel) - '(java.awt Color Graphics) - '(java.awt.image BufferedImage)) - - ;; saving graph information - ;; record keeping for graphing propagators - (def prop-graph {}) - (defmacro remember-prop [name in-cells out-cells] - `(def prop-graph - (assoc prop-graph - (quote ~name) - {:in-cells (map (fn [x#] (name x#)) (quote ~in-cells)) - :out-cells (map (fn [x#] (name x#)) (quote ~out-cells))}))) - - (defmacro propagator "Define a new propagator." - [name in-cells out-cells & body] - `(do - (remember-prop ~name ~in-cells ~out-cells) - (defn ~(with-meta name - (assoc (meta name) - :in-cells in-cells :out-cells out-cells)) - ~in-cells ~@body) - (doseq [cell# ~in-cells] (add-neighbor cell# ~name)) - ~name)) - - ;; stuff for graphing - (def dim [300 300]) - - (def frame (JFrame.)) - - (defn view "Display a graph generated by vijual" [img] - (let [mult 1.5 - width (* (.getWidth img) mult) - height (* (.getHeight img) mult) - offset 50 - panel (doto (proxy [JPanel] [] - (paint [g] - (.drawImage g img offset offset nil))))] - (doto frame (.add panel) .pack (.setSize (+ offset width) (+ offset height)).show))) - - (defn graph-propagators [] - (vec (set - (apply concat - (map (fn [key] - (let [hsh (get prop-graph key)] - (concat - (map #(vec (list % (name key))) (get hsh :in-cells)) - (map #(vec (list (name key) %)) (get hsh :out-cells))))) - (keys prop-graph)))))) - - (defn view-network [] - (view (draw-directed-graph-image (graph-propagators)))) - - (defn clear-network [] - (def prop-graph {}) - (def frame (JFrame.))) -#+end_src - -* usage -These examples can be pasted into the repl. - -** doubling a number -- simplest -#+begin_src clojure - (cell in-c 0) - (cell out-c 0) - (propagator doubler [in-c] [out-c] (* 2 in)) - ;; then any updates to in - (set-cell in-c 1) - ;; will propagate to out - @out-c -#+end_src - -** square roots -- heron -#+begin_src clojure :tangle src/heron.clj - (in-ns 'propagator) - (cell guess 1) - (cell x 9) - (cell done false) - (cell margin 0.1) - - (propagator enough [x guess] [done] - (Thread/sleep 1000) - (if (< (abs (- (* guess guess) x)) @margin) true false)) - - (propagator heron [x done guess] [guess] - (Thread/sleep 1000) - (if done - guess - (/ (+ guess (/ x guess)) 2.0))) -#+end_src - -** web server -Alright, this will use Clojure's [[http://github.com/mmcgrana/ring][Ring]] web server middle-ware. - -So, I guess the best demo here would be some reading/writing through a -MVC setup. - -The =app= will dispatch the incoming data to input cell by the route -at the end of the url, then there can be a couple of output cells -which will render different views of the related data. - -#+begin_src clojure :tangle src/web.clj - (load-file "/home/eschulte/src/propagator/src/propagator.clj") - (in-ns 'propagator) - (use 'ring.adapter.jetty) - (use 'clojure.contrib.seq-utils) - (import 'java.util.Date 'java.text.SimpleDateFormat) - - ;; cells - (cell names '()) - (cell input "") - - (propagator adder [input names] [names] - (when (> (count (seq input)) 0) - (set (cons (str input " :1") names)))) - - (defn app [req] - (or - ;; page to accept input - (when (= "/" (:uri req)) - {:status 200 - :headers {"Content-Type" "text/html" - "Title" "3000"} - :body (apply str - "
" - "Word: " - "" - "
")}) - ;; dump value into "input" cell - (when (re-matches #"/add" (:uri req)) - (set-cell input (second (re-matches #".+=(.+)" (:query-string req)))) - {:status 303 :headers {"Location" "../list"}}) - ;; render the value of the "list" cell - (when-let [matched (re-matches #"/list" (:uri req))] - {:status 200 - :headers {"Content-Type" "text/html"} - :body (apply str (flatten (list "" - "

another word

")))}))) - - (run-jetty #'app {:port 3000}) -#+end_src - -* notes -** look at mutable data stores -- http://clojure.org/agents -- http://clojure.org/atoms -- http://clojure.org/refs - -most definitely will use agents, functions to set their values are -applied to them with send (or send-off if potentially I/O bound), they -support validators, and they can be set to run actions (i.e. alert -propagators) as part of their update cycle (with add-watcher). - -** design to permit distribution across multiple machines -it should be possible to wrap these mutable items including -- network connections from other machines -- hardware (timers, I/O devices, etc...) - -in cells, so that the propagator system remains "pure" - -* licence - -Copyright (C) 2010 Eric Schulte - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a [[file:COPYING][copy of the GNU General Public License]] -along with this program. If not, see . +#+TITLE: Concurrent Propagator in Clojure +#+OPTIONS: toc:nil num:nil +#+LaTeX_CLASS: normal +#+begin_html + +#+end_html + +A concurrent propagator system implemented in [[http://clojure.org][Clojure]]. This simple +project builds on the scheme propagator system from Gerald Sussman's +[[http://dspace.mit.edu/handle/1721.1/44215][The art of the Propagator]]. + +#+begin_quote + We develop a programming model built on the idea that the basic + computational elements are autonomous machines interconnected by + shared cells through which they communicate. Each machine + continuously examines the cells it is interested in, and adds + information to some based on deductions it can make from information + from the others. This model makes it easy to smoothly combine + expression-oriented and constraint-based programming; it also easily + accommodates implicit incremental distributed search in ordinary + programs. This work builds on the original research of Guy Lewis + Steele Jr. and was developed more recently with the help of Chris + Hanson. +#+end_quote + +Major differences between this system and the one implemented in /The +art of the Propagator/ are that, +1) this implementation admits parallel execution through the use of + Clojure's [[http://clojure.org/agents][agents]]. +2) this version does not implement the backtracking system which + breaks the locality of the propagator system + +(note: this is an exploratory, educational implementation and isn't +suitable for any sort of /production/ application.) + +#+source: code-counter +#+begin_src sh :var file="src/propagator.clj" :exports none + cat $file|sed '/^[ \t]*$/d'|grep -v "^[ \t];"|wc -l +#+end_src + +This system is implemented in src_emacs-lisp[:var d=code-counter]{d} +lines of Clojure code in [[http://repo.or.cz/w/propagator.git/blob_plain/HEAD:/src/propagator.clj][src/propagator.clj]]. + +** Usage Examples +- square roots calculation using Heron's method + #+begin_src clojure :tangle src/heron.clj + (in-ns 'propagator) + (defcell guess 1) + (defcell x 9) + (defcell done false) + (defcell margin 0.1) + + ;; check if we're close enough to a solution to cease improving + (defpropagator enough [x guess] [done] + (Thread/sleep 1000) ; sleep to allow observation of incremental calculation + (if (< (abs (- (* guess guess) x)) @margin) true false)) + + ;; incrementally improve our guess + (defpropagator heron [x done guess] [guess] + (Thread/sleep 1000) + (if done + guess + (/ (+ guess (/ x guess)) 2.0))) + + (comment ; after building the system + (set-cell x 89) ; update the value of x + (deref guess) ; immediately begin observing improvements in guess + (deref guess)) + #+end_src + +- parallel spread sheet using Clojure formulas is implemented in + src_emacs-lisp[:var d=code-counter(file="src/spreadsheet.clj")]{(- d 5)} + in [[http://repo.or.cz/w/propagator.git/blob_plain/HEAD:/src/spreadsheet.clj][src/spreadsheet.clj]]. + +** License +Copyright (C) 2010 Eric Schulte + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . -- 2.11.4.GIT