1use alloc::{
4 string::{String, ToString},
5 vec,
6 vec::Vec,
7};
8
9use crate::{csr::Csr, graph::IndexType, Graph, Undirected};
10
11#[cfg(feature = "graphmap")]
12use crate::graphmap::GraphMap;
13
14#[cfg(feature = "graphmap")]
15use core::hash::BuildHasher;
16
17#[cfg(feature = "matrix_graph")]
18use crate::matrix_graph::{MatrixGraph, Nullable};
19
20#[cfg(feature = "stable_graph")]
21use crate::stable_graph::{StableGraph, StableUnGraph};
22
23const N: usize = 63;
24
25pub trait FromGraph6 {
27 fn from_graph6_string(graph6_string: String) -> Self;
28}
29
30pub fn from_graph6_representation<Ix>(graph6_representation: String) -> (usize, Vec<(Ix, Ix)>)
33where
34 Ix: IndexType,
35{
36 let (order_bytes, adj_matrix_bytes) =
37 get_order_bytes_and_adj_matrix_bytes(graph6_representation);
38
39 let order_bits = bytes_vector_to_bits_vector(order_bytes);
40 let adj_matrix_bits = bytes_vector_to_bits_vector(adj_matrix_bytes);
41
42 let graph_order = get_bits_as_decimal(order_bits);
43 let edges = get_edges(graph_order, adj_matrix_bits);
44
45 (graph_order, edges)
46}
47
48fn get_order_bytes_and_adj_matrix_bytes(graph6_representation: String) -> (Vec<usize>, Vec<usize>) {
51 let bytes: Vec<usize> = graph6_representation
52 .chars()
53 .map(|c| (c as usize) - N)
54 .collect();
55
56 let mut order_bytes = vec![];
57 let mut adj_matrix_bytes = vec![];
58
59 let first_byte = *bytes.first().unwrap();
60 if first_byte == N {
61 order_bytes.extend_from_slice(&bytes[1..=3]);
62 adj_matrix_bytes.extend_from_slice(&bytes[4..]);
63 } else {
64 order_bytes.push(first_byte);
65 adj_matrix_bytes.extend_from_slice(&bytes[1..]);
66 };
67
68 (order_bytes, adj_matrix_bytes)
69}
70
71fn bytes_vector_to_bits_vector(bytes: Vec<usize>) -> Vec<u8> {
73 bytes
74 .iter()
75 .flat_map(|&byte| get_number_as_bits(byte, 6))
76 .collect()
77}
78
79fn get_number_as_bits(n: usize, bits_length: usize) -> Vec<u8> {
81 let mut bits = Vec::new();
82 for i in (0..bits_length).rev() {
83 bits.push(((n >> i) & 1) as u8);
84 }
85 bits
86}
87
88fn get_bits_as_decimal(bits: Vec<u8>) -> usize {
90 let bits_str = bits
91 .iter()
92 .map(|bit| bit.to_string())
93 .collect::<Vec<String>>()
94 .join("");
95
96 usize::from_str_radix(&bits_str, 2).unwrap()
97}
98
99fn get_edges<Ix>(order: usize, adj_matrix_bits: Vec<u8>) -> Vec<(Ix, Ix)>
101where
102 Ix: IndexType,
103{
104 let mut edges = vec![];
105
106 let mut i = 0;
107 for col in 1..order {
108 for lin in 0..col {
109 let is_adjacent = adj_matrix_bits[i] == 1;
110
111 if is_adjacent {
112 edges.push((Ix::new(lin), Ix::new(col)));
113 };
114
115 i += 1;
116 }
117 }
118
119 edges
120}
121
122impl<Ix: IndexType> FromGraph6 for Graph<(), (), Undirected, Ix> {
123 fn from_graph6_string(graph6_string: String) -> Self {
124 let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
125
126 let mut graph: Graph<(), (), Undirected, Ix> = Graph::with_capacity(order, edges.len());
127 for _ in 0..order {
128 graph.add_node(());
129 }
130 graph.extend_with_edges(edges);
131
132 graph
133 }
134}
135
136#[cfg(feature = "stable_graph")]
137impl<Ix: IndexType> FromGraph6 for StableGraph<(), (), Undirected, Ix> {
138 fn from_graph6_string(graph6_string: String) -> Self {
139 let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
140
141 let mut graph: StableGraph<(), (), Undirected, Ix> =
142 StableUnGraph::with_capacity(order, edges.len());
143 for _ in 0..order {
144 graph.add_node(());
145 }
146 graph.extend_with_edges(edges);
147
148 graph
149 }
150}
151
152#[cfg(feature = "graphmap")]
153impl<Ix: IndexType, S: BuildHasher + Default> FromGraph6 for GraphMap<Ix, (), Undirected, S> {
154 fn from_graph6_string(graph6_string: String) -> Self {
155 let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
156
157 let mut graph: GraphMap<Ix, (), Undirected, S> =
158 GraphMap::with_capacity(order, edges.len());
159 for i in 0..order {
160 graph.add_node(Ix::new(i));
161 }
162 for (a, b) in edges {
163 graph.add_edge(a, b, ());
164 }
165
166 graph
167 }
168}
169
170#[cfg(feature = "matrix_graph")]
171impl<Null, Ix, S> FromGraph6 for MatrixGraph<(), (), S, Undirected, Null, Ix>
172where
173 Null: Nullable<Wrapped = ()>,
174 Ix: IndexType,
175 S: BuildHasher + Default,
176{
177 fn from_graph6_string(graph6_string: String) -> Self {
178 let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
179
180 let mut graph: MatrixGraph<(), (), S, Undirected, Null, Ix> =
181 MatrixGraph::with_capacity(order);
182 for _ in 0..order {
183 graph.add_node(());
184 }
185 graph.extend_with_edges(edges.iter());
186
187 graph
188 }
189}
190
191impl<Ix: IndexType> FromGraph6 for Csr<(), (), Undirected, Ix> {
192 fn from_graph6_string(graph6_string: String) -> Self {
193 let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
194
195 let mut graph: Csr<(), (), Undirected, Ix> = Csr::new();
196 let mut nodes = Vec::new();
197 for _ in 0..order {
198 let i = graph.add_node(());
199 nodes.push(i);
200 }
201 for (a, b) in edges {
202 graph.add_edge(a, b, ());
203 }
204
205 graph
206 }
207}