src/binary-decision-diagrams.lisp @ 9823fe1aea30

Add graphviz, basic BDDs
author Steve Losh <steve@stevelosh.com>
date Sat, 20 Aug 2016 20:48:06 +0000
parents (none)
children d1c9ad7b7774
(in-package #:sand.binary-decision-diagrams)


(defun required ()
  (error "Argument required."))

(defstruct (bdd-node (:constructor make-bdd-node (number low high)))
  (number (required) :type fixnum)
  (low (required) :type (or bit bdd-node))
  (high (required) :type (or bit bdd-node)))

(defun make-bdd (contents)
  (etypecase contents
    (bit contents)
    (cons
      (destructuring-bind (number low high) contents
        (make-bdd-node number (make-bdd low) (make-bdd high))))))

(defun evaluate-bdd (bdd &rest arguments)
  (recursively ((n 1)
                (bdd bdd)
                (argument (first arguments))
                (remaining (rest arguments)))
    (etypecase bdd
      (bit bdd)
      (bdd-node
        (if (> (bdd-node-number bdd) n)
          (recur (1+ n)
                 bdd
                 argument
                 remaining)
          (recur (1+ n)
                 (if (zerop argument)
                   (bdd-node-low bdd)
                   (bdd-node-high bdd))
                 (first remaining)
                 (rest remaining)))))))

(defun bdd-map-nodes (function bdd)
  (etypecase bdd
    (bit (list (funcall function bdd)))
    (bdd-node
      (append (list (funcall function bdd))
              (bdd-map-nodes function (bdd-node-low bdd))
              (bdd-map-nodes function (bdd-node-high bdd))))))

(defun bdd-map-edges (function bdd)
  (etypecase bdd
    (bit nil)
    (bdd-node
      (let ((low (bdd-node-low bdd))
            (high (bdd-node-high bdd)))
        (list* (funcall function bdd low t)
               (funcall function bdd high nil)
               (append (bdd-map-edges function low)
                       (bdd-map-edges function high)))))))


(defun node-label (node)
  (etypecase node
    (bit (if (zerop node) 'false 'true))
    (bdd-node (bdd-node-number node))))

(defun node-shape (node)
  (etypecase node
    (bit :box)
    (bdd-node :circle)))


(defun draw-bdd (bdd &optional (path "bdd.dot"))
  (let ((nodes (make-hash-table)))
    (graphviz-digraph
      (bdd-map-nodes (lambda (node)
                       (list (gethash-or-init node nodes (gensym))
                             :label (node-label node)
                             :shape (node-shape node)))
                     bdd)
      (bdd-map-edges (lambda (a b lowp)
                       (list (gethash a nodes)
                             (gethash b nodes)
                             :style (if lowp :dashed :solid)))
                     bdd)
      :path path)))


(defparameter *maj*
  (make-bdd '(1
              (2 0 (3 0 1))
              (2 (3 0 1) 1))))

(draw-bdd *maj*)