argumentation/semantics/
preferred.rs1use super::subset_enum::{sorted_args_or_too_large, subset_from_bits};
4use crate::framework::ArgumentationFramework;
5use std::collections::HashSet;
6use std::hash::Hash;
7
8impl<A: Clone + Eq + Hash + Ord> ArgumentationFramework<A> {
9 pub fn preferred_extensions(&self) -> Result<Vec<HashSet<A>>, crate::Error> {
17 let args = sorted_args_or_too_large(self)?;
18 let n = args.len();
19 let mut admissible: Vec<HashSet<A>> = Vec::new();
20 for bits in 0u64..(1u64 << n) {
21 let s = subset_from_bits(&args, bits);
22 if self.is_admissible(&s) {
23 admissible.push(s);
24 }
25 }
26 Ok(admissible
27 .iter()
28 .filter(|s| {
29 !admissible
30 .iter()
31 .any(|t| t.len() > s.len() && s.is_subset(t))
32 })
33 .cloned()
34 .collect())
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn preferred_of_figure_1_is_singleton_ac() {
44 let mut af = ArgumentationFramework::new();
45 af.add_argument("a");
46 af.add_argument("b");
47 af.add_argument("c");
48 af.add_attack(&"a", &"b").unwrap();
49 af.add_attack(&"b", &"c").unwrap();
50 let pe = af.preferred_extensions().unwrap();
51 assert_eq!(pe.len(), 1);
52 let expected: HashSet<&str> = ["a", "c"].into_iter().collect();
53 assert!(pe.contains(&expected));
54 }
55
56 #[test]
57 fn preferred_of_mutual_attack_is_two() {
58 let mut af = ArgumentationFramework::new();
59 af.add_argument("a");
60 af.add_argument("b");
61 af.add_attack(&"a", &"b").unwrap();
62 af.add_attack(&"b", &"a").unwrap();
63 let pe = af.preferred_extensions().unwrap();
64 assert_eq!(pe.len(), 2);
65 }
66
67 #[test]
68 fn every_framework_has_a_preferred_extension() {
69 let mut af = ArgumentationFramework::new();
70 af.add_argument("a");
71 af.add_argument("b");
72 af.add_argument("c");
73 af.add_attack(&"a", &"b").unwrap();
74 af.add_attack(&"b", &"c").unwrap();
75 af.add_attack(&"c", &"a").unwrap();
76 let pe = af.preferred_extensions().unwrap();
77 assert!(!pe.is_empty());
78 }
79}