petgraph/graph6/
graph6_decoder.rs

1//! [graph6 format](https://users.cecs.anu.edu.au/~bdm/data/formats.txt) decoder for undirected graphs.
2
3use 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
25/// A graph that can be converted from graph6 format string.
26pub trait FromGraph6 {
27    fn from_graph6_string(graph6_string: String) -> Self;
28}
29
30/// Converts a graph6 format string into data can be used to construct an undirected graph.
31/// Returns a tuple containing the graph order and its edges.
32pub 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
48// Converts a graph6 format string into a vector of bytes, converted from ASCII characters,
49// split into two parts, the first representing the graph order, and the second its adjacency matrix.
50fn 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
71// Converts a bytes vector into a bits vector.
72fn 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
79// Get binary representation of `n` as a vector of bits with `bits_length` length.
80fn 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
88// Convert a bits vector into its decimal representation.
89fn 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
99// Get graph edges from its order and bits vector representation of its adjacency matrix.
100fn 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}