Skip to content

Commit

Permalink
New abbreviated defmodel: defmd
Browse files Browse the repository at this point in the history
Starting to change internals names as the mood hits me.
  • Loading branch information
ktilton committed Jun 23, 2006
1 parent 5f84137 commit 4b24693
Show file tree
Hide file tree
Showing 22 changed files with 228 additions and 104 deletions.
22 changes: 11 additions & 11 deletions cell-types.lisp
Expand Up @@ -26,24 +26,24 @@ See the Lisp Lesser GNU Public License for more details.
inputp ;; t for old c-variable class
synaptic
changed
(users-store (make-fifo-queue) :type cons) ;; (C3) probably better to notify users FIFO
(caller-store (make-fifo-queue) :type cons) ;; (C3) probably better to notify callers FIFO

(state :nascent :type symbol) ;; :nascent, :awake, :optimized-away
(value-state :unbound :type symbol) ;; {:unbound | :unevaluated | :valid}
(pulse 0 :type fixnum)
debug
md-info)

(defun c-users (c)
(defun c-callers (c)
"Make it easier to change implementation"
(fifo-data (c-users-store c)))
(fifo-data (c-caller-store c)))

(defun user-ensure (used new-user)
(unless (find new-user (c-users used))
(fifo-add (c-users-store used) new-user)))
(defun caller-ensure (used new-caller)
(unless (find new-caller (c-callers used))
(fifo-add (c-caller-store used) new-caller)))

(defun user-drop (used user)
(fifo-delete (c-users-store used) user))
(defun caller-drop (used caller)
(fifo-delete (c-caller-store used) caller))

(defmethod trcp ((c cell))
nil #+(or) (and (typep (c-model c) 'index)
Expand All @@ -61,7 +61,7 @@ See the Lisp Lesser GNU Public License for more details.
;
; as of Cells3 we defer resetting ephemerals because everything
; else gets deferred and we cannot /really/ reset it until
; within finish-business we are sure all users have been recalculated
; within finish-business we are sure all callers have been recalculated
; and all outputs completed.
;
; ;; good q: what does (setf <ephem> 'x) return? historically nil, but...?
Expand All @@ -71,8 +71,8 @@ See the Lisp Lesser GNU Public License for more details.
(md-slot-value-store (c-model c) (c-slot-name c) nil)
(setf (c-value c) nil)
#+notsureaboutthis
(loop for user in (c-users c)
do (calculate-and-link user)))))
(loop for caller in (c-callers c)
do (calculate-and-link caller)))))

; -----------------------------------------------------

Expand Down
118 changes: 117 additions & 1 deletion cells-manifesto.txt
Expand Up @@ -61,7 +61,8 @@ property of software development, meaning by essential that there was no
way around it, and thus his prediction that a software silver bullet was
in principle impossible.

Which brings us to Cells.
Which brings us to Cells. See also [axiom] Phillip Eby's developiong axiomatic
definition he is developing in support of Ryan Forseth's SoC project.

DEFMODEL and Slot types
-----------------------
Expand Down Expand Up @@ -392,3 +393,118 @@ One Cells user is known to have mediated a global variable with a Cell, some wor
was done on having slots of DEFSTRUCTs mediated by Cells, and ports to C++, Java, and
Python have been explored.

_______
[axiom] Phillip Eby's axiomatic specification of Cells:

Data Pulse Axioms
=================

Overview: updates must be synchronous (all changed cells are updated at
once), consistent (no cell rule sees out of date values), and minimal (only
necessary rules run).

1. Global Update Counter:
There is a global update counter. (Guarantees that there is a
globally-consistent notion of the "time" at which updates occur.)

2. Per-Cell "As Of" Value:
Every cell has a "current-as-of" update count, that is initialized with
a value that is less than the global update count will ever be.

3. Out-of-dateness:
A cell is out of date if its update count is lower than the update
count of any of the cells it depends on.

4. Out-of-date Before:
When a rule-driven cell's value is queried, its rule is only run if the
cell is out of date; otherwise a cached previous value is
returned. (Guarantees that a rule is not run unless its dependencies have
changed since the last time the rule was run.)

5. Up-to-date After:
Once a cell's rule is run (or its value is changed, if it is an input
cell), its update count must be equal to the global update
count. (Guarantees that a rule cannot run more than once per update.)

6. Inputs Move The System Forward
When an input cell changes, it increments the global update count and
stores the new value in its own update count.


Dependency Discovery Axioms
===========================

Overview: cells automatically notice when other cells depend on them, then
notify them at most once if there is a change.


1. Thread-local "current rule cell":
There is a thread-local variable that always contains the cell whose
rule is currently being evaluated in the corresponding thread. This
variable can be empty (e.g. None).

2. "Currentness" Maintenance:
While a cell rule's is being run, the variable described in #1 must be
set to point to the cell whose rule is being run. When the rule is
finished, the variable must be restored to whatever value it had before the
rule began. (Guarantees that cells will be able to tell who is asking for
their values.)

3. Dependency Creation:
When a cell is read, it adds the "currently-being evaluated" cell as a
listener that it will notify of changes.

