use apl;
use bdd;
use base;
use base::{Op,Base,TBase,VID,NID};
pub trait Progress {
fn on_start(&self);
fn on_step<X,Y>(&self, base:&Base, bdds: &mut bdd::BddBase<X,Y>, step:u32, secs:u64,
oldtop:bdd::NID, newtop:bdd::NID)
where X: bdd::BddState, Y: bdd::BddWorker<X>;
fn on_done<X,Y>(&self, base:&Base, bdds: &mut bdd::BddBase<X,Y>, newtop:bdd::NID)
where X: bdd::BddState, Y: bdd::BddWorker<X>; }
pub struct ProgressReport<'a> {
pub save_dot: bool,
pub save_bdd: bool,
pub prefix: &'a str,
pub show_result: bool }
impl<'a> Progress for ProgressReport<'a> {
fn on_start(&self) { } fn on_step<X,Y>(&self, base:&Base, bdds: &mut bdd::BddBase<X,Y>, step:u32, secs:u64,
oldtop:bdd::NID, newtop:bdd::NID)
where X: bdd::BddState, Y: bdd::BddWorker<X> {
println!("{:4}, {:4}, {:4}→{:3?}, {:8}",
step, secs, oldtop, base[bdd::var(oldtop) as usize], newtop);
if step&7 == 0 { { let expected_steps = base.bits.len() as f64;
let percent_done = 100.0 * (step as f64) / expected_steps as f64;
println!("\n# newtop: {} step:{}/{} ({:.2}%)",
newtop, step, base.bits.len(), percent_done); }
if self.save_bdd {
bdds.tag("top".to_string(), newtop); bdds.tag("step".to_string(), bdd::nv(step));
bdds.save(format!("{}-{:04}.bdd", self.prefix, step).as_str())
.expect("failed to save"); }}
if step &31 == 0 { println!("step, seconds, change, newtop"); }
if self.save_dot && (step&31 == 0) || (step==446)
{ bdds.save_dot(newtop, format!("{}-{:04}.dot", self.prefix, step).as_str()); } }
fn on_done<X,Y>(&self, _base:&Base, bdds: &mut bdd::BddBase<X,Y>, newtop:bdd::NID)
where X: bdd::BddState, Y: bdd::BddWorker<X> {
if self.show_result {
bdds.show_named(newtop, format!("{}-final", self.prefix).as_str()); }
else {
bdds.save_dot(newtop, format!("{}-final.dot", self.prefix).as_str()); }}}
fn default_bitmask(_base:&Base, v:VID) -> u64 {
if v < 64 { 1u64 << v } else { 0 }}
pub fn sort_by_cost(base:&Base, top:NID)->(Base,NID) {
let (mut base0,kept0) = base.repack(vec![top]);
base0.tag(kept0[0], "-top-".to_string());
let (_m0,c0) = base0.masks_and_costs(default_bitmask);
let mut p = apl::gradeup(&c0); let base1 = base0.permute(&p);
let max = p.len()-1; let min = base1.nvars+1;
for i in 0..min { p[i] = i }
for i in min..p.len() { p[i] = min + (max-i) }
let ast = base1.permute(&p);
let &nid = ast.tags.get("-top-").expect("what? I just put it there.");
(ast,nid) }
pub fn bdd_refine<X,Y,P:Progress>(bdds: &mut bdd::BddBase<X,Y>, base:&Base, end:bdd::NID, pr:P)
where X: bdd::BddState, Y: bdd::BddWorker<X> {
let mut topnid = end;
let mut step = bdd::var(bdds.get(&"step".to_string()).unwrap_or(bdd::nv(0)));
let mut newtop = topnid;
pr.on_start();
while !bdd::is_rvar(topnid) {
let now = std::time::SystemTime::now();
let oldtop = topnid;
newtop = bdd_refine_one(bdds, &base, oldtop); topnid=newtop;
let secs = now.elapsed().expect("elapsed?").as_secs();
pr.on_step(base, bdds, step, secs, oldtop, newtop);
step += 1; }
pr.on_done(base, bdds, newtop); }
fn convert_nid(base:&Base, n:base::NID)->bdd::NID {
match base[n as usize] {
Op::O => bdd::O,
Op::I => bdd::I,
Op::Var(x) => bdd::nvr(x as bdd::VID),
_ => bdd::nv(n as u32) }}
fn bdd_refine_one<X,Y>(bdds: &mut bdd::BddBase<X,Y>, base:&Base, oldtop:bdd::NID)->bdd::NID
where X: bdd::BddState, Y: bdd::BddWorker<X> {
let otv = bdd::var(oldtop);
let op = base[otv as usize];
let v = |x0:base::NID|->bdd::NID { convert_nid(base, x0) };
let newdef:bdd::NID = match op {
Op::Not(x) => bdd::not(v(x)),
Op::And(x,y) => bdds.and(v(x), v(y)),
Op::Xor(x,y) => bdds.xor(v(x), v(y)),
Op::Or(x,y) => bdds.or(v(x), v(y)),
_ => { panic!("don't know how to translate {:?}", op ) }};
return bdds.replace(otv, newdef, oldtop) }