1
use std::collections::HashMap;
2
use std::fmt;
3
use std::hash::Hash;
4

            
5
use merc_collections::VecSet;
6

            
7
/// An antichain is a structure (<, S) such that < is a preorder on S, such that
8
/// for any s, t in S neither s < t nor t < s holds. In other words, all
9
/// elements of S are incomparable under the preorder <. This is dual to the
10
/// notion of a chain.
11
///
12
/// # Details
13
///
14
/// This implementation stores pairs (s, T) in S.
15
pub struct Antichain<K, V> {
16
    storage: HashMap<K, VecSet<VecSet<V>>>,
17

            
18
    /// The largest size of the antichain.
19
    max_antichain: usize,
20
    /// Number of times a pair was inserted into the antichain.
21
    antichain_misses: usize,
22
    /// Number of times antichain_insert was called.
23
    antichain_inserts: usize,
24
}
25

            
26
impl<K: Eq + Hash, V: Clone + Ord> Antichain<K, V> {
27
    /// Creates a new empty antichain.
28
4705
    pub fn new() -> Self {
29
4705
        Antichain {
30
4705
            storage: HashMap::new(),
31
4705
            max_antichain: 0,
32
4705
            antichain_misses: 0,
33
4705
            antichain_inserts: 0,
34
4705
        }
35
4705
    }
36

            
37
    /// Checks whether the antichain contains a pair (s, T') such that T > T'.
38
    /// This is the inverse of the contains check, which checks for T < T'.
39
886
    pub fn contains_superset(&self, key: &K, value: &VecSet<V>) -> bool {
40
886
        self.storage
41
886
            .get(key)
42
886
            .is_some_and(|entry| entry.iter().any(|inner_value| value.is_subset(inner_value)))
43
886
    }
44

            
45
    /// Checks whether the antichain contains a pair (s, T') such that T < T'.
46
2313
    pub fn contains_subset(&self, key: &K, value: &VecSet<V>) -> bool {
47
2313
        self.storage
48
2313
            .get(key)
49
2313
            .is_some_and(|entry| entry.iter().any(|inner_value| inner_value.is_subset(value)))
50
2313
    }
51

            
52
    /// Returns true iff the antichain is empty.
53
    pub fn is_empty(&self) -> bool {
54
        self.storage.is_empty()
55
    }
56

            
57
    /// Returns the size of the antichain.
58
    pub fn len(&self) -> usize {
59
        self.storage.len()
60
    }
61

            
62
    /// Returns the metrics of this antichain
63
    pub fn metrics(&self) -> (usize, usize, usize) {
64
        (self.max_antichain, self.antichain_misses, self.antichain_inserts)
65
    }
66

            
67
    /// Returns an iterator over the pairs in the antichain.
68
156
    pub fn iter(&self) -> impl Iterator<Item = (&K, &VecSet<V>)> {
69
156
        self.storage
70
156
            .iter()
71
272
            .flat_map(|(key, values)| values.iter().map(move |value| (key, value)))
72
156
    }
73
}
74

            
75
impl<K: Eq + Hash, V: Clone + Ord> Default for Antichain<K, V> {
76
    fn default() -> Self {
77
        Self::new()
78
    }
79
}
80

            
81
impl<K, V: fmt::Debug + Ord> Antichain<K, V> {
82
    /// Checks the internal consistency of the antichain invariant.
83
    #[cfg(test)]
84
100
    fn check_consistency(&self) {
85
994
        for (_key, values) in &self.storage {
86
4240
            for i in values.iter() {
87
20940
                for j in values.iter() {
88
20940
                    if i == j {
89
                        // Ignore identical entries
90
4240
                        continue;
91
16700
                    }
92

            
93
16700
                    assert!(
94
16700
                        !i.is_subset(j) && !j.is_subset(i),
95
                        "Antichain invariant violated: {:?} and {:?} are comparable.",
96
                        i,
97
                        j
98
                    );
99
                }
100
            }
101
        }
102
100
    }
103
}
104

            
105
/// Represents the antichain data structure used in the refinement checks.
106
pub trait AC<K: Eq + Hash, V: Clone + Ord> {
107
    /// Inserts the given (s, T) pair into the antichain and returns true iff it was
108
    /// not already present.
109
    ///
110
    /// # Details
111
    ///
112
    /// A pair (s, T) is `present` in `S` iff there exists a pair (s, T') in S such that T < T'.
113
    fn insert(&mut self, key: K, value: VecSet<V>) -> bool;
114

            
115
    /// Clears the antichain.
116
    fn clear(&mut self);
117
}
118

            
119
impl<K: Eq + Hash, V: Clone + Ord> AC<K, V> for Antichain<K, V> {
120
15141
    fn insert(&mut self, key: K, value: VecSet<V>) -> bool {
121
15141
        let mut inserted = false;
122
15141
        self.storage
123
15141
            .entry(key)
124
15141
            .and_modify(|entry| {
125
6053
                let mut contains = false;
126
15057
                entry.retain(|inner_value| {
127
15057
                    if inner_value.is_subset(&value) {
128
                        // The new value is a superset of an existing entry
129
1019
                        contains = true;
130
1019
                        true
131
14038
                    } else if value.is_subset(inner_value) {
132
                        // Remove any entry that is a superset of the new value
133
888
                        false
134
                    } else {
135
                        // Leave incomparable entries unchanged
136
13150
                        true
137
                    }
138
15057
                });
139

            
140
6053
                if !contains {
141
5089
                    self.antichain_misses += 1; // Was not present
142
5089
                    entry.insert(value.clone());
143
5089
                    inserted = true;
144
5089
                }
145
6053
            })
146
15141
            .or_insert_with(|| {
147
9088
                self.antichain_misses += 1; // Was not present
148
9088
                inserted = true;
149
9088
                VecSet::singleton(value)
150
9088
            });
151

            
152
15141
        self.antichain_inserts += 1;
153
15141
        self.max_antichain = self.max_antichain.max(self.storage.len());
154

            
155
15141
        inserted
156
15141
    }
157

            
158
825
    fn clear(&mut self) {
159
825
        self.storage.clear();
160
825
    }
161
}
162

            
163
impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Antichain<T, U> {
164
1
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165
1
        writeln!(f, "Antichain {{")?;
166
1
        for (key, values) in &self.storage {
167
1
            writeln!(f, "  {:?}: {:?}", key, values)?;
168
        }
169
1
        writeln!(f, "}}")
170
1
    }
171
}
172

            
173
#[cfg(test)]
174
mod tests {
175
    use merc_collections::vecset;
176
    use merc_utilities::random_test;
177
    use rand::RngExt;
178

            
179
    use crate::AC;
180
    use crate::Antichain;
181

            
182
    #[test]
183
1
    fn test_antichain() {
184
1
        let mut antichain: Antichain<u32, u32> = Antichain::new();
185

            
186
1
        let inserted = antichain.insert(1, vecset![2, 3]);
187
1
        assert!(inserted);
188

            
189
1
        println!("{:?}", antichain);
190

            
191
1
        let inserted = antichain.insert(1, vecset![2, 3, 6]);
192
1
        assert!(
193
1
            !inserted,
194
            "The pair (1, {{2,3,6}}) should not be inserted in {:?}.",
195
            antichain
196
        );
197

            
198
1
        let inserted = antichain.insert(1, vecset![2]);
199
1
        assert!(
200
1
            inserted,
201
            "The pair (1, {{2}}) should overwrite (1, {{2, 3}}) in {:?}.",
202
            antichain
203
        );
204

            
205
1
        let inserted = antichain.insert(1, vecset![5, 6]);
206
1
        assert!(
207
1
            inserted,
208
            "The pair (1, {{5, 6}}) should be inserted since it is incomparable to existing pairs in {:?}.",
209
            antichain
210
        );
211
1
    }
212

            
213
    #[test]
214
1
    fn test_random_antichain() {
215
100
        random_test(100, |rng| {
216
100
            let mut antichain: Antichain<u32, u32> = Antichain::new();
217

            
218
            // Insert random pairs into the antichain.
219
100
            for _ in 0..50 {
220
5000
                let key = rng.random_range(0..10);
221
5000
                let set_size = rng.random_range(1..5);
222
5000
                let mut value = vecset![];
223

            
224
12527
                for _ in 0..set_size {
225
12527
                    value.insert(rng.random_range(0..20));
226
12527
                }
227

            
228
5000
                antichain.insert(key, value);
229
            }
230

            
231
100
            antichain.check_consistency();
232
100
        })
233
1
    }
234
}