4. Dependency Creation Order:
New listeners are added only *after* the cell being read has brought
itself up-to-date, and notified any *previous* listeners of the
change. (Ensures that the listening cell does not receive redundant
notification if the listened-to cell has to be brought up-to-date first.)

5. Dependency Minimalism:
A listener should only be added if it does not already present in the
cell's listener collection. (This isn't strictly mandatory, the system
behavior will be correct but inefficient if this requirement isn't met.)

6. Dependency Removal:
Just before a cell's rule is run, it must cease to be a listener for
any other cells. (Guarantees that a dependency from a previous update
cannot trigger an unnecessary repeated calculation.)

7. Dependency Notification
Whenever a cell's value changes (due to a rule change or input change),
it must notify all of its listeners that it has changed, in such a way that
*none* of the listeners are asked to recalculate their value until *all* of
the listeners have first been notified of the change. (This guarantees
that inconsistent views cannot occur.)

7a. Deferred Recalculation
The recalculation of listeners (not the notification of the listeners'
out-of-dateness) must be deferred if a cell's value is currently being
calculated. As soon as there are no cells being calculated, the deferred
recalculations must occur. (This guarantees that in the absence of
circular dependencies, no cell can ask for a value that's in the process of
being calculated.)

8. One-Time Notification Only
A cell's listeners are removed from its listener collection as soon as
they have been notified. In particular, the cell's collection of listeners
must be cleared *before* *any* of the listeners are asked to recalculate
themselves. (This guarantees that listeners reinstated as a side effect of
recalculation will not get a duplicate notification in the current update,
or miss a notification in a future update.)

9. Conversion to Constant
If a cell's rule is run and no dependencies were created, the cell must
become a "constant" cell, and do no further listener additions or
notification, once any necessary notifications to existing listeners are
completed. (That is, if the rule's run changed the cell's value, it must
notify its existing listeners, but then the listener collection must be
cleared -- *again*, in addition to the clearing described in #8.)

10. No Changes During Notification:
It is an error to change an input cell's value while change
notifications are taking place.

11. Weak Notification
Automatically created inter-cell links must not inhibit garbage
collection of either cell. (Technically optional, but very easy to do.)
4 changes: 2 additions & 2 deletions cells-test/df-interference.lisp
Expand Up @@ -64,7 +64,7 @@
;; - b depends on c
;;
;; if c changes, depending on the accident of the order in which a and b happened to
;; be first evaluated, a might appear before b on c's list of dependents (users). then the
;; be first evaluated, a might appear before b on c's list of dependents (callers). then the
;; following happens:
;;
;; - c triggers a
Expand Down Expand Up @@ -113,7 +113,7 @@
(trc "cell is" c)
(when (typep (cdr c) 'cell)
(print `(notifier ,c))
(dolist (u (c-users (cdr c)))
(dolist (u (c-callers (cdr c)))
(print `(___ ,u)))))
))

Expand Down
5 changes: 3 additions & 2 deletions cells-test/hello-world.lisp
Expand Up @@ -24,13 +24,14 @@

(in-package :cells)


(defmd computer ()
(happen (c-in nil) :ephemeral)
(happen (c-in nil) :cell :ephemeral)
(location (c? (case (^happen)
(:leave :away)
(:arrive :at-home)
(t .cache)))) ;; ie, unchanged
(response nil :ephemeral))
(response nil :cell :ephemeral))

