Skip to content

Commit 448d2e9

Browse files
committed
docs
1 parent 712847c commit 448d2e9

1 file changed

Lines changed: 59 additions & 12 deletions

File tree

src/network/quadtree.lisp

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
;;;; network/quadtree.lisp
22
;;;;
33
;;;; A stock example for a quadtree networked family of couriers in a square grid.
4+
;;;;
5+
;;;; A typical family of quadtree routers looks like:
6+
;;;;
7+
;;;; +-+-+-+-+ +---+---+ +-------+
8+
;;;; /A/B/C/D/ / / / / /
9+
;;;; +-+-+-+-+ / 1 / 2 / / /
10+
;;;; /E/F/G/H/ / / / / /
11+
;;;; +-+-+-+-+ +---+---+ / TOP /
12+
;;;; /I/J/K/L/ / / / / /
13+
;;;; +-+-+-+-+ / 3 / 4 / / /
14+
;;;; /M/N/O/P/ / / / / /
15+
;;;; +-+-+-+-+ +---+---+ +-------+
16+
;;;;
17+
;;;; where each cell contains a router which is connected to the cell immediately above it in the
18+
;;;; hierarchy (i.e., to the right) with which contains it and to all the cells immediately below it
19+
;;;; in the hierarchy (i.e., to the left) which are contained by it. The finest-grained domains
20+
;;;; (A, ..., P) with no downward links are referred to as 'leaves'.
21+
;;;;
22+
;;;; Message routing follows containments rather than spatial structure. For instance, a message
23+
;;;; sent from A to P takes the following steps:
24+
;;;; * Inspect A's routing table, which only has an upward connection. Follow it and deliver the
25+
;;;; message to 1.
26+
;;;; * Inspect 1's routing table, which has links to A, B, E, F, and upward. P is not contained in
27+
;;;; any of the downward directions, so default to the upward direction. Follow it and deliver
28+
;;;; the message to TOP.
29+
;;;; * Inspect TOP's routing table, which has links to 1, 2, 3, and 4. P is contained in 4, so
30+
;;;; deliver the message to 4.
31+
;;;; * Inspect 4's routing table, which has has links to K, L, O, P, and an upward link back to TOP.
32+
;;;; P is contained in P, so deliver the message to P.
433

534
(in-package #:aether)
635

@@ -41,18 +70,26 @@ Returns a VALUES pair: the 2d array of leaf routers (to use as the local courier
4170
(make-courier-quadtree-rectangle rectangle nil)))
4271

4372
(defun make-courier-quadtree-rectangle (rectangle parent)
44-
"Makes one quadtree router and its children."
73+
"Makes one quadtree router and its children.
74+
75+
Returns a VALUES pair: the 2d array of leaf routers (to use as the local courier for worker processes), then the list of *all* routers (to use to prime the simulator)."
76+
;; this actual routine is only responsible for generating the 'root' router.
77+
;; all the other routers in the tree are deferred to recursive calls.
4578
(with-slots ((max-x right) (max-y top) (min-x left) (min-y bottom)) rectangle
4679
(assert (<= min-x max-x))
4780
(assert (<= min-y max-y))
48-
(let ((courier (%make-courier-quadtree :links `((:otherwise ,parent))))
49-
(half-width (floor (/ (- max-x min-x) 2)))
50-
(half-height (floor (/ (- max-y min-y) 2)))
51-
subrectangles
52-
;; NOTE: this is so that :otherwise has lowest precedence order.
53-
;; could also handle this as a slot on courier-quadtree, which might be nicer.
54-
(leaf-courier-array (make-array `(,(1+ (- max-x min-x)) ,(1+ (- max-y min-y)))))
55-
(flat-courier-list '()))
81+
;; the strategy is to divide RECTANGLE up into quarters, stored in SUBRECTANGLES.
82+
;; the relevant edge case is when RECTANGLE has width or height 1, in which case subdivision
83+
;; doesn't make sense.
84+
(initialize-and-return
85+
((courier (%make-courier-quadtree :links `((:otherwise ,parent))))
86+
(half-width (floor (/ (- max-x min-x) 2)))
87+
(half-height (floor (/ (- max-y min-y) 2)))
88+
subrectangles
89+
(flat-courier-list '())
90+
;; NOTE: this is so that :otherwise has lowest precedence order.
91+
;; could also handle this as a slot on courier-quadtree, which might be nicer.
92+
(leaf-courier-array (make-array `(,(1+ (- max-x min-x)) ,(1+ (- max-y min-y))))))
5693
(cond
5794
((and (= max-x min-x) (= max-y min-y))
5895
nil)
@@ -95,29 +132,39 @@ Returns a VALUES pair: the 2d array of leaf routers (to use as the local courier
95132
:left (+ 1 min-x half-width)
96133
:bottom (+ 1 min-y half-height))))))
97134

135+
;; having partitioned RECTANGLE into SUBRECTANGLES, we:
136+
;; * recursively build sub-quadtrees for each subrectangle.
137+
;; * stash the root of each sub-quadtree for the routing table at the router we're building.
98138
(dolist (sr subrectangles)
99139
(with-slots ((submax-x right) (submax-y top) (submin-x left) (submin-y bottom)) sr
140+
;; each of these calls generates the advertised VALUES pair:
141+
;; a 2D array of leaf routers and a flat list of all routers in the subtree.
100142
(multiple-value-bind (subcourier-array subcourier-list)
101143
(make-courier-quadtree-rectangle
102144
(make-rectangle :left submin-x :right submax-x
103145
:bottom submin-y :top submax-y)
104146
courier)
147+
;; stash the routing table entry
105148
(push `(,sr ,(first subcourier-list)) (courier-quadtree-links courier))
149+
;; accrue onto the flat list of all routers
106150
(setf flat-courier-list (nconc subcourier-list flat-courier-list))
151+
;; copy the 2D array of sub-leaf-routers into the relevant subarray of leaf routers
107152
(dotimes (i (1+ (- submax-x submin-x)))
108153
(dotimes (j (1+ (- submax-y submin-y)))
109154
(setf (aref leaf-courier-array (+ submin-x i (- min-x)) (+ submin-y j (- min-y)))
110155
(aref subcourier-array i j)))))))
111156

157+
;; base case: we add the router we're constructing to the two data structures to return.
158+
;; we always belong in the flat list of all routers.
112159
(push courier flat-courier-list)
113-
;; base case: poke ourselves into the array as a leaf
160+
;; and, if we're a leaf (i.e., we have no subrectangles), we belong in the 2D array.
114161
(unless subrectangles
115162
(setf (aref leaf-courier-array 0 0) courier
116-
(courier-id courier) `(,min-x ,min-y)))
117-
(values leaf-courier-array flat-courier-list))))
163+
(courier-id courier) `(,min-x ,min-y))))))
118164

119165
(defmethod courier-courier->route ((processing-courier courier-quadtree) destination-courier-id)
120166
"Routes according to a rectangle-membership-based routing table."
167+
121168
(loop :for (rect link) :in (courier-quadtree-links processing-courier)
122169
:when (rectangle-member? rect destination-courier-id)
123170
:do (return-from courier-courier->route link))

0 commit comments

Comments
 (0)