filtration_domination/
edges.rs

1//! Edges, edge lists, and associated functions.
2use crate::io_utils::parse_next;
3use crate::{CriticalGrade, OneCriticalGrade, Value};
4use rand::prelude::SliceRandom;
5use rand::thread_rng;
6use std::cmp::{max, Ordering};
7use std::fmt::{Display, Formatter};
8use std::hash::{Hash, Hasher};
9use std::io::BufRead;
10
11/// Common functionality of an undirected edge. See [BareEdge] and [FilteredEdge].
12pub trait Edge {
13    /// First endpoint. This is an undirected edge, but the first endpoint must be consistent
14    /// for a fixed instance.
15    fn u(&self) -> usize;
16
17    /// Returns a mutable reference to the first endpoint.
18    fn u_mut(&mut self) -> &mut usize;
19
20    /// Second endpoint. This is an undirected edge, but the second endpoint must be consistent
21    /// for a fixed instance.
22    fn v(&self) -> usize;
23
24    /// Returns a mutable reference to the second endpoint.
25    fn v_mut(&mut self) -> &mut usize;
26
27    /// The greatest endpoint.
28    fn max(&self) -> usize {
29        std::cmp::max(self.u(), self.v())
30    }
31
32    /// The least endpoint.
33    fn min(&self) -> usize {
34        std::cmp::min(self.u(), self.v())
35    }
36
37    /// Return a pair whose first element is the greatest endpoint,
38    /// and the second is the least endpoint.
39    fn minmax(&self) -> (usize, usize) {
40        (self.min(), self.max())
41    }
42}
43
44/// Edge that is not filtered.
45#[derive(Debug, Clone, Copy)]
46pub struct BareEdge(pub usize, pub usize);
47
48impl Edge for BareEdge {
49    fn u(&self) -> usize {
50        self.0
51    }
52
53    fn u_mut(&mut self) -> &mut usize {
54        &mut self.0
55    }
56
57    fn v(&self) -> usize {
58        self.1
59    }
60
61    fn v_mut(&mut self) -> &mut usize {
62        &mut self.1
63    }
64}
65
66impl PartialEq for BareEdge {
67    fn eq(&self, other: &Self) -> bool {
68        self.minmax() == other.minmax()
69    }
70}
71
72impl Eq for BareEdge {}
73
74/// Lexicographic order on the minimum and maximum vertex.
75impl PartialOrd for BareEdge {
76    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
77        Some(self.cmp(other))
78    }
79}
80
81/// Lexicographic order on the minimum and maximum vertex.
82impl Ord for BareEdge {
83    fn cmp(&self, other: &Self) -> Ordering {
84        self.minmax().cmp(&other.minmax())
85    }
86}
87
88impl Hash for BareEdge {
89    fn hash<H: Hasher>(&self, state: &mut H) {
90        self.minmax().hash(state);
91    }
92}
93
94impl std::fmt::Display for BareEdge {
95    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96        write!(f, "[{}, {}]", self.0, self.1)
97    }
98}
99
100/// An edge with its associated critical grade.
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
102pub struct FilteredEdge<G> {
103    /// The critical grade of this edge.
104    pub grade: G,
105    /// The endpoints of this edge.
106    pub edge: BareEdge,
107}
108
109impl<G> Edge for FilteredEdge<G> {
110    fn u(&self) -> usize {
111        self.edge.u()
112    }
113
114    fn u_mut(&mut self) -> &mut usize {
115        self.edge.u_mut()
116    }
117
118    fn v(&self) -> usize {
119        self.edge.v()
120    }
121
122    fn v_mut(&mut self) -> &mut usize {
123        self.edge.v_mut()
124    }
125}
126
127/// Implements a total ordering, same as .cmp().
128impl<G: Ord> PartialOrd<Self> for FilteredEdge<G> {
129    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
130        Some(self.cmp(other))
131    }
132}
133
134/// Implements a lexicographic ordering.
135/// First lexicographically compare the grades, and resolve ties by comparing edges.
136impl<G: Ord> Ord for FilteredEdge<G> {
137    fn cmp(&self, other: &Self) -> Ordering {
138        match self.grade.cmp(&other.grade) {
139            Ordering::Equal => self.edge.cmp(&other.edge),
140            not_eq => not_eq,
141        }
142    }
143}
144
145impl<G: Ord> FilteredEdge<G> {
146    /// First compare grades, by the given function `grade_cmp`,
147    /// and, if they are equal, compare edge values.
148    fn cmp_by(&self, other: &Self, grade_cmp: impl Fn(&G, &G) -> Ordering) -> Ordering {
149        match grade_cmp(&self.grade, &other.grade) {
150            Ordering::Equal => self.edge.cmp(&other.edge),
151            not_eq => not_eq,
152        }
153    }
154}
155
156impl<G: std::fmt::Display> std::fmt::Display for FilteredEdge<G> {
157    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
158        write!(f, "{}.{}", self.edge, self.grade)?;
159        Ok(())
160    }
161}
162
163impl<G> From<FilteredEdge<G>> for BareEdge {
164    fn from(e: FilteredEdge<G>) -> Self {
165        e.edge
166    }
167}
168
169/// A graph represented as a list of edges, whose vertices are in the range 0..`n_vertices`.
170/// No self-loops are allowed.
171#[derive(Debug, Clone)]
172pub struct EdgeList<E> {
173    /// Total number of vertices.
174    pub n_vertices: usize,
175    edges: Vec<E>,
176}
177
178impl<E: Edge> EdgeList<E> {
179    /// New empty edge list.
180    pub fn new(n_vertices: usize) -> Self {
181        Self {
182            n_vertices,
183            edges: Vec::new(),
184        }
185    }
186
187    /// Returns the underlying slice of edges.
188    pub fn edges(&self) -> &[E] {
189        &self.edges
190    }
191
192    /// Returns a mutable slice of the underlying slice of edges.
193    pub fn edges_mut(&mut self) -> &mut [E] {
194        &mut self.edges
195    }
196
197    /// Returns the number of edges.
198    pub fn len(&self) -> usize {
199        self.edges.len()
200    }
201
202    /// Returns whether there are edges.
203    pub fn is_empty(&self) -> bool {
204        self.len() == 0
205    }
206
207    /// Collects all the edges from the given iterator.
208    pub fn from_iterator<I: Iterator<Item = E>>(it: I) -> Self {
209        let edges: Vec<E> = it.collect();
210        edges.into()
211    }
212
213    /// Returns the number of vertices.
214    pub fn number_of_vertices(&self) -> usize {
215        self.n_vertices
216    }
217
218    /// Adds an edge to the graph.
219    /// Panics: if the edge to add is a self-loop.
220    pub fn add_edge(&mut self, e: E) {
221        let u = e.u();
222        let v = e.v();
223        assert_ne!(u, v, "Trying to add a self loop to a graph");
224
225        let greatest_vertex = max(u, v);
226        self.n_vertices = max(self.n_vertices, greatest_vertex + 1);
227        self.edges.push(e);
228    }
229
230    /// Returns an iterator over the edges.
231    pub fn edge_iter(&self) -> impl Iterator<Item = &E> + '_ {
232        self.edges.iter()
233    }
234
235    /// Returns a count of the degree of each vertex.
236    pub fn degrees(&self) -> Vec<usize> {
237        let mut degree_count = vec![0; self.n_vertices];
238        for e in self.edge_iter() {
239            degree_count[e.u()] += 1;
240            degree_count[e.v()] += 1;
241        }
242        degree_count
243    }
244
245    /// Returns the maximum degree of a vertex in the edge list.
246    pub fn maximum_degree(&self) -> usize {
247        // Return 0 as maximum degree if there are no vertices.
248        self.degrees().into_iter().max().unwrap_or(0usize)
249    }
250
251    fn count_vertices(edges: &[E]) -> usize {
252        let mut n_vertices = 0;
253
254        for e in edges.iter() {
255            n_vertices = max(n_vertices, e.max() + 1);
256        }
257
258        n_vertices
259    }
260}
261
262impl<VF: Value, const N: usize> EdgeList<FilteredEdge<OneCriticalGrade<VF, N>>> {
263    /// Sort the filtered edges lexicographically in increasing order.
264    pub fn sort_lexicographically(&mut self) {
265        self.edges.sort()
266    }
267
268    /// Reverse sort the filtered edges lexicographically.
269    pub fn sort_reverse_lexicographically(&mut self) {
270        self.edges.sort_by(|a, b| b.cmp(a))
271    }
272
273    /// Sort the filtered edges colexicographically in increasing order.
274    pub fn sort_colexicographically(&mut self) {
275        self.edges
276            .sort_by(|a, b| a.cmp_by(b, OneCriticalGrade::cmp_colexicographically))
277    }
278
279    /// Reverse sort the filtered edges colexicographically.
280    pub fn sort_reverse_colexicographically(&mut self) {
281        self.edges
282            .sort_by(|a, b| b.cmp_by(a, OneCriticalGrade::cmp_colexicographically))
283    }
284
285    /// Put a random order on the edges..
286    pub fn shuffle(&mut self) {
287        self.edges.shuffle(&mut thread_rng())
288    }
289}
290
291impl<E: Edge> From<Vec<E>> for EdgeList<E> {
292    fn from(edges: Vec<E>) -> Self {
293        let n_vertices = Self::count_vertices(&edges);
294        Self { n_vertices, edges }
295    }
296}
297
298pub fn write_edge_list<T: Value + Display, W: std::io::Write, const N: usize>(
299    edges: &EdgeList<FilteredEdge<OneCriticalGrade<T, N>>>,
300    writer: &mut W,
301    write_number: bool,
302) -> std::io::Result<()> {
303    if write_number {
304        writeln!(writer, "{}", edges.len())?;
305    }
306
307    for e in edges.edge_iter() {
308        write!(writer, "{} {}", e.edge.0, e.edge.1)?;
309        for i in 0..N {
310            write!(writer, " {}", e.grade.0[i])?;
311        }
312        writeln!(writer)?;
313    }
314
315    Ok(())
316}
317
318pub fn read_edge_list<T: Value + std::str::FromStr, R: std::io::Read, const N: usize>(
319    reader: std::io::BufReader<R>,
320) -> std::io::Result<EdgeList<FilteredEdge<OneCriticalGrade<T, N>>>>
321where
322    <T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
323{
324    let mut edge_list = EdgeList::new(0);
325    for l in reader.lines() {
326        let l = l?;
327        let mut line_parts = l.split_whitespace();
328        let u: usize = parse_next(&mut line_parts)?;
329        let v: usize = parse_next(&mut line_parts)?;
330
331        let mut grade = OneCriticalGrade::zero();
332        for grade_coord in grade.0.iter_mut() {
333            *grade_coord = parse_next(&mut line_parts)?;
334        }
335
336        edge_list.add_edge(FilteredEdge {
337            grade,
338            edge: BareEdge(u, v),
339        });
340    }
341    Ok(edge_list)
342}
343
344#[cfg(test)]
345mod tests {
346    use crate::edges::{BareEdge, EdgeList, FilteredEdge};
347    use crate::OneCriticalGrade;
348
349    #[test]
350    fn edge_list_lexicographic_order() {
351        let mut edges: EdgeList<_> = sorting_test_dataset();
352        edges.sort_lexicographically();
353        let grades: Vec<OneCriticalGrade<usize, 2>> = edges.edge_iter().map(|e| e.grade).collect();
354        let expected_grades: Vec<OneCriticalGrade<usize, 2>> =
355            vec![[1, 1].into(), [1, 2].into(), [2, 1].into(), [2, 2].into()];
356        assert_eq!(grades, expected_grades);
357    }
358
359    #[test]
360    fn edge_list_reverse_lexicographic_order() {
361        let mut edges: EdgeList<_> = sorting_test_dataset();
362        edges.sort_reverse_lexicographically();
363        let grades: Vec<OneCriticalGrade<usize, 2>> = edges.edge_iter().map(|e| e.grade).collect();
364        let expected_grades: Vec<OneCriticalGrade<usize, 2>> =
365            vec![[2, 2].into(), [2, 1].into(), [1, 2].into(), [1, 1].into()];
366        assert_eq!(grades, expected_grades);
367    }
368
369    #[test]
370    fn edge_list_colexicographic_order() {
371        let mut edges: EdgeList<_> = sorting_test_dataset();
372        edges.sort_colexicographically();
373        let grades: Vec<OneCriticalGrade<usize, 2>> = edges.edge_iter().map(|e| e.grade).collect();
374        let expected_grades: Vec<OneCriticalGrade<usize, 2>> =
375            vec![[1, 1].into(), [2, 1].into(), [1, 2].into(), [2, 2].into()];
376        assert_eq!(grades, expected_grades);
377    }
378
379    #[test]
380    fn edge_list_reverse_colexicographic_order() {
381        let mut edges: EdgeList<_> = sorting_test_dataset();
382        edges.sort_reverse_colexicographically();
383        let grades: Vec<OneCriticalGrade<usize, 2>> = edges.edge_iter().map(|e| e.grade).collect();
384        let expected_grades: Vec<OneCriticalGrade<usize, 2>> =
385            vec![[2, 2].into(), [1, 2].into(), [2, 1].into(), [1, 1].into()];
386        assert_eq!(grades, expected_grades);
387    }
388
389    fn sorting_test_dataset() -> EdgeList<FilteredEdge<OneCriticalGrade<usize, 2>>> {
390        vec![
391            FilteredEdge {
392                grade: [1, 1].into(),
393                edge: BareEdge(0, 1),
394            },
395            FilteredEdge {
396                grade: [2, 2].into(),
397                edge: BareEdge(5, 3),
398            },
399            FilteredEdge {
400                grade: [2, 1].into(),
401                edge: BareEdge(0, 3),
402            },
403            FilteredEdge {
404                grade: [1, 2].into(),
405                edge: BareEdge(2, 1),
406            },
407        ]
408        .into()
409    }
410}