BuddyScout Code
Status: Alpha
Brought to you by:
yoshisato
| File | Date | Author | Commit |
|---|---|---|---|
| examples | 2008-05-29 | yoshisato | [r2] README fixed. simple.hs slightly changed. |
| AUTHORS | 2008-05-28 | yoshisato | [r1] initial import |
| BuddyScout.chs | 2008-05-28 | yoshisato | [r1] initial import |
| COPYING | 2008-05-28 | yoshisato | [r1] initial import |
| README | 2008-05-29 | yoshisato | [r2] README fixed. simple.hs slightly changed. |
BuddyScout ver.0.3
BuddyScout is an interface between BuDDy (Binary Decision Diagram
library) and GHC (Glasgow Haskell Compiler). It enables you to use
the BDD library from within Haskell programs.
---- License
MIT style. See COPYING and each file.
---- How to use
BuddyScout is a source file to the Haskel->C translator (c2hs), which
generates an FFI (Foreign Function Interface) description in Haskell.
To compile and use it, the following tools are required. You can
consult examples/Makefile for the details of compiler options.
BuDDy (Binary Decision Diagram library)
http://sourceforge.net/projects/buddy
GHC (Glasgow Haskell Compiler)
http://www.haskell.org/ghc/
Haskell->C (Haskell Interface Generator)
http://www.cse.unsw.edu.au/~chak/haskell/c2hs/
The bundled examples are tested with the following environments, and
it is hoped to work on many other unix-like platforms.
BuDDy 2.4, GHC 6.8.2, Haskell->C 0.15.1
Mac OS X 10.5.2 (Leopard, Intel)
Linux (CentOS 5.1, i386)
Windows XP SP2 + MinGW 5.1.4 + MSYS 1.0.10
The LANG variable could lead `c2hs' to failure. If this is the case,
try `unsetenv LANG' or `env LANG=C make'.
* Note for Linux
Some distributions require you to set LD_LIBRARY_PATH to indicate the
place where the BuDDy library resides (possibly /usr/local/lib).
* Note for Windows
Cygwin does not work with GHC because it is based on MinGW. Since
path names are inconsistent with Cygwin, GHC cannot find the /usr
directory. Therefore the BuDDy library must be compiled with MinGW
and MSYS.
---- Documents
BuddyScout requires a detailed knowledge about the BuDDy library and
some about Haskell's FFI (Foreign Function Interface). For BuDDy,
good documents are included in its package. For FFI, you can consult
http://www.cse.unsw.edu.au/~chak/haskell/ffi/ .
---- Examples
There are some examples in `examples' directory.
simple.hs --- Basic usage and a callback handler.
money.hs --- Puzzle.
(Haskell version of money.cxx from the BuDDy package)
fdd.hs --- Reachable states with FDD.
(Haskell version of fdd.cxx from BuDDy)
model-checking.hs --- CTL formulas and Kripke structures.
---- Interactive session
You can use BuddyScout interactively with GHCi as follows.
% c2hs -l BuddyScout.chs
% ghc --make BuddyScout.hs
% ghci BuddyScout -lbdd
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help
Prelude BuddyScout> bdd_init 1000 1000
Prelude BuddyScout> bdd_setvarnum 10
0
Prelude BuddyScout> [a,b,c,d] <- sequence $ map bdd_ithvar [0..3]
Prelude BuddyScout> (.!)(a .& b) == ((.!)a .| (.!) b)
True
Prelude BuddyScout> import System
Prelude BuddyScout System> bdd_fnprintdot "abc.dot" ((.!)a.&b.|(.!)c)
Prelude BuddyScout System> system "dot -Tpng abc.dot > abc.png"
ExitSuccess
Prelude BuddyScout System> system "gimp abc.png"
The last few lines indicate how to use the `dot' command of Graphviz.
---- Utility functions
* fdd_extdomain :: [Int] -> Int
The original C version has two arguments to pass the array's address
and size, but the Haskell version takes a list of type [Int].
* set_varname_hook ::
(FunPtr BddFileHandler -> IO (FunPtr BddFileHandler))
-> (Int->String) -> IO ()
This function make the variable names displayed in the output of
fdd_printset and bdd_printset. It takes a Haskell function, converts
it to a C language callback, and passes it to BuDDy's hook for
bdd_printset and fdd_printset.
For example, consider the following code.
[a,b,c,d] <- sequence $ map bdd_ithvar [0..3]
bdd_printset (a.&b.&c)
You will obtain the output like this by default.
<0:1, 1:1, 2:1>
However, after you have
set_varname_hook bdd_file_hook (\n->[['a'..]!!n]) ,
then you will get the following output.
<a:1, b:1, c:1>
The first argument is bdd_file_hook or fdd_file_hook. They are the
original functions prepared in BuDDy. The second argument is the
user-specified function to convert a variable number of type Int into
the corresponding name of type String.
* withBDDPairs :: [Int] -> [Int] -> (Ptr BddPair -> IO a) -> IO a
* withFDDPairs :: [Int] -> [Int] -> (Ptr BddPair -> IO a) -> IO a
These functions manage the storage related to `bddPair'. A usage
example is as follows.
b <- withFDDPairs [2,3] [0,1] $ \p -> bdd_replace a p
These functions take two list of variable numbers, and the
user-specified function that calls bdd_replace or something to use
`bddPair'. They allocate some storage required to call bdd_newpair,
then call bdd_newpair internally, and call also bdd_setpairs or
fdd_setpairs. After these preparations, they pass the pointer to`
bddPair' to the third argument. Finally, after the execution of the
third argument finished, they free the `bddPair' area and the storage
allocated before calling bdd_newpair.
* Operators (precedence and fixity)
binary
infixl 7 .*, ./, .*#, ./#
infixl 6 .+, .-, .\
infix 5 .<<, .<<#, .>>, .>>#
infix 4 .==, .!=, .<, .<=, .>, .>=
infixl 3 .&
infixl 2 .|, .^
infixr 1 .->
infix 1 .<>
infixl 1 .<-
unary
(.!)
meanings
(.!) a = unsafePerformIO $ bdd_not a
a .& b = unsafePerformIO $ bdd_apply a b bddop_and
a .| b = unsafePerformIO $ bdd_apply a b bddop_or
a .\ b = unsafePerformIO $ bdd_apply a b bddop_diff
a .^ b = unsafePerformIO $ bdd_apply a b bddop_xor
a .-> b = unsafePerformIO $ bdd_apply a b bddop_imp
a .<> b = unsafePerformIO $ bdd_apply a b bddop_biimp
a .<- b = unsafePerformIO $ bdd_apply a b bddop_invimp
a .* b = unsafePerformIO $ bvec_mul a b
a .*# b = unsafePerformIO $ bvec_mulfixed a b
a ./ b = unsafePerformIO $ bvec_div a b
a ./# b = unsafePerformIO $ bvec_divfixed a b
a .+ b = unsafePerformIO $ bvec_add a b
a .- b = unsafePerformIO $ bvec_sub a b
a .< b = unsafePerformIO $ bvec_lth a b
a .<= b = unsafePerformIO $ bvec_lte a b
a .> b = unsafePerformIO $ bvec_gth a b
a .>= b = unsafePerformIO $ bvec_gte a b
a .== b = unsafePerformIO $ bvec_equ a b
a .!= b = unsafePerformIO $ bvec_neq a b
a .<< b = unsafePerformIO $ bvec_shl a b bddfalse
a .<<# b = unsafePerformIO $ bvec_shlfixed a b bddfalse
a .>> b = unsafePerformIO $ bvec_shr a b bddfalse
a .>># b = unsafePerformIO $ bvec_shrfixed a b bddfalse
---- Notes
* BDD
Since the `BDD' type is declared as an instance of Eq, we can use the
operator `==' to determine the equivalence of two BDDs.
* BVEC
Every time a `bvec_*' function generates a BVEC, BuddyScout translates
it into a list of BDDs. Therefore, we can manipulate it as a
Haskell's list, even though some of BVEC functions are not supported
by BuddyScout.
* Flushing the output buffer
It seems necessary to flush the output buffer of the GHC runtime
before using the BuDDy's printing functions (such as bdd_printset).
An easy way to do so is to insert the line of 'hSetBuffering stdout
NoBuffering' into the Haskell program, which disables the output
buffer.
* Garbage collection
To link the BuDDy's garbage collector with the GHC's one, we must take
care of reference counting. BuddyScout applies `bdd_addref' to
any BDDs generated by bdd_* functions, and further attaches finalizers
to the BDD objects. Such the finalizers will call bdd_delref when the
GHC runtime attempts to expire the objects. On the other hand,
BuddyScout does not apply `bdd_addref' to the BDDs contained in
BVECs, because the BuDDy package must have done it when creating them.
Because of the finalizers, BDD type must be a boxed type. It is
currently defined as `data BDD = BDD CInt'.
----------------
Yoshisato Sakai (yoshisato(at)users.sourceforge.net)