Commit cdfc237b authored by Ioanna M. Dimitriou H.'s avatar Ioanna M. Dimitriou H. 💬

This fixes issue #1 and changes the syntax of the graph* functions in a backwards compatible way.

The changes in detail:

- adds nickname :jeffrey to package :jeffrey.main
- moved assertions from main.lisp to a test in test.lisp
- in all graphing functions, STYLE is now an optional argument, which defaults to "numbers".
- exports jeffrey:random-graph, jeffrey:graph-ancestors, jeffrey:graph-descendants
- to celebrate jeffrey's first issues, I added a *brand new* (jeffrey:graph-interval top-form bottom-form filename &optional (style "numbers") ending)
- jeffrey now *also* understands which output format to use from the filename given (e.g. "filename.svg" will produce an svg file, even when the optional ending "svg" is not given).
- fixed documentation of the package jeffrey.main and in the README.md
- cleaned up some whitespace and fixed indentation here and there

Try it:

- (jeffrey:graph '(1 2 3 4 5 6) "forms-1-to-6.svg")
- (jeffrey:graph-descendants '(94) "descendants-of-94")
- (jeffrey:graph-ancestors '(399 256) "ancestors-of-399-or-256.pdf")
- (jeffrey:graph-interval 9 64 "interval-9-to-64.jpg")
- (jeffrey:random-graph 6 "random-6.png")

Still only works for "number" labels, work on "fancy" labels has started.
parent 75e15c8d
fancy-labels/
diagrams/
*~
\ No newline at end of file
......@@ -4,7 +4,9 @@ The Choiceless Grapher can produce any size of graph of the implication relation
This project is inspired by and based on the **Consequences of the Axiom of Choice Project**, the encyclopedia of set theory without the axiom of choice, by *Prof. Paul Howard and Prof. Jean E. Rubin*. I thank Paul Howard for providing me with the original implication matrix (book1), a tex document with the form statements in LaTeX form, and permision to use these files, which can be found in the folder "Howard-Rubin-data".
An overview of the program is given below. A paper with a full description and explanation of the code will appear. Until then, you can find posts about this in my ["Boole's ring"](https://boolesrings.org/ioanna/). A big **thank you** to my teammate [Max Rottenkolber](http://mr.gy) over at [interstellar ventures](http://inters.co) for showing me the light (Common Lisp), and for hosting this app:
An overview of the program is given below. A detailed description was published in my previous website, which [no longer exists](https://boolesrings.org/ioanna/). I plan to import the old posts from there to my new website [ioa.re](https://ioa.re).
This is my first fullstack program, and I pledge to maintain it for life. I wrote this while learning common-lisp, and for this, a big **thank you** to my common-lisp sensei [Max Rottenkolber](http://mr.gy) over at [interstellar ventures](http://inters.co) for showing me the light (common-lisp), for naming back then this choiceless grapher `jeffrey` (because naming is hard), and for hosting this program's web app:
## The Website, aka the CGraph app
......@@ -27,58 +29,62 @@ If you want very large diagrams (more than 70 or 80 forms)*, or if you prefer to
* Common-Lisp: I have only tested this with **SBCL** or **CCL** but it should work in any implementation that [external-program](https://github.com/sellout/external-program) supports. Please let me know if you check this!
* [Graphviz](www.graphviz.org/) (`apt-get install graphviz`)
* [Quicklisp](www.quicklisp.org)
* It only works in Linux. Windows and Macintosh support are no longer on the to-do list, since the program is accessible via its web-interface. *If you are interested in having these OS supported please send me a message or leave a comment.*
* The package `labelmaker` also requires `/bin/bash`, `pdflatex`, and `convert`.
* It only works in Linux. Windows and Macintosh support are no longer on the to-do list, since the program is accessible via its web-interface. *If you are interested in having these OS supported please send me a message.* Having said that, do try it in a Mac, as any unix system which understands `which` should work in theory. Please let me know!
* The package `labelmaker` (so to use "fancy" labels) also requires `/bin/bash`, `pdflatex`, the latex package `standalone`, and `imagemagick` for `convert`. Currently there are some issues with `convert`ing from `pdf` files, please wait for the next update to use fancy labels.
### Installation
Install this package using quicklisp ([installation instructions](https://www.quicklisp.org/beta/#installation)) and git ([installation instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)) as follows:
* Create a folder called `jeffrey` in `quicklisp/local-projects/`,
* Navigate to this folder in a terminal and type `git init` and `git clone git@github.com:ioannad/jeffrey.git`. Alternatively otherwise download the cohntents of this repository to this folder.
- Install the system dependency Graphviz, for example with aptitude (Debian, Ubuntu, et.al.) using `sudo apt install graphviz`.
- In a terminal, navigate to a directory that ASDF or quicklisp can find (e.g. `quicklisp/local-projects/`) and `git clone https://gitlab.common-lisp.net/idimitriou/jeffrey.git`. Alternatively otherwise download the contents of this repository to such a directory.
### Load the Choiceless Grapher
Open a Common Lisp REPL and type in (evaluate)
In a Common Lisp REPL, evaluate `(ql:quickload \"jeffrey\")` and `(in-package :jeffrey)`.
`(ql:quickload "jeffrey")`.
### Draw the diagram between a given list of form HR numbers
### Drawing the diagram between a given list of form HR numbers
If `'(a b c ..)` is the list of form numbers (only numbers, without parameters or equivalent form letters), whose relationships you wish to graph, e.g. `'(1 2 3 4 5)` and if you want to save the diagram in a `png` file `filename.png`, then evaluate:
If '(a b c ..) is the list of form numbers (only numbers, without parameters or equivalent form letters), whose relationships you wish to graph, and if you want to save the diagram in the file "filename", then evaluate:
`(graph '(1 2 3 4 5) "filename.png")`
`(graph '(a b c ...) "filename" "style")`
Instead of `png` you can create another output format supported by `dot`, e.g., `svg`, `pdf`, `jpg`, etc. See `man dot` for details.
If you leave out the `.*` ending, a `png` file will be produced.
where "style" should be either "numbers" to get the numbers of the nodes in the diagram, or "fancy" to get the full LaTeX-formatted statements of the nodes in the diagram. "fancy" is still experimental and doesn't work well for very large diagrams, in the magnitude of the full one (goes over 13 meters in width).
All output files are created in a (new) `diagrams/` subdirectory of this repository's base directory.
### Drawing a random diagram of a given size
You can also draw the implication diagram of a pseudo-random collection of forms, of a given size, as follows (for size 6):
`(random-graph 6 "filename" "style")`
`(random-graph 6 "filename")`
where "style", as above, should be either "numbers" or "fancy".
"Random" diagrams additionally include forms 1 (Axiom of Choice, top form) and form 0 (`0=0`, bottom form), otherwise these diagrams are often completely disconnected.
### Drawing the consequences or of a list of forms
### Drawing descendants of a list of forms
Similarly, you can draw the implication diagram of a list of forms (e.g. of `'(8 85)`) as follows:
To draw the consequences of forms in a list (e.g. all consequecnes of form 8 and of form 85), evaluate:
`(graph-descendants '(8 85) "filename" "style")`
`(graph-descendants '(8 85) "filename")`
### Output format
### Drawing ancestors of a list of forms
The default output is no longer pdf, as there is an issue with the borders of the fancy labels. The current default is `png` but you can output any filetype supported by dot (svg, ps,...) with, for example:
To draw all the forms that imply a form in a list of forms evaluate:
`(graph '(0 1 2 3 23) "test" "fancy" "ps")`
`(graph-ancestors '(399 256) "filename")`
or
### *NEW:* Drawing an interval between two forms
`(random-graph 5 "random5" "fancy" "svg")`
To draw all the consequences of the form with `name-1` (e.g., 261) that imply the form with `name-2` (e.g., 260), evaluate:
The resulting images and dot files will appear in `~/quicklisp/local-projects/jeffrey/diagrams`. If you have quicklisp installed somewhere else, then please do a `(setf *local-directory* "path/to/your/jeffrey")`, where "path/to/your/jeffrey" should be the directory where the Choiceless Grapher is installed.
`(graph-interval 261 260 "filename")`
## Detailed description
This program requires package "maxpc", "split-sequence", and "external-program".
This program requires the common-lisp packages "maxpc", "split-sequence", and "external-program". They are all available via Quicklisp, so you shouldn't have to install these separately. For the website it depends additionally in the quicklisp packages "
It's nickname is `jeffrey`, as naming is hard and this was my first full stack program.
**jeffrey.asd** contains the (defsystem ...) command that creates "jeffrey" as a system of packages. The files that comprise jeffrey's packages, their exported functions, and their dependencies are listed in **packages.lisp**.
......@@ -88,13 +94,13 @@ This program requires package "maxpc", "split-sequence", and "external-program".
**process-strings.lisp** contains functions which make the text in any LaTeX-statement LaTeX compatible (the origin is TeX). It's a crude search and replace routine.
**read.lisp** contains the functions that read input, and it can be run in its whole with `(read-all-data)`. This function will first store the form data from `FORMSNUM.TEX` as nodes in `*graph*`, then add edges and parents to these nodes, following only the direct information from `book1`. That is, if book1 has code 1 in position (i,j), then it will add an edge to the node with name i (node i) with destination node j and relation T, and it will add node i to the set of parents of node j. If book1 has code 3 in position (i,j), then it will only add an edge to node i with destination node j and relation NIL. All other codes should be derivable from this information, using the predicates in the next module.
**read.lisp** contains the functions that read input, and it can be run in its whole with `(read-all-data)`. This function will first store the form data from `FORMSNUM.TEX` as nodes in `*graph*`, then add edges and parents to these nodes, following only the direct i nformation from `book1`. That is, if book1 has code 1 in position (i,j), then it will add an edge to the node with name i (node i) with destination node j and relation T, and it will add node i to the set of parents of node j. If book1 has code 3 in position (i,j), then it will only add an edge to node i with destination node j and relation NIL. All other codes should be derivable from this information, using the predicates in the next module.
**predicates.lisp** enables the program to ask whether or not a node (form) implies another. The function implies-p only answers positive implication questions, and implies-not-p only answers negative implication questions. In particular, `(implies-p A B)` asks whether A is an ancestor of B and `(implies-not-p B A)` asks whether there is an ancestor B' of B and a descendant A' of A, such that the node B' has an edge with destination A' and relation NIL. Why is the predicate "implies-p" defined like this is clear. For `(implies-not-p B A)`, assume that there is an ancestor B-anc of B and a descendant A-desc of A, such that B-anc does not imply A-desc (the meaning of a NIL-edge from B-anc to A-desc). Then `(implies-not-p B A)` must be T, i.e., B does not imply A, because otherwise we have the implication chain:
**predicates.lisp** enables the program to ask whether or not a node (form) implies another. The function implies-p only answers positive implication questions, and implies-not-p only answers negative implication questions. In particular, `(implies-p A B)` asks whether `A` is an ancestor of `B` and `(implies-not-p B A)` asks whether there is an ancestor `B-anc` of `B` and a descendant `A-desc` of `A`, such that the node `B-anc` has an edge with destination `A-desc` and relation NIL (i.e., such that `B-anc` does not imply `A-desc`). Why is the predicate `implies-p` defined like this is clear. For `(implies-not-p B A)`, assume that there is an ancestor `B-anc` of `B` and a descendant `A-desc` of `A`, such that `B-anc` does not imply `A-desc` (the meaning of a NIL-edge from `B-anc` to `A-desc`). Then `(implies-not-p B A)` must be T, i.e., it must be the case that `B` does not imply `A`, *otherwise* we have the implication chain:
B-anc implies B implies A implies A-desc,
`B-anc` implies `B` implies `A` implies `A-desc`,
therefore B-anc implies A-desc, contradiction to the NIL-edge from B-anc to A-desc.
therefore `B-anc` implies `A-desc`, which is a contradiction to the NIL-edge from `B-anc` to `A-desc`.
**test.lisp** contains test data and testing functions, which should be run after every and any change in the above files.
Run all tests while `(in-package :jeffrey-test)` with the command `(test-all)`, which prints a report to your REPL.
......@@ -105,13 +111,15 @@ Run all tests while `(in-package :jeffrey-test)` with the command `(test-all)`,
**main.lisp** the main package is explained above.
**website.lisp** "The currently unfinished website of choiceless grapher, learning sources included at the top of the file. Uses hunchentoot as a webserver, cl-who, maxpc, parenscript, and a local css file, to serve you freshly made diagrams of your *choice*."
**website.lisp** "The website of choiceless grapher, uses [hunchentoot](https://www.cliki.net/Hunchentoot) as a webserver, and [html-template](https://www.cliki.net/html-template) to create the pages. Thanks to [Edi Weitz](https://www.cliki.net/Edi%20Weitz) for these two brilliant packages!
**diagrams/** is not included here, it is created when you create your first diagram. All diagrams you create with this program are put there.
**/diagrams/** contains diagrams with sets of forms that make sense, e.g., between forms about alephs and their properties, as well as diagrams with random sets of forms. A boldfaced arrow from A to B means that the implication is non-reversible, i.e., there exists a model of ZF set theory in which B holds and A doesn't. *Just imagine the endless possibilities for random research projects, theses, and papers, filling or boldfacing those arrows! :)* The `full-diagram.pdf` is also included, only for standard "number names" (not full statements). Its size is 3,41m x 1,72 m.
**examples/** contains diagrams with sets of forms that make sense, e.g., between forms about alephs and their properties, as well as diagrams with random sets of forms. A boldfaced arrow from A to B means that the implication is non-reversible, i.e., there exists a model of ZF set theory in which B holds and A doesn't. *Just imagine the endless possibilities for random research projects, theses, and papers, filling or boldfacing those arrows! :)* The `full-diagram.pdf` is also included, only for standard "number names" (not full statements). Its size is 3,41m x 1,72 m.
**/fancy-labels/** is not included here, but you can produce it from package `:jeffrey.labelmaker` with the command `(make-fancy-labels`).
**fancy-labels/** is not included here, but you can produce it from package `:jeffrey.labelmaker` with the command `(make-fancy-labels`). Please wait for the next update to use this.
**/Howard-Rubin-data/** contains the files from the Consequences of the Axiom of Choice Project, which were kindly provided by Prof. Paul Howard.
**Howard-Rubin-data/** contains the files from the Consequences of the Axiom of Choice Project, which were kindly provided by Prof. Paul Howard.
**complexity issues**
I have made some small steps to improve the original brute force algorithm for calculating the predicates. The biggest difference was made by memoising with the addition of the `*jeff-matrix*`. A 7%-25% improvement (SBCL and CCL resp.) was achieved by changing the double loop of `(graph-implies-not-p Y X)` to three single loops (finding destinations of nil edges of ancestors of Y, finding descendants of X, and intersecting these two lists).
I have made some small steps to improve the original brute force algorithm for calculating the predicates. The biggest difference was made by memoising with the addition of the `*jeff-matrix*`. A 7%-25% improvement (SBCL and CCL respectively, at the time of testing, on Debian in my thinkpad x201) was achieved by changing the double loop of `(graph-implies-not-p Y X)` to three single loops (finding destinations of nil edges of ancestors of Y, finding descendants of X, and intersecting these two lists).
......@@ -2,9 +2,9 @@
#|
example of expected use of exported function:
(draw '(2 3 65 43 22 102) "diagram-name")
(draw '(2 3 65 43 22 102) "diagram-name.png")
This should draw the diagram between the nodes with names in the
above list, and save the .dot and .pdf files to
above list, and save the .dot and .png files to
~/quicklisp/local-projects/jeffrey/diagrams/diagram-name.dot and
...pdf respectively.
|#
......@@ -14,6 +14,7 @@ above list, and save the .dot and .pdf files to
*local-directory*
"diagrams/"
input-filename
"."
postfix-ending))
(defun print-dot-head ()
......@@ -24,13 +25,20 @@ above list, and save the .dot and .pdf files to
node [shape=ellipse,width=0.5,height=1];~%" ))
(defun print-fancy-label (name)
"Takes the node `name` from the user input and returns a string
that makes Graphviz-dot use the pdf file in the folder
`\"form-name-pics\"`, that contains this form's LaTeX formatted
statement."
"Takes the node NAME from the user input and returns a string
that makes Graphviz-dot use the png file in the folder `fancy-labels`,
which contains this form's LaTeX formatted statement. Requires
(jeffrey.labelmaker::make-fancy-labels), which currently has issues
with `imagemagick`'s `convert`."
(let ((fancy-label-filename (format nil
"~afancy-labels/~a.png"
*local-directory* name)))
(if (probe-file fancy-label-filename)
(format *standard-output*
"~a [image=\"~afancy-labels/~a.png\", label=\" \"];~%"
name *local-directory* name))
"~a [image=\"~a\", label=\" \"];~%"
name fancy-label-filename)
(error "~&Fancy labels seem not set up, or not set up properly.
Please evaluate (jeffrey.labelmaker::make-fancy-labels) and retry."))))
(defun print-node-label (name node style)
"Writes the labels for the nodes in the style `style`, depending on
......@@ -80,33 +88,47 @@ to the `*standard-output*`."
do (print-node-label name node style)
(print-arrows-from name node input-names)))
;; IO
(defun create-dot-file (dot-file input-names style)
"DOT-FILE should be a complete pathname, with (the default) parent directory."
(ensure-directories-exist dot-file :verbose t)
(with-open-file (*standard-output* dot-file
:direction :output
:if-does-not-exist :create
:if-exists :supersede)
(print-dot-head)
(print-dot-content input-names style)
(format *standard-output* "~%}")))
(defun run-tred-dot (dot-file result-file ending)
"Runs Graphviz tred on `dot-file` and feeds the output to
Graphviz dot. Outputs `result-file`, which contains the diagram."
"Runs Graphviz tred on `dot-file` and feeds the output to Graphviz dot.
Outputs `result-file`, which contains the diagram. Requires the system
package Graphviz."
(let ((command-string (concatenate 'string
"/usr/bin/tred "
dot-file
(namestring dot-file)
" | dot -T"
ending
" -o "
result-file)))
(run "/bin/sh" (list "-c" command-string)
:output t)))
(namestring result-file))))
(if (probe-file (pathname "/usr/bin/tred"))
(run "/bin/sh"
(list "-c" command-string)
:output t)
(error "Graphviz is not installed. Please install and retry."))))
(defun draw (input-names diagram-filename style &optional (ending "png"))
(defun draw (input-names filename style ending)
"`style` should be either the string \"fancy\" or \"numbers\".
`format` can be anything supported by dot, e.g., pdf, png, svg, ps.
The default format is pdf."
(let ((dot-file (make-filename ".dot" diagram-filename))
(result-file (make-filename (concatenate 'string "." ending) diagram-filename)))
(with-open-file (*standard-output* dot-file
:direction :output
:if-does-not-exist :create
:if-exists :supersede)
(print-dot-head)
(print-dot-content input-names style)
(format *standard-output* "~%}"))
(run-tred-dot dot-file result-file ending)
(format nil
"Files ~a and ~a in diagrams/ should be created successfully."
dot-file result-file)))
If the DIAGRAM-FILENAME doesn't end in one of those formats, then png will be used."
(let ((dot-file (pathname (make-filename "dot" filename)))
(result-file (pathname
(make-filename ending filename))))
(handler-case
(progn (create-dot-file dot-file input-names style)
(run-tred-dot dot-file result-file ending))
(:no-error (message value)
(format *standard-output*
"~&Files ~a and ~a in diagrams/ should be created successfully.~%"
dot-file result-file)))))
......@@ -8,37 +8,51 @@
collect key))
(defun name-transformer (key names)
(let ((funct (case key
(let ((transformer (case key
(:these (lambda (node)
(list node)))
(:descendants #'descendants)
(:ancestors #'ancestors))))
(:ancestors #'ancestors)
(:interval #'interval)))
;; the transformers require nodes input so we get the nodes
(nodes (loop for name in names collect (gethash name *graph*))))
(remove-duplicates
(append
names
(loop for name in names
append (map 'list
#'node-name
(funcall funct (gethash name *graph*))))))))
(mapcar
#'node-name ; the transformers return nodes, so we get the names
(append nodes ; add the input nodes to the graph
(if (eq key :interval)
;; interval takes exactly the two given nodes as input
(apply transformer nodes)
;; ancestors or descendants of all the NAMES will be included
(reduce 'append (mapcar transformer nodes))))))))
(assert (equal '(0 1 2 3 4 5)
(name-transformer :these '(0 1 2 3 4 5))))
(assert (equal '(0 18 64 80 127 300 301 389 390)
(sort (name-transformer :descendants '(80 301 64))
#'<)))
(assert (equal '(1 188 193 255 256 258 261 262)
(sort (name-transformer :ancestors '(255 188))
#'<)))
(defun graph (names-list filename
&optional style ending
&aux (filename% filename))
(let ((pathname (pathname filename)))
(when (null style)
(setq style "numbers"))
(when (null (or ending
(pathname-type pathname)))
(setq ending "png"))
(when (null ending)
(setq ending (pathname-type pathname))
(setq filename% (pathname-name pathname)))
(when (pathname-directory pathname)
(warn "The parent directory of your output file is ignored.
Output files will be placed in ..jeffrey/diagrams/"))
(draw names-list filename% style ending)))
(defun graph (names-list filename style &optional (ending "png"))
(draw names-list filename style ending))
(defun graph-descendants (names-list filename &optional style ending)
(graph (name-transformer :descendants names-list)
filename style ending))
(defun graph-descendants (names-list filename style &optional (ending "png"))
(draw (name-transformer :descendants names-list)
(defun graph-ancestors (names-list filename &optional style ending)
(graph (name-transformer :ancestors names-list)
filename style ending))
(defun graph-ancestors (names-list filename style &optional (ending "png"))
(draw (name-transformer :ancestors names-list)
(defun graph-interval (name-1 name-2 filename &optional style ending)
(graph (name-transformer :interval (list name-1 name-2))
filename style ending))
;;; Random graph functions
......@@ -68,5 +82,5 @@
(append *bad-forms*
'(0 1)))))
(defun random-graph (amount-of-nodes filename style &optional (ending "png"))
(defun random-graph (amount-of-nodes filename &optional style ending)
(graph (random-HR-numbers amount-of-nodes) filename style ending))
#!/bin/bash
mkdir -p fancy-labels
for i in fancy-labels/*.tex
do
pdflatex -output-directory fancy-labels "$i"
......
......@@ -74,6 +74,7 @@ Apart from the functions described below: {make-node}, {make-edge}, {add-parent}
:setup-jeff-matrix
:descendants
:ancestors
:interval
:implies-p
:implies-not-p)
(:documentation "predicates.lisp enables the program to ask whether or not a node (form) implies another. The function implies-p only answers positive implication questions, and implies-not-p only answers negative implication questions. In particular, (implies-p A B) asks whether A is an ancestor of B and (implies-not-p B A) asks whether there is an ancestor B' of B and a descendant A' of A, such that the node B' has an edge with destination A' and relation NIL. Why is the predicate \"implies-p\" defined like this is clear. For (implies-not-p B A), assume that there is an ancestor B-anc of B and a descendant A-desc of A, such that B-anc does not imply A-desc (the meaning of a NIL-edge from B-anc to A-desc). Then (implies-not-p B A) must be T, i.e., B does not imply A, because otherwise we have the implication chain: B-anc implies B implies A implies A-desc, therefore B-anc implies A-desc, contradiction to the NIL-edge from B-desc to A-desc. "))
......@@ -108,6 +109,7 @@ Apart from the functions described below: {make-node}, {make-edge}, {add-parent}
(defpackage jeffrey.main
(:nicknames :jeffrey)
(:use :common-lisp
:jeffrey.graph
:jeffrey.read
......@@ -115,16 +117,41 @@ Apart from the functions described below: {make-node}, {make-edge}, {add-parent}
:jeffrey.draw)
(:export :name-transformer
:graph
:graph-ancestors
:graph-descendants
:graph-interval
:random-graph
:random-HR-numbers
:*local-directory*
:*names*
:*bad-forms*)
(:documentation "Install this package using quicklisp (installation instructions for quicklisp can be found in https:////www.quicklisp.org//beta//#installation) and git (https:////git-scm.com//book//en//v2//Getting-Started-Installing-Git) as follows:
(:documentation "Install this system and load it using [quicklisp](https:////www.quicklisp.org//beta//#installation) and [git](https:////git-scm.com//book//en//v2//Getting-Started-Installing-Git) as follows:
* Create a folder called `jeffrey` in `quicklisp//local-projects//`,
* Navigate to this folder in a terminal and type `git init` and `git clone git@github.com:ioannad//jeffrey.git`. Alternatively otherwise download the contents of this repository to this folder.
- Install the system dependency Graphviz, for example with aptitude (Debian, Ubuntu, et.al.) using `sudo apt install graphviz`.
- In a terminal, navigate to a directory that ASDF or quicklisp can find (e.g. `quicklisp/local-projects/`) and `git clone https://gitlab.common-lisp.net/idimitriou/jeffrey.git`. Alternatively otherwise download the contents of this repository to such a directory.
- In a Common Lisp REPL, evaluate `(ql:quickload \"jeffrey\")` and `(in-package :jeffrey)`.
To produce a diagram, open a Common Lisp REPL (I have tested it only with SBCL and Clozure CL so far. Please let me know if you test it with other implementations). Then type in `(ql:quickload \"jeffrey\")` and then type in `(in-package :jeffrey.main)`. Now, to draw the diagram between the forms with Howard-Rubin numbers (HR) a b c d ... use the command `(main \"a b c d ...\")`."))
**To draw the diagram between forms** with Howard-Rubin numbers (HR) `a b c d ...` in the file `\"filename.png\"`, evaluate
```
(graph a b c d ... \"filename.png\")
```
The png format is the default so this is equivalent to `(graph a b c d ... \"filename\"). Other supported formats are: `.svg`, `.ps`, `.jpg`. See ` $ man dot`
To draw the diagram of a pseudo-random set of forms, of size N, evaluate `(random-graph n \"filename.png\")`.
Other variations: `(graph-ancestors number \"filename.png\")`, `(graph-descendants number \"filename.png\")`, but be aware that such diagrams might be quite large.
**NEW** `(graph-interval 261 260 \"interval-261-to-260\")` draws all the consequences of form 261 which imply form 260.
All the above graphing functions take an optional extra parameter `STYLE`, where STYLE can be:
- either the string \"numbers\" (the default), using the form numbers as labels in the graph image,
- or the string \"fancy\" which uses LaTeX formatted labels with the full statements of the forms.
To enable this style, execute `./make-fancy-labels`. Requires `pdflatex`, the latex package `standalone`, and `imagemagick`.
Currently there are some issues with imagemagick's `convert` from PDF files, so wait for the next update to use fancy labels.
I have tested `:jeffrey` only with SBCL and CCL (Clozure CL) so far. Please let me know if you test it with other implementations."))
(defpackage jeffrey.parse-web-input
(:use :cl :hunchentoot :split-sequence
......
......@@ -69,6 +69,9 @@ as 'row implies column?'.")
(node-children node)
(map 'list #'descendants (node-children node))))))
(defun interval (X Y)
(intersection (descendants X) (ancestors Y)))
(defun nil-edge-p (Y X) ;; => NIL or nonempty list
"Returns T if there is an edge in (node-edges Y) with :destination X
and :relation NIL."
......
(in-package :jeffrey.test)
;; Test functions in :jeffrey.main
(defun test-name-transformer ()
(assert (equal '(0 1 2 3 4 5)
(jeffrey::name-transformer :these '(0 1 2 3 4 5))))
(assert (equal '(0 18 64 80 127 300 301 389 390)
(sort (jeffrey::name-transformer :descendants '(80 301 64))
#'<)))
(assert (equal '(1 188 193 255 256 258 261 262)
(sort (jeffrey::name-transformer :ancestors '(255 188))
#'<))))
;; Disclaimer: The test data below has no connection with the real data
;; whatsoever.
(defparameter *simple-test-matrix*
......@@ -147,6 +159,8 @@
(defun test-all ()
;; test :jeffrey.main functions
(test-name-transformer)
;; test data
(format t "Setting up test...~%")
(setup-test)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment