Skip to main content

argumentation/semantics/
admissibility.rs

1//! Conflict-freeness, defence, and admissibility (Dung 1995 ยง2 definitions).
2
3use crate::framework::ArgumentationFramework;
4use std::collections::HashSet;
5use std::hash::Hash;
6
7impl<A: Clone + Eq + Hash> ArgumentationFramework<A> {
8    /// A set `s` is conflict-free iff no argument in `s` attacks another in `s`.
9    pub fn is_conflict_free(&self, s: &HashSet<A>) -> bool {
10        for a in s {
11            for target in self.attacked_by(a) {
12                if s.contains(target) {
13                    return false;
14                }
15            }
16        }
17        true
18    }
19
20    /// `s` defends `a` iff every attacker of `a` is itself attacked by some member of `s`.
21    pub fn defends(&self, s: &HashSet<A>, a: &A) -> bool {
22        for attacker in self.attackers(a) {
23            let counter = self
24                .attackers(attacker)
25                .iter()
26                .any(|defender| s.contains(*defender));
27            if !counter {
28                return false;
29            }
30        }
31        true
32    }
33
34    /// `s` is admissible iff it is conflict-free and defends all its members.
35    pub fn is_admissible(&self, s: &HashSet<A>) -> bool {
36        if !self.is_conflict_free(s) {
37            return false;
38        }
39        s.iter().all(|a| self.defends(s, a))
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    /// Dung 1995 Figure 1: a -> b -> c (a attacks b, b attacks c).
48    fn figure_1() -> ArgumentationFramework<&'static str> {
49        let mut af = ArgumentationFramework::new();
50        af.add_argument("a");
51        af.add_argument("b");
52        af.add_argument("c");
53        af.add_attack(&"a", &"b").unwrap();
54        af.add_attack(&"b", &"c").unwrap();
55        af
56    }
57
58    #[test]
59    fn empty_set_is_conflict_free() {
60        let af = figure_1();
61        assert!(af.is_conflict_free(&HashSet::new()));
62    }
63
64    #[test]
65    fn singleton_a_is_conflict_free() {
66        let af = figure_1();
67        let s: HashSet<&str> = ["a"].into_iter().collect();
68        assert!(af.is_conflict_free(&s));
69    }
70
71    #[test]
72    fn a_and_b_together_is_not_conflict_free() {
73        let af = figure_1();
74        let s: HashSet<&str> = ["a", "b"].into_iter().collect();
75        assert!(!af.is_conflict_free(&s));
76    }
77
78    #[test]
79    fn a_defends_c() {
80        let af = figure_1();
81        let s: HashSet<&str> = ["a"].into_iter().collect();
82        assert!(af.defends(&s, &"c"));
83    }
84
85    #[test]
86    fn a_and_c_is_admissible() {
87        let af = figure_1();
88        let s: HashSet<&str> = ["a", "c"].into_iter().collect();
89        assert!(af.is_admissible(&s));
90    }
91
92    #[test]
93    fn empty_set_is_admissible() {
94        let af = figure_1();
95        assert!(af.is_admissible(&HashSet::new()));
96    }
97}