lattices/
vec_union.rs

1use std::cmp::Ordering::{self, *};
2
3use cc_traits::Iter;
4
5use crate::{DeepReveal, IsBot, IsTop, LatticeFrom, LatticeOrd, Merge};
6
7/// Vec-union compound lattice.
8///
9/// Contains any number of `Lat` sub-lattices. Sub-lattices are indexed starting at zero, merging
10/// combines corresponding sub-lattices and keeps any excess.
11///
12/// Similar to [`MapUnion<<usize, Lat>>`](super::map_union::MapUnion) but requires the key indices
13/// start with `0`, `1`, `2`, etc: i.e. integers starting at zero with no gaps.
14#[derive(Clone, Debug, Eq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct VecUnion<Lat> {
17    vec: Vec<Lat>,
18}
19
20impl<Lat> VecUnion<Lat> {
21    /// Create a new `VecUnion` from a `Vec` of `Lat` instances.
22    pub fn new(vec: Vec<Lat>) -> Self {
23        Self { vec }
24    }
25
26    /// Create a new `VecUnion` from an `Into<Vec<Lat>>`.
27    pub fn new_from(vec: impl Into<Vec<Lat>>) -> Self {
28        Self::new(vec.into())
29    }
30
31    /// Reveal the inner value as a shared reference.
32    pub fn as_reveal_ref(&self) -> &Vec<Lat> {
33        &self.vec
34    }
35
36    /// Reveal the inner value as an exclusive reference.
37    pub fn as_reveal_mut(&mut self) -> &mut Vec<Lat> {
38        &mut self.vec
39    }
40
41    /// Gets the inner by value, consuming self.
42    pub fn into_reveal(self) -> Vec<Lat> {
43        self.vec
44    }
45}
46
47impl<Lat> DeepReveal for VecUnion<Lat>
48where
49    Lat: DeepReveal,
50{
51    type Revealed = Vec<Lat::Revealed>;
52
53    fn deep_reveal(self) -> Self::Revealed {
54        self.vec.into_iter().map(DeepReveal::deep_reveal).collect()
55    }
56}
57
58impl<Lat> Default for VecUnion<Lat> {
59    fn default() -> Self {
60        Self {
61            vec: Default::default(),
62        }
63    }
64}
65
66impl<LatSelf, LatOther> Merge<VecUnion<LatOther>> for VecUnion<LatSelf>
67where
68    LatSelf: Merge<LatOther> + LatticeFrom<LatOther>,
69{
70    fn merge(&mut self, mut other: VecUnion<LatOther>) -> bool {
71        let mut changed = false;
72        // Extend `self` if `other` is longer.
73        if self.vec.len() < other.vec.len() {
74            self.vec
75                .extend(other.vec.drain(self.vec.len()..).map(LatSelf::lattice_from));
76            changed = true;
77        }
78        // Merge intersecting indices.
79        for (self_val, other_val) in self.vec.iter_mut().zip(other.vec) {
80            changed |= self_val.merge(other_val);
81        }
82        changed
83    }
84}
85
86impl<LatSelf, LatOther> LatticeFrom<VecUnion<LatOther>> for VecUnion<LatSelf>
87where
88    LatSelf: LatticeFrom<LatOther>,
89{
90    fn lattice_from(other: VecUnion<LatOther>) -> Self {
91        Self::new(other.vec.into_iter().map(LatSelf::lattice_from).collect())
92    }
93}
94
95impl<LatSelf, LatOther> PartialEq<VecUnion<LatOther>> for VecUnion<LatSelf>
96where
97    LatSelf: PartialEq<LatOther>,
98{
99    fn eq(&self, other: &VecUnion<LatOther>) -> bool {
100        if self.vec.len() != other.vec.len() {
101            false
102        } else {
103            self.vec
104                .iter()
105                .zip(other.vec.iter())
106                .all(|(val_self, val_other)| val_self == val_other)
107        }
108    }
109}
110
111impl<LatSelf, LatOther> PartialOrd<VecUnion<LatOther>> for VecUnion<LatSelf>
112where
113    LatSelf: PartialOrd<LatOther>,
114{
115    fn partial_cmp(&self, other: &VecUnion<LatOther>) -> Option<Ordering> {
116        let (self_len, other_len) = (self.vec.len(), other.vec.len());
117        let mut self_any_greater = other_len < self_len;
118        let mut other_any_greater = self_len < other_len;
119        for (self_val, other_val) in self.vec.iter().zip(other.vec.iter()) {
120            match self_val.partial_cmp(other_val) {
121                None => {
122                    return None;
123                }
124                Some(Less) => {
125                    other_any_greater = true;
126                }
127                Some(Greater) => {
128                    self_any_greater = true;
129                }
130                Some(Equal) => {}
131            }
132            if self_any_greater && other_any_greater {
133                return None;
134            }
135        }
136        match (self_any_greater, other_any_greater) {
137            (true, false) => Some(Greater),
138            (false, true) => Some(Less),
139            (false, false) => Some(Equal),
140            // We check this one after each loop iteration above.
141            (true, true) => unreachable!(),
142        }
143    }
144}
145impl<LatSelf, LatOther> LatticeOrd<VecUnion<LatOther>> for VecUnion<LatSelf> where
146    Self: PartialOrd<VecUnion<LatOther>>
147{
148}
149
150impl<Lat> IsBot for VecUnion<Lat> {
151    fn is_bot(&self) -> bool {
152        self.vec.is_empty()
153    }
154}
155
156impl<Lat> IsTop for VecUnion<Lat> {
157    fn is_top(&self) -> bool {
158        false
159    }
160}
161
162#[cfg(test)]
163mod test {
164    use std::collections::HashSet;
165
166    use super::*;
167    use crate::Max;
168    use crate::set_union::SetUnionHashSet;
169    use crate::test::{cartesian_power, check_all};
170
171    #[test]
172    fn basic() {
173        let mut my_vec_a = VecUnion::<Max<usize>>::default();
174        let my_vec_b = VecUnion::new(vec![Max::new(9), Max::new(4), Max::new(5)]);
175        let my_vec_c = VecUnion::new(vec![Max::new(2), Max::new(5)]);
176
177        assert!(my_vec_a.merge(my_vec_b.clone()));
178        assert!(!my_vec_a.merge(my_vec_b));
179        assert!(my_vec_a.merge(my_vec_c.clone()));
180        assert!(!my_vec_a.merge(my_vec_c));
181    }
182
183    #[test]
184    fn consistency() {
185        let mut test_vec = vec![VecUnion::new(vec![] as Vec<SetUnionHashSet<_>>)];
186
187        let vals = [vec![], vec![0], vec![1], vec![0, 1]]
188            .map(HashSet::from_iter)
189            .map(SetUnionHashSet::new);
190
191        test_vec.extend(
192            cartesian_power::<_, 1>(&vals)
193                .map(|row| VecUnion::new(row.into_iter().cloned().collect())),
194        );
195        test_vec.extend(
196            cartesian_power::<_, 2>(&vals)
197                .map(|row| VecUnion::new(row.into_iter().cloned().collect())),
198        );
199
200        check_all(&test_vec);
201    }
202}