argumentation/semantics/
grounded.rs1use crate::framework::ArgumentationFramework;
8use std::collections::HashSet;
9use std::hash::Hash;
10
11impl<A: Clone + Eq + Hash> ArgumentationFramework<A> {
12 pub fn grounded_extension(&self) -> HashSet<A> {
16 let mut current: HashSet<A> = HashSet::new();
17 loop {
18 let next: HashSet<A> = self
19 .arguments()
20 .filter(|a| self.defends(¤t, *a))
21 .cloned()
22 .collect();
23 if next == current {
24 return current;
25 }
26 current = next;
27 }
28 }
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34
35 #[test]
36 fn grounded_of_empty_is_empty() {
37 let af: ArgumentationFramework<&str> = ArgumentationFramework::new();
38 assert_eq!(af.grounded_extension(), HashSet::new());
39 }
40
41 #[test]
42 fn grounded_includes_unattacked_arguments() {
43 let mut af = ArgumentationFramework::new();
45 af.add_argument("a");
46 let g = af.grounded_extension();
47 let expected: HashSet<&str> = ["a"].into_iter().collect();
48 assert_eq!(g, expected);
49 }
50
51 #[test]
52 fn grounded_of_figure_1_is_a_and_c() {
53 let mut af = ArgumentationFramework::new();
54 af.add_argument("a");
55 af.add_argument("b");
56 af.add_argument("c");
57 af.add_attack(&"a", &"b").unwrap();
58 af.add_attack(&"b", &"c").unwrap();
59 let g = af.grounded_extension();
60 let expected: HashSet<&str> = ["a", "c"].into_iter().collect();
61 assert_eq!(g, expected);
62 }
63
64 #[test]
65 fn grounded_of_odd_cycle_is_empty() {
66 let mut af = ArgumentationFramework::new();
67 af.add_argument("a");
68 af.add_argument("b");
69 af.add_argument("c");
70 af.add_attack(&"a", &"b").unwrap();
71 af.add_attack(&"b", &"c").unwrap();
72 af.add_attack(&"c", &"a").unwrap();
73 assert_eq!(af.grounded_extension(), HashSet::new());
74 }
75
76 #[test]
77 fn grounded_of_even_cycle_is_empty() {
78 let mut af = ArgumentationFramework::new();
79 af.add_argument("a");
80 af.add_argument("b");
81 af.add_attack(&"a", &"b").unwrap();
82 af.add_attack(&"b", &"a").unwrap();
83 assert_eq!(af.grounded_extension(), HashSet::new());
84 }
85}