1use std::collections::HashMap;
2
3use algorithm::{Edge, Vertex};
4
5use configure::Config;
6use log::info;
7use petgraph::{graph::NodeIndex, stable_graph::StableDiGraph};
8
9mod algorithm;
10pub mod configure;
11mod util;
12
13type Layout = (Vec<(usize, (f64, f64))>, f64, f64);
14type Layouts<T> = Vec<(Vec<(T, (f64, f64))>, f64, f64)>;
15
16pub fn from_edges(edges: &[(u32, u32)], config: &Config) -> Layouts<usize> {
23 info!(target: "initializing", "Creating new layout from edges, containing {} edges", edges.len());
24 let graph = StableDiGraph::from_edges(edges);
25 algorithm::start(graph, config)
26}
27
28pub fn from_graph<V, E>(
34 graph: &StableDiGraph<V, E>,
35 vertex_size: &impl Fn(NodeIndex, &V) -> (f64, f64),
36 config: &Config,
37) -> Layouts<NodeIndex> {
38 info!(target: "initializing",
39 "Creating new layout from existing graph, containing {} vertices and {} edges.",
40 graph.node_count(),
41 graph.edge_count());
42
43 let graph = graph.map(
44 |id, v| Vertex::new(id.index(), vertex_size(id, v)),
45 |_, _| Edge::default(),
46 );
47
48 algorithm::start(graph, config)
49 .into_iter()
50 .map(|(l, w, h)| {
51 (
52 l.into_iter()
53 .map(|(id, coords)| (NodeIndex::from(id as u32), coords))
54 .collect(),
55 w,
56 h,
57 )
58 })
59 .collect()
60}
61
62pub fn from_vertices_and_edges<'a>(
73 vertices: &'a [(u32, (f64, f64))],
74 edges: &'a [(u32, u32)],
75 config: &Config,
76) -> Layouts<usize> {
77 info!(target: "initializing",
78 "Creating new layout from existing graph, containing {} vertices and {} edges.",
79 vertices.len(),
80 edges.len());
81
82 let mut graph = StableDiGraph::new();
83 let mut id_map = HashMap::new();
84 for &(v, size) in vertices {
85 let id = graph.add_node(Vertex::new(v as usize, size));
86 id_map.insert(v, id);
87 }
88
89 for (tail, head) in edges {
90 graph.add_edge(
91 *id_map.get(tail).unwrap(),
92 *id_map.get(head).unwrap(),
93 Edge::default(),
94 );
95 }
96
97 algorithm::start(graph, config)
98}
99
100#[test]
101fn run_algo_empty_graph() {
102 let edges = [];
103 let g = from_edges(&edges, &Config::default());
104 assert!(g.is_empty());
105}
106
107#[cfg(test)]
108mod benchmark {
109 use crate::configure::Config;
110
111 use super::from_edges;
112
113 #[test]
114 fn r_100() {
115 let edges = graph_generator::RandomLayout::new(100)
116 .build_edges()
117 .into_iter()
118 .map(|(r, l)| (r as u32, l as u32))
119 .collect::<Vec<(u32, u32)>>();
120 let start = std::time::Instant::now();
121 let _ = from_edges(&edges, &Config::default());
122 println!("Random 100 edges: {}ms", start.elapsed().as_millis());
123 }
124
125 #[test]
126 fn r_1000() {
127 let edges = graph_generator::RandomLayout::new(1000)
128 .build_edges()
129 .into_iter()
130 .map(|(r, l)| (r as u32, l as u32))
131 .collect::<Vec<(u32, u32)>>();
132 let start = std::time::Instant::now();
133 let _ = from_edges(&edges, &Config::default());
134 println!("Random 1000 edges: {}ms", start.elapsed().as_millis());
135 }
136
137 #[test]
138 fn r_2000() {
139 let edges = graph_generator::RandomLayout::new(2000).build_edges();
140 let start = std::time::Instant::now();
141 let _ = from_edges(&edges, &Config::default());
142 println!("Random 2000 edges: {}ms", start.elapsed().as_millis());
143 }
144
145 #[test]
146 fn r_4000() {
147 let edges = graph_generator::RandomLayout::new(4000).build_edges();
148 let start = std::time::Instant::now();
149 let _ = from_edges(&edges, &Config::default());
150 println!("Random 4000 edges: {}ms", start.elapsed().as_millis());
151 }
152
153 #[test]
154 fn l_1000_2() {
155 let n = 1000;
156 let e = 2;
157 let edges = graph_generator::GraphLayout::new_from_num_nodes(n, e).build_edges();
158 let start = std::time::Instant::now();
159 let _ = from_edges(&edges, &Config::default());
160 println!(
161 "{n} nodes, {e} edges per node: {}ms",
162 start.elapsed().as_millis()
163 );
164 }
165
166 #[test]
167 fn l_2000_2() {
168 let n = 2000;
169 let e = 2;
170 let edges = graph_generator::GraphLayout::new_from_num_nodes(n, e).build_edges();
171 let start = std::time::Instant::now();
172 let _ = from_edges(&edges, &Config::default());
173 println!(
174 "{n} nodes, {e} edges per node: {}ms",
175 start.elapsed().as_millis()
176 );
177 }
178
179 #[test]
180 fn l_4000_2() {
181 let n = 4000;
182 let e = 2;
183 let edges = graph_generator::GraphLayout::new_from_num_nodes(n, e).build_edges();
184 let start = std::time::Instant::now();
185 let _ = from_edges(&edges, &Config::default());
186 println!(
187 "{n} nodes, {e} edges per node: {}ms",
188 start.elapsed().as_millis()
189 );
190 }
191
192 #[test]
193 fn l_8000_2() {
194 let n = 8000;
195 let e = 2;
196 let edges = graph_generator::GraphLayout::new_from_num_nodes(n, e).build_edges();
197 let start = std::time::Instant::now();
198 let _ = from_edges(&edges, &Config::default());
199 println!(
200 "{n} nodes, {e} edges per node: {}ms",
201 start.elapsed().as_millis()
202 );
203 }
204}
205
206#[cfg(test)]
207mod check_visuals {
208
209 use crate::{
210 configure::{Config, RankingType},
211 from_vertices_and_edges,
212 };
213
214 use super::from_edges;
215
216 #[test]
217 fn test_no_dummies() {
218 let vertices = [
219 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
220 ];
221 let edges = [
222 (1, 2),
223 (1, 3),
224 (2, 5),
225 (2, 16),
226 (4, 5),
227 (4, 6),
228 (4, 7),
229 (6, 17),
230 (6, 3),
231 (6, 18),
232 (8, 3),
233 (8, 9),
234 (8, 10),
235 (9, 16),
236 (9, 7),
237 (9, 19),
238 (11, 7),
239 (11, 12),
240 (11, 13),
241 (12, 18),
242 (12, 10),
243 (12, 20),
244 (14, 10),
245 (14, 15),
246 (15, 19),
247 (15, 13),
248 ];
249 let _ = from_vertices_and_edges(
250 &vertices
251 .into_iter()
252 .map(|v| (v, (0.0, 0.0)))
253 .collect::<Vec<_>>(),
254 &edges,
255 &Config {
256 dummy_vertices: true,
257 ..Default::default()
258 },
259 );
260 }
261 #[test]
262 fn verify_looks_good() {
263 let edges = [
265 (0, 1),
266 (1, 2),
267 (2, 3),
268 (2, 4),
269 (3, 5),
270 (3, 6),
271 (3, 7),
272 (3, 8),
273 (4, 5),
274 (4, 6),
275 (4, 7),
276 (4, 8),
277 (5, 9),
278 (6, 9),
279 (7, 9),
280 (8, 9),
281 ];
282 let (layout, width, height) = &mut from_edges(&edges, &Config::default())[0];
283 layout.sort_by(|a, b| a.0.cmp(&b.0));
284
285 assert_eq!(*width, 4.0);
286 assert_eq!(*height, 6.0);
287 println!("{:?}", layout);
288 }
289
290 #[test]
291 fn root_vertices_on_top_disabled() {
292 let edges = [(1, 0), (2, 1), (3, 0), (4, 0)];
293 let layout = from_edges(&edges, &Config::default());
294 for (id, (_, y)) in layout[0].0.clone() {
295 if id == 2 {
296 assert_eq!(y, 0.0);
297 } else if id == 3 || id == 4 || id == 1 {
298 assert_eq!(y, 10.0);
299 } else {
300 assert_eq!(y, 20.0)
301 }
302 }
303 }
304
305 #[test]
306 fn check_coords_2() {
307 let edges = [
308 (0, 1),
309 (0, 2),
310 (0, 3),
311 (1, 4),
312 (4, 5),
313 (5, 6),
314 (2, 6),
315 (3, 6),
316 (3, 7),
317 (3, 8),
318 (3, 9),
319 ];
320 let layout = from_edges(&edges, &Config::default());
321 println!("{:?}", layout);
322 }
323
324 #[test]
325 fn hlrs_ping() {
326 let _nodes = [
327 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
328 ];
329 let edges = [
330 (1, 2),
331 (1, 4),
332 (1, 5),
333 (1, 3),
334 (2, 4),
335 (2, 5),
336 (3, 9),
337 (3, 10),
338 (3, 8),
339 (4, 6),
340 (4, 9),
341 (4, 8),
342 (5, 6),
343 (5, 10),
344 (5, 8),
345 (6, 7),
346 (7, 9),
347 (7, 10),
348 (8, 14),
349 (8, 15),
350 (8, 13),
351 (9, 11),
352 (9, 14),
353 (9, 13),
354 (10, 11),
355 (10, 15),
356 (10, 13),
357 (11, 12),
358 (12, 14),
359 (12, 15),
360 (13, 18),
361 (13, 19),
362 (13, 20),
363 (14, 16),
364 (14, 18),
365 (14, 20),
366 (15, 16),
367 (15, 19),
368 (15, 20),
369 (16, 17),
370 (17, 18),
371 (17, 19),
372 (18, 21),
373 (19, 21),
374 ]
375 .into_iter()
376 .map(|(t, h)| (t - 1, h - 1))
377 .collect::<Vec<_>>();
378
379 let layout = from_edges(
380 &edges,
381 &Config {
382 ranking_type: RankingType::Up,
383 ..Default::default()
384 },
385 );
386 println!("{layout:?}");
387 }
388
389 #[test]
390 fn run_algo_empty_graph() {
391 use super::from_edges;
392 let edges = [];
393 let g = from_edges(&edges, &Config::default());
394 assert!(g.is_empty());
395 }
396
397 #[test]
398 fn run_algo_with_duplicate_edges() {
399 let edges = [
400 (1, 2),
401 (2, 5),
402 (2, 6),
403 (2, 3),
404 (3, 4),
405 (4, 3),
406 (4, 8),
407 (8, 4),
408 (8, 7),
409 (3, 7),
410 (6, 7),
411 (7, 6),
412 (5, 6),
413 (5, 1),
414 ];
415
416 let layout = from_edges(&edges, &Config::default());
417 println!("{layout:?}");
418 }
419}