Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
(*
* $ID: $
*
*
* CBG Squanderer ROBDD BDD toy package in SML.
* (C) 2003 DJ Greaves.
*
* Look carefully at this code, it uses a hash tree to avoid replication of identical subtrees
* but it still has a fatal flaw! Dynamic programming must be added to the body of jb_apply.
*
* a) Explain the idea of dynamic programming
* b) Explain what is wrong with the software in this file
* c) Add a second array to act as a cache of computed subexpressions
* d) Add a garbage collector for your new array. When should this be called ?
*
*
* Harder: Automatic re-ordering is frequently implemented in a bdd package. How would
* you go about adding this facility ?
*)
datatype jb_t = JB_false | JB_true | JB of int * int * bool ref * jb_t * jb_t
;
exception jb_sfault of string
;
val jb_current_marx = ref false
;
val jb_hash_base = 81973
;
val JB_TAB = Array.array(jb_hash_base, []);
fun
jb_level(JB_false) = 0 (* some systems may have this maxint instead *)
| jb_level(JB_true) = 0
| jb_level(JB(lev, h, marx, hi, lo)) = lev
;
fun
jb_hash(JB_false) = 0
| jb_hash(JB_true) = 1
| jb_hash(JB(lev, h, marx, hi, lo)) = h
;
fun jb_hash_form(lev, hl, hr) =
let val s = (lev * 4 + hl * 64 + hr)
in s mod jb_hash_base
end
;
fun
jb_scan(nil, lev, ll, lr) = NONE
| jb_scan(JB(l, h, marx, hi, lo)::tt, lev, ll, lr) =
if (lev=l andalso lo=ll andalso hi=lr) then SOME(JB(l, h, marx, hi, lo)) else jb_scan(tt, lev, ll, lr)
;
fun jb_gen(lev, ll, rr) = if (ll=rr) then ll else
let val hl = jb_hash(ll)
val hr = jb_hash(rr)
val h = jb_hash_form(lev, hl, hr)
val ov = Array.sub(JB_TAB, h)
val k = jb_scan(ov, lev, ll, rr)
in if (k<> NONE) then valOf(k)
else let val nv = JB(lev, h, ref(!jb_current_marx), ll, rr)
val _ = Array.update(JB_TAB, h, nv::ov)
in nv
end end
;
fun jb_lo(JB(lev, h, marx, hi, lo)) = lo
| jb_lo(_) = raise jb_sfault("jb_lo")
;
fun jb_hi(JB(lev, h, marx, hi, lo)) = hi
| jb_hi(_) = raise jb_sfault("jb_hi")
;
fun
jb_and(JB_true, r) = r
| jb_and(r, JB_true) = r
| jb_and(r, JB_false) = JB_false
| jb_and(JB_false, r) = JB_false
| jb_and(_, _) = raise jb_sfault("jb_and")
;
fun
jb_or(JB_true, r) = JB_true
| jb_or(r, JB_true) = JB_true
| jb_or(r, JB_false) = r
| jb_or(JB_false, r) = r
| jb_or(_, _) = raise jb_sfault("jb_or")
;
fun jb_leaf(JB_true) = true
| jb_leaf(JB_false) = true
| jb_leaf(_) = false
;
(*
* The first arg is the TRUE/hi one and the second is the FALSE/lo one.
* This is the same way around as the traditional QUERY or MUX2.
*)
fun jb_leaf_gen(l) = jb_gen(l, JB_true, JB_false)
;
fun
jb_not(JB_true) = JB_false
| jb_not(JB_false) = JB_true
| jb_not(JB(l, h, marx, hi, lo)) = jb_gen(l, jb_not(hi), jb_not(lo))
;
fun jb_xor(a, b) =
let val a1 = jb_apply(jb_and, a, jb_not(b))
val b1 = jb_apply(jb_and, jb_not(a), b)
in jb_apply(jb_or, a1, b1)
end
;
fun jb_apply(f, u1, u2) =
if (jb_leaf(u1) andalso jb_leaf(u2)) then f(u1, u2)
else
let val l1 = jb_level(u1)
val l2 = jb_level(u2)
in if (l1=l2) then jb_gen(l1, jb_apply(f, jb_hi(u1), jb_hi(u2)), jb_apply(f, jb_lo(u1), jb_lo(u2)))
else if (l1 ll) then JB(ll, h, marx, hi, lo)
else if (v) then hi else lo
;
(*
* Existential quant \E x. P(x) implemented as P(0) \/ P(1)
*)
fun jb_exists(lev, q) = jb_or(jb_restrict(q, lev, true), jb_restrict(q, lev, false))
;
(*
* Universal quant \E x. P(x) implemented as P(0) /\ P(1)
*)
fun jb_forall(lev, q) = jb_and(jb_restrict(q, lev, true), jb_restrict(q, lev, false))
;
(*
* Existential quantifier: BDDs are efficient at quantifying over a number of variables
* at once. We can conveniently represent a list of variables with the BDD for their conjunction, so that
* the list is in the correct order to perform over the whole list with a single walk of the tree.
*)
fun
jb_exists(JB_true, b) = b
| jb_exists(_, JB_true) = JB_true
| jb_exists(_, JB_false) = JB_false
| jb_exists(a, b) =
let val la = jb_level(a)
val lb = jb_level(b)
in if (la>lb) then jb_exists(jb_hi(a), b)
else if (la=lb) then jb_apply(jb_orf, jb_exists(jb_hi(a), jb_hi(b)),
jb_exists(jb_hi(a), jb_lo(b)))
else jb_gen(lb, jb_exists(a, jb_hi(b)), jb_exists(a, jb_lo(b)))
end
;
(* The jb_forall routine is the same as jb_exists with then jb_orf changed to jb_andf *)
fun
jb_fold(JB_true, f, cc) = cc
| jb_fold(JB_false, f, cc) = cc
| jb_fold(JB(lev, h, marx, hh, ll), f, cc) = f(lev, jb_fold(hh, f, jb_fold(ll, f, cc)))
;
fun
jb_truth(JB_true) = true
| jb_truth(_) = false
;
fun
jb_invalid(JB_false) = true
| jb_invalid(_) = false
;
(* Garbage Collector - it is necessary to call the garbage collector from time to time *)
fun
jb_garb_mark_scan(JB_true) = ()
| jb_garb_mark_scan(JB_false) = ()
| jb_garb_mark_scan(JB(lev, h, marx, hi, lo)) =
if (!marx)=(!jb_current_marx) then ()
else (
marx := (!jb_current_marx);
jb_garb_mark_scan(lo);
jb_garb_mark_scan(hi);
()
)
;
fun jb_garb_sweep(n:int) =
if (n >= jb_hash_base) then ()
else
let val ov = Array.sub(JB_TAB, n)
fun jb_garb_sweep1(nil) = nil
| jb_garb_sweep1(JB(l, h, marx, hi, lo)::tt) =
if ((!marx)=(!jb_current_marx)) then JB(l, h, marx, hi, lo)::jb_garb_sweep1(tt)
else jb_garb_sweep1(tt)
val nv = jb_garb_sweep1(ov)
val _ = Array.update(JB_TAB, n, nv)
val _ = jb_garb_sweep(n+1)
in ()
end
;
val jb_gc_timer = ref 0;
(*
* l is a list of things we wish to keep.
*)
fun jb_garbage(l) =
if (!jb_gc_timer = 0) then
(
jb_current_marx := not(!jb_current_marx);
app jb_garb_mark_scan l;
jb_garb_sweep(0);
jb_gc_timer := 40
)
else jb_gc_timer := (!jb_gc_timer - 1)
;
(* eof *)