2020-02-20 00:56:30 +01:00
|
|
|
#lang racket
|
2020-02-15 13:57:49 +01:00
|
|
|
|
2020-02-20 00:56:30 +01:00
|
|
|
;;; Tests for dds/networks.
|
2020-02-15 13:57:49 +01:00
|
|
|
|
2020-02-20 15:56:48 +01:00
|
|
|
(require rackunit graph "networks.rkt")
|
2020-02-15 13:57:49 +01:00
|
|
|
|
2020-02-15 20:30:46 +01:00
|
|
|
;;; This test case sets up the following Boolean network:
|
|
|
|
;;; x1 = x1 AND NOT x2
|
|
|
|
;;; x2 = NOT x2
|
2020-02-18 12:20:32 +01:00
|
|
|
(test-case "Basic definitions"
|
2020-02-20 00:56:30 +01:00
|
|
|
(let* ([f1 (λ (s)
|
2020-02-18 12:20:32 +01:00
|
|
|
(let ([x1 (hash-ref s 'x1)]
|
|
|
|
[x2 (hash-ref s 'x2)])
|
|
|
|
(and x1 (not x2))))]
|
2020-02-20 00:56:30 +01:00
|
|
|
[f2 (λ (s)
|
2020-02-18 12:20:32 +01:00
|
|
|
(let ([x2 (hash-ref s 'x2)])
|
|
|
|
(not x2)))]
|
2020-02-20 00:56:30 +01:00
|
|
|
[bn (make-network-from-functions `((x1 . ,f1) (x2 . ,f2)))])
|
2020-02-15 20:30:46 +01:00
|
|
|
|
2020-02-26 15:51:25 +01:00
|
|
|
(test-case "States"
|
|
|
|
(check-equal? (make-state-booleanize '((a . 0) (b . 1)))
|
|
|
|
(st '((a . #f) (b . #t))))
|
2020-02-26 21:05:06 +01:00
|
|
|
(check-equal? (stb #hash((a . 0) (b . 1)))
|
2020-02-26 20:47:38 +01:00
|
|
|
(st '((a . #f) (b . #t))))
|
|
|
|
(check-equal? (booleanize-state (st '((a . 0) (b . 1))))
|
2020-02-26 15:51:25 +01:00
|
|
|
(st '((a . #f) (b . #t)))))
|
|
|
|
|
2020-02-18 12:20:32 +01:00
|
|
|
(test-case "One-step syncronous update"
|
|
|
|
(let* ([s (make-state '((x1 . #t) (x2 . #f)))]
|
|
|
|
[new-s (update bn s '(x2 x1))])
|
2020-02-23 09:25:08 +01:00
|
|
|
(check-equal? s #hash((x1 . #t) (x2 . #f)))
|
|
|
|
(check-equal? new-s #hash((x1 . #t) (x2 . #t)))))
|
2020-02-15 20:30:46 +01:00
|
|
|
|
2020-02-18 12:20:32 +01:00
|
|
|
(test-case "One-step asynchronous update"
|
|
|
|
(let* ([s (make-state '((x1 . #f) (x2 . #f)))]
|
|
|
|
[new-s (update bn s '(x2 x1))])
|
2020-02-23 09:25:08 +01:00
|
|
|
(check-equal? s #hash((x1 . #f) (x2 . #f)))
|
|
|
|
(check-equal? new-s #hash((x1 . #f) (x2 . #t)))))))
|
2020-02-18 11:41:16 +01:00
|
|
|
|
2020-02-18 12:20:32 +01:00
|
|
|
(test-case "Syntactic description of Boolean networks"
|
|
|
|
(let ([s (make-state '((x . #t) (y . #f)))]
|
2020-02-20 00:56:30 +01:00
|
|
|
[f (update-function-form->update-function '(and x y))])
|
2020-02-18 12:20:32 +01:00
|
|
|
(check-equal? (f s) #f))
|
2020-02-20 00:56:30 +01:00
|
|
|
(let ([bn1 (network-form->network (make-hash '((a . (and a b)) (b . (not b)))))]
|
|
|
|
[bn2 (make-network-from-forms '((a . (and a b))
|
|
|
|
(b . (not b))))]
|
2020-02-23 20:28:11 +01:00
|
|
|
[bn3 (nn #hash((a . (and a b))
|
|
|
|
(b . (not b))))]
|
2020-02-18 12:39:11 +01:00
|
|
|
[s (st '((a . #t) (b . #t)))])
|
2020-02-18 12:20:32 +01:00
|
|
|
(check-equal? ((hash-ref bn1 'a) s) #t)
|
2020-02-18 12:36:26 +01:00
|
|
|
(check-equal? ((hash-ref bn2 'a) s) #t)
|
|
|
|
(check-equal? ((hash-ref bn3 'a) s) #t)))
|
2020-02-20 15:17:32 +01:00
|
|
|
|
|
|
|
(test-case "Inferring interaction graphs"
|
2020-02-20 15:56:48 +01:00
|
|
|
(let* ([n #hash((a . (+ a b c))
|
|
|
|
(b . (- b c)))]
|
|
|
|
[ig (build-interaction-graph n)])
|
2020-02-20 15:17:32 +01:00
|
|
|
(check-true (set=? (list-interactions n 'a) '(a b)))
|
2020-02-20 15:56:48 +01:00
|
|
|
(check-true (set=? (list-interactions n 'b) '(b)))
|
|
|
|
(check-true (has-vertex? ig 'a))
|
|
|
|
(check-true (has-vertex? ig 'b))
|
|
|
|
(check-false (has-vertex? ig 'c))
|
|
|
|
(check-true (has-edge? ig 'a 'a))
|
|
|
|
(check-true (has-edge? ig 'b 'a))
|
|
|
|
(check-true (has-edge? ig 'b 'b))
|
|
|
|
(check-false (has-edge? ig 'c 'b))
|
2020-02-22 22:27:40 +01:00
|
|
|
(check-false (has-edge? ig 'c 'a)))
|
|
|
|
|
2020-02-23 09:25:08 +01:00
|
|
|
(check-equal? (build-all-states #hash((a . (#t #f)) (b . (1 2 3))))
|
|
|
|
'(#hash((a . #t) (b . 1))
|
|
|
|
#hash((a . #t) (b . 2))
|
|
|
|
#hash((a . #t) (b . 3))
|
|
|
|
#hash((a . #f) (b . 1))
|
|
|
|
#hash((a . #f) (b . 2))
|
|
|
|
#hash((a . #f) (b . 3))))
|
|
|
|
(check-equal? (make-boolean-domains '(a b))
|
|
|
|
#hash((a . (#f #t)) (b . (#f #t))))
|
2020-02-23 20:13:37 +01:00
|
|
|
(check-equal? (build-all-boolean-states '(a b))
|
|
|
|
'(#hash((a . #f) (b . #f))
|
|
|
|
#hash((a . #f) (b . #t))
|
|
|
|
#hash((a . #t) (b . #f))
|
|
|
|
#hash((a . #t) (b . #t))))
|
2020-02-23 00:04:19 +01:00
|
|
|
|
2020-02-23 01:00:09 +01:00
|
|
|
(let* ([n #hash((a . (not b)) (b . a))]
|
|
|
|
[doms (make-boolean-domains '(a b))]
|
2020-02-23 10:00:48 +01:00
|
|
|
[sig1 (build-signed-interaction-graph n doms)]
|
|
|
|
[sig2 (build-boolean-signed-interaction-graph n)])
|
2020-02-23 00:04:19 +01:00
|
|
|
(check-equal? (get-interaction-sign n doms 'a 'b) '+)
|
2020-02-23 01:00:09 +01:00
|
|
|
(check-equal? (get-interaction-sign n doms 'b 'a) '-)
|
|
|
|
|
2020-02-23 10:00:48 +01:00
|
|
|
(check-true (has-vertex? sig1 'a))
|
|
|
|
(check-true (has-vertex? sig1 'b))
|
|
|
|
(check-false (has-vertex? sig1 'c))
|
|
|
|
(check-false (has-edge? sig1 'a 'a))
|
|
|
|
(check-true (has-edge? sig1 'b 'a))
|
|
|
|
(check-false (has-edge? sig1 'b 'b))
|
|
|
|
(check-false (has-edge? sig1 'c 'b))
|
|
|
|
(check-false (has-edge? sig1 'c 'a))
|
|
|
|
(check-equal? (edge-weight sig1 'a 'b) 1)
|
|
|
|
(check-equal? (edge-weight sig1 'b 'a) -1)
|
|
|
|
|
|
|
|
(check-true (has-vertex? sig2 'a))
|
|
|
|
(check-true (has-vertex? sig2 'b))
|
|
|
|
(check-false (has-vertex? sig2 'c))
|
|
|
|
(check-false (has-edge? sig2 'a 'a))
|
|
|
|
(check-true (has-edge? sig2 'b 'a))
|
|
|
|
(check-false (has-edge? sig2 'b 'b))
|
|
|
|
(check-false (has-edge? sig2 'c 'b))
|
|
|
|
(check-false (has-edge? sig2 'c 'a))
|
|
|
|
(check-equal? (edge-weight sig2 'a 'b) 1)
|
|
|
|
(check-equal? (edge-weight sig2 'b 'a) -1)))
|
2020-02-23 11:25:19 +01:00
|
|
|
|
|
|
|
(test-case "Dynamics of networks"
|
2020-02-26 21:27:02 +01:00
|
|
|
(check-equal? (pretty-print-state (st '((a . #f) (b . 3) (c . 4)))) "a:#f b:3 c:4")
|
|
|
|
(check-equal? (pretty-print-boolean-state (st '((a . #f) (b . #t) (c . #t)))) "a:0 b:1 c:1")
|
2020-02-23 11:25:19 +01:00
|
|
|
(let ([vars '(a b c)])
|
|
|
|
(check-equal? (make-asyn vars) (set (set 'a) (set 'b) (set 'c)))
|
2020-02-23 11:42:01 +01:00
|
|
|
(check-equal? (make-syn vars) (set (set 'a 'b 'c))))
|
2020-02-23 20:28:11 +01:00
|
|
|
(let* ([n (nn #hash((a . (not a)) (b . b)))]
|
2020-02-23 11:42:01 +01:00
|
|
|
[asyn (make-asyn-dynamics n)]
|
|
|
|
[syn (make-syn-dynamics n)])
|
|
|
|
(check-equal? (dynamics-network asyn) n)
|
|
|
|
(check-equal? (dynamics-mode asyn) (set (set 'a) (set 'b)))
|
|
|
|
(check-equal? (dynamics-network syn) n)
|
2020-02-23 12:19:47 +01:00
|
|
|
(check-equal? (dynamics-mode syn) (set (set 'a 'b))))
|
2020-02-23 20:28:11 +01:00
|
|
|
(let* ([n (nn #hash((a . (not a)) (b . b)))]
|
2020-02-23 12:19:47 +01:00
|
|
|
[asyn (make-asyn-dynamics n)]
|
|
|
|
[syn (make-syn-dynamics n)]
|
2020-02-23 15:09:02 +01:00
|
|
|
[s (st '((a . #t) (b . #f)))]
|
|
|
|
[ss (set (st '((a . #t) (b . #t)))
|
2020-02-23 18:51:57 +01:00
|
|
|
(st '((a . #f) (b . #t))))]
|
|
|
|
[gr1 (dds-build-n-step-state-graph asyn (set s) 1)]
|
2020-02-23 19:44:55 +01:00
|
|
|
[gr-full (dds-build-state-graph asyn (set s))]
|
|
|
|
[gr-full-pp (ppsg gr-full)]
|
2020-02-23 20:13:37 +01:00
|
|
|
[gr-full-ppb (ppsgb gr-full)]
|
2020-02-28 21:56:42 +01:00
|
|
|
[gr-complete-bool (build-full-boolean-state-graph asyn)]
|
|
|
|
[gr-complete-bool-ann (build-full-boolean-state-graph-annotated asyn)])
|
2020-02-23 12:23:55 +01:00
|
|
|
(check-equal? (dds-step-one asyn s) (set (st '((a . #f) (b . #f)))
|
2020-02-23 13:28:51 +01:00
|
|
|
(st '((a . #t) (b . #f)))))
|
2020-02-23 14:11:55 +01:00
|
|
|
(check-equal? (dds-step-one-annotated asyn s)
|
|
|
|
(set (cons (set 'b) '#hash((a . #t) (b . #f)))
|
|
|
|
(cons (set 'a) '#hash((a . #f) (b . #f)))))
|
2020-02-23 13:28:51 +01:00
|
|
|
(check-equal? (dds-step-one syn s) (set (st '((a . #f) (b . #f)))))
|
2020-02-23 15:09:02 +01:00
|
|
|
(check-equal? (dds-step asyn ss)
|
2020-02-23 13:28:51 +01:00
|
|
|
(set (st '((a . #f) (b . #t)))
|
2020-02-23 18:51:57 +01:00
|
|
|
(st '((a . #t) (b . #t)))))
|
|
|
|
(check-true (has-vertex? gr1 #hash((a . #t) (b . #f))))
|
|
|
|
(check-true (has-vertex? gr1 #hash((a . #f) (b . #f))))
|
|
|
|
(check-false (has-vertex? gr1 #hash((a . #t) (b . #t))))
|
|
|
|
(check-true (has-edge? gr1 #hash((a . #t) (b . #f)) #hash((a . #f) (b . #f))))
|
|
|
|
(check-true (has-edge? gr1 #hash((a . #t) (b . #f)) #hash((a . #t) (b . #f))))
|
|
|
|
(check-false (has-edge? gr1 #hash((a . #f) (b . #f)) #hash((a . #t) (b . #f))))
|
|
|
|
|
|
|
|
(check-true (has-vertex? gr-full #hash((a . #t) (b . #f))))
|
|
|
|
(check-true (has-vertex? gr-full #hash((a . #f) (b . #f))))
|
|
|
|
(check-false (has-vertex? gr-full #hash((a . #t) (b . #t))))
|
|
|
|
(check-true (has-edge? gr-full #hash((a . #t) (b . #f)) #hash((a . #f) (b . #f))))
|
|
|
|
(check-true (has-edge? gr-full #hash((a . #t) (b . #f)) #hash((a . #t) (b . #f))))
|
|
|
|
(check-true (has-edge? gr-full #hash((a . #f) (b . #f)) #hash((a . #t) (b . #f))))
|
2020-02-23 19:44:55 +01:00
|
|
|
(check-true (has-edge? gr-full #hash((a . #f) (b . #f)) #hash((a . #f) (b . #f))))
|
|
|
|
|
|
|
|
(check-true (has-vertex? gr-full-pp "a:#f b:#f"))
|
|
|
|
(check-true (has-vertex? gr-full-pp "a:#t b:#f"))
|
|
|
|
(check-true (has-vertex? gr-full-ppb "a:0 b:0"))
|
2020-02-23 20:13:37 +01:00
|
|
|
(check-true (has-vertex? gr-full-ppb "a:1 b:0"))
|
|
|
|
|
|
|
|
(check-equal? (get-edges gr-complete-bool)
|
|
|
|
'((#hash((a . #f) (b . #f)) #hash((a . #t) (b . #f)))
|
|
|
|
(#hash((a . #f) (b . #f)) #hash((a . #f) (b . #f)))
|
|
|
|
(#hash((a . #t) (b . #f)) #hash((a . #t) (b . #f)))
|
|
|
|
(#hash((a . #t) (b . #f)) #hash((a . #f) (b . #f)))
|
|
|
|
(#hash((a . #t) (b . #t)) #hash((a . #f) (b . #t)))
|
|
|
|
(#hash((a . #t) (b . #t)) #hash((a . #t) (b . #t)))
|
|
|
|
(#hash((a . #f) (b . #t)) #hash((a . #f) (b . #t)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(#hash((a . #f) (b . #t)) #hash((a . #t) (b . #t)))))
|
|
|
|
|
|
|
|
(check-equal? (get-edges gr-complete-bool-ann)
|
|
|
|
'((#hash((a . #f) (b . #f)) #hash((a . #t) (b . #f)))
|
|
|
|
(#hash((a . #f) (b . #f)) #hash((a . #f) (b . #f)))
|
|
|
|
(#hash((a . #t) (b . #f)) #hash((a . #t) (b . #f)))
|
|
|
|
(#hash((a . #t) (b . #f)) #hash((a . #f) (b . #f)))
|
|
|
|
(#hash((a . #t) (b . #t)) #hash((a . #f) (b . #t)))
|
|
|
|
(#hash((a . #t) (b . #t)) #hash((a . #t) (b . #t)))
|
|
|
|
(#hash((a . #f) (b . #t)) #hash((a . #f) (b . #t)))
|
|
|
|
(#hash((a . #f) (b . #t)) #hash((a . #t) (b . #t)))))
|
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #f) (b . #f)) #hash((a . #t) (b . #f)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'a)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #f) (b . #f)) #hash((a . #f) (b . #f)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'b)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #t) (b . #f)) #hash((a . #t) (b . #f)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'b)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #t) (b . #f)) #hash((a . #f) (b . #f)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'a)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #t) (b . #t)) #hash((a . #f) (b . #t)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'a)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #t) (b . #t)) #hash((a . #t) (b . #t)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'b)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #f) (b . #t)) #hash((a . #f) (b . #t)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'b)))
|
2020-02-28 21:56:42 +01:00
|
|
|
(check-equal? (edge-weight gr-complete-bool-ann
|
|
|
|
#hash((a . #f) (b . #t)) #hash((a . #t) (b . #t)))
|
2020-03-02 18:18:23 +01:00
|
|
|
(set (set 'a)))))
|
2020-03-15 16:12:35 +01:00
|
|
|
|
2020-03-22 14:40:23 +01:00
|
|
|
(test-case "Tabulating functions and networks"
|
2020-03-15 16:12:35 +01:00
|
|
|
(check-equal? (tabulate/domain-list (λ (x y) (and x y)) '((#f #t) (#f #t)))
|
|
|
|
'((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t)))
|
|
|
|
(check-equal? (tabulate (λ (x y) (and x y)) '(#f #t) '(#f #t))
|
|
|
|
'((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t)))
|
|
|
|
(check-equal? (tabulate/boolean (lambda (x y) (and x y)))
|
2020-03-18 21:40:09 +01:00
|
|
|
'((#f #f #f) (#f #t #f) (#t #f #f) (#t #t #t)))
|
2020-03-22 14:34:40 +01:00
|
|
|
(let ([func (λ (st) (not (hash-ref st 'a)))])
|
2020-03-22 19:22:54 +01:00
|
|
|
(check-equal? (tabulate-state/boolean func '(a)) '((a f) (#f #t) (#t #f))))
|
|
|
|
(let ([bn (nn #hash((a . (not a)) (b . b)))])
|
|
|
|
(check-equal? (tabulate-boolean-network bn)
|
|
|
|
'((a b f-a f-b) (#f #f #t #f) (#f #t #t #t) (#t #f #f #f) (#t #t #f #t)))
|
|
|
|
(check-equal? (tabulate-boolean-network bn #:headers #f)
|
|
|
|
'((#f #f #t #f) (#f #t #t #t) (#t #f #f #f) (#t #t #f #t)))))
|
2020-03-22 14:40:23 +01:00
|
|
|
|
|
|
|
(test-case "Constructing functions"
|
2020-03-20 16:41:26 +01:00
|
|
|
(check-equal? (boolean-power 2) '((#f #f) (#f #t) (#t #f) (#t #t)))
|
|
|
|
(check-equal? (stream->list (boolean-power/stream 2)) '((#f #f) (#f #t) (#t #f) (#t #t)))
|
2020-03-18 21:40:09 +01:00
|
|
|
(let ([negation (table->function '((#t #f) (#f #t)))]
|
|
|
|
[negation/list (table->function/list '((#t #f) (#f #t)))])
|
|
|
|
(check-true (negation #f)) (check-false (negation #t))
|
2020-03-19 23:40:08 +01:00
|
|
|
(check-true (negation/list '(#f))) (check-false (negation/list '(#t))))
|
2020-03-20 00:15:51 +01:00
|
|
|
(let ([f1 (stream-first (enumerate-boolean-functions 1))]
|
|
|
|
[f1/list (stream-first (enumerate-boolean-functions/list 1))])
|
2020-03-19 23:40:08 +01:00
|
|
|
(check-false (f1 #f)) (check-false (f1 #t))
|
2020-03-20 22:22:33 +01:00
|
|
|
(check-false (f1/list '(#f))) (check-false (f1/list '(#t)))))
|
|
|
|
|
2020-03-22 14:40:23 +01:00
|
|
|
(test-case "Random functions and networks"
|
2020-03-22 14:36:02 +01:00
|
|
|
(random-seed 0)
|
|
|
|
(check-equal? (random-boolean-table 2) '((#f #f #t) (#f #t #t) (#t #f #f) (#t #t #f)))
|
|
|
|
(let ([f (random-boolean-function 2)])
|
|
|
|
(check-true (f #f #f)) (check-false (f #f #t)) (check-true (f #t #f)) (check-false (f #t #t)))
|
|
|
|
(let ([f (random-boolean-function/list 2)])
|
|
|
|
(check-false (f '(#f #f))) (check-true (f '(#f #t)))
|
|
|
|
(check-true (f '(#t #f))) (check-false (f '(#t #t))))
|
|
|
|
(begin
|
|
|
|
(random-seed 0)
|
|
|
|
(define f (random-boolean-function/state '(x1 x2)))
|
|
|
|
(check-equal? (tabulate-state/boolean f '(x1 x2))
|
2020-03-22 19:34:08 +01:00
|
|
|
'((x1 x2 f) (#f #f #f) (#f #t #f) (#t #f #t) (#t #t #t)))
|
2020-03-22 14:36:02 +01:00
|
|
|
(check-equal? (tabulate-state/boolean f '(x1 x2) #:headers #f)
|
2020-03-22 19:34:08 +01:00
|
|
|
'((#f #f #f) (#f #t #f) (#t #f #t) (#t #t #t)))
|
2020-03-22 19:28:44 +01:00
|
|
|
(define bn (random-boolean-network/vars 3))
|
|
|
|
(check-equal? (tabulate-boolean-network bn)
|
|
|
|
'((x0 x1 x2 f-x0 f-x1 f-x2)
|
|
|
|
(#f #f #f #f #t #f)
|
2020-03-22 19:34:08 +01:00
|
|
|
(#f #f #t #t #f #f)
|
|
|
|
(#f #t #f #f #t #t)
|
2020-03-22 19:28:44 +01:00
|
|
|
(#f #t #t #t #f #f)
|
|
|
|
(#t #f #f #t #f #t)
|
2020-03-22 19:34:08 +01:00
|
|
|
(#t #f #t #f #f #t)
|
|
|
|
(#t #t #f #f #f #f)
|
2020-03-22 19:28:44 +01:00
|
|
|
(#t #t #t #t #t #t)))))
|