flag_algebra/flags/
cgraph.rs

1//! Example of flags: Graphs.
2
3use crate::combinatorics;
4use crate::flag::{Flag, SubClass};
5use crate::flags::common::*;
6use crate::flags::Colored;
7use crate::iterators;
8use crate::iterators::StreamingIterator;
9use canonical_form::Canonize;
10use const_format::concatcp;
11use std::fmt;
12use std::fmt::Debug;
13
14/// Edge-colored graphs.
15///
16/// Implentation of graphs whose edges are colored by a number in a set `{1,…,K-1}`
17/// (So that accounting for non-edges, each pair has `K` possible states).
18#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Serialize, Deserialize)]
19pub struct CGraph<const K: u8> {
20    pub size: usize,
21    edge: SymNonRefl<u8>,
22}
23
24impl<const K: u8> CGraph<K> {
25    /// Returns `true` if `uv` is an edge.
26    pub fn is_edge(&self, u: usize, v: usize) -> bool {
27        u != v && self.edge[(u, v)] > 0
28    }
29    /// Return the color of an edge `uv`.
30    /// Returns `0` if there is no edge.
31    pub fn edge(&self, u: usize, v: usize) -> u8 {
32        self.edge[(u, v)]
33    }
34    /// Return the vector of vertices adjacent to `v`.
35    pub fn nbrs(&self, v: usize) -> Vec<usize> {
36        let mut res = Vec::new();
37        for u in 0..self.size {
38            if self.is_edge(u, v) {
39                res.push(u);
40            }
41        }
42        res
43    }
44    /// Create a new colored graph with the specified edges.
45    /// Edges not listed get value 0.
46    pub fn new(n: usize, edge: &[((usize, usize), u8)]) -> Self {
47        let mut res = Self::empty(n);
48        for &((u, v), val) in edge {
49            assert!(u < n);
50            assert!(v < n);
51            assert!(u != v);
52            assert!(val < K);
53            assert_eq!(res.edge[(u, v)], 0);
54            res.edge[(u, v)] = val;
55        }
56        res
57    }
58    /// Create the graph on `n` vertices with no edge.  
59    pub fn empty(n: usize) -> Self {
60        Self {
61            size: n,
62            edge: SymNonRefl::new(0, n),
63        }
64    }
65}
66
67impl<const K: u8> fmt::Display for CGraph<K> {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        let sep = if self.size < 10 { "" } else { "-" };
70        write!(f, "(|V|={}, E={{", self.size)?;
71        for u in 0..self.size {
72            for v in 0..u {
73                let uv = self.edge[(u, v)];
74                if uv > 0 {
75                    write!(f, " {v}{sep}{u}:{uv}")?
76                }
77            }
78        }
79        write!(f, " }})")
80    }
81}
82
83impl<const K: u8> Canonize for CGraph<K> {
84    fn size(&self) -> usize {
85        self.size
86    }
87    fn invariant_neighborhood(&self, v: usize) -> Vec<Vec<usize>> {
88        assert!(v < self.size);
89        let mut res = vec![Vec::new(); (K - 1) as usize];
90        for u in 0..self.size() {
91            if u != v {
92                let edge = self.edge[(u, v)];
93                if edge > 0 {
94                    res[edge as usize - 1].push(u)
95                }
96            }
97        }
98        res
99    }
100
101    fn apply_morphism(&self, p: &[usize]) -> Self {
102        self.induce(&combinatorics::invert(p))
103    }
104}
105
106macro_rules! name {
107    ($i:expr) => {
108        concatcp!("CGraph_", $i)
109    };
110}
111
112impl<const K: u8> Flag for CGraph<K> {
113    fn induce(&self, p: &[usize]) -> Self {
114        Self {
115            size: p.len(),
116            edge: self.edge.induce0(p),
117        }
118    }
119
120    // Hack to avoid current limitation in rust consts (FIXME)
121    // Should be 'concat("CGraph_", K)'
122    const NAME: &'static str = [
123        name!(0u8),
124        name!(1u8),
125        name!(2u8),
126        name!(3u8),
127        name!(4u8),
128        name!(5u8),
129        name!(6u8),
130        name!(7u8),
131        name!(8u8),
132    ][K as usize];
133
134    fn size_zero_flags() -> Vec<Self> {
135        vec![Self::empty(0)]
136    }
137
138    fn superflags(&self) -> Vec<Self> {
139        let n = self.size;
140        let mut res = Vec::new();
141        let mut iter = iterators::Functions::new(n, K as usize);
142        while let Some(map) = iter.next() {
143            let mut edge = self.edge.clone();
144            edge.resize(n + 1, 0);
145            for (v, &c) in map.iter().enumerate() {
146                edge[(v, n)] = c as u8;
147            }
148            res.push(Self { edge, size: n + 1 });
149        }
150        res
151    }
152}
153
154/// This should be properly implemented with a trait:
155
156impl<A, const K: u8> SubClass<CGraph<K>, A> {
157    pub fn size(&self) -> usize {
158        self.content.size
159    }
160    pub fn is_edge(&self, u: usize, v: usize) -> bool {
161        self.content.is_edge(u, v)
162    }
163    pub fn edge(&self, u: usize, v: usize) -> u8 {
164        self.content.edge(u, v)
165    }
166}
167
168impl<const K: u8, const N: u8> Colored<CGraph<K>, N> {
169    pub fn size(&self) -> usize {
170        self.content.size
171    }
172    pub fn is_edge(&self, u: usize, v: usize) -> bool {
173        self.content.is_edge(u, v)
174    }
175    pub fn edge(&self, u: usize, v: usize) -> u8 {
176        self.content.edge(u, v)
177    }
178}
179
180impl<A, const K: u8, const N: u8> SubClass<Colored<CGraph<K>, N>, A> {
181    pub fn size(&self) -> usize {
182        self.content.size()
183    }
184    pub fn is_edge(&self, u: usize, v: usize) -> bool {
185        self.content.is_edge(u, v)
186    }
187    pub fn edge(&self, u: usize, v: usize) -> u8 {
188        self.content.edge(u, v)
189    }
190}
191
192/// Tests
193#[cfg(test)]
194mod tests {
195    use super::*;
196
197    #[test]
198    fn new_unit() {
199        let g =
200            CGraph::<3>::new(4, &[((0, 1), 1), ((2, 3), 1), ((0, 2), 2), ((0, 3), 2)]).canonical();
201        let h =
202            CGraph::<3>::new(4, &[((1, 0), 2), ((2, 1), 2), ((3, 1), 1), ((0, 2), 1)]).canonical();
203        assert_eq!(g, h);
204    }
205
206    #[test]
207    fn generate_cgraph() {
208        type G1 = CGraph<1>;
209        type G2 = CGraph<2>;
210        type G3 = CGraph<3>;
211
212        assert_eq!(G1::generate(12).len(), 1);
213        assert_eq!(G2::generate(6).len(), 156);
214        assert_eq!(G3::generate(3).len(), 10);
215    }
216}