476 lines
14 KiB
Org Mode
476 lines
14 KiB
Org Mode
#+TITLE: Examples of usage of =dds=
|
|
|
|
#+PROPERTY: header-args:racket :prologue "#lang racket\n(require graph (file \"~/Candies/prj/racket/dds/networks.rkt\") (file \"~/Candies/prj/racket/dds/utils.rkt\"))"
|
|
|
|
* Introduction
|
|
This document shows some examples of usage of the modules in =dds=
|
|
with Org-mode. It relies on [[https://github.com/hasu/emacs-ob-racket][emacs-ob-racket]].
|
|
|
|
The [[intro][following section]] describes how Org-mode can interact with
|
|
Racket, and how this interaction can be used for a fluid workflow
|
|
with =dds=. In particular, the code block =munch-table= is [[tabread][defined]]
|
|
in this section.
|
|
|
|
The subsequent sections show off some the functionalities of the
|
|
submodules of =dds=.
|
|
|
|
* Org-mode, Racket, and =dds= <<intro>>
|
|
** Importing a module from file
|
|
:PROPERTIES:
|
|
:header-args:racket: :prologue "#lang racket\n(require (file \"~/Candies/prj/racket/dds/networks.rkt\"))"
|
|
:END:
|
|
|
|
To require the modules from the files of =dds=, you can use the
|
|
following code (I only reset the prelude here because I set at the
|
|
top of this file):
|
|
|
|
#+BEGIN_SRC racket :results output :prologue ""
|
|
#lang racket
|
|
(require (file "~/Candies/prj/racket/dds/networks.rkt"))
|
|
(require (file "~/Candies/prj/racket/dds/utils.rkt"))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
|
|
Note that this code will not work with =:results value=. I think it
|
|
is because in this case the code is not really evaluated at top
|
|
level.
|
|
|
|
These initialisation lines can be put into the prologue of every
|
|
code block in a subtree by setting =:prologue= via
|
|
=:header-args:racket:= in the properties drawer. Check out the
|
|
properties drawer of this section for an example.
|
|
|
|
Alternatively, this property can be set via a =#+PROPERTY= line at
|
|
the top the file. For example, this file has such a line. Whenever
|
|
this property line changes, refresh the setup of the file by hitting
|
|
=C-c C-c= on the property line. This will update the prologue for
|
|
all racket code blocks.
|
|
|
|
Finally, you can also set =:prologue= (and other properties with
|
|
long values) in the following way:
|
|
|
|
#+HEADER: :prologue "#lang racket\n(require (file \"~/Candies/prj/racket/dds/networks.rkt\"))"
|
|
#+BEGIN_SRC racket :results output drawer
|
|
(st '((a . 1)))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
'#hash((a . 1))
|
|
:END:
|
|
|
|
** Output formats for results of evaluation of code blocks
|
|
[[https://orgmode.org/manual/Results-of-Evaluation.html#Results-of-Evaluation][This section]] of the Org manual describes various different formats
|
|
for presenting the results of code blocks. I find the following
|
|
three particularly useful as of [2020-02-22 Sat]: =output=, =list=,
|
|
and =table=.
|
|
|
|
The =output= result format is the simplest and the most natural
|
|
ones. It works as if the code block were inserted into a module
|
|
which would then be evaluated.
|
|
|
|
#+BEGIN_SRC racket :results output drawer
|
|
(println "This is the first line of output.")
|
|
(println (+ 1 2))
|
|
(println "This the third line of output.")
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
"This is the first line of output."
|
|
3
|
|
"This the third line of output."
|
|
:END:
|
|
|
|
The =list= result format typesets the result of the last line in the
|
|
code block as a list:
|
|
#+BEGIN_SRC racket :results list
|
|
'(1 "hello" (and x y))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
- 1
|
|
- "hello"
|
|
- (and x y)
|
|
|
|
Note how nested lists are not recursively shown as nested Org-mode
|
|
lists.
|
|
|
|
For some reason, the =list= output format does not work with the
|
|
result drawer:
|
|
#+BEGIN_SRC racket :results list drawer
|
|
'(1 "hello" (and x y))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
- (1 "\"hello\"" (and x y))
|
|
:END:
|
|
|
|
Finally, the =table= result format typesets the output as a table:
|
|
#+BEGIN_SRC racket :results table drawer
|
|
'((a . #t) (b . #f))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
| a | #t |
|
|
| b | #f |
|
|
:END:
|
|
|
|
This is clearly very useful for printing states (and hash tables,
|
|
more generally):
|
|
|
|
#+BEGIN_SRC racket :results table drawer
|
|
(st '((a . 1) (b . #f) (c . "hello")))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
| a | 1 |
|
|
| b | #f |
|
|
| c | "hello" |
|
|
:END:
|
|
|
|
*** A note about printing update function forms
|
|
Automatic table typesetting may go in the way of readability for
|
|
hash tables whose values are lists, as the following example shows:
|
|
|
|
#+BEGIN_SRC racket :results table drawer
|
|
#hash((a . (and a b)) (b . (not b)))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
| a | and | a | b |
|
|
| b | not | b | |
|
|
:END:
|
|
|
|
To tackle this issue, [[../utils.rkt][=dds/utils=]] provides
|
|
=stringify-variable-mapping= (with the shortcut =sgfy=) which
|
|
converts all the values of a given variable mapping to strings:
|
|
|
|
#+BEGIN_SRC racket :results table drawer
|
|
(sgfy #hash((a . (and a b)) (b . (not b))))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
| a | "(and a b)" |
|
|
| b | "(not b)" |
|
|
:END:
|
|
|
|
** Reading Org-mode tables<<tabread>>
|
|
Org-mode allows supplying tables as arguments for code blocks.
|
|
|
|
#+NAME: test-table
|
|
| a | "(and a b)" |
|
|
| b | (or b (not a)) |
|
|
|
|
#+BEGIN_SRC elisp :var tab=test-table :results output drawer
|
|
tab
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
:END:
|
|
((a (and a b)) (b (or b (not a))))
|
|
|
|
Unfortunately, the same trick does not work with Racket directly,
|
|
because Racket interprets the first elements in the parentheses as
|
|
function applications:
|
|
|
|
#+BEGIN_SRC racket :results output drawer :var tab=test-table
|
|
tab
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
application: not a procedure;
|
|
expected a procedure that can be applied to arguments
|
|
given: "a"
|
|
arguments...:
|
|
"(and a b)"
|
|
context...:
|
|
"/tmp/babel-qkvrRR/org-babel-c4wuju.rkt": [running body]
|
|
temp37_0
|
|
for-loop
|
|
run-module-instance!125
|
|
perform-require!78
|
|
:END:
|
|
|
|
Fortunately, we can easily remedy this problem by creating a named
|
|
parameterised Elisp source block which will explicitly convert the
|
|
table to a string:
|
|
|
|
#+NAME: munch-table
|
|
#+BEGIN_SRC elisp :results output drawer :var tab=test-table
|
|
(prin1 tab)
|
|
#+END_SRC
|
|
|
|
#+RESULTS: munch-table
|
|
:RESULTS:
|
|
(("a" "(and a b)") ("b" "(or b (not a))"))
|
|
:END:
|
|
|
|
We can now correctly receive this table in a Racket source code
|
|
block by threading it through =munch-table=:
|
|
#+BEGIN_SRC racket :results output drawer :var tab=munch-table(tab=test-table)
|
|
(println tab)
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
"((\"a\" \"(and a b)\") (\"b\" \"(or b (not a))\"))"
|
|
:END:
|
|
|
|
[[../utils.rkt][=dds/utils=]] has several functions for parsing such strings, and
|
|
notably =read-org-variable-mapping=, with the shortcut =unorg=:
|
|
#+BEGIN_SRC racket :results output drawer :var tab=munch-table(tab=test-table)
|
|
(unorg tab)
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
'#hash((a . (and a b)) (b . (or b (not a))))
|
|
:END:
|
|
|
|
Of course, we can use =munch-table= to prepare any other table than
|
|
=test-table= for use with Racket:
|
|
|
|
#+NAME: another-test-table
|
|
| a | (not a) |
|
|
| b | (and a c) |
|
|
| c | (and a (not b)) |
|
|
|
|
#+BEGIN_SRC racket :results output drawer :var tab=munch-table(tab=another-test-table)
|
|
(unorg tab)
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
'#hash((a . (not a)) (b . (and a c)) (c . (and a (not b))))
|
|
:END:
|
|
|
|
** Inline graph visualisation with Graphviz
|
|
Some functions in =dds= build graphs:
|
|
|
|
#+BEGIN_SRC racket :results output drawer :var bf=munch-table(another-test-table)
|
|
(build-interaction-graph (unorg bf))
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
#<unweighted-graph>
|
|
:END:
|
|
|
|
The =graph= library allows building a Graphviz description of the
|
|
constructed graph. (Note that you have to install the =graph=
|
|
library by running =raco pkg install graph= and require it. The
|
|
long property line at the top of this file defining the prologue for
|
|
racket source code blocks takes care of requiring =graph=.)
|
|
|
|
#+NAME: igraph
|
|
#+BEGIN_SRC racket :results output drawer :var bf=munch-table(another-test-table)
|
|
(display (graphviz (build-interaction-graph (unorg bf))))
|
|
#+END_SRC
|
|
|
|
#+RESULTS: igraph
|
|
:RESULTS:
|
|
digraph G {
|
|
node0 [label="c"];
|
|
node1 [label="b"];
|
|
node2 [label="a"];
|
|
subgraph U {
|
|
edge [dir=none];
|
|
node0 -> node1;
|
|
node2 -> node2;
|
|
}
|
|
subgraph D {
|
|
node2 -> node0;
|
|
node2 -> node1;
|
|
}
|
|
}
|
|
:END:
|
|
|
|
You can have an inline drawing of this graph by calling the previous
|
|
code block (=igraph=) via a noweb reference in Graphviz/DOT source
|
|
block:
|
|
|
|
#+BEGIN_SRC dot :file dots/exampleBQNp7Z.svg :results raw drawer :cmd sfdp :noweb yes
|
|
<<igraph()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/exampleBQNp7Z.svg]]
|
|
:END:
|
|
|
|
Note that the =graph= library draws self-loops as undirected edges.
|
|
It also draws double-sided edges as undirected edges (e.g., in the
|
|
preceding graph, b depends on c and c depends on b).
|
|
|
|
* =dds/networks=
|
|
The [[../networks.rkt][=dds/networks=]] is a module for working with different network
|
|
models. A network is a set of variables which are updated according
|
|
to their corresponding update functions. The variables to be
|
|
updated at each step are given by the mode. This model can
|
|
generalise Boolean networks, TBANs, multivalued networks, etc.
|
|
|
|
** Boolean networks
|
|
Consider the following Boolean network:
|
|
#+NAME: simple-bn
|
|
| a | b |
|
|
| b | (and (not a) c) |
|
|
| c | (not c) |
|
|
|
|
Here's the unsigned interaction graph of this network:
|
|
#+NAME: simple-bn-ig
|
|
#+BEGIN_SRC racket :results silent :var simple-bn=munch-table(simple-bn)
|
|
(dotit (build-interaction-graph (unorg simple-bn)))
|
|
#+END_SRC
|
|
|
|
#+BEGIN_SRC dot :file dots/examplejTo8XT.svg :results raw drawer :cmd sfdp :noweb yes
|
|
<<simple-bn-ig()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/examplejTo8XT.svg]]
|
|
:END:
|
|
|
|
Here's the signed interaction graph of this network:
|
|
|
|
#+NAME: simple-bn-sig
|
|
#+BEGIN_SRC racket :results silent :var simple-bn=munch-table(simple-bn)
|
|
(dotit (build-boolean-signed-interaction-graph (unorg simple-bn)))
|
|
#+END_SRC
|
|
|
|
#+BEGIN_SRC dot :file dots/exampledpQygl.svg :results raw drawer :cmd sfdp :noweb yes
|
|
<<simple-bn-sig()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/exampledpQygl.svg]]
|
|
:END:
|
|
|
|
For the interaction a \to b, note indeed that when c is #f, b is
|
|
always #f (positive interaction). On the other hand, when c is #t,
|
|
b becomes (not a) (negative interaction). Therefore, the influence
|
|
of a on b is neither activating nor inhibiting.
|
|
|
|
Here is the full state graph of this network under the asynchronous
|
|
dynamics:
|
|
#+NAME: simple-bn-sg
|
|
#+BEGIN_SRC racket :results silent :var simple-bn=munch-table(simple-bn)
|
|
(let* ([bn (nn (unorg simple-bn))]
|
|
[bn-asyn (make-asyn-dynamics bn)])
|
|
(dotit (ppsg (build-full-boolean-state-graph bn-asyn))))
|
|
#+END_SRC
|
|
|
|
|
|
#+BEGIN_SRC dot :file dots/examplem7LpTs.svg :results raw drawer :cmd sfdp :noweb yes
|
|
<<simple-bn-sg()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/examplem7LpTs.svg]]
|
|
:END:
|
|
|
|
Alternatively, you may prefer a slighty more compact representation
|
|
of Boolean values as 0 and 1:
|
|
#+NAME: simple-bn-sg-bool
|
|
#+BEGIN_SRC racket :results silent :var simple-bn=munch-table(simple-bn)
|
|
(let* ([bn (nn (unorg simple-bn))]
|
|
[bn-asyn (make-asyn-dynamics bn)])
|
|
(dotit (ppsgb (build-full-boolean-state-graph bn-asyn))))
|
|
#+END_SRC
|
|
|
|
#+BEGIN_SRC dot :file dots/examplex1Irnk.svg :results raw drawer :cmd sfdp :noweb yes
|
|
<<simple-bn-sg-bool()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/examplex1Irnk.svg]]
|
|
:END:
|
|
|
|
Consider the following state (appearing in the upper left corner of
|
|
the state graph):
|
|
|
|
#+NAME: some-state
|
|
| a | 0 |
|
|
| c | 1 |
|
|
| b | 1 |
|
|
|
|
These are the states which can be reached from it in at most 2
|
|
steps:
|
|
#+NAME: simple-bn-some-state
|
|
#+HEADER: :var simple-bn=munch-table(simple-bn)
|
|
#+HEADER: :var some-state=munch-table(some-state)
|
|
#+BEGIN_SRC racket :results silent
|
|
(let* ([bn (nn (unorg simple-bn))]
|
|
[bn-asyn (make-asyn-dynamics bn)]
|
|
[s0 (stb (unorg some-state))])
|
|
(dotit (ppsgb (dds-build-n-step-state-graph bn-asyn (set s0) 2))))
|
|
#+END_SRC
|
|
|
|
#+BEGIN_SRC dot :file dots/examplecHA6gL.svg :results raw drawer :cmd sfdp :noweb yes
|
|
<<simple-bn-some-state()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/examplecHA6gL.svg]]
|
|
:END:
|
|
|
|
Here is the complete state graph with edges annotated with the
|
|
modality leading to the update.
|
|
#+NAME: simple-bn-sg-bool-ann
|
|
#+BEGIN_SRC racket :results silent :var simple-bn=munch-table(simple-bn)
|
|
(let* ([bn (nn (unorg simple-bn))]
|
|
[bn-asyn (make-asyn-dynamics bn)])
|
|
(dotit (ppsgb (build-full-boolean-state-graph-annotated bn-asyn))))
|
|
#+END_SRC
|
|
|
|
#+BEGIN_SRC dot :file dots/examplei4we6j.svg :results raw drawer :cmd sfdp :noweb yes
|
|
<<simple-bn-sg-bool-ann()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/examplei4we6j.svg]]
|
|
:END:
|
|
|
|
For some networks, a single transition between two states may be
|
|
due to different modalities. Consider the following network:
|
|
#+NAME: bn2
|
|
| a | (not b) |
|
|
| b | b |
|
|
|
|
#+NAME: bn2-sgr
|
|
#+BEGIN_SRC racket :results silent :var input-bn=munch-table(bn2)
|
|
(let* ([bn (nn (unorg input-bn))]
|
|
[bn-asyn (make-asyn-dynamics bn)])
|
|
(dotit (ppsgb (build-full-boolean-state-graph-annotated bn-asyn))))
|
|
#+END_SRC
|
|
|
|
#+BEGIN_SRC dot :file dots/examplehsuRqc.svg :results raw drawer :cmd dot :noweb yes
|
|
<<bn2-sgr()>>
|
|
#+END_SRC
|
|
|
|
#+RESULTS:
|
|
:RESULTS:
|
|
[[file:dots/examplehsuRqc.svg]]
|
|
:END:
|
|
|
|
|
|
* Local Variables :noexport:
|
|
# Local Variables:
|
|
# eval: (auto-fill-mode)
|
|
# ispell-local-dictionary: "en"
|
|
# org-link-file-path-type: relative
|
|
# End:
|