extern crate rand;
extern crate zdd;
use std::collections::BTreeSet;
use std::fs::OpenOptions;
use std::sync::Arc;
use rand::prelude::*;
use zdd::{ZddPrint, ZddTreeOps};
type Lbl = u8;
type Set = BTreeSet<Lbl>;
type SSet = BTreeSet<Set>;
type Zdd = zdd::wrapped::Zdd<Lbl>;
type FBuilder = zdd::FactoryBuilder;
fn sset_print(sset: &SSet, pref: String) {
println!("{}{{", pref);
for set in sset.iter() {
print!("{} {{ ", pref);
let mut first = true;
for e in set.iter() {
print!(
"{}{}",
if first {
first = false;
""
} else {
", "
},
e
)
}
println!(" }}");
}
println!("{}}}", pref)
}
fn set_zero() -> SSet {
SSet::new()
}
fn set_one() -> SSet {
let mut sset = SSet::new();
sset.insert(Set::new());
sset
}
fn set_offset(sset: &SSet, lbl: &Lbl) -> SSet {
let mut nu_sset = SSet::new();
for set in sset.iter() {
let mut nu_set = Set::new();
let mut saw_lbl = false;
for e in set.iter() {
if lbl == e {
saw_lbl = true
} else {
nu_set.insert(*e);
()
}
}
if !saw_lbl {
nu_sset.insert(nu_set);
()
}
}
nu_sset
}
fn set_onset(sset: &SSet, lbl: &Lbl) -> SSet {
let mut nu_sset = SSet::new();
for set in sset.iter() {
let mut nu_set = Set::new();
let mut saw_lbl = false;
for e in set.iter() {
if lbl == e {
saw_lbl = true
} else {
nu_set.insert(*e);
()
}
}
if saw_lbl {
nu_sset.insert(nu_set);
()
}
}
nu_sset
}
fn set_change(sset: &SSet, lbl: &Lbl) -> SSet {
let mut nu_sset = SSet::new();
for set in sset.iter() {
let mut nu_set = Set::new();
let mut saw_lbl = false;
for e in set.iter() {
if lbl == e {
saw_lbl = true
} else {
nu_set.insert(*e);
()
}
}
if !saw_lbl {
nu_set.insert(*lbl);
()
};
nu_sset.insert(nu_set);
()
}
nu_sset
}
fn set_union(lhs: &SSet, rhs: &SSet) -> SSet {
let mut nu_sset = lhs.clone();
for set in rhs.iter() {
nu_sset.insert(set.clone());
()
}
nu_sset
}
fn set_inter(lhs: &SSet, rhs: &SSet) -> SSet {
let mut nu_sset = SSet::new();
for set in lhs.iter() {
if rhs.contains(set) {
nu_sset.insert(set.clone());
()
}
}
nu_sset
}
fn set_minus(lhs: &SSet, rhs: &SSet) -> SSet {
let mut nu_sset = lhs.clone();
for set in rhs.iter() {
nu_sset.remove(set);
()
}
nu_sset
}
fn offset(zdd: &Zdd, sset: &SSet, lbl: &Lbl) -> (Zdd, SSet) {
let name = "offset";
let res_zdd = zdd | lbl;
let res_sset = set_offset(sset, lbl);
if res_zdd.to_set() != res_sset {
println!("{} {}", name, lbl);
println!("zdd:");
zdd.print("| ".to_string());
println!("set:");
sset_print(&sset, "| ".to_string());
println!("res_zdd:");
res_zdd.print("| ".to_string());
println!("res_set:");
sset_print(&res_sset, "| ".to_string());
panic!("{} | result mismatch", name)
};
(res_zdd, res_sset)
}
fn onset(zdd: &Zdd, sset: &SSet, lbl: &Lbl) -> (Zdd, SSet) {
let name = "onset";
let res_zdd = zdd % lbl;
let res_sset = set_onset(sset, lbl);
if res_sset != res_zdd.to_set() {
println!("{} {}", name, lbl);
println!("zdd:");
zdd.print("| ".to_string());
println!("set:");
sset_print(&sset, "| ".to_string());
println!("res_zdd:");
res_zdd.print("| ".to_string());
println!("res_set:");
sset_print(&res_sset, "| ".to_string());
panic!("{} | result mismatch", name)
};
(res_zdd, res_sset)
}
fn change(zdd: &Zdd, sset: &SSet, lbl: &Lbl) -> (Zdd, SSet) {
let name = "change";
let res_zdd = zdd ^ lbl;
let res_sset = set_change(sset, lbl);
if res_sset != res_zdd.to_set() {
println!("{} {}", name, lbl);
println!("zdd:");
zdd.print("| ".to_string());
println!("set:");
sset_print(&sset, "| ".to_string());
println!("res_zdd:");
res_zdd.print("| ".to_string());
println!("res_set:");
sset_print(&res_sset, "| ".to_string());
panic!("{} | result mismatch", name)
};
(res_zdd, res_sset)
}
fn union(lhs_zdd: &Zdd, rhs_zdd: &Zdd, lhs_sset: &SSet, rhs_sset: &SSet) -> (Zdd, SSet) {
let name = "union";
let res_zdd = lhs_zdd + rhs_zdd;
let res_sset = set_union(lhs_sset, rhs_sset);
if res_sset != res_zdd.to_set() {
println!("{}", name);
println!("lhs_zdd:");
lhs_zdd.print("| ".to_string());
println!("rhs_zdd:");
rhs_zdd.print("| ".to_string());
println!("lhs_set:");
sset_print(&lhs_sset, "| ".to_string());
println!("rhs_set:");
sset_print(&rhs_sset, "| ".to_string());
println!("res_zdd:");
res_zdd.print("| ".to_string());
println!("res_set:");
sset_print(&res_sset, "| ".to_string());
panic!("{} | result mismatch", name)
};
assert!(lhs_zdd << &res_zdd);
assert!(rhs_zdd << &res_zdd);
(res_zdd, res_sset)
}
fn inter(lhs_zdd: &Zdd, rhs_zdd: &Zdd, lhs_sset: &SSet, rhs_sset: &SSet) -> (Zdd, SSet) {
let name = "inter";
let res_zdd = lhs_zdd & rhs_zdd;
let res_sset = set_inter(lhs_sset, rhs_sset);
if res_sset != res_zdd.to_set() {
println!("{}", name);
println!("lhs_zdd:");
lhs_zdd.print("| ".to_string());
println!("rhs_zdd:");
rhs_zdd.print("| ".to_string());
println!("lhs_set:");
sset_print(&lhs_sset, "| ".to_string());
println!("rhs_set:");
sset_print(&rhs_sset, "| ".to_string());
println!("res_zdd:");
res_zdd.print("| ".to_string());
println!("res_set:");
sset_print(&res_sset, "| ".to_string());
panic!("{} | result mismatch", name)
};
assert!(&res_zdd << lhs_zdd);
assert!(&res_zdd << rhs_zdd);
(res_zdd, res_sset)
}
fn minus(lhs_zdd: &Zdd, rhs_zdd: &Zdd, lhs_sset: &SSet, rhs_sset: &SSet) -> (Zdd, SSet) {
let name = "minus";
let res_zdd = lhs_zdd - rhs_zdd;
let res_sset = set_minus(lhs_sset, rhs_sset);
if res_sset != res_zdd.to_set() {
println!("{}", name);
println!("lhs_zdd:");
lhs_zdd.print("| ".to_string());
println!("rhs_zdd:");
rhs_zdd.print("| ".to_string());
println!("lhs_set:");
sset_print(&lhs_sset, "| ".to_string());
println!("rhs_set:");
sset_print(&rhs_sset, "| ".to_string());
println!("res_zdd:");
res_zdd.print("| ".to_string());
println!("res_set:");
sset_print(&res_sset, "| ".to_string());
panic!("{} | result mismatch", name)
};
assert!(&res_zdd << lhs_zdd);
assert!(rhs_zdd.is_zero() || !(rhs_zdd << &res_zdd));
(res_zdd, res_sset)
}
fn run(factory: &zdd::wrapped::Factory<Lbl>, u_bound: usize, max: usize) -> usize {
let mut max = max;
let mut rng = rand::thread_rng();
let mut vec = vec![
(Zdd::zero(factory), set_zero()),
(Zdd::one(factory), set_one()),
];
for i in 0..u_bound {
let res = match rng.gen::<f64>() {
f if f < 0.50f64 || i < 10 => {
let index = rng.gen::<usize>() % (vec.len());
let (ref zdd, ref sset) = vec[index];
let c = rng.gen::<Lbl>() % 100u8;
match f {
f if f < 0.16f64 || i < 10 => offset(zdd, sset, &c),
f if f < 0.32f64 => onset(zdd, sset, &c),
_ => change(zdd, sset, &c),
}
}
f => {
let index = rng.gen::<usize>() % (vec.len());
let (ref lhs_zdd, ref lhs_sset) = vec[index];
let index = rng.gen::<usize>() % (vec.len());
let (ref rhs_zdd, ref rhs_sset) = vec[index];
match f {
f if f < 0.80f64 => union(lhs_zdd, rhs_zdd, lhs_sset, rhs_sset),
f if f < 0.90f64 => inter(lhs_zdd, rhs_zdd, lhs_sset, rhs_sset),
_ => minus(lhs_zdd, rhs_zdd, lhs_sset, rhs_sset),
}
}
};
let count = res.0.count();
if count > max {
match OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open("graph")
{
Ok(mut wrt) => res.0.write_as_gv(&mut wrt).unwrap(),
Err(e) => panic!("{}", e),
}
max = count
};
vec.push(res)
}
max
}
#[test]
fn thirteen_times_100() {
let factory = Arc::new(FBuilder::mk().len(1300).build());
for _ in 0..13 {
run(&factory, 100, 100);
}
}
#[test]
fn seven_times_10000() {
let factory = Arc::new(FBuilder::mk().len(10000).build());
for _ in 0..7 {
run(&factory, 10000, 100);
}
}
#[test]
fn three_times_1000000() {
let factory = Arc::new(FBuilder::mk().len(1000000).build());
let mut max = 0;
for _ in 0..3 {
max = run(&factory, 1000000, max)
}
}