1 ;; honey.el - Higher Order NEsted Yarnknotter --- back-end for Arxana
3 ;; Copyright (C) 2010, 2011, 2012, 2013 Raymond S. Puzio
5 ;; This program is free software: you can redistribute it and/or modify
6 ;; it under the terms of the GNU Affero General Public License as published by
7 ;; the Free Software Foundation, either version 3 of the License, or
8 ;; (at your option) any later version.
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;; GNU Affero General Public License for more details.
15 ;; You should have received a copy of the GNU Affero General Public License
16 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ;; See honey-demo.tex for background.
24 (defvar plexus-registry nil
)
26 (defun add-plexus (parent)
27 "Create a new plexus."
28 (let ((newbie (list '*plexus
*
30 (make-hash-table :test
'equal
) ; nema table
31 (make-hash-table :test
'equal
) ; forward links
32 (make-hash-table :test
'equal
) ; backward links
33 (make-hash-table :test
'equal
) ; forward labels
34 (make-hash-table :test
'equal
) ; backward labels
36 ;; Define ground and type nodes.
37 (puthash 0 '(0 0) (nth 2 newbie
))
38 (puthash 1 '(0 0) (nth 2 newbie
))
39 (puthash 0 '((0 .
0) (1 .
0)) (nth 3 newbie
))
40 (puthash 0 '((0 .
0) (1 .
0)) (nth 4 newbie
))
41 (puthash 0 '"ground" (nth 5 newbie
))
42 (puthash '"ground" 0 (nth 6 newbie
))
43 (puthash 1 '"type" (nth 5 newbie
))
44 (puthash '"type" 1 (nth 6 newbie
))
45 ;; Register the new object and return it.
46 (setq plexus-registry
(cons newbie plexus-registry
))
49 (defun remove-plexus (plex)
51 ;; Wipe out the hash tables
53 (clrhash (nth (+ i
2) plex
))) )
55 (defun show-plexus-registry ()
60 (defun set-current-plexus (plex)
61 "Examine a different plexus instead."
62 (setq current-plexus plex
))
64 (defmacro with-current-plexus
(plex &rest expr
)
65 (append `(let ((current-plexus ,plex
))) ,expr
))
67 (defun show-current-plexus ()
68 "Return the plexus currently being examined."
71 (defun reset-plexus ()
72 "Reset the database to its initial configuration."
73 ; Reset nema counter and hash tables.
74 (setcar (cdr current-plexus
) 1)
76 (clrhash (nth (+ n
2) current-plexus
)))
77 ;; Define ground and nema-type.
78 (puthash 0 '(0 0) (nth 2 current-plexus
))
79 (puthash 1 '(0 0) (nth 2 current-plexus
))
80 (puthash 0 '((0 .
0) (1 .
0)) (nth 3 current-plexus
))
81 (puthash 0 '((0 .
0) (1 .
0)) (nth 4 current-plexus
))
82 (puthash 0 '"ground" (nth 5 current-plexus
))
83 (puthash '"ground" 0 (nth 6 current-plexus
))
84 (puthash 1 '"nema-type" (nth 5 current-plexus
))
85 (puthash '"nema-type" 1 (nth 6 current-plexus
))
88 ;; (defun next-unique-id ()
89 ;; "Produce a yet unused unique identifier."
90 ;; (setcar (cdr current-plexus)
91 ;; (1+ (cadr current-plexus))))
95 (defun download-en-masse ()
96 "Produce a representation of the database as quintuples."
98 (maphash (lambda (uid tplt
)
100 (let ((src (car tplt
))
102 (txt (nthcdr 2 tplt
)))
103 ; Obtain next label if exists.
104 (setq lbl
(gethash uid
105 (nth 5 current-plexus
)
107 ; Write data to list.
108 (setq plex
(cons `(,uid
,lbl
,src
,snk .
,txt
)
110 (nth 2 current-plexus
))
111 ; Return list of data.
114 (defun upload-en-masse (plex)
115 "Load a representation of a database as quintuples into memory."
116 (dolist (qplt plex t
)
118 (let ((uid (car qplt
))
122 (txt (nthcdr 4 qplt
)))
126 (nth 2 current-plexus
))
129 (gethash src
(nth 3 current-plexus
) nil
))
130 (nth 3 current-plexus
))
134 (gethash snk
(nth 4 current-plexus
) nil
))
135 (nth 4 current-plexus
))
138 (puthash uid lbl
(nth 5 current-plexus
))
139 (puthash lbl uid
(nth 6 current-plexus
))))
140 ; Bump up nema counter if needed.
141 (when (> uid
(cadr current-plexus
))
142 (setcar (cdr current-plexus
) uid
)))))
144 (defun add-en-masse (plex)
145 "Add multiple nemata given as list of quartuplets."
146 (mapcar (lambda (qplt)
147 (let ((uid next-unique-id
))
148 (put-nema (nth 1 plex
)
151 (label-nema uid
(car qplt
))))
154 ;; Individual operations.
156 (defun add-nema (src snk txt
)
157 "Enter a new nema to the database."
158 (let ((uid (next-unique-id)))
159 ;; Add record to nema table.
162 (nth 2 current-plexus
))
163 ;; Add record to list of forward links of source.
166 (gethash src
(nth 3 current-plexus
) nil
))
167 (nth 3 current-plexus
))
168 ;; Add record to list of backward links of sink.
172 (gethash snk
(nth 4 current-plexus
) nil
))
173 (nth 4 current-plexus
))
174 ;; Return the id of the new nema.
177 (defun get-content (uid)
178 "Return the content of the nema."
179 (cddr (gethash uid
(nth 2 current-plexus
))))
181 (defun get-source (uid)
182 "Return the source of the nema."
183 (car (gethash uid
(nth 2 current-plexus
))))
185 (defun get-sink (uid)
186 "Return the sink of the nema."
187 (cadr (gethash uid
(nth 2 current-plexus
))))
189 (defun update-content (uid txt
)
190 "Replace the content of the nema."
192 (let ((x (gethash uid
(nth 2 current-plexus
))))
193 `(,(car x
) ; old source
194 ,(cadr x
) .
; old sink
196 (nth 2 current-plexus
)))
198 (defun update-source (uid new-src
)
199 "Replace the source of the nema."
200 (let* ((x (gethash uid
(nth 2 current-plexus
)))
201 (old-src (car x
)) ; extract current source
202 (old-snk (cadr x
)) ; extract current sink
203 (old-txt (cddr x
))) ; extract current content
204 ;; Update the entry in the nema table.
206 `(,new-src
,old-snk .
,old-txt
)
207 (nth 2 current-plexus
))
208 ;; Remove the entry with the old source in the
209 ;; forward link table. If that is the only entry
210 ;; filed under old-src, remove it from table.
211 (let ((y (delete `(,uid .
,old-snk
)
213 (nth 3 current-plexus
)
216 (puthash old-src y
(nth 3 current-plexus
))
217 (remhash old-src
(nth 3 current-plexus
))))
218 ;; Add an entry with the new source in the
219 ;; forward link table.
221 (cons `(,uid .
,old-snk
)
222 (gethash old-src
(nth 3 current-plexus
) nil
))
223 (nth 3 current-plexus
))
224 ;; Update the entry in the backward link table.
226 (cons `(,uid .
,new-src
)
227 (delete `(,uid .
,old-src
)
229 (nth 4 current-plexus
)
231 (nth 4 current-plexus
))))
233 (defun update-sink (uid new-snk
)
234 "Change the sink of the nema."
235 (let* ((x (gethash uid
(nth 2 current-plexus
)))
236 (old-src (car x
)) ; extract current source
237 (old-snk (cadr x
)) ; extract current sink
238 (old-txt (cddr x
))) ; extract current content
239 ; Update the entry in the nema table.
241 `(,old-src
,new-snk .
,old-txt
)
242 (nth 2 current-plexus
))
243 ;; Remove the entry with the old sink in the
244 ;; backward link table. If that is the only entry
245 ;; filed under old-src, remove it from table.
246 (let ((y (delete `(,uid .
,old-src
)
248 (nth 4 current-plexus
)
251 (puthash old-snk y
(nth 4 current-plexus
))
252 (remhash old-snk
(nth 4 current-plexus
))))
253 ;; Add an entry with the new source in the
254 ;; backward link table.
256 (cons `(,uid .
,old-src
)
258 (nth 4 current-plexus
)
260 (nth 4 current-plexus
))
261 ;; Update the entry in the forward link table.
263 (cons `(,uid .
,new-snk
)
264 (delete `(,uid .
,old-snk
)
266 (nth 3 current-plexus
)
268 (nth 3 current-plexus
))))
270 (defun remove-nema (uid)
271 "Remove this nema from the database."
272 (let ((old-src (car (gethash uid
(nth 2 current-plexus
))))
273 (old-snk (cadr (gethash uid
(nth 2 current-plexus
)))))
274 ;; Remove forward link created by nema.
275 (let ((new-fwd (delete `(,uid .
,old-snk
)
276 (gethash old-src
(nth 3 current-plexus
)))))
278 (puthash old-src new-fwd
(nth 3 current-plexus
))
279 (remhash old-src
(nth 3 current-plexus
))))
280 ;; Remove backward link created by nema.
281 (let ((new-bkw (delete `(,uid .
,old-src
)
282 (gethash old-snk
(nth 4 current-plexus
)))))
284 (puthash old-snk new-bkw
(nth 4 current-plexus
))
285 (remhash old-snk
(nth 4 current-plexus
))))
286 ;; Remove record from nema table.
287 (remhash uid
(nth 2 current-plexus
))))
289 (defun get-forward-links (uid)
290 "Return all links having given object as source."
291 (mapcar 'car
(gethash uid
(nth 3 current-plexus
))))
293 (defun get-backward-links (uid)
294 "Return all links having given object as sink."
295 (mapcar 'car
(gethash uid
(nth 4 current-plexus
))))
299 (defun label-nema (uid label
)
300 "Assign the label to the given object."
301 (puthash uid label
(nth 5 current-plexus
))
302 (puthash label uid
(nth 6 current-plexus
)))
304 (defun label2uid (label)
305 "Return the unique identifier corresponding to a label."
306 (gethash label
(nth 6 current-plexus
) nil
))
308 (defun uid2label (uid)
309 "Return the label associated to a unique identifier."
310 (gethash uid
(nth 5 current-plexus
) nil
))
315 "Is this a valid uid?"
317 (not (eq z
(gethash uid
(nth 2 current-plexus
) z
)))))
320 "List of all valid uid's."
321 (maphash (lambda (key val
) key
)
322 (nth 2 current-plexus
)))
324 (defun ground-p (uid)
325 "Is this nema the ground?"
328 (defun source-p (x y
)
329 "Is the former nema the sink of the latter?"
330 (equal x
(get-source y
)))
333 "Is the former nema the sink of the latter?"
334 (equal x
(get-sink y
)))
336 (defun links-from (x y
)
337 "Return all links from nema x to nema y."
338 (filter '(lambda (z) (source-p x z
))
339 (get-backward-links y
)))
342 "Does nema x link to nema y?"
343 (when (member x
(mapcar
345 (get-backward-links y
)))
348 (defun triple-p (x y z
)
349 "Do the three items form a triplet?"
354 "Is this object a plexus?"
357 (equal (car x
) "*plexus*")))
361 (setq ans
(and ans
(hash-table-p