dds/scribblings/networks.scrbl

947 lines
28 KiB
Text
Raw Normal View History

#lang scribble/manual
@(require scribble/example racket/sandbox
(for-label typed/racket/base
graph
(only-in typed/graph Graph)
2022-08-30 17:41:44 +02:00
(only-in racket/class send)
"../networks.rkt"
"../utils.rkt"
2022-08-30 17:41:44 +02:00
"../functions.rkt"
"../dynamics.rkt"))
@(define networks-evaluator
(parameterize ([sandbox-output 'string]
[sandbox-error-output 'string]
[sandbox-memory-limit 500])
(make-evaluator 'typed/racket #:requires '("networks.rkt"))))
@(define-syntax-rule (ex . args)
(examples #:eval networks-evaluator . args))
@(define-syntax-rule (deftypeform . args)
(defform #:kind "type" . args))
2022-04-29 16:32:22 +02:00
@(define-syntax-rule (deftype . args)
(defidform #:kind "type" . args))
@title[#:tag "networks"]{dds/networks: Formal Dynamical Networks}
@defmodule[dds/networks]
This module provides definitions for and analysing 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.
2022-04-29 15:33:46 +02:00
@section[#:tag "networks-basics"]{Basic types}
@deftypeform[(State a)]{
An immutable mapping (a hash table) assigning elements of type @racket[a] to
the variables. A synonym of @racket[VariableMapping].
}
@deftypeform[(UpdateFunction a)]{
2022-04-27 00:15:03 +02:00
An update function is a function computing a value from the given
state. This is a synonym of the type @racket[(-> (State a) a)].
}
@deftypeform[(Domain a)]{
2022-04-29 16:10:36 +02:00
A domain which is a subset of the type @racket[a].
@racket[(Domain a)] is a synonym of @racket[(Listof a)].
}
@deftypeform[(DomainMapping a)]{
2022-04-27 00:15:03 +02:00
A domain mapping is a hash table mapping variables to the lists of values in
their domains.
}
2022-04-30 00:23:38 +02:00
@section{Common examples}
The examples in this document often use the same definitions, which are
therefore grouped here to avoid duplicating them.
These are two functions calculating an @italic{AND} and an @italic{OR} between
the variables @racket[a] and @racket[b]:
@ex[
(: or-func (UpdateFunction Boolean))
(define (or-func s)
(or (hash-ref s 'a) (hash-ref s 'b)))
(: and-func (UpdateFunction Boolean))
(define (and-func s)
(and (hash-ref s 'a) (hash-ref s 'b)))
]
These are two functions calculating an @italic{AND} and an @italic{OR} between
two variables @racket[a] and @racket[b] whose values are in @tt{{0,1}}:
@ex[
(require (only-in "utils.rkt" assert-type))
(: or-func/01 (UpdateFunction (U Zero One)))
(define (or-func/01 s)
(assert-type (max (hash-ref s 'a) (hash-ref s 'b))
(U Zero One)))
(: and-func/01 (UpdateFunction (U Zero One)))
(define (and-func/01 s)
(assert-type (min (hash-ref s 'a) (hash-ref s 'b))
(U Zero One)))
]
@section{Utilities}
@defproc[(01->boolean/state [s (State (U Zero One))]) (State Boolean)]{
Converts the values 0 and 1 in a state to @racket[#f] and
@racket[#t] respectively.
@ex[
(01->boolean/state (hash 'a 0 'b 1))
]}
@defproc[(make-same-domains [vars (Listof Variable)]
[domain (Domain a)])
(DomainMapping a)]{
Makes a hash set mapping all variables to a single domain.
@ex[
(make-same-domains '(a b) '(1 2))
]}
@defproc[(make-boolean-domains [vars (Listof Variable)])
(DomainMapping Boolean)]{
Makes a hash set mapping all variables to the Boolean domain.
@ex[
(make-boolean-domains '(a b))
]}
@defproc[(make-01-domains [vars (Listof Variable)])
(DomainMapping (U Zero One))]{
Makes a hash set mapping all variables to the Boolean domain, expressed as
@tt{{0,1}}.
@ex[
(make-01-domains '(a b))
]}
2022-04-29 17:31:36 +02:00
@section{Networks}
2022-04-28 23:47:37 +02:00
@defstruct*[network ([functions (VariableMapping (UpdateFunction a))]
[domains (DomainMapping a)])]{
A network consists of a mapping from its variables to its update variables, as
a well as of a mapping from its variables to their domains.
Instances of @racket[network] have the type @racket[Network].
}
2022-05-02 00:22:47 +02:00
@deftypeform[(Network a)]{
2022-04-28 23:47:37 +02:00
2022-05-02 00:22:47 +02:00
The type of the instances of @racket[network].
2022-04-28 23:47:37 +02:00
@ex[
(network (hash 'a or-func
'b and-func)
(hash 'a '(#f #t)
'b '(#f #t)))
]}
2022-04-30 22:49:03 +02:00
@defproc[(make-boolean-network [funcs (VariableMapping (UpdateFunction Boolean))])
(Network Boolean)]{
Builds a Boolean network from a given hash table assigning functions to
variables by attributing Boolean domains to every variable.
@ex[
(make-boolean-network (hash 'a or-func 'b and-func))
]}
@defproc[(make-01-network [funcs (VariableMapping (UpdateFunction (U Zero One)))])
(Network (U Zero One))]{
Build a network from a given hash table assigning functions to variables by
attributing the domain @tt{{0,1}} to every variable.
@ex[
(make-01-network (hash 'a or-func/01 'b and-func/01))
]}
2022-05-01 00:31:28 +02:00
@defproc[(update [network (Network a)] [s (State a)] [xs (Listof Variable)])
(State a)]{
Given a state @racket[s] updates all the variables of @racket[network] from
@racket[xs].
@ex[
(update (make-boolean-network (hash 'a or-func 'b and-func))
(hash 'a #f 'b #t)
'(a))
]}
@section{Syntactic description of networks}
2022-05-02 00:16:16 +02:00
@deftype[UpdateFunctionForm]{
An update function form is any form which can appear as a body of a function
and which can be evaluated with @racket[eval].
@ex[
(ann '(and x y (not z)) UpdateFunctionForm)
(ann '(+ 1 a (- b 10)) UpdateFunctionForm)
]
@racket[UpdateFunctionForm] is a synonym of @racket[Any].
}
2022-05-02 00:27:55 +02:00
@defstruct*[network-form ([functions (VariableMapping NetworkForm)]
[domains (DomainMapping a)])]{
A network form consists of a mapping from variables to the forms of their
update functions, together with a mapping from its variables to its
update functions.
The domain mapping does not have to assign domains to all variables (e.g., it
may be empty), but in this case the functions which need to know the domains
will not work.
Instances of @racket[network-form] have the type @racket[NetworkForm].
}
@deftypeform[(NetworkForm a)]{
The type of instances of @racket[network-form].
@ex[
(network-form (hash 'a '(and a b) 'b '(or a b))
(hash 'a '(#f #t) 'b '(#f #t)))
]}
2022-05-02 00:16:16 +02:00
@defproc[(update-function-form->update-function/any [func UpdateFunctionForm])
(UpdateFunction Any)]{
Builds an update function from an update function form.
@ex[
(define and-from-form (update-function-form->update-function/any '(and x y)))
(and-from-form (hash 'x #f 'y #f))
(and-from-form (hash 'x #f 'y #t))
(and-from-form (hash 'x #t 'y #f))
(and-from-form (hash 'x #t 'y #t))
]}
@defproc[(update-function-form->update-function/boolean [func UpdateFunctionForm])
(UpdateFunction Boolean)]{
Like @racket[update-function-form->update-function/any], but the resulting
function operates on Boolean states.
@ex[
(define and-from-form/boolean (update-function-form->update-function/boolean '(and x y)))
(and-from-form/boolean (hash 'x #f 'y #f))
(and-from-form/boolean (hash 'x #f 'y #t))
(and-from-form/boolean (hash 'x #t 'y #f))
(and-from-form/boolean (hash 'x #t 'y #t))
]}
@defproc[(update-function-form->update-function/01 [func UpdateFunctionForm])
(UpdateFunction (U Zero One))]{
Like @racket[update-function-form->update-function/01], but the resulting
function operates on Boolean states, with the domain @tt{{0,1}}.
@ex[
(define and-from-form/01 (update-function-form->update-function/01 '(min x y)))
(and-from-form/01 (hash 'x 0 'y 0))
(and-from-form/01 (hash 'x 0 'y 1))
(and-from-form/01 (hash 'x 1 'y 0))
(and-from-form/01 (hash 'x 1 'y 1))
]}
@defproc[(network-form->network/any [nf (NetworkForm Any)]) (Network Any)]{
Builds a network from a network form.
@ex[
(network-form->network/any
(network-form (hash 'a '(and a b)
'b '(not b))
(hash 'a '(#f #t)
'b '(#f #t))))
]}
2022-05-04 01:12:52 +02:00
@defproc[(network-form->network/boolean [nf (NetworkForm Boolean)]) (Network Boolean)]{
Like @racket[network-form->network/any], but builds a Boolean network.
@ex[
(network-form->network/boolean
(network-form (hash 'a '(and a b)
'b '(not b))
(hash 'a '(#f #t)
'b '(#f #t))))
]}
2022-05-04 01:21:11 +02:00
@defproc[(network-form->network/01 [nf (NetworkForm (U Zero One))]) (Network (U Zero One))]{
Like @racket[network-form->network/any], but builds a Boolean network, whose
domains are expressed as @tt{{0,1}}.
@ex[
(network-form->network/01
(network-form (hash 'a '(min a b)
'b '(- 1 b))
(hash 'a '(0 1)
'b '(0 1))))
]}
2022-05-05 11:25:10 +02:00
@defproc[(make-boolean-network-form [forms (VariableMapping UpdateFunctionForm)])
(NetworkForm Boolean)]{
Build a Boolean network form from a given mapping assigning forms to variables.
@ex[
(make-boolean-network-form (hash 'a '(and a b)
'b '(not b)))
]}
2022-05-05 11:56:21 +02:00
@defproc[(forms->boolean-network [forms (VariableMapping UpdateFunctionForm)])
(Network Boolean)]{
Build a Boolean network from a given mapping assigning forms to variables.
@ex[
(forms->boolean-network (hash 'a '(and a b)
'b '(not b)))
]}
2022-05-15 14:52:47 +02:00
@section{Dynamics of networks}
This section contains definitions for building and analysing the dynamics
of networks.
@defproc[(build-all-states [vars-domains (DomainMapping a)])
(Listof (State a))]{
Given a @racket[DomainMapping], constructs the list of all possible states.
@ex[
(build-all-states (make-boolean-domains '(a b)))
]}
2022-05-15 19:05:07 +02:00
@defproc[(build-all-boolean-states [vars (Listof Variable)])
(Listof (State Boolean))]{
Builds all Boolean states over a given list of variables.
@ex[
(build-all-boolean-states '(a b))
]}
2022-05-15 19:52:37 +02:00
@defproc[(build-all-01-states [vars (Listof Variable)])
(Listof (State Boolean))]{
Builds all Boolean states over a given set of variables, but with the Boolean
values represented as 0 and 1.
@ex[
(build-all-01-states '(a b))
]}
2022-07-05 23:53:14 +02:00
@deftype[Modality]{
A modality is a list of variables. This is a synonym of @racket[(Listof
2022-07-05 23:53:14 +02:00
Variable)].
}
@deftype[Mode]{
A mode is a list of modalities. This is a synonym of @racket[(Listof Modality)].
2022-07-05 23:53:14 +02:00
}
2022-08-30 17:41:44 +02:00
@defclass[dynamics% dds% ()]{
A model of dynamics of a network is a @racket[Network] with a @racket[Mode].
@defconstructor[([network (Network a)] [mode Mode])]{
Creates a new instance of @racket[dynamics%] from a @racket[network] and
a @racket[mode]. Both are available as public fields of the class.
}
@defmethod[(step/annotated [st (State a)]) (Listof (Pairof Modality (State a)))]{
Apply the network stored in this class to the state @racket[st] with all
modalities of the mode stored in this class.
This is the only method of @racket[dds%] overridden in this class.
@ex[
(let* ([n (forms->boolean-network (hash 'a '(and a b)
'b '(not b)))]
[syn '((a) (b))]
[syn-dynamics (new (inst dynamics% Boolean) [network n] [mode syn])]
[st (hash 'a #f 'b #f)])
(send syn-dynamics step/annotated st))
2022-09-18 00:56:09 +02:00
]}}
2022-08-30 17:41:44 +02:00
2022-09-15 20:40:07 +02:00
@deftypeform[(Dynamics% a)]{
The type of an instance of @racket[dynamics%] with values of type @racket[a].
@ex[
2022-09-17 15:36:08 +02:00
(let* ([n (forms->boolean-network (hash 'a '(and a b)
'b '(not b)))]
[syn '((a) (b))]
[syn-dynamics (new (inst dynamics% Boolean) [network n] [mode syn])])
(ann syn-dynamics (Dynamics% Boolean)))
2022-09-15 20:40:07 +02:00
]
Note that, as of 2022-09-15, Typed Racket does not seem to allow to pass type
parameters from a child class to a parent class. Therefore, @racket[dynamics%]
inherits in fact from a @racket[dds%] with its first type parameter set to
@racket[(State Any)]. This can be seen by examining the type of
@racket[dynamics%].
@ex[dynamics%]
The type constructor @racket[Dynamics%] takes this limitation into account.
}
2022-09-16 17:57:15 +02:00
@defproc[(make-asyn [vars (Listof Variable)]) Mode]{
Given a list of variables, builds the asynchronous mode, i.e. a set of
singleton sets of variables.
@ex[(make-asyn '(x y z))]
}
@defproc[(make-syn [vars (Listof Variable)]) Mode]{
Given a list of variables, builds the synchronous mode, i.e. a singleton set
containing the set of all variables.
@ex[(make-syn '(x y z))]
}
@defproc[(make-asyn-dynamics [network (Network a)]) (Dynamics% a)]{
Creates the asynchronous dynamics for a given network: an instance of
@racket[dynamics%] with @tt{network} as the network and the asynchronous
mode as @tt{mode}.
2022-09-22 01:22:11 +02:00
See @racket[build-full-state-graph/annotated] for an example.
}
@defproc[(make-syn-dynamics [network (Network a)]) (Dynamics% a)]{
Creates the synchronous dynamics for a given network: an instance of
@racket[dynamics%] with @tt{network} as the network and the synchronous mode as
@tt{mode}.
2022-09-22 00:15:35 +02:00
See @racket[build-full-state-graph] for an example.
}
@defproc[(build-full-state-graph [dyn (Dynamics% a)]) Graph]{
Builds the full state graph of the given dynamics.
@ex[
(require (only-in "utils.rkt" dotit))
(let* ([n (forms->boolean-network (hash 'a '(and a b)
'b '(not b)))]
[syn-dynamics (make-syn-dynamics n)])
(dotit ((inst build-full-state-graph Boolean) syn-dynamics)))
]
2022-08-30 17:41:44 +02:00
}
2022-09-22 01:22:11 +02:00
@defproc[(build-full-state-graph/annotated [dyn (Dynamics% a)]) Graph]{
Builds the full annotated state graph of the given dynamics.
@ex[
(require (only-in "utils.rkt" dotit))
(let* ([n (forms->boolean-network (hash 'a '(and a b)
'b '(not b)))]
[asyn-dynamics (make-asyn-dynamics n)])
(dotit ((inst build-full-state-graph/annotated Boolean) asyn-dynamics)))
]
}
@section[#:tag "networks_Pretty_printing"]{Pretty printing}
This section defines various functions for nicely formatting node and edge
labels in state graphs of networks.
@defproc[(pretty-print-state [s (State a)]) String]{
Pretty-prints a state of a network.
@ex[(pretty-print-state (hash 'a #f 'b 3 'c 4))]
}
2022-08-30 17:41:44 +02:00
2022-09-22 01:06:16 +02:00
@defproc[(pretty-print-state/01 [s (State a)]) String]{
2022-09-19 00:10:42 +02:00
Pretty-prints a state of a network, replacing all @racket[#f] values with 0 and
all other values with 1.
2022-09-22 01:06:16 +02:00
@ex[(pretty-print-state/01 (hash 'a #f 'b 3 'c '() 'd #t))]
2022-09-19 00:10:42 +02:00
}
2022-09-20 11:40:21 +02:00
@defproc[(pretty-print-state-graph-with [gr Graph] [pprinter (-> Any Any)]) Graph]{
Given a state graph @racket[gr] and the pretty-printer for states
@racket[pprinter], build a new state graph in which the nodes are
pretty-printed with @racket[pprinter] and the edges with
@racket[pretty-print-set-sets].
}
@defproc[(pretty-print-state-graph [gr Graph]) Graph]{
Calls @racket[pretty-print-state-graph-with] with @racket[pretty-print-state].
@ex[
(let* ([n (forms->boolean-network (hash 'a '(and a b)
'b '(not b)))]
[syn-dynamics (make-syn-dynamics n)])
(dotit (pretty-print-state-graph
((inst build-full-state-graph Boolean) syn-dynamics))))
]
}
@defproc[(ppsg [gr Graph]) Graph]{
A shortcut for @racket[pretty-print-state-graph].
}
2022-09-22 01:06:16 +02:00
@defproc[(pretty-print-state-graph/01 [gr Graph]) Graph]{
2022-09-22 01:06:16 +02:00
Calls @racket[pretty-print-state-graph-with] with @racket[pretty-print-state/01].
@ex[
(let* ([n (forms->boolean-network (hash 'a '(and a b)
'b '(not b)))]
[syn-dynamics (make-syn-dynamics n)])
2022-09-22 01:06:16 +02:00
(dotit (pretty-print-state-graph/01
((inst build-full-state-graph Boolean) syn-dynamics))))
]
}
2022-09-22 01:06:16 +02:00
@defproc[(ppsg01 [gr Graph]) Graph]{
2022-09-22 01:06:16 +02:00
A shortcut for @racket[pretty-print-state-graph/01].
}
@section{Inferring interaction graphs}
This section provides inference of both unsigned and signed interaction graphs.
Since the inference of signed interaction graphs is based on analysing the
dynamics of the networks, it may be quite resource-consuming, especially since
any syntactic forms are allowed in the definitions of the functions.
We use the term @emph{syntactic interaction graph} to refer to the graph in
which the presence of an arc from @tt{x} to @tt{y} is based on whether @tt{x}
appears in the form of @tt{y}. This is quite different from the canonical
definition of the @emph{interaction graph}, in which the arc from @tt{x} to
@tt{y} represents the fact that a change in the value of @tt{x} may lead to
a change in the value of @tt{y}. Thus the syntactic interaction graph may have
extra arcs if @tt{x} appears in the form of @tt{y}, but has no actual influence
on @tt{y}.
2022-05-09 10:54:53 +02:00
@defproc[(list-syntactic-interactions [nf (NetworkForm a)]
[x Variable])
(Listof Variable)]{
Lists the variables of the network form appearing in the update function form
for @racket[x].
The variables which are not part of the network are excluded from the listing.
@ex[
(list-syntactic-interactions
(make-boolean-network-form #hash((a . (+ a b))
(b . (- b))))
'a)
(list-syntactic-interactions
(make-boolean-network-form #hash((a . (+ a b c))
(b . (- b c))))
'a)
]}
@defproc[(build-syntactic-interaction-graph [n (NetworkForm a)])
Graph]{
Builds the graph in which the vertices are the variables of a given network,
and which contains an arrow from @racket[x] to @racket[y] whenever @racket[x]
appears in @racket[(list-interactions y)].
@ex[
(require (only-in "utils.rkt" dotit))
(dotit (build-syntactic-interaction-graph
(make-boolean-network-form #hash((a . (+ a b))
(b . (- b))))))
]}
2022-05-09 10:54:53 +02:00
2022-07-01 00:25:19 +02:00
@defproc[(interaction? [network (Network a)]
[x Variable]
[y Variable])
Boolean]{
Given two variables @racket[x] and @racket[y] of a @racket[network], verifies
if they interact, i.e. that there exists a pair of states @italic{s} and
@italic{s'} with the following properties:
@itemlist[
@item{@italic{s} and @italic{s'} only differ in the value of @racket[x];}
@item{running the network from @italic{s} and @italic{s'} yields different
values for @racket[y].}
]
@ex[
(let ([bn (forms->boolean-network #hash((a . (and a b))
(b . (not b))))])
(values (interaction? bn 'a 'b)
(interaction? bn 'b 'a)))
]}
2022-07-03 23:03:48 +02:00
@defproc[(get-interaction-sign [network (Network a)]
[x Variable]
[y Variable])
(Option Integer)]{
Given two variables @racket[x] and @racket[y] of @racket[network], checks
whether they interact, and if they interact, returns 1 if increasing @racket[x]
leads to an increase in @racket[y], -1 if it leads to a decrease in @racket[y],
and 0 if it can lead to both. If @racket[x] has no impact on @racket[y], returns @racket[#f].
The values in the domains are ordered according to the order in which they are
listed in @racket[network].
Since @racket[get-interaction-sign] needs to check all possible interactions
between @racket[x] and @racket[y], it is more costly than calling
@racket[interaction?].
@ex[
(let ([bn (forms->boolean-network #hash((a . (and a b))
(b . (not b))))])
(values (get-interaction-sign bn 'a 'b)
(get-interaction-sign bn 'b 'a)
(get-interaction-sign bn 'b 'b)))
]}
@defproc[(build-interaction-graph [network (Network a)]) Graph]{
Given a network, builds its interaction graph. The graph has variables as
nodes and has a directed edge from @italic{x} to @italic{y} if
@racket[interaction?] returns @racket[#t] for these variables, in this order.
@ex[
(dotit (build-interaction-graph
(forms->boolean-network #hash((a . (and a b))
(b . (not b))))))
]}
@defproc[(build-interaction-graph/form [nf (NetworkForm a)]) Graph]{
Like @racket[build-interaction-graph], but accepts a network form and
converts it a to @racket[(Network a)] first.
@ex[
(dotit (build-interaction-graph/form
(make-boolean-network-form #hash((a . (and a b))
(b . (not b))))))
]}
@defproc[(build-signed-interaction-graph [network (Network a)]) Graph]{
Given a network, builds its signed interaction graph. The graph has variables
as nodes and has a directed edge from @italic{x} to @racket{y} labelled by the
value @racket[get-interaction-sign] produces for these variables, in that
order, unless this value is @racket[#f].
@ex[
(dotit (build-signed-interaction-graph
(forms->boolean-network #hash((a . (and a b))
(b . (not b))))))
]}
@defproc[(build-signed-interaction-graph/form [nf (NetworkForm a)]) Graph]{
Like @racket[build-signed-interaction-graph], but takes a network form and
converts it to a network.
@ex[
(dotit (build-signed-interaction-graph/form
(make-boolean-network-form #hash((a . (and a b))
(b . (not b))))))
]}
@section{Tabulating functions and networks}
2022-09-27 00:14:25 +02:00
@defproc[(tabulate-state* [funcs (Listof (-> (State a) a))]
[domains (DomainMapping a)])
(Listof (Listof a))]{
Like @racket[tabulate*], but the functions operate on states.
This function will produce a joint truth table of the given functions—a list of
lists, in which the first columns list all possible combinations of the values
of the input values, and the last columns give the corresponding values of the
functions. @racket[domains] defines the domains of each of the component of
the states.
@ex[
2022-11-06 22:48:30 +01:00
(require (only-in "utils.rkt" λ/:))
(tabulate-state* (list (λ/: (State Integer) (+ :a :b))
(λ/: (State Integer) (- :a :b)))
(hash 'a '(1 2) 'b '(2 3)))
2022-09-27 00:14:25 +02:00
]}
@defproc[(tabulate-state*+headers [funcs (Listof (-> (State a) a))]
[domains (DomainMapping a)])
(Pairof (Listof Symbol) (Listof (Listof a)))]{
Like @racket[tabulate-state*], but the first line of the result lists the names
of the variables and the functions.
@ex[
(tabulate-state*+headers (list (λ/: (State Integer) (+ :a :b))
(λ/: (State Integer) (- :a :b)))
(hash 'a '(1 2) 'b '(2 3)))
]}
2022-09-28 00:44:31 +02:00
@defproc[(tabulate-state*/boolean [funcs (Listof (-> State Boolean) Boolean)]
[args (Listof Variable)])
(Listof (Listof Boolean))]{
Like @racket[tabulate-state*], but the functions operate on Boolean states.
The list @racket[args] is used to generate all possible Boolean states
containing the variables appearing on this list.
@ex[
2022-11-06 22:48:30 +01:00
(tabulate-state*/boolean (list (λ/: (State Boolean) (and :a :b))
(λ/: (State Boolean) (or :a :b)))
'(a b))
2022-09-28 00:44:31 +02:00
]}
@defproc[(tabulate-state*+headers/boolean
[funcs (Listof (-> State Boolean) Boolean)]
[args (Listof Variable)])
(Pairof (Listof Symbol) (Listof (Listof Boolean)))]{
Like @racket[tabulate-state*+headers], but the functions operate on Boolean
states, like @racket[tabulate-state*].
@ex[
(tabulate-state*+headers/boolean
(list (λ/: (State Boolean) (and :a :b))
(λ/: (State Boolean) (or :a :b)))
'(a b))
]}
@deftogether[(@defproc[(tabulate-state [func (-> (State a) a)]
[domains (DomainMapping a)])
(Listof (Listof a))]
@defproc[(tabulate-state+headers
[func (-> (State a) a)]
[domains (DomainMapping a)])
(Pairof (Listof Symbol) (Listof (Listof a)))]
@defproc[(tabulate-state/boolean [func (-> (State Boolean) Boolean)]
[args (Listof Variable)])
(Listof (Listof Boolean))]
@defproc[(tabulate-state+headers/boolean
[func (-> (State Boolean) Boolean)]
[args (Listof Variable)])
(Pairof (Listof Symbol) (Listof (Listof Boolean)))])]{
Like the starred versions @racket[tabulate-state*],
@racket[tabulate-state*+headers], @racket[tabulate-state/boolean], and
@racket[tabulate-state+headers/boolean], but only tabulate one
function instead of a list.
@ex[
(tabulate-state
(λ/: (State Boolean) (and :a :b))
(hash 'a '(#f #t) 'b '(#f #t)))
(tabulate-state+headers
(λ/: (State Boolean) (and :a :b))
(hash 'a '(#f #t) 'b '(#f #t)))
(tabulate-state/boolean
(λ/: (State Boolean) (and :a :b))
'(a b))
(tabulate-state+headers/boolean
(λ/: (State Boolean) (and :a :b))
'(a b))
]}
@defproc[(tabulate-network [network (Network a)]) (Listof (Listof a))]{
Tabulates all the functions of @racket[network], producing an output
similar to that of @racket[tabulate-state*].
@ex[
(tabulate-network (forms->boolean-network (hash 'a '(not a) 'b 'b)))
]}
@defproc[(tabulate-network+headers [network (Network a)]) (Listof (Listof a))]{
Tabulates all the functions of @racket[network], producing an output
similar to that of @racket[tabulate-state*+headers] , except that the
function names in the corresponding column headers are of the form
@tt{f-x}, where @tt{x} is the name of the corresponding variable.
@ex[
(tabulate-network+headers (forms->boolean-network (hash 'a '(not a) 'b 'b)))
]}
@section{Constructing functions and networks}
2023-03-17 23:03:50 +01:00
@defproc[(table+vars->network [var-names (Listof Variable)]
[table (Listof (Listof a))])
(Network a)]{
2023-03-10 23:52:01 +01:00
2023-03-17 23:03:50 +01:00
Given a @racket[table] like the one produced by
@racket[tabulate-network] and the list of variable names
@racket[var-names], constructs a network having this behaviour.
2023-03-10 23:52:01 +01:00
2023-03-17 23:03:50 +01:00
The columns defining the functions are taken to be in the same order
as the columns defining the variables. The domains of the network are
a mapping assigning to each variable the set of values which can
appear in the corresponding column in the table.
2023-03-10 23:52:01 +01:00
This function relies on @racket[table->unary-function], so the same
performance caveats apply.
This function does not check whether the table is complete.
@ex[
2023-03-17 23:03:50 +01:00
(let ([n (table+vars->network '(a b)
'((#f #f #f #f)
(#f #t #f #t)
(#t #f #t #f)
(#t #t #t #t)))])
2023-03-10 23:52:01 +01:00
(tabulate-network n))
]}
2023-03-17 23:36:50 +01:00
@defproc[(table->network [table (Listof (Listof a))]) (Network a)]{
Like @racket[table+vars->network], but generates variable names as
@tt{xi}, where 1 ≤ @tt{i} ≤ number of variables.
@ex[
(let ([n (table->network '((#f #f #f #f)
(#f #t #f #t)
(#t #f #t #f)
(#t #t #t #t)))])
(network-domains n))
]}
2023-03-23 16:16:02 +01:00
@defproc[(table+headers->network [table (Pairof (Listof Symbol) (Listof (Listof a)))])
(Network a)]{
Like @racket[table+vars->network], but the variable names are taken
from the first line of @racket[table].
The lines of @racket[table] are taken to be of the same length, so it
is assumed that half of the first line contain variable names, and the
other half function names. Function names are discarded.
@ex[
(let ([n (table+headers->network '((a b fa fb)
(#f #f #f #f)
(#f #t #f #t)
(#t #f #t #f)
(#t #t #t #t)))])
(network-domains n))
]}
@section{Random functions and networks}
2023-03-24 14:43:59 +01:00
@defproc[(random-function/state [arg-domains (DomainMapping a)]
[func-doman (Domain a)])
(-> (State a) a)]{
Generates a random function accepting a state over the domains given
by @racket[arg-domains] and producing values in @racket[func-domain].
@ex[
(let* ([doms (hash 'a '(1 2) 'b '(3 4))]
[f (random-function/state doms '(e f))])
(tabulate-state+headers f doms))
]}
2023-03-24 14:44:08 +01:00
@defproc[(random-boolean-function/state [args (Listof Variable)])
(-> (State a) a)]{
Generates a random Boolean function accepting states over the
variables in @racket[args].
@ex[
(tabulate-state+headers/boolean (random-boolean-function/state '(a b)) '(a b))
]}
2023-03-24 16:20:23 +01:00
@defproc[(random-network [domains (DomainMapping a)])
(Network a)]{
Generates a random network from the given domain mapping.
@ex[
(tabulate-network+headers (random-network (hash 'a '(1 2) 'b '(#f #t))))
]}
2023-03-25 16:29:33 +01:00
@defproc[(random-boolean-network [vars (Listof Variable)])
(Network Boolean)]{
Generates a random Boolean network with the given variables.
@ex[
(tabulate-network+headers (random-boolean-network '(x y z)))
]}
2023-03-26 22:34:45 +02:00
@defproc[(random-boolean-network/n [n Positive-Integer])
(Network Boolean)]{
Like @racket[random-boolean-network], but also generates the names of
the variables for the network. The variables have the names @tt{x0}
to @tt{xk}, where @italic{k = n - 1}.
@ex[
(tabulate-network+headers (random-boolean-network/n 3))
]}