(defobserver response(self new-response old-response)
(when new-response
Expand Down
1 change: 0 additions & 1 deletion cells-test/test-synapse.lisp
Expand Up @@ -22,7 +22,6 @@

(in-package :cells)


(defmodel m-syn ()
((m-syn-a :initform nil :initarg :m-syn-a :accessor m-syn-a)
(m-syn-b :initform nil :initarg :m-syn-b :accessor m-syn-b)
Expand Down
6 changes: 3 additions & 3 deletions cells-test/test.lisp
Expand Up @@ -34,14 +34,14 @@ sees stale data, etc etc
- make sure they fire when they should, and do not when they should not
- make sure they survive an evaluation by the user which does not branch to
- make sure they survive an evaluation by the caller which does not branch to
them (ie, does not access them)
- make sure they optimize away
- test with forms which access multiple other cells
- look at direct alteration of a user
- look at direct alteration of a caller
- does SETF honor not propagating, as well as a c-ruled after re-calcing
Expand Down Expand Up @@ -233,7 +233,7 @@ subclass for them?)
collect (cons sn c))))
(trc "dependencies of" self)
(loop for (sn . c) in slot-cells
do (trc "slot" sn :users (mapcar 'c-slot-name (c-users c))))))
do (trc "slot" sn :callers (mapcar 'c-slot-name (c-callers c))))))

(def-cell-test m-worst-case
(let ((m (make-instance 'm-worst-case)))
Expand Down
4 changes: 2 additions & 2 deletions cells.lisp
Expand Up @@ -64,7 +64,7 @@ See the Lisp Lesser GNU Public License for more details.
`(c-break ,fmt$ ,@fmt-args)
`(c-break "failed assertion: ~a" ',assertion)))))

(defvar *c-calculators* nil)
(defvar *call-stack* nil)

(defmacro def-c-trace (model-type &optional slot cell-type)
`(defmethod trcp ((self ,(case cell-type
Expand All @@ -76,7 +76,7 @@ See the Lisp Lesser GNU Public License for more details.
`t))))

(defmacro without-c-dependency (&body body)
`(let (*c-calculators*) ,@body))
`(let (*call-stack*) ,@body))

(define-symbol-macro .cause
(car *causation*))
Expand Down
2 changes: 1 addition & 1 deletion cells.lpr
@@ -1,4 +1,4 @@
;; -*- lisp-version: "8.0 [Windows] (May 22, 2006 0:51)"; cg: "1.81"; -*-
;; -*- lisp-version: "8.0 [Windows] (Jun 21, 2006 9:54)"; cg: "1.81"; -*-

(in-package :cg-user)

Expand Down
4 changes: 3 additions & 1 deletion defmodel.lisp
Expand Up @@ -124,6 +124,7 @@ the defmodel form for ~a" ',class ',class))))
(defun defmd-canonicalize-slot (slotname
&key
(cell nil cell-p)
(type nil type-p)
(initform nil initform-p)
(initarg (intern (symbol-name slotname) :keyword))
(documentation nil documentation-p)
Expand All @@ -135,6 +136,7 @@ the defmodel form for ~a" ',class ',class))))
(list* slotname :initarg initarg
(append
(when cell-p (list :cell cell))
(when type-p (list :type type))
(when initform-p (list :initform initform))
(when unchanged-if-p (list :unchanged-if unchanged-if))
(when reader-p (list :reader reader))
Expand All @@ -158,7 +160,7 @@ the defmodel form for ~a" ',class ',class))))
((keywordp (car spec))
(assert (find (car spec) '(:documentation :metaclass)))
(push spec class-options))
((find (cadr spec) '(:initarg :cell :initform :allocation :reader :writer :accessor :documentation))
((find (cadr spec) '(:initarg :type :cell :initform :allocation :reader :writer :accessor :documentation))
(push (apply 'defmd-canonicalize-slot spec) slots))
(t ;; shortform (slotname initform &rest slotdef-key-values)
(push (apply 'defmd-canonicalize-slot
Expand Down
2 changes: 1 addition & 1 deletion gui-geometry/defpackage.lisp
Expand Up @@ -22,7 +22,7 @@ See the Lisp Lesser GNU Public License for more details.
#:^px #:^py #:^ll #:^lt #:^lr #:^lb
#:u96ths #:udots #:uinches #:uin #:upoints #:upts #:u8ths #:u16ths #:u32nds
#:mkr #:v2-move #:l-height #:mkv2 #:^offset-within #:inset-lr #:v2-v #:v2-h
#:r-bounds
#:r-bounds #:l-box
#:lb
#:cs-target-res
#:nr-make
Expand Down
4 changes: 2 additions & 2 deletions gui-geometry/geometer.lisp
Expand Up @@ -57,8 +57,8 @@ See the Lisp Lesser GNU Public License for more details.
:lr (c? (geo-kid-wrap self 'pr))
:lb (c? (geo-kid-wrap self 'pb))))

(defun l-rect (geo)
(count-it :l-rect)
(defun l-box (geo)
(count-it :l-box)
(mkr (ll geo) (lt geo) (lr geo) (lb geo)))

;---------- gOffset -------------------
Expand Down
6 changes: 3 additions & 3 deletions initialize.lisp
Expand Up @@ -36,13 +36,13 @@ See the Lisp Lesser GNU Public License for more details.
(ephemeral-reset c))

(defmethod awaken-cell ((c c-ruled))
(let (*c-calculators*)
(let (*call-stack*)
(calculate-and-set c)))

#+cormanlisp ; satisfy CormanCL bug
(defmethod awaken-cell ((c c-dependent))
(let (*c-calculators*)
(trc nil "awaken-cell c-dependent clearing *c-calculators*" c)
(let (*call-stack*)
(trc nil "awaken-cell c-dependent clearing *call-stack*" c)
(calculate-and-set c)))

(defmethod awaken-cell ((c c-drifter))
Expand Down
4 changes: 2 additions & 2 deletions integrity.lisp
Expand Up @@ -64,7 +64,7 @@ outside computation."
(let ((*within-integrity* nil)
*unfinished-business*
*defer-changes*
*c-calculators*
*call-stack*
(*data-pulse-id* 0))
(funcall action)))

Expand Down Expand Up @@ -138,7 +138,7 @@ outside computation."
; of cells3, I coded an ephemeral cell and initialized it to non-nil, hitting a runtime
; error (now gone) saying I had no idea what a non-nil ephemeral would mean. That had been
; my conclusion when the idea occurred to me the first time, so I stuck in an assertion
; to warn off users.
; to warn off callers.
;
; But the new
; datachange progression defined by Cells3 had already forced me to manage ephemeral resets
Expand Down

0 comments on commit 4b24693

Please sign in to comment.