diff --git a/Cargo.lock b/Cargo.lock index 8be9d79..2831505 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "adf_bdd" -version = "0.2.3" +version = "0.2.4" dependencies = [ "biodivine-lib-bdd", "derivative", @@ -21,7 +21,7 @@ dependencies = [ [[package]] name = "adf_bdd-solver" -version = "0.2.3" +version = "0.2.4" dependencies = [ "adf_bdd", "assert_cmd", diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 111efa6..8a4f947 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "adf_bdd-solver" -version = "0.2.3" +version = "0.2.4" authors = ["Stefan Ellmauthaler "] edition = "2021" license = "GPL-3.0-only" diff --git a/bin/src/main.rs b/bin/src/main.rs index 1dbcf20..13fb052 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -105,9 +105,12 @@ struct App { /// Compute the stable models #[clap(long = "stm")] stable: bool, - /// Compute the stable models with the help of modelcounting - #[clap(long = "stmc")] - stable_counting: bool, + /// Compute the stable models with the help of modelcounting using heuristics a + #[clap(long = "stmca")] + stable_counting_a: bool, + /// Compute the stable models with the help of modelcounting using heuristics b + #[clap(long = "stmcb")] + stable_counting_b: bool, /// Compute the stable models with a pre-filter (only hybrid lib-mode) #[clap(long = "stmpre")] stable_pre: bool, @@ -218,8 +221,14 @@ impl App { } } - if self.stable_counting { - for model in naive_adf.stable_count_optimisation() { + if self.stable_counting_a { + for model in naive_adf.stable_count_optimisation_heu_a() { + print!("{}", printer.print_interpretation(&model)); + } + } + + if self.stable_counting_b { + for model in naive_adf.stable_count_optimisation_heu_b() { print!("{}", printer.print_interpretation(&model)); } } diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 85a8e6e..d5c8a72 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "adf_bdd" -version = "0.2.3" +version = "0.2.4" authors = ["Stefan Ellmauthaler "] edition = "2021" repository = "https://github.com/ellmau/adf-obdd/" diff --git a/lib/src/adf.rs b/lib/src/adf.rs index 6eb1d11..fafb08b 100644 --- a/lib/src/adf.rs +++ b/lib/src/adf.rs @@ -351,14 +351,32 @@ impl Adf { /// Computes the stable models. /// Returns an iterator which contains all stable models. - /// This variant uses the computation of model and counter-model counts. - pub fn stable_count_optimisation<'a, 'c>(&'a mut self) -> impl Iterator> + 'c + /// This variant uses the heuristic, which uses maximal var impact, minimal self-cyclye impact and the minimal amount of paths . + pub fn stable_count_optimisation_heu_a<'a, 'c>( + &'a mut self, + ) -> impl Iterator> + 'c where 'a: 'c, { log::debug!("[Start] stable count optimisation"); let grounded = self.grounded(); - self.two_val_model_counts(&grounded) + self.two_val_model_counts(&grounded, Self::heu_max_imp_min_nacyc_impact_min_paths) + .into_iter() + .filter(|int| self.stability_check(int)) + } + + /// Computes the stable models. + /// Returns an iterator which contains all stable models. + /// This variant uses the heuristic, which uses minimal number of paths and maximal variable-impact. + pub fn stable_count_optimisation_heu_b<'a, 'c>( + &'a mut self, + ) -> impl Iterator> + 'c + where + 'a: 'c, + { + log::debug!("[Start] stable count optimisation"); + let grounded = self.grounded(); + self.two_val_model_counts(&grounded, Self::heu_min_paths_max_imp) .into_iter() .filter(|int| self.stability_check(int)) } @@ -387,11 +405,14 @@ impl Adf { true } - fn two_val_model_counts(&mut self, interpr: &[Term]) -> Vec> { - self.two_val_model_counts_logic(interpr, &vec![Term::UND; interpr.len()], 0) + fn two_val_model_counts(&mut self, interpr: &[Term], heuristic: H) -> Vec> + where + H: Fn(&Self, (Var, Term), (Var, Term), &[Term]) -> std::cmp::Ordering + Copy, + { + self.two_val_model_counts_logic(interpr, &vec![Term::UND; interpr.len()], 0, heuristic) } - fn heuristic1( + fn heu_max_imp_min_nacyc_impact_min_paths( &self, lhs: (Var, Term), rhs: (Var, Term), @@ -417,19 +438,50 @@ impl Adf { value => value, } } - fn two_val_model_counts_logic( + + fn heu_min_paths_max_imp( + &self, + lhs: (Var, Term), + rhs: (Var, Term), + interpr: &[Term], + ) -> std::cmp::Ordering { + match self + .bdd + .paths(lhs.1, true) + .minimum() + .cmp(&self.bdd.paths(rhs.1, true).minimum()) + { + std::cmp::Ordering::Equal => self + .bdd + .var_impact(rhs.0, interpr) + .cmp(&self.bdd.var_impact(lhs.0, interpr)), + + value => value, + } + } + + fn two_val_model_counts_logic( &mut self, interpr: &[Term], will_be: &[Term], depth: usize, - ) -> Vec> { + heuristic: H, + ) -> Vec> + where + H: Fn(&Self, (Var, Term), (Var, Term), &[Term]) -> std::cmp::Ordering + Copy, + { log::debug!("two_val_model_recursion_depth: {}/{}", depth, interpr.len()); if let Some((idx, ac)) = interpr .iter() .enumerate() .filter(|(idx, val)| !(val.is_truth_value() || will_be[*idx].is_truth_value())) .min_by(|(idx_a, val_a), (idx_b, val_b)| { - self.heuristic1((Var(*idx_a), **val_a), (Var(*idx_b), **val_b), interpr) + heuristic( + self, + (Var(*idx_a), **val_a), + (Var(*idx_b), **val_b), + interpr, + ) }) { let mut result = Vec::new(); @@ -473,6 +525,7 @@ impl Adf { &upd_int, will_be, depth + 1, + heuristic, )); } } @@ -497,6 +550,7 @@ impl Adf { &upd_int, &must_be_new, depth + 1, + heuristic, )); } } @@ -785,7 +839,7 @@ mod test { .unwrap(); let mut adf = Adf::from_parser(&parser); - let mut stable = adf.stable_count_optimisation(); + let mut stable = adf.stable_count_optimisation_heu_a(); assert_eq!( stable.next(), Some(vec![ @@ -801,7 +855,7 @@ mod test { let parser = AdfParser::default(); parser.parse()("s(a).s(b).ac(a,neg(b)).ac(b,neg(a)).").unwrap(); let mut adf = Adf::from_parser(&parser); - let mut stable = adf.stable_count_optimisation(); + let mut stable = adf.stable_count_optimisation_heu_a(); assert_eq!(stable.next(), Some(vec![Term::BOT, Term::TOP])); assert_eq!(stable.next(), Some(vec![Term::TOP, Term::BOT])); @@ -812,14 +866,20 @@ mod test { let mut adf = Adf::from_parser(&parser); assert_eq!( - adf.stable_count_optimisation().collect::>(), + adf.stable_count_optimisation_heu_a().collect::>(), + vec![vec![Term::BOT, Term::BOT]] + ); + + assert_eq!( + adf.stable_count_optimisation_heu_b().collect::>(), vec![vec![Term::BOT, Term::BOT]] ); let parser = AdfParser::default(); parser.parse()("s(a).s(b).ac(a,neg(a)).ac(b,a).").unwrap(); let mut adf = Adf::from_parser(&parser); - assert_eq!(adf.stable_count_optimisation().next(), None); + assert_eq!(adf.stable_count_optimisation_heu_a().next(), None); + assert_eq!(adf.stable_count_optimisation_heu_b().next(), None); } #[test]