initial (very spare) draft of the FARM talk
[arxana.git] / latex / arxana-merge.tex
blob7033c03d0aeb423152c32eeb344aa5792550f301
1 %;; Copyright (C) 2005-2017 Joe Corneli <holtzermann17@gmail.com>
2 %;; Copyright (C) 2010-2017 Ray Puzio <rsp@novres.org>
4 %;; This program is free software: you can redistribute it and/or modify
5 %;; it under the terms of the GNU Affero General Public License as published by
6 %;; the Free Software Foundation, either version 3 of the License, or
7 %;; (at your option) any later version.
8 %;;
9 %;; This program is distributed in the hope that it will be useful,
10 %;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 %;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 %;; GNU Affero General Public License for more details.
13 %;;
14 %;; You should have received a copy of the GNU Affero General Public License
15 %;; along with this program. If not, see <http://www.gnu.org/licenses/>.
17 %% (defun load-arxana ()
18 %% (interactive)
19 %% (find-file "~/arxana/latex/arxana-merge.tex")
20 %% (save-excursion
21 %% (goto-char (point-max))
22 %% (let ((beg (progn (search-backward "\\begin{verbatim}")
23 %% (match-end 0)))
24 %% (end (progn (search-forward "\\end{verbatim}")
25 %% (match-beginning 0))))
26 %% (eval-region beg end)
27 %% (lit-eval)
28 %% (autoimport-arxana)
29 %% (pick-a-name))))
31 %%% Commentary:
33 %% To load: remove %'s above and evaluate with C-x C-e, then run M-x load-arxana RET
35 %% Alternatively, run this:
36 % head -n 29 arxana-merge.tex | sed -e "/%* \{0,1\}/s///" > arxana-loader.el
37 %% on the command line to produce something you can use
38 %% to load Arxana when you start Emacs:
39 % emacs -l arxana-loader.el
41 %% Or put the expression in your ~/.emacs
43 %% Or search for a similar form below and evaluate there!
45 %%% Code:
47 \documentclass{article}
48 %\usepackage{showframe}
50 \usepackage[T1]{fontenc}
51 \usepackage{textcomp}
53 \usepackage{hyperref}
54 \usepackage{amsmath}
55 \usepackage{amsthm}
56 \usepackage{verbatim}
57 \usepackage{url}
59 \usepackage{makeidx}
60 \makeindex
61 \usepackage{idxlayout}
63 \newcommand{\todo}[1]{\footnote{\bf TODO: #1}}
64 \newcommand{\meta}[1]{$\langle${\it #1}$\rangle$}
66 \theoremstyle{definition}
67 \newtheorem{nota}{Note}[section]
69 \parindent = 1.2em
71 \newenvironment{notate}[1]
72 {\index{#1}%
73 \begin{nota}[{\bf {\em #1}}]}%
74 {\end{nota}}
76 \makeatletter
77 \newenvironment{elisp}
78 {\let\ORGverbatim@font\verbatim@font
79 \def\verbatim@font{\ttfamily\scshape}%
80 \verbatim}
81 {\endverbatim
82 \let\verbatim@font\ORGverbatim@font}
83 \makeatother
85 \makeatletter
86 \newenvironment{idea}
87 {\let\ORGverbatim@font\verbatim@font
88 \def\verbatim@font{\ttfamily\slshape}%
89 \verbatim}
90 {\endverbatim
91 \let\verbatim@font\ORGverbatim@font}
92 \makeatother
94 \usepackage{newverbs}
95 \newcommand{\verbal}{\collectverb{\scshape}}
97 \begin{document}
99 \title{\emph{Arxana 2017}}
101 \author{Joseph Corneli \& Raymond Puzio\thanks{Copyright (C) 2005-2017
102 Joseph Corneli {\tt <holtzermann17@gmail.com>}\newline
103 Copyright (C) 2010-2017 Raymond Puzio {\tt <rsp@novres.org>}\newline
104 $\longrightarrow$ transferred to the public domain.}}
105 \date{Last revised: \today}
107 \maketitle
109 \abstract{A tool for building hackable semantic hypertext platforms.
110 An overview and link to our source code repository is at {\tt
111 http://arxana.net}.}
113 \tableofcontents
115 \section{Introduction}
117 \begin{notate}{What is ``Arxana''?} \label{arxana}
118 \emph{Arxana} is the name of a ``next generation'' hypertext system
119 that emphasizes annotation. Every object in this system is
120 annotatable. Because of this, our first name for the program ``the
121 scholium system'', but ``Arxana'' better reflects our aim: to explore
122 the mysterious world of links, attachments, correspondences, and
123 side-effects. This edition of the program relies entirely on Emacs
124 for storage and display, and integrates a backend storage mechanism
125 devised by Ray Puzio, and frontend interactions from earlier
126 prototypes by Joe Corneli, and (in Section \ref{farm-demo}) a new
127 application to modelling mathematical dialogues jointly developed by
128 both authors. Previous versions contain often excessive but
129 sometimes interesting discussion of ideas for future work.
130 Such discussion has been kept to a minimum here.
131 \end{notate}
133 \begin{notate}{Using the program}
134 If you are looking at the source version of this document
135 in Emacs, evaluate the following s-expression (type
136 \emph{C-x C-e} with the cursor positioned just after its
137 final parenthesis). This prepares the Emacs environment
138 for interactive use. (The code that achieves this is
139 in Appendix \ref{appendix-lit}.)
141 \begin{idea}
142 (save-excursion
143 (let ((beg (search-forward "\\begin{verbatim}"))
144 (end (progn (search-forward "\\end{verbatim}")
145 (match-beginning 0))))
146 (eval-region beg end)
147 (lit-process)))
148 \end{idea}
150 If you are looking at this in a PDF or printout, you will see that the
151 document has a ``literate'' style. That is, it can be read as text,
152 not just as code. In Section \ref{frontend}, we define functions that
153 allow the user to read and revise the contents of this document as
154 hypertext.
155 \end{notate}
157 \section{Backend}
159 \begin{notate}{Overview of the backend}
160 This backend is a Higher Order NEtwork Yarnknotter or HONEY for short.
161 It stores a \emph{network} of quintuplets of the form {\tt(uid label
162 source sink . content)}. One such quintuplet is called a
163 \emph{nema}. The structure of an individual nema is as follows: The
164 {\tt uid} is a numeric identifier that is unique on a network
165 basis. The {\tt label} is an (optional) string that corresponds
166 uniquely to the uid. The {\tt source} is the nema (identified by
167 uid) to the ``left'' of our quintuplet, and the {\tt sink} is the
168 uid to the ``right'' of our quintuplet. One or both may be {\tt
169 0}, and in case both are, the nema is understood to be a
170 \emph{node}. Lastly, the nema's {\tt content} can be any Lisp
171 object -- including another nema in the same network or another
172 network.\todo{(Check this last statement...)}
173 \end{notate}
175 \subsection{Preliminaries}
177 \begin{notate}{Some preliminaries}
178 We define several simple preliminary functions that we use later on.
179 \end{notate}
181 \begin{notate}{Required packages}
182 We use the Common Lisp compatibility functions.
183 \end{notate}
185 \begin{elisp}
186 (require 'cl)
187 \end{elisp}
189 \begin{notate}{On `filter'}
190 This is a useful utility to filter elements of a list satisfying a condition.
191 Returns the subset of stuff which satisfies the predicate pred.
192 \end{notate}
194 \begin{elisp}
195 (defun filter (pred stuff)
196 (let ((ans nil))
197 (dolist (item stuff (reverse ans))
198 (if (funcall pred item)
199 (setq ans (cons item ans))
200 nil))))
201 \end{elisp}
203 \begin{idea}
204 (filter '(lambda (x) (= (% x 2) 1)) '(1 2 3 4 5 6 7))
205 => (1 3 5 7)
206 \end{idea}
208 \begin{notate}{On `intersection'}
209 Set-theoretic intersection operation. More general than the version
210 coming from the `cl' package.
211 \end{notate}
213 \begin{elisp}
214 (defun intersection (&rest arg)
215 (cond ((null arg) nil)
216 ((null (cdr arg)) (car arg))
217 (t (let ((ans nil))
218 (dolist (elmt (car arg) ans)
219 (let ((remainder (cdr arg)))
220 (while (and remainder
221 (member elmt (car remainder)))
222 (setq remainder (cdr remainder))
223 (when (null remainder)
224 (setq ans (cons elmt ans))))))))))
225 \end{elisp}
227 \begin{idea}
228 (intersection '(a b c d e f g h j)
229 '(a b h j k)
230 '(b d g h j k))
231 => (j h b)
232 \end{idea}
234 \begin{notate}{On `mapply'}
235 Map and apply rolled into one.
236 \end{notate}
237 \begin{elisp}
238 (defun mapply (f l)
239 (if (member nil l) nil
240 (cons (apply f (mapcar 'car l))
241 (mapply f (mapcar 'cdr l)))))
242 \end{elisp}
244 \begin{idea}
245 (mapply '+ '((1 2) (3 4)))
246 => (4 6)
247 \end{idea}
249 \begin{notate}{On `sublis'}
250 Substitute objects in a list.
251 \end{notate}
253 \begin{elisp}
254 (defun sublis (sub lis)
255 (cond
256 ((null lis) nil)
257 ((assoc lis sub) (cadr (assoc lis sub)))
258 ((atom lis) lis)
259 (t (cons (sublis sub (car lis))
260 (sublis sub (cdr lis))))))
261 \end{elisp}
263 \subsection{Core definitions}
265 \begin{notate}{HONEY set up}
266 These variables are needed for a coherent set-up.\todo{Explain
267 what they will do.}
268 \end{notate}
270 \begin{elisp}
271 (defvar plexus-registry '(0 nil))
272 (defvar current-plexus nil)
273 \end{elisp}
275 \begin{notate}{The `add-plexus' function} \label{the-new-net-function}
276 We use this create a new plexus for storage. It defines a
277 counter (beginning at 1), together with several hash tables that allow
278 efficient access to the plexus' contents: an article table, forward
279 links, backward links, forward labels, and backward labels.
280 Additionally, it defines a ``ground'' and
281 ``type'' nodes.\todo{Explain these things in more detail.}\todo{NB. it could be useful
282 to maintain a registry available networks, by analogy with
283 Emacs's `buffer-list', which
284 I think could be done if we use `cl-defstruct' below
285 instead of `list', and set up the constructor suitably
286 (info \textquotedbl(cl) Structures\textquotedbl).}
287 \end{notate}
289 \begin{elisp}
290 (defun add-plexus ()
291 "Create a new plexus."
292 (let ((newbie (list '*plexus*
293 1 ; nema counter
294 (make-hash-table :test 'equal) ; nema table
295 (make-hash-table :test 'equal) ; forward links
296 (make-hash-table :test 'equal) ; backward links
297 (make-hash-table :test 'equal) ; forward labels
298 (make-hash-table :test 'equal) ; backward labels
299 (car plexus-registry))))
300 ;; Define ground and type nodes.
301 (puthash 0 '(0 0) (nth 2 newbie))
302 (puthash 1 '(0 0) (nth 2 newbie))
303 (puthash 0 '((0 . 0) (1 . 0)) (nth 3 newbie))
304 (puthash 0 '((0 . 0) (1 . 0)) (nth 4 newbie))
305 (puthash 0 '"ground" (nth 5 newbie))
306 (puthash '"ground" 0 (nth 6 newbie))
307 (puthash 1 '"type" (nth 5 newbie))
308 (puthash '"type" 1 (nth 6 newbie))
309 ;; Register the new object and return it.
310 (setq plexus-registry
311 (append
312 `(,(+ (car plexus-registry) 1)
313 ,newbie)
314 (cdr plexus-registry)))
315 newbie))
316 \end{elisp}
318 \begin{notate}{The ``remove-plexus'' function}
319 When we're done with our plexus, we should tidy up after ourselves.
320 \end{notate}
322 \begin{elisp}
323 (defun remove-plexus (plex)
324 "Remove a plexus."
325 ;; Wipe out the hash tables
326 (dotimes (i 5)
327 (clrhash (nth (+ i 2) plex)))
328 ;; Remove the entry from the registry.
329 (setq plexus-registry
330 (cons
331 (car plexus-registry)
332 (delete
333 (assoc (nth 7 plex)
334 (cdr plexus-registry))
335 (cdr plexus-registry)))))
336 \end{elisp}
338 \begin{elisp}
339 (defun show-plexus-registry ()
340 plexus-registry)
341 \end{elisp}
343 \begin{notate}{Network selection}
344 We can work with several networks, only one of
345 which is ``current'' at any given time.
346 \end{notate}
348 \begin{elisp}
349 (defun set-current-plexus (plex)
350 "Examine a different plexus instead."
351 (setq current-plexus plex))
353 (defmacro with-current-plexus (plex &rest expr)
354 (declare (debug (&rest form)))
355 (append `(let ((current-plexus ,plex))) expr))
357 (defun show-current-plexus ()
358 "Return the plexus currently being examined."
359 current-plexus)
360 \end{elisp}
362 \begin{notate}{On `next-unique-id'}
363 Increment the identifier that tells us how many nemas are in our network.
364 \end{notate}
366 \begin{elisp}
367 (defun next-unique-id ()
368 "Produce a yet unused unique identifier."
369 (1+ (cadr current-plexus)))
370 \end{elisp}
372 \begin{notate}{On `reset-plexus'}
373 Reset article counter and hash tables. Redefine ``ground'' and
374 ``article-type''.
375 \end{notate}
377 \begin{elisp}
378 (defun reset-plexus ()
379 "Reset the database to its initial configuration."
380 ; Reset nema counter and hash tables.
381 (setcar (cdr current-plexus) 1)
382 (dotimes (n 5)
383 (clrhash (nth (+ n 2) current-plexus)))
384 ;; Define ground and nema-type.
385 (puthash 0 '(0 0) (nth 2 current-plexus))
386 (puthash 1 '(0 0) (nth 2 current-plexus))
387 (puthash 0 '((0 . 0) (1 . 0)) (nth 3 current-plexus))
388 (puthash 0 '((0 . 0) (1 . 0)) (nth 4 current-plexus))
389 (puthash 0 '"ground" (nth 5 current-plexus))
390 (puthash '"ground" 0 (nth 6 current-plexus))
391 (puthash 1 '"type" (nth 5 current-plexus))
392 (puthash '"type" 1 (nth 6 current-plexus))
393 nil)
394 \end{elisp}
396 \subsection{Individual Operations}
398 \begin{notate}{On `add-nema'}
399 Add record to article table.
400 Add record to list of forward links of source.
401 Add record to list of backward links of sink.
402 Return the id of the new article.\todo{Should we add an alias `add-triple'
403 for this function, to make it more clear that our middle/frontend
404 is not implementation specific?}
405 \end{notate}
407 \begin{elisp}
408 (defun add-nema (src txt snk)
409 "Enter a new nema to the database."
410 (let ((uid (next-unique-id)))
411 ;; Add record to nema table.
412 (puthash uid
413 `(,src ,snk . ,txt)
414 (nth 2 current-plexus))
415 ;; Add record to list of forward links of source.
416 (puthash src
417 (cons `(,uid . ,snk)
418 (gethash src (nth 3 current-plexus) nil))
419 (nth 3 current-plexus))
420 ;; Add record to list of backward links of sink.
421 (puthash snk
422 (cons
423 `(,uid . ,src)
424 (gethash snk (nth 4 current-plexus) nil))
425 (nth 4 current-plexus))
426 ;; Update the counter for long-term storage
427 (setcar (cdr current-plexus) uid)
428 ;; Return the id of the new nema.
429 uid))
430 \end{elisp}
432 \begin{notate}{Retrieving elements of a nema} \label{retrieving-elements}
433 These functions exist to get the relevant components
434 of a nema, given its uid.
435 \end{notate}
437 \begin{elisp}
438 (defun get-content (uid)
439 "Return the content of the nema."
440 (cddr (gethash uid (nth 2 current-plexus))))
442 (defun get-source (uid)
443 "Return the source of the nema."
444 (car (gethash uid (nth 2 current-plexus))))
446 (defun get-sink (uid)
447 "Return the sink of the nema."
448 (cadr (gethash uid (nth 2 current-plexus))))
450 (defun get-triple (uid)
451 (list (get-source uid)
452 (get-content uid)
453 (get-sink uid)))
454 \end{elisp}
456 \begin{notate}{On `update-content'}
457 old source
458 old sink
459 new content
460 \end{notate}
462 \begin{elisp}
463 (defun update-content (uid txt)
464 "Replace the content of the nema."
465 (puthash uid
466 (let ((x (gethash uid (nth 2 current-plexus))))
467 `(,(car x) ; old source
468 ,(cadr x) . ; old sink
469 ,txt)) ; new content
470 (nth 2 current-plexus)))
471 \end{elisp}
473 \begin{notate}{On `update-source'}
474 Extract current source.
475 Extract current sink.
476 Extract current content.
477 Update the entry in the article table.
478 Remove the entry with the old source in the
479 forward link table. If that is the only entry
480 filed under old-src, remove it from table.
481 Add an entry with the new source in the
482 forward link table.
483 Update the entry in the backward link table.
484 \end{notate}
486 \begin{elisp}
487 (defun update-source (uid new-src)
488 "Replace the source of the nema."
489 (let* ((x (gethash uid (nth 2 current-plexus)))
490 (old-src (car x)) ; extract current source
491 (old-snk (cadr x)) ; extract current sink
492 (old-txt (cddr x))) ; extract current content
493 ;; Update the entry in the nema table.
494 (puthash uid
495 `(,new-src ,old-snk . ,old-txt)
496 (nth 2 current-plexus))
497 ;; Remove the entry with the old source in the
498 ;; forward link table. If that is the only entry
499 ;; filed under old-src, remove it from table.
500 (let ((y (delete `(,uid . ,old-snk)
501 (gethash old-src
502 (nth 3 current-plexus)
503 nil))))
504 (if y
505 (puthash old-src y (nth 3 current-plexus))
506 (remhash old-src (nth 3 current-plexus))))
507 ;; Add an entry with the new source in the
508 ;; forward link table.
509 (puthash new-src
510 (cons `(,uid . ,old-snk)
511 (gethash old-src (nth 3 current-plexus) nil))
512 (nth 3 current-plexus))
513 ;; Update the entry in the backward link table.
514 (puthash old-snk
515 (cons `(,uid . ,new-src)
516 (delete `(,uid . ,old-src)
517 (gethash old-src
518 (nth 4 current-plexus)
519 nil)))
520 (nth 4 current-plexus))))
521 \end{elisp}
523 \begin{notate}{On `update-sink'} \label{update-sink}
524 Extract current source.
525 Extract current sink.
526 Extract current content.
527 Update the entry in the article table.
528 Remove the entry with the old sink in the
529 backward link table. If that is the only entry
530 filed under old-src, remove it from table.
531 Add an entry with the new source in the
532 backward link table.
533 Update the entry in the forward link table.
534 \end{notate}
536 \begin{elisp}
537 (defun update-sink (uid new-snk)
538 "Change the sink of the nema."
539 (let* ((x (gethash uid (nth 2 current-plexus)))
540 (old-src (car x)) ; extract current source
541 (old-snk (cadr x)) ; extract current sink
542 (old-txt (cddr x))) ; extract current content
543 ; Update the entry in the nema table.
544 (puthash uid
545 `(,old-src ,new-snk . ,old-txt)
546 (nth 2 current-plexus))
547 ;; Remove the entry with the old sink in the
548 ;; backward link table. If that is the only entry
549 ;; filed under old-src, remove it from table.
550 (let ((y (delete `(,uid . ,old-src)
551 (gethash old-snk
552 (nth 4 current-plexus)
553 nil))))
554 (if y
555 (puthash old-snk y (nth 4 current-plexus))
556 (remhash old-snk (nth 4 current-plexus))))
557 ;; Add an entry with the new source in the
558 ;; backward link table.
559 (puthash new-snk
560 (cons `(,uid . ,old-src)
561 (gethash old-snk
562 (nth 4 current-plexus)
563 nil))
564 (nth 4 current-plexus))
565 ;; Update the entry in the forward link table.
566 (puthash old-src
567 (cons `(,uid . ,new-snk)
568 (delete `(,uid . ,old-snk)
569 (gethash old-src
570 (nth 3 current-plexus)
571 nil)))
572 (nth 3 current-plexus))))
573 \end{elisp}
575 \begin{notate}{On `remove-nema'}
576 Remove forward link created by article.
577 Remove backward link created by article.
578 Remove record from article table.
579 \end{notate}
581 \begin{elisp}
582 (defun remove-nema (uid)
583 "Remove this nema from the database."
584 (let ((old-src (car (gethash uid (nth 2 current-plexus))))
585 (old-snk (cadr (gethash uid (nth 2 current-plexus)))))
586 ;; Remove forward link created by nema.
587 (let ((new-fwd (delete `(,uid . ,old-snk)
588 (gethash old-src (nth 3 current-plexus)))))
589 (if new-fwd
590 (puthash old-src new-fwd (nth 3 current-plexus))
591 (remhash old-src (nth 3 current-plexus))))
592 ;; Remove backward link created by nema.
593 (let ((new-bkw (delete `(,uid . ,old-src)
594 (gethash old-snk (nth 4 current-plexus)))))
595 (if new-bkw
596 (puthash old-snk new-bkw (nth 4 current-plexus))
597 (remhash old-snk (nth 4 current-plexus))))
598 ;; Remove record from nema table.
599 (remhash uid (nth 2 current-plexus))))
600 \end{elisp}
602 \begin{notate}{Functions for gathering links}
603 Links are stored on triples alongside other
604 elements.
605 \end{notate}
607 \begin{elisp}
608 (defun get-forward-links (uid)
609 "Return all links having given object as source."
610 (mapcar 'car (gethash uid (nth 3 current-plexus))))
612 (defun get-backward-links (uid)
613 "Return all links having given object as sink."
614 (mapcar 'car (gethash uid (nth 4 current-plexus))))
615 \end{elisp}
617 \begin{notate}{On `label-nema'}
618 Nemas can be given a unique human-readable label in addition
619 to their numeric uid.
620 \end{notate}
622 \begin{elisp}
623 (defun label-nema (uid label)
624 "Assign the label to the given object."
625 (puthash uid label (nth 5 current-plexus))
626 (puthash label uid (nth 6 current-plexus)))
627 \end{elisp}
629 \begin{notate}{Label to uid and uid to label lookup}
630 These functions allow the exchange of uid and label.
631 \end{notate}
633 \begin{elisp}
634 (defun label2uid (label)
635 "Return the unique identifier corresponding to a label."
636 (gethash label (nth 6 current-plexus) nil))
638 (defun uid2label (uid)
639 "Return the label associated to a unique identifier."
640 (gethash uid (nth 5 current-plexus) nil))
641 \end{elisp}
643 \subsection{Bulk Operations}
645 \begin{notate}{On `download-en-masse'}
646 Unpack triplets, obtain labels if they exist.
647 Write data in the network to a list, and return.
648 \end{notate}
650 \begin{elisp}
651 (defun download-en-masse ()
652 "Produce a representation of the database as quintuples."
653 (let ((plex nil))
654 (maphash (lambda (uid tplt)
655 ;; Unpack triplet.
656 (let ((src (car tplt))
657 (snk (nth 1 tplt))
658 (txt (nthcdr 2 tplt)))
659 ;; Obtain label if exists.
660 (setq lbl (gethash uid
661 (nth 5 current-plexus)
662 nil))
663 ;; Write data to list.
664 (setq plex (cons `(,uid ,lbl ,src ,snk . ,txt)
665 plex))))
666 (nth 2 current-plexus))
667 ;; Return list of data.
668 (reverse plex)))
669 \end{elisp}
671 \begin{notate}{On `upload-en-masse'}
672 Unpack quintuplets. Plug into tables.
673 Bump up article counter as needed.
674 \end{notate}
676 \begin{elisp}
677 (defun upload-en-masse (plex)
678 "Load a representation of a database as quintuples into memory."
679 (dolist (qplt plex t)
680 ; unpack quintuplet
681 (let ((uid (car qplt))
682 (lbl (nth 1 qplt))
683 (src (nth 2 qplt))
684 (snk (nth 3 qplt))
685 (txt (nthcdr 4 qplt)))
686 ; plug into tables
687 (puthash uid
688 `(,src ,snk . ,txt)
689 (nth 2 current-plexus))
690 (puthash src
691 (cons `(,uid . ,snk)
692 (gethash src (nth 3 current-plexus) nil))
693 (nth 3 current-plexus))
694 (puthash snk
695 (cons
696 `(,uid . ,src)
697 (gethash snk (nth 4 current-plexus) nil))
698 (nth 4 current-plexus))
699 (when lbl
700 (progn
701 (puthash uid lbl (nth 5 current-plexus))
702 (puthash lbl uid (nth 6 current-plexus))))
703 ; Bump up nema counter if needed.
704 (when (> uid (cadr current-plexus))
705 (setcar (cdr current-plexus) uid)))))
706 \end{elisp}
708 \begin{notate}{On `add-en-masse'}
709 Given several articles, add all of them at once.
710 \end{notate}
712 \begin{elisp}
713 (defun add-en-masse (plex)
714 "Add multiple nemata given as list of quartuplets."
715 (mapcar (lambda (qplt)
716 (let ((uid (next-unique-id)))
717 (add-nema (nth 1 plex)
718 (nthcar 2 plex)
719 (nth 2 plex))
720 (label-nema uid (car qplt))))
721 plex))
722 \end{elisp}
724 \subsection{Query}
726 \begin{notate}{Overview of search and query functionality}
727 We first describe several elementary functions for
728 accessing elements of the network. We then describe a
729 robust search pipeline and show how it is implemented.
730 \end{notate}
732 \begin{notate}{Various lookup functions}
733 These functions allow testing and lookup of various elements
734 of a net.
735 \end{notate}
737 \begin{elisp}
738 (defun uid-p (uid)
739 "Is this a valid uid?"
740 (let ((z '(())))
741 (not (eq z (gethash uid (nth 2 current-plexus) z)))))
743 (defun uid-list ()
744 "List of all valid uid's."
745 (maphash (lambda (key val) key)
746 (nth 2 current-plexus)))
748 (defun ground-p (uid)
749 "Is this nema the ground?"
750 (= uid 0))
752 (defun source-p (x y)
753 "Is the former nema the sink of the latter?"
754 (equal x (get-source y)))
756 (defun sink-p (x y)
757 "Is the former nema the sink of the latter?"
758 (equal x (get-sink y)))
760 (defun links-from (x y)
761 "Return all links from nema x to nema y."
762 (filter '(lambda (z) (source-p x z))
763 (get-backward-links y)))
765 (defun links-p (x y)
766 "Does nema x link to nema y?"
767 (when (member x (mapcar
768 'get-source
769 (get-backward-links y)))
772 (defun triple-p (x y z)
773 "Do the three items form a triplet?"
774 (and (source-p y x)
775 (sink-p y z)))
777 (defun plexus-p (x)
778 "Is this object a plexus?"
779 (let ((ans t))
780 (setq ans (and ans
781 (equal (car x) "*plexus*")))
782 (setq ans (and ans
783 (integrp (cadr x))))
784 (dotimes (n 5)
785 (setq ans (and ans (hash-table-p
786 (nth (+ n 2) x)))))
787 ans))
788 \end{elisp}
790 \subsection{Iteration}
792 \begin{notate}{Iterating over a plexus}
793 These functions allow users to run loops over a plexus without
794 having to delve into its internal structure.\todo{I forget whether the
795 use of `apply' here is good form.}
796 \end{notate}
798 \begin{elisp}
799 (defmacro do-plexus (var res body)
800 `((maphash (lambda (,var val) ,body)
801 (nth 2 current-plexus))
802 ,res))
804 ;; This maps over the keys; func should be
805 ;; defined appropriately.
806 (defun map-plexus (func)
807 (let ((ans nil))
808 (maphash
809 (lambda (key val)
810 (push (apply func (list key)) ans))
811 (nth 2 current-plexus))
812 ans))
814 (defun filter-plexus (pred)
815 (let ((ans nil))
816 (maphash
817 (lambda (key val)
818 (when (apply pred (list key))
819 (push key ans)))
820 (nth 2 current-plexus))
821 ans))
822 \end{elisp}
824 \begin{notate}{Filtering convenience functions}
825 Several convenience functions for filtering the plexus can be
826 defined. They give lists of uids, which can be expanded
827 using get-triple.
828 \end{notate}
830 \begin{elisp}
831 (defun nemas-given-beginning (node)
832 "Get triples outbound from the given NODE."
833 (filter-plexus
834 (lambda (x) (when (equal (get-source x)
835 node)
836 (list node
837 (get-content x)
838 (get-sink x))))))
840 (defun nemas-given-end (node)
841 "Get triples inbound into NODE."
842 (filter-plexus
843 (lambda (x) (when (equal (get-sink x)
844 node)
845 (list (get-source x)
846 (get-content x)
847 node)))))
849 (defun nemas-given-middle (edge)
850 "Get the triples that run along EDGE."
851 (filter-plexus
852 (lambda (x) (when (equal (get-content x)
853 edge)
854 (list (get-source x)
855 edge
856 (get-sink x))))))
858 (defun nemas-given-middle-and-end (edge node)
859 "Get the triples that run along EDGE into NODE."
860 (filter-plexus
861 (lambda (x) (when (and
862 (equal (get-content x)
863 edge)
864 (equal (get-sink x)
865 node))
866 (list (get-source x)
867 edge
868 node)))))
870 (defun nemas-given-beginning-and-middle (node edge)
871 "Get the triples that run from NODE along EDGE."
872 (filter-plexus
873 (lambda (x) (when (and
874 (equal (get-source x)
875 node)
876 (equal (get-content x)
877 edge))
878 (list node
879 edge
880 (get-sink x))))))
882 (defun nemas-given-beginning-and-end (node1 node2)
883 "Get the triples that run from NODE1 to NODE2."
884 (filter-plexus
885 (lambda (x) (when (and
886 (equal (get-source x)
887 node1)
888 (equal (get-sink x)
889 node2))
890 (list node1
891 (get-content x)
892 node2)))))
894 (defun nemas-exact-match (node1 edge node2)
895 "Get the triples that run from NODE1 along EDGE to
896 NODE2."
897 (filter-plexus
898 (lambda (x) (when (and
899 (equal (get-source x)
900 node1)
901 (equal (get-content x)
902 edge)
903 (equal (get-sink x)
904 node2))
905 (list node1
906 edge
907 node2)))))
908 \end{elisp}
910 \begin{notate}{Additional elementary functions for node access}
911 These functions give access to the various parts of a node.\todo{Note:
912 since `article-list' is not defined, should these functions be deleted?
913 Or should they be rewritten to access `current-plexus'?}
914 \end{notate}
916 \begin{elisp}
917 (defun get-src (n)
918 (car (nth 0 (cdr (assoc n (cdr article-list))))))
920 (defun get-flk (n)
921 (cdr (nth 0 (cdr (assoc n (cdr article-list))))))
923 (defun get-txt (n)
924 (nth 1 (cdr (assoc n (cdr article-list)))))
926 (defun get-snk (n)
927 (car (nth 2 (cdr (assoc n (cdr article-list))))))
929 (defun get-blk (n)
930 (cdr (nth 2 (cdr (assoc n (cdr article-list))))))
932 (defun get-ids nil
933 (mapcar (quote car) (cdr article-list)))
935 (defun get-gnd nil 0)
936 \end{elisp}
938 \begin{notate}{On `search-cond'} \label{search-cond}
939 Surround the search within dolist loops on free variables.
940 Wrap no further when finished.\todo{Upgrade this to concatenate the results together.
941 Also maybe allow options to add headers or to
942 only loop over unique tuplets.}\todo{Explain; how does this differ from
943 the function defined at Note \ref{search}?}
944 \end{notate}
946 \begin{elisp}
947 (defmacro search-cond (vars prop)
948 "Find all n-tuplets satisfying a condition"
949 (let ((foo '(lambda (vars cmnd)
950 (if vars
951 Wrap in a loop.
952 `(dolist (,(car vars) uids)
953 ,(funcall foo (cdr vars) cmnd))
954 cmnd))))
955 (funcall foo vars prop)))
956 \end{elisp}
958 \begin{notate}{Overview of the search pipeline}
959 We will implement the search as a pipeline which gradually
960 transforms the query into a series of expressions which produce
961 the sought-after result, then evaluate those expressions.
963 A search query designates predicates apply to the nodes
964 and the network relationships that apply to them. The network relationships
965 function as wildcards.
967 The basic model of the data is triplets that point to other triplets.
968 The following query asks for a \emph{funny} link from a
969 \emph{big blue object} to a \emph{small green link} pointing outwards
970 from the big blue object.
971 \begin{idea}
972 (((a blue big) (b funny) (c green small)
973 ((b src a) (b snk c) (c src a))
974 \end{idea}
975 The first step of processing is to put the quaerenda in some
976 order so that each item links up with at least one previous item:
977 \begin{idea}
978 (scheduler
979 '((b funny)
980 (c green small))
981 '((b src a)
982 (b snk c)
983 (c src a))
984 '((a blue big)))
986 ((c (green small) ((b snk c) (c src a)))
987 (b (funny) ((b src a)))
988 (a blue big))
989 \end{idea}
990 Note that the order is reversed due to technicalities of
991 implementing `scheduler' --- that is to say, a is first and does
992 not link to any other variable, b is next and links to only a,
993 whilst c is last and links to both a and b.
994 At the same time, we have also rearranged things so that the
995 links to previous items to which a given object are listed
996 alongside that object. The next step is to replace the links with the commands which
997 generate a list of such objects:
998 \begin{idea}
999 ((c (green small) ((b snk c) (c src a)))
1000 (b (funny) ((b src a)))
1001 (a blue big))
1003 ((c (green small)
1004 (intersection (list (get-snk b)) (get-forward-links a)))
1005 (b (funny)
1006 (intersection (get-backward-links a)))
1007 (a blue big))
1008 \end{idea}
1009 This is done using the function `tplts2cmd', e.g.
1010 \begin{idea}
1011 (tplts2cmd 'c '((b snk c) (c src a)))
1013 (intersection (list (get-snk b)) (get-forward-links a))
1014 \end{idea}
1015 Subsequently, we filter over the predicates:
1016 \begin{idea}
1017 ((c (filter '(lambda (c) (and (green c) (small c)))
1018 (intersection (list (get-snk b))
1019 (get-forward-links))))
1020 (b (filter '(lambda (b) (and (funny b)))
1021 (intersection (get-backward-links a)))))
1022 \end{idea}
1023 This is done with the command `add-filt':
1024 \begin{idea}
1025 (add-filt 'c
1026 '(green small)
1027 '((b snk c) (c src a)))
1029 (c (filter (quote (lambda (c) (and (green c) (small c))))
1030 (intersection (list (get-snk b))
1031 (get-forward-links a))))
1032 \end{idea}
1033 This routine calls up the previously described routine `tplts2cmd'
1034 to take care of the third argument. The last entry, {\tt (a blue big)}
1035 gets processed a little differently because we don't as yet have
1036 anything to filter over; instead, we generate the initial list by
1037 looping over the current network:
1038 \begin{idea}
1039 (a (let ((ans nil))
1040 (donet 'node
1041 (when (and (blue (get-content node))
1042 (big (get-content node)))
1043 (setq ans (cons node ans))))
1044 ans))
1045 \end{idea}
1046 This is done by invoking `first2cmd':
1047 \begin{idea}
1048 (first2cmd '(blue big))
1050 (let ((ans nil))
1051 (donet (quote node)
1052 (when (and (blue (get-content node))
1053 (big (get-content node)))
1054 (setq ans (cons node ans))))
1055 ans)
1056 \end{idea}
1057 And putting this all together:
1058 \begin{idea}
1059 (query2cmd
1060 '((c (green small) ((b snk c) (c src a)))
1061 (b (funny) ((b src a)))
1062 (a blue big)))
1064 ((c (filter (quote (lambda (c) (and (green c) (small c))))
1065 (intersection (list (get-snk b))
1066 (get-forward-links a))))
1067 (b (filter (quote (lambda (b) (and (funny b))))
1068 (intersection (get-forward-links a))))
1069 (a (let ((ans nil))
1070 (donet (quote node)
1071 (when (and (blue (get-content node))
1072 (big (get-content node)))
1073 (setq ans (cons node ans))))
1074 ans)))
1075 \end{idea}
1076 To carry out these instructions in the correct order and generate
1077 a set of variable assignments, we employ the `matcher' function.
1078 Combining this last layer, we have the complete pipeline:
1079 \begin{idea}
1080 (matcher nil
1081 (query2cmd
1082 (scheduler
1083 '((b funny)
1084 (c green small))
1085 '((b src a)
1086 (b snk c)
1087 (c src a))
1088 '((a blue big)))))
1089 \end{idea}
1090 This combination of operations is combined into the `search'
1091 function, which can be called as follows:
1092 \begin{idea}
1093 (search
1094 '(((a blue big)
1095 (b funny)
1096 (c green small))
1097 ((b src a)
1098 (b snk c)
1099 (c src a))))
1100 \end{idea}
1102 Having described what the functions are supposed to do and how
1103 they work together, we now proceed to implement them.
1104 \end{notate}
1106 \begin{notate}{On `scheduler'}
1107 The scheduler function takes a list search query and rearranges it
1108 into an order suitable for computing the answer to that query.
1109 Specifically, a search query is a pair of lists --- the first list
1110 consists of lists whose heads are names of variables and whose
1111 tails are predicates which the values of the variables should
1112 satisfy and the second list consists of triples indicating the
1113 relations between the values of the variables.
1114 Its arguments are:
1115 \begin{itemize}
1116 \item new-nodes, a list of items of the form \verbal|(node &rest property)|;
1117 \item \verbal|links|, a list of triplets;
1118 \item \verbal|sched| is a list whose items consist of triplets of the
1119 form\newline \verbal|(node (&rest property) (&rest link))|.
1120 \end{itemize}
1122 A recursive function to find linked nodes.
1123 If done, return answer.
1124 New nodes yet to be examined.
1125 Element of remaining-nodes currently under consideration.
1126 List of links between candidate and old-nodes.
1127 List of nodes already scheduled.
1128 Loop through new nodes until find one linked to an old node.
1129 Look at the next possible node.
1130 Find the old nodes linking to the candidate node and record the answer in ``ties''.
1131 Pick out the triplets whose first element is the node under consideration and whose third element is already on the list or vice-versa.
1132 Recursively add the rest of the nodes.
1133 \end{notate}
1135 \begin{elisp}
1136 (defun scheduler (new-nodes links sched)
1137 (if (null new-nodes)
1138 sched
1139 (let ((remaining-nodes new-nodes)
1140 (candidate nil)
1141 (ties nil)
1142 (old-nodes (mapcar 'car sched)))
1143 (while (null ties)
1144 (setq candidate (car remaining-nodes))
1145 (setq remaining-nodes (cdr remaining-nodes))
1146 (setq ties
1147 (filter '(lambda (x)
1149 (and (eq (first x) (car candidate))
1150 (member (third x) old-nodes))
1151 (and (member (first x) old-nodes)
1152 (eq (third x) (car candidate)))))
1153 links)))
1154 (scheduler (remove candidate new-nodes)
1155 links
1156 (cons (list (car candidate)
1157 (cdr candidate)
1158 ties)
1159 sched)))))
1160 \end{elisp}
1162 \begin{notate}{On `tplts2cmd'}
1163 \ldots\todo{Explain.}
1164 \end{notate}
1166 \begin{elisp}
1167 (defun tplts2cmd (var tplts)
1168 (cons 'intersection
1169 (mapcar
1170 #'(lambda (tplt)
1171 (cond ((and (eq (third tplt) var)
1172 (eq (second tplt) 'src))
1173 `(get-flk ,(first tplt)))
1174 ((and (eq (third tplt) var)
1175 (eq (second tplt) 'snk))
1176 `(get-blk ,(first tplt)))
1177 ((and (eq (first tplt) var)
1178 (eq (second tplt) 'src))
1179 `(list (get-src ,(third tplt))))
1180 ((and (eq (first tplt) var)
1181 (eq (second tplt) 'snk))
1182 `(list (get-snk ,(third tplt))))
1183 (t nil)))
1184 tplts)))
1185 \end{elisp}
1187 \begin{notate}{On `add-filt'}
1188 \ldots\todo{Explain.}
1189 \end{notate}
1191 \begin{elisp}
1192 (defun add-filt (var preds tplts)
1193 `(,var
1194 (filter
1195 #'(lambda (,var)
1196 ,(cons 'and
1197 (mapcar
1198 #'(lambda (pred)
1199 (list pred
1200 (list 'get-txt var)))
1201 preds)))
1202 ,(tplts2cmd var tplts))))
1203 \end{elisp}
1205 \begin{notate}{On `first2cmd'}
1206 \ldots\todo{Explain.}
1207 \end{notate}
1209 \begin{elisp}
1210 (defun first2cmd (preds)
1211 `(let ((ans nil))
1212 (dolist (node (get-ids) ans)
1213 (when
1214 ,(cons 'and
1215 (mapcar
1216 #'(lambda (pred)
1217 (cons pred '((get-txt node))))
1218 preds))
1219 (setq ans (cons node ans))))))
1220 \end{elisp}
1222 \begin{notate}{On `query2cmd'}
1223 \ldots\todo{Explain.}
1224 \end{notate}
1226 \begin{elisp}
1227 (defun query2cmd (query)
1228 (let ((backwards (reverse query)))
1229 (reverse
1230 (cons
1231 (list (caar backwards)
1232 (first2cmd (cdar backwards)))
1233 (mapcar
1234 #'(lambda (x)
1235 (add-filt (first x) (second x) (third x)))
1236 (cdr backwards))))))
1237 \end{elisp}
1239 \begin{notate}{On `matcher'}
1240 \ldots\todo{Explain.}
1241 \end{notate}
1243 \begin{elisp}
1244 (defun matcher (assgmt reqmts)
1245 (if (null reqmts) (list assgmt)
1246 (apply 'append
1247 (mapcar
1248 #'(lambda (x)
1249 (matcher (cons (list (caar reqmts) x)
1250 assgmt)
1251 (cdr reqmts)))
1252 (apply 'intersection
1253 (eval `(let ,assgmt
1254 (mapcar 'eval
1255 (cdar reqmts)))))))))
1256 \end{elisp}
1258 \begin{notate}{How matcher works}
1259 Here are some examples unrelated to what comes up in searching
1260 triplets which illustrate how matcher works:
1261 \end{notate}
1263 \begin{idea}
1264 (matcher '((x 1)) '((y (list 1 3))
1265 (z (list (+ x y) (- y x)))))
1267 (((z 2) (y 1) (x 1))
1268 ((z 0) (y 1) (x 1))
1269 ((z 4) (y 3) (x 1))
1270 ((z 2) (y 3) (x 1)))
1272 (matcher nil '((x (list 1))
1273 (y (list 1 3))
1274 (z (list (+ x y) (- y x)))))
1276 (((z 2) (y 1) (x 1))
1277 ((z 0) (y 1) (x 1))
1278 ((z 4) (y 3) (x 1))
1279 ((z 2) (y 3) (x 1)))
1280 \end{idea}
1282 \begin{notate}{On `search'} \label{search}
1283 \ldots\todo{Explain; how does this differ from
1284 the macro defined at Note \ref{search-cond}?}
1285 \end{notate}
1287 \begin{elisp}
1288 (defun search (query)
1289 (matcher nil
1290 (reverse
1291 (query2cmd
1292 (scheduler
1293 (cdar query)
1294 (cadr query)
1295 (list (caar query)))))))
1296 \end{elisp}
1298 \subsection{Scholium programming}
1300 \begin{notate}{Scholium programming}
1301 The next several functions allow us to store and retrieve code
1302 from inside of the network.
1303 \end{notate}
1305 \begin{notate}{On `node-fun'}
1306 \ldots\todo{Explain.}
1307 Produce a list of commands to produce temporary bindings.
1308 Produce a list of commands to reset function values.
1309 \end{notate}
1311 \begin{elisp}
1312 (defun node-fun (node get-code get-links)
1313 (let ((code (funcall get-code node))
1314 (links (funcall get-links node)))
1315 (list
1316 'lambda
1317 (car code)
1318 (cons
1319 'prog1
1320 (cons
1321 (append
1322 '(progn)
1323 (mapcar #'(lambda (x)
1324 `(fset ',(car x)
1325 (node-fun ,(cdr x)
1326 ',get-code
1327 ',get-links)))
1328 links)
1329 (cdr code))
1330 (mapcar #'(lambda (x)
1331 (if (fboundp (car x))
1332 `(fset ',(car x)
1333 ',(symbol-function (car x)))
1334 `(fmakunbound ',(car x))))
1335 links))))))
1336 \end{elisp}
1338 \begin{notate}{On `tangle-module'}
1339 Recursively replace the chunks to recover executable code.\todo{Explain.}
1340 \end{notate}
1342 \begin{elisp}
1343 (defun tangle-module (node get-cont ins-links)
1344 (insert-chunk
1345 (funcall get-cont node)
1346 (mapcar #'(lambda (x)
1347 (cons (car x)
1348 (tangle-module (cdr x)
1349 get-cont
1350 ins-links)))
1351 (funcall ins-links node))))
1352 \end{elisp}
1354 \begin{notate}{On `insert-chunk'}
1355 Given a node and an association list of replacement texts, insert
1356 the chunks at the appropriate places.
1357 \end{notate}
1359 \begin{elisp}
1360 (defun insert-chunk (body chunks)
1361 (cond ((null body) nil)
1362 ((null chunks) body)
1363 ((equal (car body) '*insert*)
1364 (cdr (assoc (cadr body) chunks)))
1365 (t (cons (insert-chunk (car body) chunks)
1366 (insert-chunk (cdr body) chunks)))))
1367 \end{elisp}
1369 \begin{notate}{Functions for rewriting nemas}
1370 Several functions for rewriting nemas.\todo{How does this stuff relate to what's
1371 going on in the vicinity of Note \ref{update-sink}?}
1372 \end{notate}
1374 \begin{elisp}
1375 (defun set-src (n x)
1376 (if (equal n 0)
1378 (progn (let ((old-backlink
1379 (nth 1 (assoc (get-src n)
1380 (cdr article-list)))))
1381 (setcdr old-backlink
1382 (delete n (cdr old-backlink))))
1383 (let ((new-backlink
1384 `(nth 1 (assoc x (cdr article-list)))))
1385 (setcdr new-backlink (cons n (cdr new-backlink))))
1386 (setcar (nth 1 (assoc n (cdr article-list))) x))))
1388 (defun set-txt (n x)
1389 (setcar (cdr (cdr (assoc n (cdr article-list)))) x))
1391 (defun set-snk (n x)
1392 (if (equal n 0)
1394 (progn (let ((old-backlink
1395 (nth 3 (assoc (get-snk n)
1396 (cdr article-list)))))
1397 (setcdr old-backlink
1398 (delete n (cdr old-backlink))))
1399 (let ((new-backlink
1400 (nth 3 (assoc x (cdr article-list)))))
1401 (setcdr new-backlink (cons n (cdr new-backlink))))
1402 (setcar (nth 3 (assoc n (cdr article-list))) x))))
1404 (defun ins-nod (src txt snk)
1405 (progn (setcdr article-list
1406 (cons (list (car article-list)
1407 (list src)
1409 (list snk))
1410 (cdr article-list)))
1411 (let ((backlink
1412 (nth 3 (assoc snk (cdr article-list)))))
1413 (setcdr backlink (cons (car article-list)
1414 (cdr backlink))))
1415 (let ((backlink
1416 (nth 1 (assoc src (cdr article-list)))))
1417 (setcdr backlink (cons (car article-list)
1418 (cdr backlink))))
1419 (- (setcar article-list (+ 1 (car article-list))) 1)))
1421 (defun del-nod (n)
1422 (if (or (equal n 0)
1423 (get-blk n)
1424 (get-flk n))
1426 (progn (let ((old-backlink
1427 (nth 3 (assoc (get-snk n)
1428 (cdr article-list)))))
1429 (setcdr old-backlink
1430 (delete n (cdr old-backlink))))
1431 (let ((old-backlink
1432 (nth 1 (assoc (get-src n)
1433 (cdr article-list)))))
1434 (setcdr old-backlink
1435 (delete n (cdr old-backlink))))
1436 (setcdr article-list
1437 (delete (assoc n (cdr article-list))
1438 (cdr article-list)))
1439 t)))
1440 \end{elisp}
1442 \subsection{Initialization}
1444 \begin{notate}{Initialize with a new network}
1445 For now, we just create one network to import things into. Additional
1446 networks can be added later (see Section \ref{applications}).
1447 \end{notate}
1449 \begin{elisp}
1450 (set-current-plexus (add-plexus))
1451 \end{elisp}
1453 \section{An example middle\"end} \label{middle-end}
1455 \begin{notate}{A middle\"end for managing collections of articles}
1456 This middle\"end is a set of functions that add triples into the
1457 backend. At this stage we basically ignore details of storage, and
1458 rely on the convenience functions defined above as the backend's API.
1459 In principle it would be possible to swap out the backend for another
1460 storage mechanism. We will give an example later on that uses more of
1461 the LISP-specific aspects of the backend implementation.\todo{Let's
1462 try to be a bit more concrete about this, especially in Section
1463 \ref{farm-demo}.} In this example, rather than talking about nemas
1464 and networks, we will talk about \emph{articles} and \emph{scholia}.
1465 These objects are things that user will want to access, create, and
1466 manipulate. However, we will deal with functions for user interaction
1467 (input, display, and editing) in Section \ref{frontend}, not here.
1468 Like the backend, the middle\"end could also be swapped out in
1469 applications where a different kind of data is modelled. And in fact,
1470 we come to some examples of other mid-level interfaces in Section
1471 \ref{applications}.
1472 \end{notate}
1474 \subsection{Database interaction} \label{interaction}
1476 \begin{notate}{The `article' function} \label{the-article-function}
1477 You can use this function to create an article with a
1478 given name and contents. You can optionally put it in a
1479 list by specifying the heading that it is under. (If this
1480 is used multiple times with the same heading, that just becomes
1481 a cone over the contents.)
1482 \end{notate}
1484 \begin{elisp}
1485 (defun article (name contents &optional heading)
1486 (let ((coordinates (add-nema name
1487 "has content"
1488 contents)))
1489 (when heading (add-nema coordinates "in" heading))
1490 coordinates))
1491 \end{elisp}
1493 \begin{notate}{The `scholium' function} \label{the-scholium-function}
1494 You can use this function to link annotations to objects.
1495 As with the `article' function, you can optionally
1496 categorize the connection under a given heading (cf. Note
1497 \ref{the-article-function}).
1498 \end{notate}
1500 \begin{elisp}
1501 (defun scholium (beginning link end &optional heading)
1502 (let ((coordinates (add-nema beginning
1503 link
1504 end)))
1505 (when heading (add-nema coordinates "in" heading))
1506 coordinates))
1507 \end{elisp}
1509 \begin{notate}{Uses of coordinates}
1510 It is convenient to do further immediate processing of the object
1511 we've created while we still have ahold of the coordinates
1512 returned by `add-nema' (e.g., for importing code
1513 that is adjacent to the article, see Note
1514 \ref{import-code-continuations}).
1515 \end{notate}
1517 \begin{notate}{On `get-article'} \label{get-article}
1518 Get the contents of the article named `name'.
1519 We assume that there is only one such article for now.
1520 \end{notate}
1522 \begin{elisp}
1523 (defun get-article (name)
1524 (get-sink
1525 (first
1526 (nemas-given-beginning-and-middle
1527 (first
1528 (nemas-given-beginning-and-end
1529 name "arxana-merge.tex"))
1530 "has content"))))
1531 \end{elisp}
1533 \begin{notate}{On `get-names'} \label{get-names}
1534 This function simply gets the names of articles that have
1535 names -- in other words, every triple built around the
1536 ``has content'' relation.\todo{This seems to work but
1537 are both map operations needed?}
1538 \end{notate}
1540 \begin{elisp}
1541 (defun get-names (&optional heading)
1542 (mapcar #'get-source
1543 (mapcar #'get-source (nemas-given-middle "has content"))))
1544 \end{elisp}
1546 \section{An example frontend} \label{frontend}
1548 \begin{notate}{Overview of the frontend}
1549 The frontend provides a demonstration of Arxana's functionality that
1550 is directly accessible to the user. Specifically, it is used to
1551 import \LaTeX\ documents into a network structure. They can then be
1552 edited, remixed, saved, browsed, and exported.\todo{Some of this
1553 functionality still needs to be merged in or written!}
1554 \end{notate}
1556 \subsection{Importing \LaTeX\ documents} \label{importing}
1558 \begin{notate}{Importing sketch} \label{importing-sketch}
1559 The code in this section imports a document, represented as a
1560 collection of (sub-)sections and notes. It gathers the sections,
1561 sub-sections, and notes recursively and records their content in a
1562 tree whose nodes are places and whose links express the
1563 ``component-of'' relation described in Note \ref{order-of-order}.
1565 This representation lets us see the geometric, hierarchical, structure
1566 of the document we've imported. It exemplifies a general principle,
1567 that geometric data should be represented by relationships between
1568 places, not direct relationships between strings. This is because
1569 ``the same'' string often appears in ``different'' places in any given
1570 document (e.g. a paper's many sub-sections titled ``Introduction''
1571 will not all have the same content).\todo{Do we need to relax this?}
1573 What goes into the places is in some sense arbitrary. The key is that
1574 whatever is in or attached to these places must tell us
1575 everything we need to know about the part of the document associated
1576 with that place (e.g., in the case of a note, its title and contents).
1577 That's over and above the structural links which say how the
1578 places relate to one another. Finally, all of these places and
1579 structural links will be added to a heading that represents the
1580 document as a whole.
1582 A natural convention we'll use is to put the name of any document
1583 component that's associated with a given place into that place, and
1584 add all other information as annotations.\todo{Does this contradict
1585 what is said above about Introductions?}
1587 Following our usual coding convention, functions are introduced
1588 below ``from the bottom up.''
1589 \end{notate}
1591 \begin{notate}{On `import-code-continuations'} \label{import-code-continuations}
1592 This function will run within the scope of `import-notes'.
1593 In fact, it is meant to run right after a Note itself
1594 has been scanned. The job of this function is to turn the
1595 series of Lisp chunks or other code snippets that follow a given note
1596 into a scholium attached to that note. Each separate snippet becomes
1597 its own annotation. The ``conditional regexps'' form used here only
1598 works with Emacs version 23 or higher.\todo{Note the use of an
1599 edge-pointing-to-an-edge for categorization; is this a good style?}
1600 \end{notate}
1602 \begin{elisp}
1603 ;; coords don't exist anymore, now we use uids
1604 (defun import-code-continuations (coords)
1605 (let ((possible-environments
1606 "\\(?1:elisp\\|idea\\|common\\)"))
1607 (while (looking-at
1608 (concat "\n*?\\\\begin{"
1609 possible-environments
1610 "}"))
1611 (let* ((beg (match-end 0))
1612 (environment (match-string 1))
1613 (end (progn (search-forward-regexp
1614 (concat "\\\\end{"
1615 environment
1616 "}"))
1617 (match-beginning 0)))
1618 (content (buffer-substring-no-properties
1620 end)))
1621 (scholium (scholium coords
1622 "has attachment"
1623 content)
1624 "has type"
1625 environment)))))
1626 \end{elisp}
1628 \begin{notate}{On `import-notes'} \label{import-notes}
1629 We're going to make the daring assumption that the ``textual''
1630 portions of incoming \LaTeX\ documents are contained in ``Notes''.
1631 That assumption is true, at least, for the current document. The
1632 function takes a buffer position `end' that denotes the end of the
1633 current section. The function returns the count of the number of
1634 notes imported, so that `import-within' knows where to start counting
1635 this section's non-note children.\todo{Would this same function work
1636 to import all notes from a buffer without examining its sectioning
1637 structure? Not quite, but close! (Could be a fun exercise to fix
1638 this.)}
1639 \end{notate}
1641 \begin{elisp}
1642 (defun import-notes (end)
1643 (let ((index 0))
1644 (while (re-search-forward (concat "\\\\begin{notate}"
1645 "{\\([^}\n]*\\)}"
1646 "\\( +\\\\label{\\)?"
1647 "\\([^}\n]*\\)?")
1648 end t)
1649 (let* ((name
1650 (match-string-no-properties 1))
1651 (tag (match-string-no-properties 3))
1652 (beg
1653 (progn (next-line 1)
1654 (line-beginning-position)))
1655 (end
1656 (progn (search-forward-regexp
1657 "\\\\end{notate}")
1658 (match-beginning 0)))
1659 ;; get the uid for our new nema
1660 (coords (add-nema name "in" buffername)))
1661 (scholium coords
1662 "has content"
1663 (buffer-substring-no-properties
1664 beg end))
1665 (setq index (1+ index))
1666 ;; current-parent is in scope inside import-within
1667 (scholium current-parent
1668 index
1669 coords
1670 buffername)
1671 (import-code-continuations coords)))
1672 index))
1673 \end{elisp}
1675 \begin{notate}{On `import-within'}
1676 Recurse through levels of sectioning in a document to import
1677 \LaTeX\ code. Children that are notes are attached to the
1678 hierarchical structure by the subroutine `import-notes', called by
1679 this function. Sections are attached directly by `import-within'. We
1680 observe that a note ``has content'' whereas a section does not.
1682 Incidentally, when looking for the end of an importing level, `nil' is
1683 an OK result: that describes the case when we have reached the
1684 \emph{last} section at this level \emph{and} there is no subsequent
1685 section at a higher level.
1686 \end{notate}
1688 \begin{elisp}
1689 (defun import-within (levels)
1690 (let ((this-level (car levels))
1691 (next-level (car (cdr levels))) answer)
1692 (while (re-search-forward
1693 (concat
1694 "^\\\\" this-level "{\\([^}\n]*\\)}"
1695 "\\( +\\\\label{\\)?"
1696 "\\([^}\n]*\\)?")
1697 level-end t)
1698 (let* ((name (match-string-no-properties 1))
1699 (at (add-nema name "in" buffername))
1700 (level-end
1701 (or (save-excursion
1702 (search-forward-regexp
1703 (concat "^\\\\" this-level "{.*")
1704 level-end t))
1705 level-end))
1706 (notes-end
1707 (if next-level
1708 (or (progn (point)
1709 (save-excursion
1710 (search-forward-regexp
1711 (concat "^\\\\"
1712 next-level "{.*")
1713 level-end t)))
1714 level-end)
1715 level-end))
1716 (index (let ((current-parent at))
1717 (import-notes notes-end)))
1718 (subsections (let ((current-parent at))
1719 (import-within (cdr levels)))))
1720 (while subsections
1721 (let ((coords (car subsections)))
1722 (setq index (1+ index))
1723 (scholium at
1724 index
1725 coords
1726 buffername)
1727 (setq subsections (cdr subsections))))
1728 (setq answer (cons at answer))))
1729 (reverse answer)))
1730 \end{elisp}
1732 \begin{notate}{On `import-buffer'}
1733 This function imports a \LaTeX\ document, taking care of
1734 the high-level, non-recursive, aspects of this operation.
1735 It imports frontmatter (everything up to the first
1736 \texttt{\textbackslash begin\{section\}}), but assumes ``backmatter'' is
1737 trivial, and does not attempt to import it. The imported
1738 material is classified as a ``document'' with the same
1739 name as the imported buffer.
1741 Links to sections will be made under the ``heading'' of this
1742 document.\todo{The sectioning levels should maybe be scholia attached
1743 to root-coords, but for some reason that wasn't working so well --
1744 investigate later -- maybe it just wasn't good to run after running
1745 `import-within'.}
1746 \end{notate}
1748 \begin{elisp}
1749 (defun import-buffer (&optional buffername)
1750 (save-excursion
1751 (set-buffer (get-buffer (or buffername
1752 (current-buffer))))
1753 (goto-char (point-min))
1754 (search-forward-regexp "\\\\begin{document}")
1755 (search-forward-regexp "\\\\section")
1756 (goto-char (match-beginning 0))
1757 (scholium buffername "is a" "document")
1758 (scholium buffername
1759 "has frontmatter"
1760 (buffer-substring-no-properties
1761 (point-min)
1762 (point))
1763 buffername)
1764 (let* ((root-coords (add-nema buffername "in" buffername))
1765 (levels
1766 '("section" "subsection" "subsubsection"))
1767 (current-parent buffername)
1768 (level-end nil)
1769 (sections (import-within levels))
1770 (index 0))
1771 (while sections
1772 (let ((coords (car sections)))
1773 (setq index (1+ index))
1774 (scholium root-coords
1775 index
1776 coords
1777 buffername))
1778 (setq sections (cdr sections))))))
1779 \end{elisp}
1781 \begin{notate}{On `autoimport-arxana'} \label{autoimport-arxana}
1782 This just calls `import-buffer', and imports this document
1783 into the system.
1784 \end{notate}
1786 \begin{elisp}
1787 (defun autoimport-arxana ()
1788 (interactive)
1789 (import-buffer "arxana-merge.tex"))
1790 \end{elisp}
1792 \subsection{Browsing database contents} \label{browsing}
1794 \begin{notate}{Browsing sketch} \label{browsing-sketch}
1795 This section facilitates browsing of documents represented
1796 with structures like those created in Section
1797 \ref{importing}, and sets the ground for browsing other
1798 sorts of contents (e.g. collections of tasks, as in
1799 Section \ref{managing-tasks}).
1801 In order to facilitate general browsing, it is not enough
1802 to simply use `get-article' (Note \ref{get-article}) and
1803 `get-names' (Note \ref{get-names}), although these
1804 functions provide our defaults. We must provide the means
1805 to find and display different things differently -- for
1806 example, a section's table of contents will typically
1807 be displayed differently from its actual contents.
1809 Indeed, the ability to display and select elements of
1810 document sections (Note \ref{display-section}) is
1811 basically the core browsing deliverable. In the process
1812 we develop a re-usable article selector (Note
1813 \ref{selector}; cf. Note \ref{browsing-tasks}). This in
1814 turn relies on a flexible function for displaying
1815 different kinds of articles (Note \ref{display-article}).
1816 \end{notate}
1818 \begin{notate}{On `display-article'} \label{display-article}
1819 This function takes in the name of the article to display.
1820 Furthermore, it takes optional arguments `retriever' and
1821 `formatter', which tell it how to look up and/or format
1822 the information for display, respectively.
1824 Thus, either we make some statement up front (choosing our
1825 `formatter' based on what we already know about the
1826 article), or we decide what to display after making some
1827 investigation of information attached to the article, some
1828 of which may be retrieved and displayed (this requires
1829 that we specify a suitable `retriever' and a complementary
1830 `formatter').
1832 For example, the major mode in which to display the
1833 article's contents could be stored as a scholium attached
1834 to the article; or we might maintain some information
1835 about ``areas'' of the database that would tell us up
1836 front what which mode is associated with the current area.
1837 (The default is to simply insert the data with no markup
1838 whatsoever.)
1840 Observe that this works when no heading argument is given,
1841 because in that case `get-article' looks for \emph{all}
1842 place pseudonyms. (But of course that won't work well
1843 when we have multiple theories containing things with the
1844 same names, so we should get used to using the heading
1845 argument.)
1847 (The business about requiring the data to be a sequence
1848 before engaging in further formatting is, of course, just
1849 a matter of expediency for making things work with the
1850 current dataset.)
1851 \end{notate}
1853 \begin{elisp}
1854 (defun display-article
1855 (name &optional heading retriever formatter)
1856 (interactive "Mname: ")
1857 (let* ((data (if retriever
1858 (funcall retriever name heading)
1859 (get-article name))))
1860 (when (and data (sequencep data))
1861 (save-excursion
1862 (if formatter
1863 (funcall formatter data heading)
1864 (pop-to-buffer (get-buffer-create
1865 "*Arxana Display*"))
1866 (delete-region (point-min) (point-max))
1867 (insert "NAME: " name "\n\n")
1868 (insert data)
1869 (goto-char (point-min)))))))
1870 \end{elisp}
1872 \begin{notate}{An interactive article selector} \label{selector}
1873 The function `get-names' (Note \ref{get-names}) and
1874 similar functions can give us a collection of articles.
1875 The next few functions provide an interactive
1876 functionality for moving through this collection to find
1877 the article we want to look at.
1879 We define a ``display style'' that the article selector
1880 uses to determine how to display various articles. These
1881 display styles are specified by text properties attached
1882 to each option the selector provides. Similarly, when
1883 we're working within a given heading, the relevant heading
1884 is also specified as a text property.
1886 At selection time, these text properties are checked to
1887 determine which information to pass along to
1888 `display-article'.
1889 \end{notate}
1891 \begin{elisp}
1892 (defvar display-style '((nil . (nil nil))))
1894 (defun thing-name-at-point ()
1895 (buffer-substring-no-properties
1896 (line-beginning-position)
1897 (line-end-position)))
1899 (defun get-display-type ()
1900 (get-text-property (line-beginning-position)
1901 'arxana-display-type))
1903 (defun get-relevant-heading ()
1904 (get-text-property (line-beginning-position)
1905 'arxana-relevant-heading))
1907 (defun arxana-list-select ()
1908 (interactive)
1909 (apply 'display-article
1910 (thing-name-at-point)
1911 (get-relevant-heading)
1912 (cdr (assoc (get-display-type)
1913 display-style))))
1915 (define-derived-mode arxana-list-mode fundamental-mode
1916 "arxana-list" "Arxana List Mode.
1918 \\{arxana-list-mode-map}")
1920 (define-key arxana-list-mode-map (kbd "RET")
1921 'arxana-list-select)
1922 \end{elisp}
1924 \begin{notate}{On `pick-a-name'} \label{pick-a-name}
1925 Here `generate' is the name of a function to call to
1926 generate a list of items to display, and `format' is a
1927 function to put these items (including any mark-up) into
1928 the buffer from which individiual items can then be
1929 selected.
1931 One simple way to get a list of names to display would be
1932 to reuse a list that we had already produced (this would
1933 save querying the database each time). We could, in fact,
1934 store a history list of lists of names that had been
1935 displayed previously (cf. Note \ref{local-storage}).
1937 We'll eventually want versions of `generate' that provide
1938 various useful views into the data, e.g., listing all of
1939 the elements of a given section (Note
1940 \ref{display-section}).
1942 Finding all the elements that match a given search term,
1943 whether that's just normal text search or some kind of
1944 structured search would be worthwhile too. Upgrading the
1945 display to e.g. color-code listed elements according to
1946 their type would be another nice feature to add.
1947 \end{notate}
1949 \begin{elisp}
1950 (defun pick-a-name (&optional generate format heading)
1951 (interactive)
1952 (let ((items (if generate
1953 (funcall generate)
1954 (reverse (get-names heading)))))
1955 (when items
1956 (set-buffer (get-buffer-create "*Arxana Articles*"))
1957 (toggle-read-only -1)
1958 (delete-region (point-min)
1959 (point-max))
1960 (if format
1961 (funcall format items)
1962 (mapc (lambda (item) (insert item "\n")) items))
1963 (toggle-read-only t)
1964 (arxana-list-mode)
1965 (goto-char (point-min))
1966 (pop-to-buffer (get-buffer "*Arxana Articles*")))))
1967 \end{elisp}
1969 \begin{notate}{On `get-section-contents'} \label{get-section-contents}
1970 This function is used by `display-section'
1971 (Note \ref{display-section}) to `pick-a-name' as a generator
1972 for the table of contents of the section with the given
1973 name under the given heading.
1975 This function first finds the triples that begin with the
1976 name of the section, then checks to see which of these represent structural
1977 information about that document. It also looks at the
1978 items found at via these links to see if they are
1979 sections or notes (``noteness'' is determined by them
1980 having content). The links are then sorted by their
1981 middles (which show the numerical order in which the components
1982 have in the section we're examining). After this ordering
1983 information has been used for sorting, it is deleted, and
1984 we're left with just a list of names in the appropriate
1985 order, together with an indication of their
1986 noteness.\todo{The initial import strategy used in
1987 the latest round (as of July 12 2017) doesn't
1988 seem to make the same assumptions about order of sections
1989 and their contents that are made in this function.}
1990 \end{notate}
1992 \begin{elisp}
1993 (defun get-section-contents (name heading)
1994 (let (contents)
1995 (dolist (triple (mapcar #'get-triple
1996 (nemas-given-beginning
1997 ;; ???
1998 name)))
1999 (when (get-triple
2000 ;; hopefully assuming uniqueness
2001 ;; doesn't defeat the purpose
2002 (first
2003 (nemas-exact-match
2004 (car triple) "in" heading)))
2005 (let* ((number (print-middle triple))
2006 (site (isolate-end triple))
2007 (noteness
2008 (when (get-triple
2009 (nemas-given-beginning-and-middle
2010 site "has content"))
2011 t)))
2012 (setq contents
2013 (cons (list number
2014 (print-system-object
2015 (place-contents site))
2016 noteness)
2017 contents)))))
2018 (mapcar 'cdr
2019 (sort contents
2020 (lambda (component1 component2)
2021 (< (parse-integer (car component1))
2022 (parse-integer (car component2))))))))
2023 \end{elisp}
2025 \begin{notate}{On `format-section-contents'} \label{format-section-contents}
2026 A formatter for document contents, used by
2027 `display-document' (Note \ref{display-document}) as input
2028 for `pick-a-name' (Note \ref{pick-a-name}).
2030 Instead of just printing the items one by one,
2031 like the default formatter in `pick-a-name' does,
2032 this version adds appropriate text properties, which
2033 we determine based the second component of
2034 of `items' to format.
2035 \end{notate}
2037 \begin{elisp}
2038 (defun format-section-contents (items heading)
2039 ;; just replicating the default and building on that.
2040 (mapc (lambda (item)
2041 (insert (car item))
2042 (let* ((beg (line-beginning-position))
2043 (end (1+ beg)))
2044 (unless (second item)
2045 (put-text-property beg end
2046 'arxana-display-type
2047 'section))
2048 (put-text-property beg end
2049 'arxana-relevant-heading
2050 heading))
2051 (insert "\n"))
2052 items))
2053 \end{elisp}
2055 \begin{notate}{On `display-section'} \label{display-section}
2056 When browsing a document, if you select a section, you
2057 should display a list of that section's constituent
2058 elements, be they notes or subsections. The question
2059 comes up: when you go to display something, how do you
2060 know whether you're looking at the name of a section, or
2061 the name of an article?
2063 When you get the section's contents out of the database
2064 (Note \ref{get-section-contents})
2065 \end{notate}
2067 \begin{elisp}
2068 (defun display-section (name heading)
2069 (interactive (list (read-string
2070 (concat
2071 "name (default "
2072 (buffer-name)
2073 "): ")
2074 nil nil (buffer-name))))
2075 ;; should this pop to the Articles window?
2076 (pick-a-name `(lambda ()
2077 (get-section-contents
2078 ,name ,heading))
2079 `(lambda (items)
2080 (format-section-contents
2081 items ,heading))))
2083 (add-to-list 'display-style
2084 '(section . (display-section
2085 nil)))
2086 \end{elisp}
2088 \begin{notate}{On `display-document'} \label{display-document}
2089 This file shows the top-level table of contents of a document.
2090 (Most typically, a list of all of that document's major sections.)
2091 In order to do this, we must find the triples that are begin at the node
2092 representing this document \emph{and} that are in the
2093 heading of this document. This boils down to treating the
2094 document's root as if it was a section and using the
2095 function `display-section' (Note \ref{display-section}).\todo{Assuming that
2096 the name comes from the current buffer is perhaps a bit odd.}
2097 \end{notate}
2099 \begin{elisp}
2100 (defun display-document (name)
2101 (interactive (list (read-string
2102 (concat
2103 "name (default "
2104 (buffer-name) "): ")
2105 nil nil (buffer-name))))
2106 (display-section name name))
2107 \end{elisp}
2109 \begin{notate}{Work with `heading' argument}
2110 We should make sure that if we know the heading we're
2111 working with (e.g. the name of the document we're
2112 browsing) that this information gets communicated in the
2113 background of the user interaction with the article
2114 selector.
2115 \end{notate}
2117 \begin{notate}{Selecting from a hierarchical display} \label{hierarchical-display}
2118 A fancier ``article selector'' would be able to display
2119 several sections with nice indenting to show their
2120 hierarchical order.
2121 \end{notate}
2123 \begin{notate}{Browser history tricks} \label{history-tricks}
2124 I want to put together (or put back together) something
2125 similar to the multihistoried browser that I had going in
2126 the previous version of Arxana and my Emacs/Lynx-based web
2127 browser, Nero\footnote{\url{http://metameso.org/~joe/nero.el}}.
2128 The basic features are:
2129 (1) forward, back, and up inside the structure of a given
2130 document; (2) switch between tabs. More advanced features
2131 might include: (3) forward and back globally across all
2132 tabs; (4) explicit understanding of paths that loop.
2134 These sorts of features are independent of the exact
2135 details of what's printed to the screen each time
2136 something is displayed. So, for instance, you could flip
2137 between section manifests a la Note \ref{display-section},
2138 or between hierarchical displays a la Note
2139 \ref{hierarchical-display}, or some combination; the key
2140 thing is just to keep track in some sensible way of
2141 whatever's been displayed!
2142 \end{notate}
2144 \begin{notate}{Local storage for browsing purposes} \label{local-storage}
2145 Right now, in order to browse the contents of the
2146 database, you need to query the database every time. It
2147 might be handy to offer the option to cache names of
2148 things locally, and only sync with the database from time
2149 to time. Indeed, the same principle could apply in
2150 various places; however, it may also be somewhat
2151 complicated to set up. Using two systems for storage, one
2152 local and one permanent, is certainly more heavy-duty than
2153 just using one permanent storage system and the local
2154 temporary display. However, one thing in favor of local
2155 storage systems is that that's what I used in the the
2156 previous prototype of Arxana -- so some code already
2157 exists for local storage! (Caching the list of
2158 \emph{names} we just made a selection from would be one
2159 simple expedient, see Note \ref{pick-a-name}.)
2160 \end{notate}
2162 \begin{notate}{Hang onto absolute references}
2163 Since `get-article' (Note \ref{get-article}) translates
2164 strings into their ``place pseudonyms'', we may want to
2165 hang onto those pseudonyms, because they are, in fact, the
2166 absolute references to the objects we end up working with.
2167 In particular, they should probably go into the
2168 text-property background of the article selector, so it
2169 will know right away what to select!
2170 \end{notate}
2172 \subsection{Exporting \LaTeX\ documents$^*$}
2174 \begin{notate}{Roundtripping}
2175 The easiest test is: can we import a document into the
2176 system and then export it again, and find it unchanged?
2177 \end{notate}
2179 \begin{notate}{Data format}
2180 We should be able to \emph{stably} import and export a
2181 document, as well as export any modifications to the
2182 document that were generated within Arxana. This means
2183 that the exporting functions will have to read the data
2184 format that the importing functions use, \emph{and} that
2185 any functions that edit document contents (or structure)
2186 will also have to use the same format. Furthermore,
2187 \emph{browsing} functions will have to be somewhat aware
2188 of this format. So, this is a good time to ask -- did we
2189 use a good format?
2190 \end{notate}
2192 \subsection{Editing database contents$^*$} \label{editing}
2194 \begin{notate}{Roundtripping, with changes}
2195 Here, we should import a document into the system and then
2196 make some simple changes, and after exporting, check with
2197 diff to make sure the changes are correct.
2198 \end{notate}
2200 \begin{notate}{Re-importing}
2201 One nice feature would be a function to ``re-import'' a
2202 document that has changed outside of the system, and make
2203 changes in the system's version whereever changes appeared
2204 in the source version.
2205 \end{notate}
2207 \begin{notate}{Editing document structure}
2208 The way we have things set up currently, it is one thing
2209 to make a change to a document's textual components, and
2210 another to change its structure. Both types of changes
2211 must, of course, be supported.
2212 \end{notate}
2214 \section{Applications} \label{applications}
2216 \subsection{Managing tasks} \label{managing-tasks}
2218 \begin{notate}{What are tasks?}
2219 Each task tends to have a \emph{name}, a
2220 \emph{description}, a collection of \emph{prerequisite
2221 tasks}, a description of other \emph{material
2222 dependencies}, a \emph{status}, some \emph{justification
2223 of that status}, a \emph{creation date}, and an
2224 \emph{estimated time of completion}. There might actually
2225 be several ``estimated times of completion'', since the
2226 estimate would tend to improve over time. To really
2227 understand a task, one should keep track of revisions like
2228 this.
2229 \end{notate}
2231 \begin{notate}{On `store-task-data'} \label{store-task-data}
2232 Here, we're just filling in a frame. Since ``filling in a
2233 frame'' seems like the sort of operation that might happen
2234 over and over again in different contexts, to save space,
2235 it would probably be nice to have a macro (or similar)
2236 that would do a more general version of what this function
2237 does.
2238 \end{notate}
2240 \begin{elisp}
2241 (defun store-task-data
2242 (name description prereqs materials status
2243 justification submitted eta)
2244 (add-nema name "is a" "task")
2245 (add-nema name "description" description)
2246 (add-nema name "prereqs" prereqs)
2247 (add-nema name "materials" materials)
2248 (add-nema name "status" status)
2249 (add-nema name "status justification" justification)
2250 (add-nema name "date submitted" submitted)
2251 (add-nema name "estimated time of completion" eta))
2252 \end{elisp}
2254 \begin{notate}{On `generate-task-data'} \label{generate-task-data}
2255 This is a simple function to create a new task matching
2256 the description above.
2257 \end{notate}
2259 \begin{elisp}
2260 (defun generate-task-data ()
2261 (interactive)
2262 (let ((name (read-string "Name: "))
2263 (description (read-string "Description: "))
2264 (prereqs (read-string
2265 "Task(s) this task depends on: "))
2266 (materials (read-string "Material dependencies: "))
2267 (status (completing-read
2268 "Status (tabled, in progress, completed):
2269 " '("tabled" "in progress" "completed")))
2270 (justification (read-string "Why this status? "))
2271 (submitted
2272 (read-string
2273 (concat "Date submitted (default "
2274 (substring (current-time-string) 0 10)
2275 "): ")
2276 nil nil (substring (current-time-string) 0 10)))
2277 (eta
2278 (read-string "Estimated date of completion:")))
2279 (store-task-data name description prereqs materials
2280 status
2281 justification submitted eta)))
2282 \end{elisp}
2284 \begin{notate}{Possible enhancements to `generate-task-data'}
2285 In order to make this function very nice, it would be good
2286 to allow ``completing read'' over known tasks when filling
2287 in the prerequisites. Indeed, it might be especially nice
2288 to offer a type of completing read that is similar in some
2289 sense to the tab-completion you get when completing a file
2290 name, i.e., quickly completing certain sub-strings of the
2291 final string (in this case, these substrings would
2292 correspond to task areas we are progressively zooming down
2293 into).
2295 As for the task description, rather than forcing the user
2296 to type the description into the minibuffer, it might be
2297 nice to pop up a separate buffer instead (a la the
2298 Emacs/w3m textarea). If we had a list of all the known
2299 tasks, we could offer completing-read over the names of
2300 existing tasks to generate the list of `prereqs'. It
2301 might be nice to systematize date data, so we could more
2302 easily e.g. sort and display task info ``by date''.
2303 (Perhaps we should be working with predefined database
2304 types for dates and so on.)
2306 Also, before storing the task, it might be nice to offer
2307 the user the chance to review the data they entered.
2308 \end{notate}
2310 \begin{notate}{On `get-filler'} \label{get-filler}
2311 Just a wrapper for `nemas-given-beginning-and-middle'.
2312 (Maybe we should add `heading' as an optional argument here.)
2313 \end{notate}
2315 \begin{elisp}
2316 (defun get-filler (frame slot)
2317 (third (first
2318 (print-triples
2319 (mapcar #'get-triple
2320 (nemas-given-beginning-and-middle frame
2321 slot))))))
2322 \end{elisp}
2324 \begin{notate}{On `get-task'} \label{get-task}
2325 Uses `get-filler' (Note \ref{get-filler}) to assemble the
2326 elements of a task's frame.
2327 \end{notate}
2329 \begin{elisp}
2330 (defun get-task (name)
2331 (when (triple-exact-match name "is a" "task")
2332 (list (get-filler name "description")
2333 (get-filler name "prereqs")
2334 (get-filler name "materials")
2335 (get-filler name "status")
2336 (get-filler name "status justification")
2337 (get-filler name "date submitted")
2338 (get-filler name
2339 "estimated time of completion"))))
2340 \end{elisp}
2342 \begin{notate}{On `review-task'} \label{review-task}
2343 This is a function to review a task by name.
2344 \end{notate}
2346 \begin{elisp}
2347 (defun review-task (name)
2348 (interactive "MName: ")
2349 (let ((task-data (get-task name)))
2350 (if task-data
2351 (display-task task-data)
2352 (message "No data."))))
2354 (defun display-task (data)
2355 (save-excursion
2356 (pop-to-buffer (get-buffer-create
2357 "*Arxana Display*"))
2358 (delete-region (point-min) (point-max))
2359 (insert "NAME: " name "\n\n")
2360 (insert "DESCRIPTION: " (first data) "\n\n")
2361 (insert "TASKS THIS TASK DEPENDS ON: "
2362 (second data) "\n\n")
2363 (insert "MATERIAL DEPENDENCIES: "
2364 (third data) "\n\n")
2365 (insert "STATUS: " (fourth data) "\n\n")
2366 (insert "WHY THIS STATUS?: " (fifth data) "\n\n")
2367 (insert "DATE SUBMITTED:" (sixth data) "\n\n")
2368 (insert "ESTIMATED TIME OF COMPLETION: "
2369 (seventh data) "\n\n")
2370 (goto-char (point-min))
2371 (fill-individual-paragraphs (point-min) (point-max))))
2372 \end{elisp}
2374 \begin{notate}{Possible enhancements to `review-task'}
2375 Breaking this down into a function to select the task and
2376 another function to display the task would be nice. Maybe
2377 we should have a generic function for selecting any object
2378 ``by name'', and then special-purpose functions for
2379 displaying objects with different properties.
2381 Using text properties, we could set up a ``field-editing
2382 mode'' that would enable you to select a particular field
2383 and edit it independently of the others. Another more
2384 complex editing mode would \emph{know} which fields the
2385 user had edited, and would store all edits back to the
2386 database properly. See Section \ref{editing} for more on
2387 editing.
2388 \end{notate}
2390 \begin{notate}{Browsing tasks} \label{browsing-tasks}
2391 The function `pick-a-name' (Note \ref{pick-a-name}) takes
2392 two functions, one that finds the names to choose from,
2393 and the other that says how to present these names. We
2394 can therefore build `pick-a-task' on top of `pick-a-name'.
2395 \end{notate}
2397 \begin{elisp}
2398 (defun get-tasks ()
2399 (mapcar #'first
2400 (print-triples
2401 (mapcar #'get-triple
2402 (nemas-given-middle-and-end "is a" "task")
2403 t))))
2405 (defun pick-a-task ()
2406 (interactive)
2407 (pick-a-name
2408 'get-tasks
2409 (lambda (items)
2410 (mapc (lambda (item)
2411 (let ((pos (line-beginning-position)))
2412 (insert item)
2413 (put-text-property pos (1+ pos)
2414 'arxana-display-type
2415 'task)
2416 (insert "\n"))) items))))
2418 (add-to-list 'display-style
2419 '(task . (get-task display-task)))
2420 \end{elisp}
2422 \begin{notate}{Working with theories}
2423 Presumably, like other related functions, `get-tasks'
2424 should take a heading argument.
2425 \end{notate}
2427 \begin{notate}{Check display style}
2428 Check if this works, and make style consistent between
2429 this usage and earlier usage.
2430 \end{notate}
2432 \begin{notate}{Example tasks}
2433 It might be fun to add some tasks associated with
2434 improving Arxana, just to show that it can be done...
2435 maybe along with a small importer to show how importing
2436 something without a whole lot of structure can be easy.
2437 \end{notate}
2439 \begin{notate}{Org mode integration}
2440 The ``default'' task manager on Emacs is Org mode. It would be good
2441 to provide integration between Org mode and Arxana. This is one of
2442 the first things that Emacs people ask about when they hear about
2443 Arxana.
2444 \end{notate}
2446 \subsection{``Modelling mathematics the way it is really done''} \label{farm-demo}
2448 \begin{notate}{Demonstration of an application to modelling mathematics}
2449 In a paper for the 5th ACM SIGPLAN International Workshop on
2450 Functional Art, Music, Modelling and Design (FARM 2017), we talk about
2451 how Arxana can be applied to model mathematical proofs. A rather
2452 advanced form of ``mathematical knowledge management'' is proposed,
2453 that integrates dialogue, heuristics, and that ultimately moves in the
2454 direction of an AI system. In this section, we will walk through this
2455 application.
2457 The basic idea here is to write an interpreter that will read
2458 s-expressions and convert them into triples in the backend. So we
2459 will need a function that reads s-exps into some designated storage.
2460 The s-expressions are constrained to follow the grammar defined
2461 for the Inference Anchoring Theory + Content (IATC) language.
2462 The primatives of this language are described below. The
2463 number of arguments is indicated in the variable name.
2464 (1.5 means that it takes one and, optionally, two arguments.)
2466 We will create a new plexus to store this content.
2467 \end{notate}
2469 \begin{elisp}
2470 (add-plexus)
2472 ;; (with-current-plexus (second plexus-registry)
2473 ;; (add-nema "this" "is a" "test"))
2475 (defvar iatc-performatives-2 '(Define))
2476 (defvar iatc-performatives-1.5 '(Assert Agree Challenge Retract))
2477 (defvar iatc-performatives-1 '(Suggest Judge Query))
2478 (defvar iatc-performatives-A '(QueryE))
2480 (defvar iatc-intermediate-2 '(implies strategy auxiliary analogy
2481 implements generalises wlog
2482 has_property instance_of
2483 indep_of))
2484 (defvar iatc-intermediate-1.5 '(easy))
2485 (defvar iatc-intermediate-1 '(not goal plausible beautiful useful
2486 heuristic))
2487 (defvar iatc-intermediate-A '(conjunction and))
2488 (defvar iatc-intermediate-1A '(case_split))
2490 (defvar iatc-content-2 '(used_in sub_prop reform instantiates
2491 expands sums))
2492 (defvar iatc-content-1 '(extensional_set))
2494 (defvar iatc-verbs (append iatc-performatives-2
2495 iatc-performatives-1.5
2496 iatc-performatives-1
2497 iatc-performatives-A
2498 iatc-intermediate-2
2499 iatc-intermediate-1.5
2500 iatc-intermediate-1
2501 iatc-intermediate-A
2502 iatc-intermediate-1A iatc-content-2
2503 iatc-content-1))
2505 (defvar iatc-imported-matcher
2506 (concat (regexp-opt (mapcar #'symbol-name iatc-verbs)) "[0-9]*"))
2507 \end{elisp}
2509 \begin{notate}{Second attempt}
2510 This code is based on the simpler idea of printing parent-child
2511 relationships.\footnote{\url{https://stackoverflow.com/a/45772888/821010}}
2512 But it is a bit more complicated, partly because we need different behaviour
2513 in the different cases outlined above.
2515 It would be nice, and, actually, necessary, to have ``multiple''
2516 return values, per the example below. The reason we need these return
2517 values is that new structure is developed relative to existing graph
2518 structure.
2520 The function works recursively. It will always turn the top-level
2521 verb into a nema and return it. It will also create one or more nemas
2522 along the way (behaviour depends on the specific verb).
2524 We also want to build up a structure that mirrors the tree that was
2525 put in, but that shows how the elements of that structure have been
2526 mapped into the graph.
2527 \end{notate}
2529 \begin{elisp}
2530 ;; utility function
2531 (defun get-verbs (tree)
2532 (let ((head (car tree))
2533 (tail (cdr tree)))
2534 (append
2535 (if (consp head)
2536 (get-verbs head)
2537 (list head))
2538 (let (acc)
2539 (while tail
2540 (setq child (car tail)
2541 tail (cdr tail))
2542 ;; we are only interested in recursing to add'l
2543 ;; function applications
2544 (when (consp child)
2545 (setq acc (append (get-verbs child) acc))))
2546 acc))))
2548 ; (get-verbs '(a (b (c 1 2)) 8 9 (d (e 1 2 3) (g 4 5))))
2550 ;; This function will takes in a tree that indicates a given subgraph,
2551 ;; marks up the subgraph with a cone (unless one exists already) and
2552 ;; return a handle to the cone.
2554 ;; Note that the cone itself can be stored as a list of nemas.
2556 ;; The natural extension would take a forest, find all of the cones,
2557 ;; and merge them.
2558 (defun sexp-to-cone-contents (tree &optional entailed-nemas)
2559 (with-current-plexus
2560 (second plexus-registry)
2561 ;; we have to parse input in much the same way as done by
2562 ;; `read-tree'. This is because both *named* nodes and
2563 ;; *additional* entailed structure will be (e.g., edges). But this
2564 ;; time, instead of creating any new structure, we just put the
2565 ;; entailed items in our grab-bag
2566 (let* (;; verb to handle - it may correspond to a nema
2567 (verb (car tree))
2568 ;; as a nema, if such exists.
2569 ;; (is it OK to retrieve by label?)
2570 (atom (label2uid verb)))
2572 (when atom (push atom entailed-nemas))
2573 (cond
2574 ((string= (symbol-name verb) "and")
2575 ;; there will be edges pointing to any children; we grab the edges here
2576 (dolist (child (cdr tree))
2577 (push (:id (nemas-exact-match atom
2579 (label2uid child)))
2580 entailed-nemas))
2581 (sexp-to-cone-contents child entailed-nemas))
2582 ((string= (symbol-name verb) "implies")
2583 ;; an *implies* node gets two associated edges:
2584 ;; one pointing to its antecedent and one pointing to its
2585 ;; consequent
2586 (let ((antecedent (first (cdr tree)))
2587 (consequent (second (cdr tree))))
2588 (push (:id (nemas-exact-match atom
2589 "antecedent"
2590 (label2uid child)))
2591 entailed-nemas)
2592 (push (:id (nemas-exact-match atom
2593 "consequent"
2594 (label2uid child)))
2595 entailed-nemas)))
2597 ;; default behaviour covers these verbs:
2598 ;; - and (multiple clauses; included above to illustrate)
2599 ;; - analogy (do we need to check that it only has 2 terms?)
2600 (dolist (child (cdr tree))
2601 (push (:id (nemas-exact-match atom
2603 (label2uid child)))
2604 entailed-nemas))))
2605 entailed-nemas)))
2607 ;; simulate "multi-value return"
2608 (defun read-tree (tree)
2609 (second (highlight-tree tree)))
2611 ;; recursively chase through the tree, import it, and mark it up
2612 (defun highlight-tree (tree &optional highlights)
2613 (with-current-plexus
2614 (second plexus-registry)
2615 ;; Cases:
2616 ;; (1):IATC - create an internal identifier for it.
2617 ;; (2):already-imported IATC - don't import it again, just refer to it
2618 ;; (3):string - if we want to deal with this separately, just create a schematic node
2619 ;; (4):generic hcode or other LISP - push form into a node as contents
2620 (cond
2621 ;; (1):IATC
2622 ;; we need to import the tree ->
2623 ((member (car tree) iatc-verbs)
2624 (let* ((verb (car tree)) ; verb to import
2625 (symb (gensym (symbol-name verb))) ; as a symbol
2626 (atom (add-nema 0 symb 0)) ; as a nema
2627 ; *this will be 1st return value*
2628 (label (label-nema atom symb)) ; we give it a handle
2629 (type (add-nema symb "type" verb))) ; we annotate it with a type
2630 (cond
2631 ((string= (symbol-name verb) "and")
2632 ;; Connect each of the children, which we process here
2633 (dolist (child (cdr tree))
2634 (add-nema atom
2636 (if (consp child)
2637 (first (highlight-tree child))
2638 child))))
2639 ((string= (symbol-name verb) "implies")
2640 ;; an *implies* node gets two associated edges:
2641 ;; one pointing to its antecedent and one pointing to its
2642 ;; consequent
2643 (let ((antecedent (first (cdr tree)))
2644 (consequent (second (cdr tree))))
2645 (add-nema atom
2646 "antecedent"
2647 (if (consp antecedent)
2648 (first (highlight-tree antecedent))
2649 antecedent))
2650 (add-nema atom
2651 "consequent"
2652 (if (consp consequent)
2653 (first (highlight-tree consequent))
2654 consequent))))
2656 ;; default behaviour covers these verbs:
2657 ;; - and (multiple clauses; included above to illustrate)
2658 ;; - analogy (do we need to check that it only has 2 terms?)
2659 (dolist (child (cdr tree))
2660 (add-nema atom
2662 (if (consp child)
2663 (first (highlight-tree child))
2664 child)))))
2665 ;; we replace the verb with its new symbol as a handle
2666 (rplaca tree symb)
2667 (list atom tree)))
2668 ;; (2):already-imported IATC, as indicated by the verb's form
2669 ((string-match iatc-imported-matcher (symbol-name verb))
2670 ;; the s-exp rooted on this verb is representative of a
2671 ;; subgraph that has already been imported. We convert it
2672 ;; to a cone over the subgraph, and return that.
2674 ;; (3):string
2675 ((stringp (car tree))
2676 ;; just add it.
2677 ;; This is a terminal node so no more recursion here.
2678 (list (add-nema 0 (car tree) 0) nil)
2680 ;; (4):generic hcode
2684 \end{elisp}
2686 \begin{notate}{Example: describing and querying a simple analogy}
2687 The first example proposes a superficially simple analogy. Note that while it builds up a structure in the backend,
2688 the interpreter returns some convenient handles for the contents that
2689 are entered.
2690 \end{notate}
2692 \begin{idea}
2693 (with-current-plexus (second plexus-registry)
2694 (reset-plexus))
2696 (setq
2697 %1-implies
2698 (read-tree '(Assert (implies (and "G finite group"
2699 "H subgroup of G"
2700 "[G : H] finite")
2701 "G not equal to union of ghg^-1"))))
2702 ;=> %1-implies
2704 (setq
2705 %2-analogy
2706 (read-tree
2707 `(Assert (analogy
2708 ,(cadr %1-implies)
2709 (implies (and "G infinite group"
2710 "H subgroup of G"
2711 "[G : H] finite")
2712 "G not equal to union of ghg^-1")))))
2713 ;=> %2-analogy
2715 (setq %3-question `(Question ,(car (cddadr %2-implies))))
2716 ;=> %3-question
2717 \end{idea}
2719 \begin{notate}{A challenge problem}
2720 The second example is a full solution to a challenge problem.
2721 \end{notate}
2723 \begin{idea}
2724 ;; What is the 500th digit of (sqrt(3)+sqrt(2))^2012?
2726 (Assert
2727 "goal"
2728 "compute 500th digit of (sqrt(3)+sqrt(2))^2012")
2730 ;; Even this...
2732 (Assert (exists (strategy "goal"
2733 "strategy X")))
2735 (Assert (has_property "strategy X"
2736 "HAL"))
2738 ;; For now...
2740 (Suggest (strategy goal
2741 "simplify and compute"))
2743 ;; Furthermore...
2745 (Suggest (strategy goal
2746 "this should be straightforward
2747 once we find the trick"))
2749 ;; Can we do...
2751 (Assert
2752 (analogy
2753 "compute 500th digit of (sqrt(2)+sqrt(3))^2012"
2754 "compute 500th digit of (x+y)^2012"))
2756 (Assert
2757 (analogy
2758 "compute 500th digit of (sqrt(2)+sqrt(3))^2012"
2759 "compute 500th digit of e^2012"))
2761 (Assert
2762 (analogy
2763 "compute 500th digit of (sqrt(2)+sqrt(3))^2012"
2764 "compute 500th digit of r^2012,
2765 where r is a rational with small denominator"))
2767 (Assert
2768 (has_property
2769 "compute 500th digit of r^2012,
2770 where r is a rational with small denominator"
2771 "we can really compute this"))
2773 (Assert
2774 (has_evidence
2775 "we can really compute this"
2776 "e.g. 500th digit of (1/10)^2012 is 0"))
2778 ;; How about small...
2780 (Suggest (strategy goal
2781 "the trick might be: it
2782 is close to something
2783 we can compute"))
2785 ;; mth digit of...
2787 (Suggest (auxilliary
2788 "generalise"
2789 "general form of the problem:
2790 mth digit of (sqrt(3)+sqrt(2))^n"))
2792 ;; (sqrt(3)+sqrt(2))^2
2794 (Suggest (auxilliary
2795 "specialise"
2796 "(sqrt(3)+sqrt(2))^2"))
2798 (Assert (instantiates
2799 "(sqrt(3)+sqrt(2))^2"
2800 "general form of the problem:
2801 mth digit of (sqrt(3)+sqrt(2))^n"))
2803 (Assert (has_property
2804 "(sqrt(3)+sqrt(2))^2"
2805 "we can really compute this"))
2807 ;; 2 + 2 sqrt(2) sqrt(3) + 3
2809 (Assert (expands
2810 "(sqrt(3)+sqrt(2))^2"
2811 "2 + 2 sqrt(3) sqrt(2) + 3"))
2813 ;; (sqrt(3)+sqrt(2))^2 + (sqrt(3)-sqrt(2))^2 = 10
2815 (Suggest (strategy "eliminate cross terms"))
2817 (Assert (expands "(sqrt(3)+sqrt(2))^2 + (sqrt(3)-sqrt(2))^2"
2818 "2 + 2 sqrt(2) sqrt(3) + 3
2819 + 2 - 2 sqrt(2) sqrt(3) + 3"))
2821 (Assert (sums "2 + 2 sqrt(2) sqrt(3) + 3
2822 + 2 - 2 sqrt(2) sqrt(3) + 3"
2823 "10"))
2825 ;; (sqrt(3)+sqrt(2))^2012 + (sqrt(3)-sqrt(2))^2012 is an integer
2827 (Suggest (strategy "binomial theorem"))
2829 (Assert (generalises "binomial theorem"
2830 "eliminate cross terms"))
2832 (Assert (sums "(sqrt(3)+sqrt(2))^2012 + (sqrt(3)-sqrt(2))^2012"
2833 "some integer"))
2835 ;; And (sqrt(3)-sqrt(2))^2012 is a very small number
2837 (Assert (contains_as_summand
2838 "(sqrt(2)+sqrt(3))^2012+(sqrt(3)-sqrt(2))^2012"
2839 "(sqrt(3)-sqrt(2))^2012"))
2841 (Assert (has_property "(sqrt(3)-sqrt(2))^2012"
2842 "is small"))
2844 (Assert (implements #SUBGRAPH
2845 "the trick might be: it
2846 is close to something
2847 we can compute"))
2849 (Suggest (strategy "numbers that are very close
2850 to integers have \"9\"
2851 in many places of their
2852 decimal expansion"))
2854 ;; We need to check...
2856 (Assert "sqrt(3)-sqrt(2)<1/2")
2857 (Assert "0<a<b<1 => a^N < b^N")
2858 (Assert "(1/2)^2012 = ((1/2)^4)^503")
2859 (Assert "(1/2)^4 = 1/16")
2860 (Assert "1/16 < .1")
2861 (Assert ".1^503 has 502 0's
2862 in its decimal expansion")
2863 (Assert "an integer minus something with
2864 at least 502 0's in its decimal
2865 expansion has at least 503 9's
2866 in its decimal expansion")
2868 (Assert (implies #SUBGRAPH2
2869 "(sqrt(2)+sqrt(3))^2012
2870 = (sqrt(2)+sqrt(3))^2012
2871 +(sqrt(2)+sqrt(3))^2012
2872 -(sqrt(2)-sqrt(3))^2012
2873 has at least 503 9's in its
2874 decimal expansion"))
2876 (Assert (has_specialisation
2877 "(sqrt(2)+sqrt(3))^2012
2878 = (sqrt(2)+sqrt(3))^2012
2879 +(sqrt(2)+sqrt(3))^2012
2880 -(sqrt(2)-sqrt(3))^2012
2881 has at least 503 9's in its
2882 decimal expansion"
2883 "(sqrt(2)+sqrt(3))^2012 has 500
2884 9s in its decimal expansion"))
2886 (Assert "(sqrt(2)+sqrt(3))^2012 has 500
2887 9s in its decimal expansion")
2888 \end{idea}
2890 \section{Conclusion} \label{conclusion}
2892 \begin{notate}{Ending and beginning again}
2893 This is the end of this Arxana demo system. Contributions that
2894 support the development of the Arxana project are welcome.
2895 \end{notate}
2897 \appendix
2899 \section{Appendix: A simple literate programming system} \label{appendix-lit}
2901 \begin{notate}{The literate programming system used in this paper}
2902 This code defines functions that grab all the Lisp portions of this
2903 document, and evaluates the Emacs Lisp sections. It requires that the
2904 \LaTeX\ be written in a certain consistent way. The function assumes
2905 that this document is the current buffer.
2907 \begin{verbatim}
2908 (defvar lit-code-beginning-regexp
2909 "^\\\\begin{elisp}")
2911 (defvar lit-code-end-regexp
2912 "^\\\\end{elisp}")
2914 (defvar lit-count 0)
2916 (defun lit-eval ()
2917 (interactive)
2918 (lit-process 'eval))
2920 (defun lit-process (&optional code)
2921 (interactive)
2922 (setq lit-count (1+ lit-count))
2923 (save-excursion
2924 (let ((to-buffer (concat "*Lit Code " (int-to-string
2925 lit-count)"*"))
2926 (from-buffer (buffer-name (current-buffer))))
2927 (set-buffer (get-buffer-create to-buffer))
2928 (erase-buffer)
2929 (set-buffer (get-buffer-create from-buffer))
2930 (goto-char (point-min))
2931 (while (re-search-forward
2932 lit-code-beginning-regexp nil t)
2933 (let* ((beg (match-end 0))
2934 (end (save-excursion
2935 (search-forward-regexp
2936 lit-code-end-regexp nil t)
2937 (match-beginning 0)))
2938 (match (buffer-substring beg end)))
2939 (save-excursion
2940 (set-buffer to-buffer)
2941 (insert match))))
2942 (case code
2943 ('eval
2944 (set-buffer to-buffer)
2945 (eval-buffer)
2946 ;; (kill-buffer (current-buffer))
2949 (switch-to-buffer to-buffer))))))
2950 \end{verbatim}
2951 \end{notate}
2953 \begin{notate}{A literate style}
2954 Ideally, each function will have its own Note to introduce
2955 it, and will not be called before it has been defined. I
2956 sometimes make an exception to this rule, for example,
2957 functions used to form recursions may appear with no
2958 further introduction, and may be called before they are
2959 defined.
2960 \end{notate}
2962 \clearpage
2963 \printindex
2965 \end{document}