1 /* swig interface wrapper file for cffi binding generation
-*- lisp
-*- */
2 /* swig
-cffi interface for CUDD
*/
3 /* (c
) 2009 Utz-Uwe Haus
*/
7 %feature
("intern_function","1"); // use swig-lispify
8 %feature
("export"); // export wrapped things
11 ;;; Auto-generated
-*- lisp
-*- file
12 ;;; generated from $Id
:$
13 (eval-when
(:compile-toplevel
:load-toplevel
)
14 (declaim
(optimize
(speed
3) (debug
0) (safety
1))))
18 (cl
:in-package
:swig-macros
)
20 (cl
:defun swig-lispify
(name flag cl
:&optional (package (find-package :cuddapi)))
21 (cl
:labels
((helper
(lst last rest cl
:&aux (c (cl:car lst)))
26 (helper
(cl
:cdr lst
) 'upper
28 ((lower digit
) (cl
:list
* c #\
- rest
))
29 (cl
:t
(cl
:cons c rest
)))))
31 (helper
(cl
:cdr lst
) 'lower
(cl
:cons
(cl
:char-upcase c
) rest
)))
33 (helper
(cl
:cdr lst
) 'digit
35 ((upper lower
) (cl
:list
* c #\
- rest
))
36 (cl
:t
(cl
:cons c rest
)))))
37 ((cl
:char-equal c #\_
)
38 (helper
(cl
:cdr lst
) '_
(cl
:cons #\
- rest
)))
39 ((cl
:char-equal c #\
-)
40 (helper
(cl
:cdr lst
) '
- (cl
:cons #\
- rest
)))
42 (cl
:error
"Invalid character: ~A" c
)))))
43 (cl
:let
((fix
(cl
:case flag
44 ((constant enumvalue
) "+")
51 (cl
:nreverse
(helper
(cl
:concatenate 'cl
:list name
) cl
:nil cl
:nil
))
60 /* includes that SWIG needs to see to parse the cudd.h file go here
*/
64 %insert
("swiglisp") %{
67 (cl
:in-package
:cuddapi
)
69 %insert
("swiglisp") %{
70 ;; foreign type definitions to hide pointer values
71 (defclass wrapped-pointer
()
72 ((ptrval
:reader get-ptrval
:initarg
:ptrval
)
73 (ctype
:reader get-ctype
:initarg
:ctype
))
74 (:documentation
"A wrapped pointer"))
76 (defmethod print-object
((p wrapped-pointer
) stream
)
77 (print-unreadable-object
(p stream
:type nil
:identity nil
)
78 (format stream
"wrapper around `~A' @0x~16R" (get-ctype p
) (get-ptrval p
))))
80 (define-condition foreign-null-pointer-condition
(error
)
82 :reader foreign-null-pointer-condition-type
))
83 (:report
(lambda
(condition stream
)
84 (format stream
"The foreign pointer of type ~A was NULL"
85 (foreign-null-pointer-condition-type condition
)))))
89 %define TYPEMAP_WRAPPED_POINTER
(PTRTYPE
,LISPCLASS
)
91 %insert
("swiglisp") %{
92 (define-foreign-type LISPCLASS
()
94 (:actual-type
:pointer
)
95 (:documentation
"cffi wrapper type around PTRTYPE."))
97 (define-parse-method LISPCLASS
()
98 (make-instance 'LISPCLASS
))
100 (defmethod translate-from-foreign
(value
(type LISPCLASS
))
101 "Wrap PTRTYPE, signaling a null-pointer-exception if value is NULL."
102 (if
(cffi
:null-pointer-p value
)
103 (error 'foreign-null-pointer-condition
:type type
)
104 (make-instance 'wrapped-pointer
:ptrval value
:ctype
"PTRTYPE")))
106 (defmethod translate-to-foreign
((g wrapped-pointer
) (type LISPCLASS
))
111 %typemap
(cin
) PTRTYPE
"LISPCLASS"
112 %typemap
(cout
) PTRTYPE
"LISPCLASS"
115 TYPEMAP_WRAPPED_POINTER
(DdManager
*, cudd-manager
)
116 TYPEMAP_WRAPPED_POINTER
(DdNode
*, cudd-node
)
118 %typemap
(cin
) DdManager
* "cudd-manager"
119 %typemap
(cout
) DdManager
* "cudd-manager"
120 %typemap
(cin
) DdNode
* "cudd-node"
121 %typemap
(cout
) DdNode
* "cudd-node"
123 /* Now parse and wrap the API header
*/
124 %insert
("swiglisp") %{
125 (eval-when
(:compile-toplevel
:load-toplevel
)
126 ;; Muffle compiler-notes globally
127 #
+sbcl
(declaim
(sb-ext
:muffle-conditions sb-ext
:defconstant-uneql
))
131 %include
"cudd/cudd.h"
132 %insert
("swiglisp") %{
133 ) ;; end of eval-when to avoid top-level export
136 %insert
("swiglisp") %{
137 ;; (defmethod translate-from-foreign
:around
(manager
(type cudd-manager
))
138 ;; (let
((cudd-manager
(call-next-method
)))
140 ;; (trivial-garbage
:finalize cudd-manager #'
(lambda
()
141 ;; ;; (break
"finalize manager #x~x~%" manager
)
142 ;; ;; (format T
"kill mgmr ~A~%" manager
) (force-output
)
146 ;; (format T
"~D nodes unfreed in manager ~A" (cuddapi
:cudd-check-zero-ref manager
) manager
)
147 ;; ;; (cuddapi
:cudd-quit manager
)
148 ;; ;; (format T
"killed mgmr ~A~%" manager
) (force-output
)
153 %insert
("swiglisp") %{
154 ;; (defmethod translate-from-foreign
:around
(node
(type cudd-node
))
155 ;; (let
((cudd-node
(call-next-method
)))
157 ;; (trivial-garbage
:finalize cudd-node #'
(lambda
()
158 ;; ;; (format T
"finalize node #x~x~%" node
)
159 ;; ;; (format T
"kill node ~A" node
) (force-output
)
161 ;; ;; (format T
"~&killed ~A~%" node
)
162 ;; ;; (format T
"killed node ~A~%" node
) (force-output
)
170 %insert
("swiglisp") %{
173 (cl
:in-package
:cudd
)
176 ;; for garbage collection purposes we wrap a reference to the manager with each
178 (defvar
*bdd-env
* nil
179 "A special variable holding the current BDD Environment.")
181 (deftype wrapped-bdd
()
184 (defmacro wrap-bdd
(bdd env
)
185 "Build a lisp object object around the cudd-node v."
187 (make-array
2 :adjustable NIL
:fill-pointer NIL
192 (defmacro unwrap-bdd
(bdd
)
193 "Extract the cudd-node object from bdd."
194 `
(svref
(the wrapped-bdd
,bdd
) 0)
198 (defun make-cudd-manager
(&key
200 (initial-num-slots
256) ;; #.
(cuddapi
:CUDD-UNIQUE-SLOTS
)
201 (cache-size
262144) ;; #.
(cuddapi
:CUDD-CACHE-SLOTS
)
203 (cuddapi
:cudd-init initial-num-vars
209 (defstruct
(bdd-environment
(:constructor construct-bdd-environment
))
210 "A wrapper object describing a CUDD-based BDD environment."
212 (name
"" :type string
)
213 ;; caching of the T and F objects of this manager to save FF overhead
216 ;; mapping VARs to foreign IDs
217 (var-
>id
(make-hash-table
:test #'eq
) :type hash-table
)
218 (nextvar
0 :type
(integer
0 #.
(expt
2 (* 8 (- (cffi
:foreign-type-size
:int
) 1))))))
220 (defmethod print-object
((e bdd-environment
) stream
)
221 (print-unreadable-object
(e stream
:type T
)
222 (format stream
"~A (manager @#x~X, ~D vars)"
223 (bdd-environment-name e
)
224 (cuddapi
::get-ptrval
(bdd-environment-manager e
))
225 (bdd-environment-nextvar e
))))
227 (defun make-bdd-environment
(&key
228 (manager
(make-cudd-manager
))
229 (name
(format nil
"BDD Environment ~A" (gensym
"BDDE"))))
230 (let
((res
(construct-bdd-environment
:manager manager
:name name
)))
231 (setf
(bdd-environment-true res
)
232 (wrap-bdd
(cuddapi
:cudd-read-one manager
) res
))
233 (setf
(bdd-environment-false res
)
234 (wrap-bdd
(cuddapi
:cudd-read-logic-zero manager
) res
))
235 ;; these need no finalization
:
236 (trivial-garbage
:cancel-finalization
(unwrap-bdd
(bdd-environment-false res
)))
237 (trivial-garbage
:cancel-finalization
(unwrap-bdd
(bdd-environment-true res
)))
240 (let
((vartab
(bdd-environment-var-
>id res
)))
241 (trivial-garbage
:finalize res
243 (format T
"~&killing ~D vars in ~A~%"
244 (hash-table-size vartab
)
246 (maphash #'
(lambda
(key val
)
247 (declare
(ignore val
))
248 (cuddapi
:cudd-recursive-deref
254 (eval-when
(:load-toplevel
)
255 (setf
*bdd-env
* (or
*bdd-env
*
256 (make-bdd-environment
:name
"The global BDD Environment."))))
258 (defmacro with-bdd-environment
(env
&body body)
259 "Execute BODY within the bdd environment ENV."
260 `
(let
((*bdd-env
* ,env
))
263 ;;; utility functions for the environment
264 (defun var-
>id
(var
&optional (env *bdd-env*))
265 "Return the ID for VAR in ENV (which defaults to *bdd-env*)."
266 (gethash var
(bdd-environment-var-
>id env
)))
268 (defsetf var-
>id
(var
&optional (env *bdd-env*)) (id)
269 `
(setf
(gethash
,var
(bdd-environment-var-
>id
,env
)) ,id
))
271 (defun id-
>var
(id
&optional (env *bdd-env*))
272 "Return the VAR for ID in ENV (which defaults to *bdd-env*)."
273 (wrap-bdd
(cuddapi
:cudd-bdd-ith-var
(bdd-environment-manager env
) id
) env
))
277 (bdd-environment-true
*bdd-env
*))
280 (bdd-environment-false
*bdd-env
*))
282 (defun bdd-new-variable
()
285 (cuddapi
:cudd-bdd-new-var
(bdd-environment-manager
*bdd-env
*))
287 (id
(bdd-environment-nextvar
*bdd-env
*)))
289 (incf
(bdd-environment-nextvar
*bdd-env
*))
290 (setf
(var-
>id v
*bdd-env
*) id
)
292 (cuddapi
::foreign-null-pointer-condition
(c
)
294 ;; FIXME
: maybe try a garbage collection here
295 (error
"CUDD failed to allocate a variable ~D:~%BDD environment ~A full."
296 (bdd-environment-nextvar
*bdd-env
*)
299 (defun bdd-restrict
(var val bdd
)
301 (cuddapi
:cudd-bdd-restrict
(bdd-environment-manager
*bdd-env
*)
303 (unwrap-bdd
(if val var
(bdd-not var
))))
308 (cuddapi
:cudd-bdd-and
(bdd-environment-manager
*bdd-env
*)
309 (unwrap-bdd x
) (unwrap-bdd y
))
314 (cuddapi
:cudd-bdd-or
(bdd-environment-manager
*bdd-env
*)
315 (unwrap-bdd x
) (unwrap-bdd y
))
319 ;; FIXME
: cudd-not is a macro and hence not swig'ed
, but would probably
322 (cuddapi
:cudd-bdd-nand
(bdd-environment-manager
*bdd-env
*)
329 (cuddapi
:cudd-bdd-xor
(bdd-environment-manager
*bdd-env
*)
334 (defun bdd-nand
(x y
)
336 (cuddapi
:cudd-bdd-nand
(bdd-environment-manager
*bdd-env
*)
343 (cuddapi
:cudd-bdd-nor
(bdd-environment-manager
*bdd-env
*)
348 (defun bdd-and-not
(bdd1 bdd2
)
349 (bdd-and bdd1
(bdd-not bdd2
)))
351 (defun bdd-or-not
(bdd1 bdd2
)
352 (bdd-or bdd1
(bdd-not bdd2
)))
354 (defun bdd-implies
(bdd1 bdd2
)
355 (bdd-or-not bdd1 bdd2
))
357 (defun bdd-iff
(bdd1 bdd2
)
358 (bdd-and
(bdd-implies bdd1 bdd2
)
359 (bdd-implies bdd2 bdd1
)))
361 (defun bdd-equal
(bdd1 bdd2
)
362 "Check whether BDD1 and BDD2 are equal."
363 (let
((b1
(unwrap-bdd bdd1
))
364 (b2
(unwrap-bdd bdd2
)))
365 (and
(= 1 (cuddapi
:cudd-bdd-leq
(bdd-environment-manager
*bdd-env
*) b1 b2
))
366 (= 1 (cuddapi
:cudd-bdd-leq
(bdd-environment-manager
*bdd-env
*) b2 b1
)))))
368 (defun bdd-tautologyp
(bdd
&optional (fixings '()))
369 "Check whether BDD is tautologic, possibly under a given fixing in FIXINGS, a list of pairs (bddvar . value), value being T or NIL. "
371 (bdd-tautologyp
(bdd-restrict
(caar fixings
) (cadr fixings
) bdd
)
373 (bdd-equal bdd
(bdd-true
))))
375 (defun bdd-satisfiablep
(bdd
&optional (fixings '()))
376 "Check whether BDD is satisfiable, possibly under a given fixing in FIXINGS, a list of pairs (bddvar . value), value being T or NIL. "
378 (bdd-satisfiablep
(bdd-restrict
(caar fixings
) (cadr fixings
) bdd
)
380 (not
(bdd-equal bdd
(bdd-false
)))))
382 (defun bdd-var-fixed0
(bdd var
)
383 (ecase
(cuddapi
:cudd-bdd-is-var-essential
(bdd-environment-manager
*bdd-env
*)
385 (var-
>id var
*bdd-env
*)
390 (defun bdd-var-fixed1
(bdd var
)
391 (ecase
(cuddapi
:cudd-bdd-is-var-essential
(bdd-environment-manager
*bdd-env
*)
398 (defgeneric deserialize-bdd
(source
)
399 (:documentation
"Parse a textual representation of a BDD from SOURCE within the current BDD environment."))
401 (defmethod deserialize-bdd
((s string
))
402 (with-input-from-string
(f s
)
403 (deserialize-bdd f
)))
405 (defmethod deserialize-bdd
((s pathname
))
406 (with-open-file
(f s
:direction
:input
)
407 (deserialize-bdd f
)))
409 (defmethod deserialize-bdd
((l list
))
410 (with-input-from-string
(f
(format nil
"~W" l
))
411 (deserialize-bdd f
)))
413 (defmethod deserialize-bdd
((s stream
))
414 "Read a textual external representation of a bdd from STREAM.
415 New variables are allocated in the current bdd environment.
416 Returns two values: the bdd structure and an alist mapping variable numbers to the
417 variable names specified in the bdd file."
418 (labels
((parse-bddfile
(s
)
419 (let
* ((bddblock
(read s
))
420 (data
(member
"BDD" bddblock
:test #'string-equal
) )
424 (error
"Could not find BDD block in ~A" data
))
425 (setf data
(cdr data
))
426 (setf tree
(assoc
"DAG" data
:test #'string-equal
))
428 (error
"Could not find BDD DAG in ~A" data
))
429 (setf tree
(cadr tree
))
430 (setf nodenames
(assoc
"VARNAMES" data
:test #'string-equal
))
432 (error
"Could not find node name mapping in ~A" data
))
433 (setf nodenames
(cadr nodenames
))
434 (values tree nodenames
)))
436 ;; we depend on having consecutive variable numbers in the bdd file
438 ;; Deducing maxvarnum from tree instead of varnames is safer because some
439 ;; variable may be missing a name. In that case we fail softly
: the tree will be
440 ;; fine
, but the mapping returned to the caller will be defective in the same way
441 ;; that the user messed it up when calling serialize-bdd with an incomplete name map.
444 (max-varnum
(third tree
))
445 (max-varnum
(fourth tree
)))
447 (multiple-value-bind
(tree nodenames
)
449 (let
* ((maxvar
(max-varnum tree
))
450 (mapping
(make-hash-table
:size maxvar
:test #'eql
)))
451 ;; fetch new variables
452 (loop
:for i
:from
2 :upto maxvar
453 :do
(setf
(gethash i mapping
) (bdd-new-variable
)))
454 (labels
((walk
(bddtext
)
461 (let
((thisvar
(gethash
(second bddtext
) mapping
))
462 (t-child
(walk
(third bddtext
)))
463 (nil-child
(walk
(fourth bddtext
))))
464 (bdd-or
(bdd-and thisvar t-child
)
465 (bdd-and
(bdd-not thisvar
) nil-child
)))))))
468 (loop
:for pair
:in nodenames
469 :as oldnum
:= (car pair
)
471 (gethash oldnum mapping
))
472 :finally
(return nodenames
))))))))