3

How to visualise arbitrary tree?

for example: (define T1 '(and (or x1 x2)(or x3 x4 x5)))

or one generated with:

(define functions '(not if and or))
(define terminals '(A0 A1 A2 D0 D1))
(define functions&terminals (append terminals functions ))

(define (pick-one list)
  (list-ref list (random (length list))))

(define arities '((if . 3)(and . 2)(or . 2)(not . 1)))

(define (terminal? symbol)
  (find (lambda (x)(eq? x symbol)) terminals))

(define (function? symbol)
  (find (lambda (x)(eq? x symbol)) functions))

(define (arity non-terminal)
  (let ((arity (find (lambda (x)(eq? non-terminal (car x))) arities)))
    (if arity
        (cdr arity)
        0)))

(define (numbers n)
  (if (= n 0) 
      '()
      (cons n (numbers (- n 1)))))

(define (gen-tree) 
  (let ((node (pick-one functions&terminals))) 
    (if (terminal? node) 
        node 
        (cons node (map (lambda (x) (gen-tree)) (numbers (arity 
node)))))))

> (gen-tree)
'(or (if A1 (and A1 (not (if D1 (and A0 A0) (or A0 A0)))) (or A0 A0)) D0)

Racket seems to have: https://docs.racket-lang.org/pict/Tree_Layout.html

is it enough to visualise trees of functions with the name of the function and params in the circle?

soegaard
  • 30,661
  • 4
  • 57
  • 106
X10D
  • 600
  • 2
  • 13

2 Answers2

6

You can do something like this to visualize arbitrarily sized trees:

(require pict
         pict/tree-layout)

(define (draw tree)
  (define (viz tree)
    (cond
      ((null? tree) #f)
      ((not (pair? tree))
       (tree-layout #:pict (cc-superimpose
                            (disk 30 #:color "white")
                            (text (symbol->string tree)))))
      ((not (pair? (car tree)))
       (apply tree-layout (map viz (cdr tree))
              #:pict (cc-superimpose
                      (disk 30 #:color "white")
                      (text (symbol->string (car tree))))))))
  (if (null? tree)
      #f
      (naive-layered (viz tree))))

For example, using the lists you provided:

(define t1 '(and (or x1 x2) (or x3 x4 x5)))
(define t2 '(or (if A1 (and A1 (not (if D1 (and A0 A0) (or A0 A0)))) (or A0 A0)) D0))

enter image description here

assefamaru
  • 2,751
  • 2
  • 10
  • 14
  • for additional points how would an animation of evaluation and reduction be done? – X10D Feb 13 '19 at 20:32
  • looks good for smaller trees but for bigger it starts getting weird: (draw '(if (not D0) (if (and (and D0 D1) (or (if (and D0 (if A1 A1 (not D1))) (not (not (or A2 (and (if (and A1 A2) A2 (and D1 (if A1 A0 (not (not A0))))) A2)))) (and D1 (and A0 (not (or A0 A0))))) A2)) D1 (not A1)) D0)) – X10D Feb 13 '19 at 21:06
  • how did you save the tree as image? im using dr racket – X10D Feb 13 '19 at 21:07
  • 3
    The above is just a screenshot image, but you can convert the generated picts and save them locally by doing: ``(define generated-pict (draw tree))`` then ``(send (pict->bitmap generated-pict) save-file "example.png" 'png)``. – assefamaru Feb 13 '19 at 21:26
  • follow up question: https://stackoverflow.com/questions/54681139/how-to-evaluate-expression-by-one-step-in-scheme – X10D Feb 13 '19 at 23:41
4

I think improvements can be made to assefamaru's answer -

  • Separate list traversal from individual node rendering
  • Simplify case analysis of input
    1. If the input is null (base case), return empty tree, #f
    2. Otherwise (inductive) the input is not null. If the input is a list, Create a tree-layout of op and recursively apply draw to args
    3. Otherwise (inductive) the input is not null and the input is not a list. Create a tree-layout of atom a

Numbered lines above correspond to comments below -

(require pict
         pict/tree-layout)

(define (my-node a)
  (cc-superimpose
   (disk 30 #:color "white")
   (text (symbol->string a))))

(define (draw atom->pict a)
  (cond ((null? a) #f)                                 ;; 1
        ((list? a) (match a                            ;; 2
                     ((cons op args)
                      (apply tree-layout
                             #:pict (atom->pict op)
                             (map (curry draw atom->pict) args)))
                     (_ #f)))
        (else (tree-layout #:pict (atom->pict a)))))   ;; 3

(define my-tree
  '(or (if A1 (and A1 (not (if D1 (and A0 A0) (or A0 A0)))) (or A0 A0)) D0))

(naive-layered (draw my-node my-tree))

enter image description here

Mulan
  • 129,518
  • 31
  • 228
  • 259