1use super::{GraphConversion, IOError};
2use crate::{
3 utils::{fill_bitvector, get_size},
4 WriteGraph,
5};
6
7#[derive(Debug)]
9pub struct Graph {
10 pub bit_vec: Vec<usize>,
11 pub n: usize,
12}
13impl Graph {
14 pub fn from_g6(repr: &str) -> Result<Self, IOError> {
27 let bytes = repr.as_bytes();
28 let n = get_size(bytes, 0)?;
29 let bit_vec = Self::build_bitvector(bytes, n)?;
30 Ok(Self { bit_vec, n })
31 }
32
33 pub fn from_adj(adj: &[usize]) -> Result<Self, IOError> {
51 let n2 = adj.len();
52 let n = (n2 as f64).sqrt() as usize;
53 if n * n != n2 {
54 return Err(IOError::InvalidAdjacencyMatrix);
55 }
56 let mut bit_vec = vec![0; n * n];
57 for i in 0..n {
58 for j in 0..n {
59 if adj[i * n + j] == 1 {
60 let idx = i * n + j;
61 let jdx = j * n + i;
62 bit_vec[idx] = 1;
63 bit_vec[jdx] = 1;
64 }
65 }
66 }
67 Ok(Self { bit_vec, n })
68 }
69
70 fn build_bitvector(bytes: &[u8], n: usize) -> Result<Vec<usize>, IOError> {
72 let bv_len = n * (n - 1) / 2;
73 let Some(bit_vec) = fill_bitvector(bytes, bv_len, 1) else {
74 return Err(IOError::NonCanonicalEncoding);
75 };
76 Self::fill_from_triangle(&bit_vec, n)
77 }
78
79 fn fill_from_triangle(tri: &[usize], n: usize) -> Result<Vec<usize>, IOError> {
81 let mut bit_vec = vec![0; n * n];
82 let mut tri_iter = tri.iter();
83 for i in 1..n {
84 for j in 0..i {
85 let idx = i * n + j;
86 let jdx = j * n + i;
87 let Some(&val) = tri_iter.next() else {
88 return Err(IOError::NonCanonicalEncoding);
89 };
90 bit_vec[idx] = val;
91 bit_vec[jdx] = val;
92 }
93 }
94 Ok(bit_vec)
95 }
96}
97impl GraphConversion for Graph {
98 fn bit_vec(&self) -> &[usize] {
100 &self.bit_vec
101 }
102
103 fn size(&self) -> usize {
105 self.n
106 }
107
108 fn is_directed(&self) -> bool {
110 false
111 }
112}
113impl WriteGraph for Graph {}
114
115#[cfg(test)]
116mod testing {
117 use super::{Graph, GraphConversion, WriteGraph};
118
119 #[test]
120 fn test_graph_n2() {
121 let graph = Graph::from_g6("A_").unwrap();
122 assert_eq!(graph.size(), 2);
123 assert_eq!(graph.bit_vec(), &[0, 1, 1, 0]);
124 }
125
126 #[test]
127 fn test_graph_n2_empty() {
128 let graph = Graph::from_g6("A?").unwrap();
129 assert_eq!(graph.size(), 2);
130 assert_eq!(graph.bit_vec(), &[0, 0, 0, 0]);
131 }
132
133 #[test]
134 fn test_graph_n3() {
135 let graph = Graph::from_g6("Bw").unwrap();
136 assert_eq!(graph.size(), 3);
137 assert_eq!(graph.bit_vec(), &[0, 1, 1, 1, 0, 1, 1, 1, 0]);
138 }
139
140 #[test]
141 fn test_graph_n4() {
142 let graph = Graph::from_g6("C~").unwrap();
143 assert_eq!(graph.size(), 4);
144 assert_eq!(
145 graph.bit_vec(),
146 &[0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0]
147 );
148 }
149
150 #[test]
151 fn test_too_short_input() {
152 let parsed = Graph::from_g6("a");
153 assert!(parsed.is_err());
154 }
155
156 #[test]
157 fn test_invalid_char() {
158 let parsed = Graph::from_g6("A1");
159 assert!(parsed.is_err());
160 }
161
162 #[test]
163 fn test_to_adjacency() {
164 let graph = Graph::from_g6("A_").unwrap();
165 let adj = graph.to_adjmat();
166 assert_eq!(adj, "0 1\n1 0\n");
167 }
168
169 #[test]
170 fn test_to_dot() {
171 let graph = Graph::from_g6("A_").unwrap();
172 let dot = graph.to_dot(None);
173 assert_eq!(dot, "graph {\n0 -- 1;\n}");
174 }
175
176 #[test]
177 fn test_to_dot_with_label() {
178 let graph = Graph::from_g6("A_").unwrap();
179 let dot = graph.to_dot(Some(1));
180 assert_eq!(dot, "graph graph_1 {\n0 -- 1;\n}");
181 }
182
183 #[test]
184 fn test_to_net() {
185 let repr = r"A_";
186 let graph = Graph::from_g6(repr).unwrap();
187 let net = graph.to_net();
188 assert_eq!(net, "*Vertices 2\n1 \"0\"\n2 \"1\"\n*Arcs\n1 2\n2 1\n");
189 }
190
191 #[test]
192 fn test_to_flat() {
193 let repr = r"A_";
194 let graph = Graph::from_g6(repr).unwrap();
195 let flat = graph.to_flat();
196 assert_eq!(flat, "0110");
197 }
198
199 #[test]
200 fn test_write_n2() {
201 let repr = r"A_";
202 let graph = Graph::from_g6(repr).unwrap();
203 let g6 = graph.write_graph();
204 assert_eq!(g6, repr);
205 }
206
207 #[test]
208 fn test_write_n3() {
209 let repr = r"Bw";
210 let graph = Graph::from_g6(repr).unwrap();
211 let g6 = graph.write_graph();
212 assert_eq!(g6, repr);
213 }
214
215 #[test]
216 fn test_write_n4() {
217 let repr = r"C~";
218 let graph = Graph::from_g6(repr).unwrap();
219 let g6 = graph.write_graph();
220 assert_eq!(g6, repr);
221 }
222
223 #[test]
224 fn test_from_adj() {
225 let adj = &[0, 0, 1, 0];
226 let graph = Graph::from_adj(adj).unwrap();
227 assert_eq!(graph.size(), 2);
228 assert_eq!(graph.bit_vec(), &[0, 1, 1, 0]);
229 assert_eq!(graph.write_graph(), "A_");
230 }
231
232 #[test]
233 fn test_from_nonsquare_adj() {
234 let adj = &[0, 0, 1, 0, 1];
235 let graph = Graph::from_adj(adj);
236 assert!(graph.is_err());
237 }
238}