dds/scribblings/tbn.scrbl

475 lines
15 KiB
Text
Raw Normal View History

2023-03-26 23:29:51 +02:00
#lang scribble/manual
@(require scribble/example racket/sandbox
(for-label typed/racket/base
2023-03-27 23:23:34 +02:00
(submod "../tbn.rkt" typed)
2023-03-26 23:29:51 +02:00
"../networks.rkt"
"../utils.rkt"
"../functions.rkt"
"../dynamics.rkt"))
@(define tbn-evaluator
(parameterize ([sandbox-output 'string]
[sandbox-error-output 'string]
[sandbox-memory-limit 500])
2023-03-27 23:23:34 +02:00
(make-evaluator 'typed/racket #:requires '((submod "tbn.rkt" typed)))))
2023-03-26 23:29:51 +02:00
@(define-syntax-rule (ex . args)
(examples #:eval tbn-evaluator . args))
@(define-syntax-rule (deftypeform . args)
(defform #:kind "type" . args))
@(define-syntax-rule (deftype . args)
(defidform #:kind "type" . args))
@title[#:tag "tbn"]{dds/tbn: Threshold and Sign Boolean Networks (TBN and SBN)}
2023-03-27 23:23:34 +02:00
@defmodule[(submod dds/tbn typed)]
2023-03-26 23:29:51 +02:00
2023-04-03 15:35:12 +02:00
@section{TBFs and states}
2023-03-26 23:29:51 +02:00
This module defines threshold Boolean networks (TBN), as well as sign
Boolean networks (SBN). The update functions in such networks are
respectively @seclink["tbf" #:doc '(lib
"dds/scribblings/dds.scrbl")]{threshold Boolean functions} and sign
Boolean functions.
2023-03-27 23:23:34 +02:00
@defproc[(apply-tbf-to-state [a-tbf TBF] [st (State (U Zero One))])
(U Zero One)]{
Applies a TBF to a state.
The values of the variables of the state are ordered by
@racket[hash-map] and fed to the TBF in order. The number of the
inputs of the TBF must match the number of variables in the state.
@ex[
(require "functions.rkt")
(apply-tbf-to-state (tbf #(1 1) 1) (hash 'x1 0 'x2 1))
]}
@defstruct*[tbf/state ([weights (VariableMapping Real)]
[threshold Real])]{
A state TBF is a @racket[TBF] with named inputs. A state TBF can be
applied to states in an unambiguous ways.
}
@deftype[TBF/State]{
The type of the instances of @racket[tbf/state].
}
@deftogether[(@defproc[(tbf/state-w [tbfs TBF/State]) (VariableMapping Real)]
@defproc[(tbf/state-θ [tbfs TBF/State]) Real])]{
Shorter synonyms for field accessors of @racket[tbf/state].
@ex[
(let ([tbfs (tbf/state (hash 'a 1 'b 1) 1)])
(values (tbf/state-w tbfs)
(tbf/state-θ tbfs)))
]}
2023-03-29 01:21:29 +02:00
@defproc[(make-tbf/state [pairs (Listof (Pairof Variable Real))]
[threshold Real])
TBF/State]{
Makes a @racket[TBF/State] from a list of pairs of names of variables
and weights, as well as a threshold.
@ex[
(make-tbf/state '((x1 . 1) (x2 . 1)) 1)
]}
2023-03-29 17:46:53 +02:00
@defproc[(sbf/state? [tbfs TBF/State]) Boolean]{
A state sign Boolean function (SBF) is a @racket[TBF/State] whose
threshold is 0.
@ex[
(sbf/state? (tbf/state (hash 'a -1 'b 1) 0))
(sbf/state? (tbf/state (hash 'a -1 'b 1) 1))
]}
2023-04-03 00:00:06 +02:00
@defproc[(apply-tbf/state [tbfs TBF/State]
[st (State (U Zero One))])
(U Zero One)]{
Applies a @racket[TBF/State] to its inputs given by the state
@racket[st].
Applying a TBF consists in multiplying the weights by the
corresponding inputs and comparing the sum of the products to
the threshold.
This function is similar to @racket[apply-tbf], but because it applies
a @racket[TBF/State] to a @racket[(State (U Zero One))], it avoids
potential mismatches between weights and the corresponding
input values.
@ex[
(apply-tbf/state (tbf/state (hash 'a 2 'b -2) 1)
(hash 'a 1 'b 0 'c 1))
]}
2023-04-03 16:00:37 +02:00
@section{Reading and printing TBFs and SBFs}
2023-04-03 16:00:37 +02:00
@defproc[(lists+vars->tbfs/state [vars (Listof Variable)]
[lsts (Listof (Listof Real))])
(Listof TBF/State)]{
Reads a list of @racket[TBF/State] from a list of list of
@racket[Real]s.
The last element of each list is taken to be the threshold of the
TBFs, and the rest of the elements are taken to be the weights.
@ex[
(lists+vars->tbfs/state '(x y) '((1 2 3) (1 1 2)))
]}
2023-04-03 16:24:33 +02:00
@defproc[(lists+headers->tbfs/state [lsts+headers (Pairof (Listof Variable) (Listof (Listof Real)))])
(Listof TBF/State)]{
Like @racket[lists+vars->tbfs/state], but the names of the variables
are taken from the first line of @racket[lsts+headers].
All the lines in @racket[lsts+headers] are assumed to be of the same
lenght, which means in particular that the last element of the first
line (the threshold column) is discarded.
@ex[
(lists+headers->tbfs/state '((x y f) (1 2 3) (1 1 2)))
]}
2023-04-03 16:36:08 +02:00
@defproc[(lists->tbfs/state [lsts (Listof (Liostf Real))])
(Listof TBF/State)]{
Like @racket[lists+vars->tbfs/state], but the names of the variables
are generated as @tt{xi}, where @italic{i} is the index of the
variable, starting from 0.
@ex[
(lists->tbfs/state '((1 2 3) (1 1 2)))
]}
2023-06-10 12:03:09 +02:00
@defproc[(lists->tbfs/state/opt-headers
[lsts (Listof (Listof (U Variable Real)))]
[#:headers hdr Boolean])
(Listof TBF/State)]{
This function allows selecting between @racket[lists->tbfs/state] and
@racket[lists+headers->tbfs/state] based on the value of @racket[hdr].
If @racket[hdr] is @racket[#f], then @racket[lists->tbfs/state] is
applied to @racket[lsts], otherwise @racket[lists+headers->tbfs/state]
is applied.
@ex[
(lists->tbfs/state/opt-headers '((1 2 3) (1 1 2)) #:headers #f)
(lists->tbfs/state/opt-headers '((x y f) (1 2 3) (1 1 2)) #:headers #t)
]}
@deftogether[(@defproc[(lists+vars->sbfs/state [vars (Listof Variable)]
[lsts (Listof (Listof Real))])
(Listof TBF/State)]
@defproc[(lists+headers->sbfs/state
[lsts (Pairof (Listof Variable) (Listof (Listof Real)))])
(Listof TBF/State)]
@defproc[(lists->sbfs/state [lsts (Listof (Listof Real))])
(Listof TBF/State)])]{
Like the corresponding TBF-related functions, but which create SBFs.
In other words, the input lists are treated as lists of weights, and
the thresholds are set to 0.
@ex[
(lists+vars->sbfs/state '(x y) '((1 2) (1 1)))
(lists+headers->sbfs/state '((x y) (1 2) (1 1)))
(lists->sbfs/state '((1 2) (1 1)))
]}
@defproc[(read-org-tbfs/state [str String]) (Listof TBF/State)]{
Reads a list of @racket[TBF/State] from an Org-mode string containing
a sexp, containing a list of lists of numbers. As in
@racket[lists->tbfs/state], the last element of each list is taken to
be the threshold of the TBF, and the rest of the elements are taken to
be the weights.
Similarly to @racket[lists->tbfs/state], the names of the variables
are generated as @tt{xi}, where @italic{i} is the index of the
variable, starting from 0.
@ex[
(read-org-tbfs/state "((1 2 3) (1 1 2))")
]}
@defproc[(read-org-tbfs/state+headers [str String]) (Listof TBF/State)]{
Like @racket[read-org-tbfs/state], but the first list in @racket[str]
is taken to contain the names of the variables, similarly to
@racket[lists+headers->tbfs/state].
@ex[
(read-org-tbfs/state+headers "((a b f) (1 2 3) (1 1 2))")
]}
@defproc[(tbfs/state->lists [tbfs (Listof TBF/State)]) (Listof (Listof Real))]{
Given a list of @racket[TBF/State], produces a sexp that Org-mode can
interpret as a table.
All @racket[TBF/State] in the list must have the same inputs.
The function does not check this property.
@ex[
(tbfs/state->lists (list (tbf/state (hash 'a 1 'b 2) 3)
(tbf/state (hash 'a -2 'b 1) 1)))
]}
@defproc[(tbfs/state->lists+headers [tbfs (Listof TBF/State)])
(Pairof (Listof Variable) (Listof (Listof Real)))]{
Like @racket[tbfs/state->lists+headers], but the first list of the
result is the list of input names of the first @racket[TBF/State] in
@racket[tbfs]. The last element of this first list is @racket['θ] and
corresponds to the column giving the thresholds of the TBFs.
@ex[
(tbfs/state->lists+headers
(list (tbf/state (hash 'a 1 'b 2) 3)
(tbf/state (hash 'a -2 'b 1) 1)))
]}
2023-05-25 14:51:55 +02:00
@defproc[(sbfs/state->lists [sbfs (Listof TBF/State)])
(Listof (Listof Real))]{
Like @racket[tbfs/state->lists], but the thresholds are omitted.
@ex[
(sbfs/state->lists (list (tbf/state (hash 'a 1 'b 2) 0)
(tbf/state (hash 'a -2 'b 1) 0)))
]
Note that this function just drops the threshold, without checking
whether it is actually 0:
@ex[
(sbfs/state->lists (list (tbf/state (hash 'a 1 'b 2) 3)))
]}
2023-05-25 15:19:25 +02:00
@defproc[(sbfs/state->lists+headers [sbfs (Listof TBF/State)])
(Pairof (Listof Variable) (Listof (Listof Real)))]{
Like @racket[sbfs/state->lists], but also shows the names of the
variables as column headers.
@ex[
(sbfs/state->lists+headers (list (tbf/state (hash 'a 1 'b 2) 0)
(tbf/state (hash 'a -2 'b 1) 0)))
]}
@section{Tabulating TBFs and SBFs}
@defproc[(tabulate-tbfs/state [tbfs (Listof TBF/State)]) (Listof (Listof Real))]{
Tabulates a list of @racket[TBF/State].
As in the case of @racket[tbf-tabulate*], the result is a list of
lists giving the truth tables of the given TBFs. The first elements
of each row give the values of the inputs, while the last elements
give the values of each function corresponding to the input.
All the TBFs must have exactly the same inputs. This function does
not check this property.
@ex[
(tabulate-tbfs/state
(list (tbf/state (hash 'a 1 'b 2) 2)
(tbf/state (hash 'a -2 'b 2) 1)))
]}
@defproc[(tabulate-tbfs/state+headers [tbfs (Listof TBF/State)])
(Pairof (Listof Variable)
(Listof (Listof Real)))]{
Like @racket[tabulate-tbfs/state], but the first list of the result is
a gives the names of the variables appearing in the inputs of
@racket[(car tbfs)], followed by function names. The function names
are generated as @tt{fi}, where @tt{i} is the number of the TBF in
the list.
@ex[
(tabulate-tbfs/state+headers
(list (tbf/state (hash 'a 1 'b 2) 2)
(tbf/state (hash 'a -2 'b 2) 1)))
]}
@deftogether[(@defproc[(tabulate-tbf/state [tbf TBF/State])
(Listof (Listof Real))]
@defproc[(tabulate-tbf/state+headers [tbf TBF/State])
(Pairof (Listof Variable) (Listof (Listof Real)))])]{
Like @racket[tabulate-tbfs/state] and
@racket[tabulate-tbfs/state+headers], but only tabulate single TBFs.
@ex[
(tabulate-tbf/state (tbf/state (hash 'a 1 'b 2) 2))
(tabulate-tbf/state+headers (tbf/state (hash 'a 1 'b 2) 2))
]}
2023-05-22 15:34:27 +02:00
2023-05-22 15:55:36 +02:00
@section{TBNs and SBNs}
@deftype[TBN]{
The type of a TBN, i.e. a mapping assigning to each variable
a @racket[TBF/State].
}
2023-05-22 16:27:35 +02:00
@defproc[(sbn? [tbn TBN]) Boolean]{
A SBN is a @racket[TBN] in which all @racket[TBF/State]s satisfy
@racket[sbf/state?].
All functions in @racket[tbn] must only reference variables appearing
in the network. This function does not check this condition.
@ex[
(let ([f1 (tbf/state (hash 'a -1 'b 1) 0)]
[f2 (tbf/state (hash 'a -1 'b 1) 1)])
(values (sbn? (hash 'a f1 'b f1))
(sbn? (hash 'a f1 'b f2))))
]}
2023-05-25 14:34:58 +02:00
@defproc[(tbn->network [tbn TBN]) (Network (U Zero One))]{
Constructs a @racket[Network] out of the given @racket[tbn].
@ex[
(require (only-in "networks.rkt" update))
(let* ([tbn-form (hash 'a (tbf/state (hash 'a -1 'b 1) 0)
'b (tbf/state (hash 'a -1 'b 1) 1))]
[tbn (tbn->network tbn-form)]
[s (hash 'a 0 'b 1)])
(update tbn s '(a b)))
]}
@defproc[(parse-org-tbn [tab (Listof (Listof (U Symbol Real)))]
[#:headers headers Boolean #t]
[#:func-names func-names Boolean #t])
TBN]{
Reads a TBN from a list of lists of numbers or symbols, which may
represent an Org-mode table. As in @racket[lists->tbfs/state], the
last element of each list is taken to be the threshold of the TBF, and
the rest of the elements are taken to be the weights.
If @racket[headers] is @racket[#t], the names of the variables to
appear as the inputs of the TBF are taken from the first list.
The last element of this list (corresponding to the column giving the
threshold) is discarded. If @racket[headers] is @racket[#f], the
names of the variables are generated as @tt{xi}, where @tt{i} is
the index of the variable.
If @racket[func-names] is @racket[#t], the first element in every row
except the first one are taken to be the name of the variable to which
the TBF should be associated. If @racket[func-names] is @racket[#f],
the functions are assigned to variables in lexicographic order.
@racket[func-names] cannot be @racket[#t] if @racket[headers] is
@racket[#f]. The function does not check this condition.
This is a helper function for @racket[read-org-tbn] and
@racket[read-org-sbn].
@ex[
(parse-org-tbn '((1 2 3) (3 2 1)) #:headers #f #:func-names #f)
(parse-org-tbn '((a b θ) (1 2 3) (3 2 1)) #:headers #t #:func-names #f)
(parse-org-tbn '((dummy a b θ) (b 3 2 1) (a 1 2 3)) #:headers #t #:func-names #t)
]}
@defproc[(read-org-tbn [str String]
[#:headers headers Boolean #t]
[#:func-names func-names Boolean #t])
TBN]{
Reads a TBN from an string containing a sexp, containing a list of
lists of numbers and possibly symbols. This string may be produced by
Org-mode.
As in @racket[lists->tbfs/state], the last element of each list is
taken to be the threshold of the TBFs, and the rest of the elements
are taken to be the weights.
As in @racket[parse-org-tbn], if @racket[headers] is @racket[#t], the
names of the variables to appear as the inputs of the TBF are taken
from the first list. The last element of this list is discarded.
If @racket[headers] is @racket[#f], the names of the variables are
generated as @tt{xi}, where @tt{i} is the index of the variable.
If @racket[func-names] is @racket[#t], the first element in every row
except the first one, are taken to be the name of the variable to
which the TBF should be associated. If @racket[func-names] is
@racket[#f], the functions are assigned to variables in
alphabetical order.
As in @racket[parse-org-tbn], @racket[func-names] cannot be
@racket[#t] if @racket[headers] is @racket[#f]. The function does not
check this condition.
@ex[
(read-org-tbn "((\"-\" \"x\" \"y\" \"θ\") (\"y\" -1 0 -1) (\"x\" 0 -1 -1))")
]}
@defproc[(read-org-sbn [str String]
[#:headers headers Boolean #t]
[#:func-names func-names Boolean #t])
TBN]{
Like @racket[read-org-tbn], but reads an SBN from the input string,
i.e. all the numbers are taken to be the weights, and the threshold is
set to 0.
@ex[
(read-org-sbn "((\"-\" \"x\" \"y\") (\"y\" -1 0) (\"x\" 0 -1))")
]}
2023-07-12 20:12:09 +02:00
@defproc[(build-tbn-state-graph [tbn TBN]) Graph]{
Builds the state graph of a @racket[TBN].
This function constructs a @racket[(Network (U Zero One))] from
@racket[tbn], then builds the state graph of its synchronous dynamics,
and pretty-prints the node labels.
@ex[
(require (only-in "utils.rkt" dotit))
(dotit (build-tbn-state-graph
(hash 'a (tbf/state (hash 'a -1 'b 1) 0)
'b (tbf/state (hash 'a -1 'b 1) 1))))
]}
2023-05-22 15:34:27 +02:00
@section{Miscellaneous utilities}
@defproc[(group-truth-table-by-nai [tt (Listof (Listof Integer))])
(Listof (Listof (Listof Integer)))]{
Given the truth table @racket[tt] of a Boolean function, groups the
lines by the @italic{N}umber of @italic{A}ctivated @italic{I}nputs—the
number of inputs which are 1 in the input vector.
@ex[
(group-truth-table-by-nai '((0 0 0 1)
(0 0 1 1)
(0 1 0 0)
(0 1 1 1)
(1 0 0 0)
(1 0 1 0)
(1 1 0 1)
(1 1 1 0)))
]}