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 (defun new-net (parent)
25 "Create a new network."
26 (let ((newbie (list '*network
*
28 (make-hash-table :test
'equal
) ; article table
29 (make-hash-table :test
'equal
) ; forward links
30 (make-hash-table :test
'equal
) ; backward links
31 (make-hash-table :test
'equal
) ; forward labels
32 (make-hash-table :test
'equal
) ; backward labels
34 ; Define ground and article-type.
35 (puthash 0 '(0 0) (nth 2 newbie
))
36 (puthash 1 '(0 0) (nth 2 newbie
))
37 (puthash 0 '((0 .
0) (1 .
0)) (nth 3 newbie
))
38 (puthash 0 '((0 .
0) (1 .
0)) (nth 4 newbie
))
39 (puthash 0 '"ground" (nth 5 newbie
))
40 (puthash '"ground" 0 (nth 6 newbie
))
41 (puthash 1 '"article-type" (nth 5 newbie
))
42 (puthash '"article-type" 1 (nth 6 newbie
))
48 "Examine a different network instead."
49 (setq current-net net
))
51 (defmacro with-current-net
(net &rest expr
)
52 (append `(let ((current-net ,net
))) ,expr
))
55 "Return the network currently being examined."
59 "Reset the database to its initial configuration."
60 ; Reset article counter and hash tables.
61 (setcar (cdr current-net
) 1)
62 (dotimes (n 5) (clrhash (nth (+ n
2) current-net
)))
63 ; Define ground and article-type.
64 (puthash 0 '(0 0) (nth 2 current-net
))
65 (puthash 1 '(0 0) (nth 2 current-net
))
66 (puthash 0 '((0 .
0) (1 .
0)) (nth 3 current-net
))
67 (puthash 0 '((0 .
0) (1 .
0)) (nth 4 current-net
))
68 (puthash 0 '"ground" (nth 5 current-net
))
69 (puthash '"ground" 0 (nth 6 current-net
))
70 (puthash 1 '"article-type" (nth 5 current-net
))
71 (puthash '"article-type" 1 (nth 6 current-net
))
74 (defun next-unique-id ()
75 "Produce a yet unused unique identifier."
76 (setcar (cdr current-net
)
77 (1+ (cadr current-net
))))
79 (defun download-en-masse ()
80 "Produce a representation of the database as quintuples."
82 (maphash '(lambda (uid tplt
)
84 (let ((src (car tplt
))
86 (txt (nthcdr 2 tplt
)))
87 ; Obtain next label if exists.
88 (setq lbl
(gethash uid
92 (setq net
(cons `(,uid
,lbl
,src
,snk .
,txt
)
95 ; Return list of data.
98 (defun upload-en-masse (net)
99 "Load a representation of a database as quintuples into memory."
102 (let ((uid (car qplt
))
106 (txt (nthcdr 4 qplt
)))
113 (gethash src
(nth 3 current-net
) nil
))
118 (gethash snk
(nth 4 current-net
) nil
))
122 (puthash uid lbl
(nth 5 current-net
))
123 (puthash lbl uid
(nth 6 current-net
))))
124 ; Bump up article counter if needed.
125 (when (> uid
(cadr current-net
))
126 (setcar (cdr current-net
) uid
)))))
128 (defun add-en-masse (net)
129 "Add multiple articles given as list of quartuplets."
130 (mapcar '(lambda (qplt)
131 (let ((uid next-unique-id
))
132 (put-article (nth 1 net
)
135 (label-article uid
(car qplt
))))
138 (defun put-article (src snk txt
)
139 "Enter a new article to the database."
140 (let ((uid (next-unique-id)))
141 ; Add record to article table.
145 ; Add record to list of forward links of source.
148 (gethash src
(nth 3 current-net
) nil
))
150 ; Add record to list of backward links of sink.
154 (gethash snk
(nth 4 current-net
) nil
))
158 (defun get-content (uid)
159 "Return the content of the article."
160 (cddr (gethash uid
(nth 2 current-net
))))
162 (defun get-source (uid)
163 "Return the source of the article."
164 (car (gethash uid
(nth 2 current-net
))))
166 (defun get-sink (uid)
167 "Return the sink of the article."
168 (cadr (gethash uid
(nth 2 current-net
))))
170 (defun update-content (uid txt
)
171 "Replace the ontent of the article."
173 (let ((x (gethash uid
(nth 2 current-net
))))
174 `(,(car x
) ; old source
175 ,(cadr x
) .
; old sink
177 (nth 2 current-net
)))
179 (defun update-source (uid new-src
)
180 "Replace the source of the article."
181 (let* ((x (gethash uid
(nth 2 current-net
)))
182 (old-src (car x
)) ; extract current source
183 (old-snk (cadr x
)) ; extract current sink
184 (old-txt (cddr x
))) ; extract current content
185 ; Update the entry in the article table.
187 `(,new-src
,old-snk .
,old-txt
)
189 ; Remove the entry with the old source in the
190 ; forward link table. If that is the only entry
191 ; filed under old-src, remove it from table.
192 (let ((y (delete `(,uid .
,old-snk
)
193 (gethash old-src
(nth 3 current-net
) nil
))))
195 (puthash old-src y
(nth 3 current-net
))
196 (remhash old-src
(nth 3 current-net
))))
197 ; Add an entry with the new source in the
198 ; forward link table.
200 (cons `(,uid .
,old-snk
)
201 (gethash old-src
(nth 3 current-net
) nil
))
203 ; Update the entry in the backward link table.
205 (cons `(,uid .
,new-src
)
206 (delete `(,uid .
,old-src
)
207 (gethash old-src
(nth 4 current-net
) nil
)))
208 (nth 4 current-net
))))
210 (defun update-sink (uid new-snk
)
211 "Chane the sink of the article."
212 (let* ((x (gethash uid
(nth 2 current-net
)))
213 (old-src (car x
)) ; extract current source
214 (old-snk (cadr x
)) ; extract current sink
215 (old-txt (cddr x
))) ; extract current content
216 ; Update the entry in the article table.
218 `(,old-src
,new-snk .
,old-txt
)
220 ; Remove the entry with the old sink in the
221 ; backward link table. If that is the only entry
222 ; filed under old-src, remove it from table.
223 (let ((y (delete `(,uid .
,old-src
)
224 (gethash old-snk
(nth 4 current-net
) nil
))))
226 (puthash old-snk y
(nth 4 current-net
))
227 (remhash old-snk
(nth 4 current-net
))))
228 ; Add an entry with the new source in the
229 ; backward link table.
231 (cons `(,uid .
,old-src
)
232 (gethash old-snk
(nth 4 current-net
) nil
))
234 ; Update the entry in the forward link table.
236 (cons `(,uid .
,new-snk
)
237 (delete `(,uid .
,old-snk
)
238 (gethash old-src
(nth 3 current-net
) nil
)))
239 (nth 3 current-net
))))
241 (defun remove-article (uid)
242 "Remove this article from the database."
243 (let ((old-src (car (gethash uid
(nth 2 current-net
))))
244 (old-snk (cadr (gethash uid
(nth 2 current-net
)))))
245 ; Remove forward link created by article.
246 (let ((new-fwd (delete `(,uid .
,old-snk
)
247 (gethash old-src
(nth 3 current-net
)))))
249 (puthash old-src new-fwd
(nth 3 current-net
))
250 (remhash old-src
(nth 3 current-net
))))
251 ; Remove backward link created by article.
252 (let ((new-bkw (delete `(,uid .
,old-src
)
253 (gethash old-snk
(nth 4 current-net
)))))
255 (puthash old-snk new-bkw
(nth 4 current-net
))
256 (remhash old-snk
(nth 4 current-net
))))
257 ; Remove record from article table.
258 (remhash uid
(nth 2 current-net
))))
260 (defun get-forward-links (uid)
261 "Return all links having given object as source."
262 (mapcar 'car
(gethash uid
(nth 3 current-net
))))
264 (defun get-backward-links (uid)
265 "Return all links having given object as sink."
266 (mapcar 'car
(gethash uid
(nth 4 current-net
))))
268 (defun label-article (uid label
)
269 "Assign the label to the given object."
270 (puthash uid label
(nth 5 current-net
))
271 (puthash label uid
(nth 6 current-net
)))
273 (defun label2uid (label)
274 "Return the unique identifier corresponding to a label."
275 (gethash label
(nth 6 current-net
) nil
))
277 (defun uid2label (uid)
278 "Return the label associated to a unique identifier."
279 (gethash uid
(nth 5 current-net
) nil
))
283 (defun ground-p (uid)
284 "Is this article the ground?"
287 (defun source-p (x y
)
288 "Is the former article the sink of the latter?"
289 (equal x
(get-source y
)))
292 "Is the former article the sink of the latter?"
293 (equal x
(get-sink y
)))
295 (defun links-from (x y
)
296 "Return all links from article x to artice y."
297 (filter '(lambda (z) (source-p x z
))
298 (get-backward-links y
)))
301 "Does article x link to article y?"
302 (when (member x
(mapcar
304 (get-backward-links y
))) t
))
306 (defun triple-p (x y z
)
307 "Do the three articles form a triplet?"
312 "Is this object a network?"
315 (equal (car x
) "*network*")))
319 (setq ans
(and ans
(hash-table-p
323 (defmacro search
(vars prop
)
324 "Find all n-tuplets satisfying a condition"
325 ; Surround the search within dolist loops on free variables.
326 (let ((foo '(lambda (vars cmnd
)
329 `(dolist (,(car vars
) uids
)
330 ,(funcall foo
(cdr vars
) cmnd
))
331 ; Wrap no further when finished.
333 (funcall foo vars prop
)))