graph6_rs/
directed.rs

1use super::{GraphConversion, IOError};
2use crate::{
3    utils::{fill_bitvector, get_size},
4    WriteGraph,
5};
6
7/// Creates a directed graph from a graph6 representation
8#[derive(Debug)]
9pub struct DiGraph {
10    pub bit_vec: Vec<usize>,
11    pub n: usize,
12}
13impl DiGraph {
14    /// Creates a new DiGraph from a graph6 representation string
15    ///
16    /// # Arguments
17    /// * `repr` - A graph6 representation string
18    ///
19    /// # Errors
20    /// Returns an error if the graph6 representation is invalid (i.e. missing digraph header '&')
21    ///
22    /// # Examples
23    /// ```
24    /// use graph6_rs::DiGraph;
25    /// let graph = DiGraph::from_d6("&AG").unwrap();
26    /// assert_eq!(graph.n, 2);
27    /// assert_eq!(graph.bit_vec, &[0, 0, 1, 0]);
28    /// ```
29    pub fn from_d6(repr: &str) -> Result<Self, IOError> {
30        let bytes = repr.as_bytes();
31        Self::valid_digraph(bytes)?;
32        let n = get_size(bytes, 1)?;
33        let bit_vec = Self::build_bitvector(bytes, n);
34        Ok(Self { bit_vec, n })
35    }
36
37    /// Creates a new DiGraph from a flattened adjacency matrix
38    ///
39    /// # Arguments
40    /// * `adj` - A flattened adjacency matrix
41    ///
42    /// # Errors
43    /// Returns an error if the adjacency matrix is invalid (i.e. not square)
44    ///
45    /// # Examples
46    /// ```
47    /// use graph6_rs::DiGraph;
48    /// let graph = DiGraph::from_adj(&[0, 0, 1, 0]).unwrap();
49    /// assert_eq!(graph.n, 2);
50    /// assert_eq!(graph.bit_vec, &[0, 0, 1, 0]);
51    /// ```
52    pub fn from_adj(adj: &[usize]) -> Result<Self, IOError> {
53        let n2 = adj.len();
54        let n = (n2 as f64).sqrt() as usize;
55        if n * n != n2 {
56            return Err(IOError::InvalidAdjacencyMatrix);
57        }
58        let bit_vec = adj.to_vec();
59        Ok(Self { bit_vec, n })
60    }
61
62    /// Validates graph6 directed representation
63    fn valid_digraph(repr: &[u8]) -> Result<bool, IOError> {
64        if repr[0] == b'&' {
65            Ok(true)
66        } else {
67            Err(IOError::InvalidDigraphHeader)
68        }
69    }
70
71    /// Iteratores through the bytes and builds a bitvector
72    /// representing the adjaceny matrix of the graph
73    fn build_bitvector(bytes: &[u8], n: usize) -> Vec<usize> {
74        let bv_len = n * n;
75        let bit_vec = fill_bitvector(bytes, bv_len, 2);
76        bit_vec
77    }
78}
79
80impl GraphConversion for DiGraph {
81    fn bit_vec(&self) -> &[usize] {
82        &self.bit_vec
83    }
84
85    fn size(&self) -> usize {
86        self.n
87    }
88
89    fn is_directed(&self) -> bool {
90        true
91    }
92}
93
94impl WriteGraph for DiGraph {}
95
96#[cfg(test)]
97mod testing {
98    use crate::WriteGraph;
99
100    use super::GraphConversion;
101
102    #[test]
103    fn test_header() {
104        let repr = b"&AG";
105        assert!(super::DiGraph::valid_digraph(repr).is_ok());
106    }
107
108    #[test]
109    fn test_invalid_header() {
110        let repr = b"AG";
111        assert!(super::DiGraph::valid_digraph(repr).is_err());
112    }
113
114    #[test]
115    fn test_from_adj() {
116        let adj = &[0, 0, 1, 0];
117        let graph = super::DiGraph::from_adj(adj).unwrap();
118        assert_eq!(graph.size(), 2);
119        assert_eq!(graph.bit_vec(), vec![0, 0, 1, 0]);
120        assert_eq!(graph.write_graph(), "&AG");
121    }
122
123    #[test]
124    fn test_from_nonsquare_adj() {
125        let adj = &[0, 0, 1, 0, 1];
126        let graph = super::DiGraph::from_adj(adj);
127        assert!(graph.is_err());
128    }
129
130    #[test]
131    /// Adjacency matrix:
132    /// 0 0
133    /// 1 0
134    fn test_bitvector_n2() {
135        let repr = "&AG";
136        let graph = super::DiGraph::from_d6(repr).unwrap();
137        assert_eq!(graph.size(), 2);
138        assert_eq!(graph.bit_vec(), vec![0, 0, 1, 0]);
139    }
140
141    #[test]
142    /// Adjacency matrix:
143    /// 0 1 1
144    /// 1 0 1
145    /// 1 1 0
146    fn test_bitvector_n3() {
147        let repr = r"&B\o";
148        let graph = super::DiGraph::from_d6(repr).unwrap();
149        assert_eq!(graph.size(), 3);
150        assert_eq!(graph.bit_vec(), vec![0, 1, 1, 1, 0, 1, 1, 1, 0]);
151    }
152
153    #[test]
154    /// Adjacency matrix:
155    /// 0 1 1 1
156    /// 1 0 1 1
157    /// 1 1 0 1
158    /// 1 1 1 0
159    fn test_bitvector_n4() {
160        let repr = r"&C]|w";
161        let graph = super::DiGraph::from_d6(repr).unwrap();
162        assert_eq!(graph.size(), 4);
163        assert_eq!(
164            graph.bit_vec(),
165            vec![0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0]
166        );
167    }
168
169    #[test]
170    fn test_init_invalid_n2() {
171        let repr = "AG";
172        let graph = super::DiGraph::from_d6(repr);
173        assert!(graph.is_err());
174    }
175
176    #[test]
177    fn test_to_adjacency() {
178        let repr = r"&C]|w";
179        let graph = super::DiGraph::from_d6(repr).unwrap();
180        let adj = graph.to_adjmat();
181        assert_eq!(adj, "0 1 1 1\n1 0 1 1\n1 1 0 1\n1 1 1 0\n");
182    }
183
184    #[test]
185    fn test_to_dot() {
186        let repr = r"&AG";
187        let graph = super::DiGraph::from_d6(repr).unwrap();
188        let dot = graph.to_dot(None);
189        assert_eq!(dot, "digraph {\n1 -> 0;\n}");
190    }
191
192    #[test]
193    fn test_to_dot_with_id() {
194        let repr = r"&AG";
195        let graph = super::DiGraph::from_d6(repr).unwrap();
196        let dot = graph.to_dot(Some(1));
197        assert_eq!(dot, "digraph graph_1 {\n1 -> 0;\n}");
198    }
199
200    #[test]
201    fn test_to_net() {
202        let repr = r"&AG";
203        let graph = super::DiGraph::from_d6(repr).unwrap();
204        let net = graph.to_net();
205        assert_eq!(net, "*Vertices 2\n1 \"0\"\n2 \"1\"\n*Arcs\n2 1\n");
206    }
207
208    #[test]
209    fn test_to_flat() {
210        let repr = r"&AG";
211        let graph = super::DiGraph::from_d6(repr).unwrap();
212        let flat = graph.to_flat();
213        assert_eq!(flat, "0010");
214    }
215
216    #[test]
217    fn test_write_n2() {
218        let repr = r"&AG";
219        let graph = super::DiGraph::from_d6(repr).unwrap();
220        let graph6 = graph.write_graph();
221        assert_eq!(graph6, repr);
222    }
223
224    #[test]
225    fn test_write_n3() {
226        let repr = r"&B\o";
227        let graph = super::DiGraph::from_d6(repr).unwrap();
228        let graph6 = graph.write_graph();
229        assert_eq!(graph6, repr);
230    }
231
232    #[test]
233    fn test_write_n4() {
234        let repr = r"&C]|w";
235        let graph = super::DiGraph::from_d6(repr).unwrap();
236        let graph6 = graph.write_graph();
237        assert_eq!(graph6, repr);
238    }
239}