igraph/lib.rs
1#![doc = include_str!("../README.md")]
2#![allow(non_upper_case_globals)]
3#![allow(non_camel_case_types)]
4#![allow(non_snake_case)]
5
6use std::mem;
7
8include!("../bindings.rs");
9
10impl Drop for igraph_t {
11 fn drop(&mut self) {
12 unsafe {
13 igraph_destroy(self);
14 }
15 }
16}
17
18impl Drop for igraph_vector_int_t {
19 fn drop(&mut self) {
20 unsafe {
21 igraph_vector_int_destroy(self);
22 }
23 }
24}
25
26impl igraph_vector_int_t {
27 pub fn size(&self) -> usize {
28 unsafe { igraph_vector_int_size(self) as usize }
29 }
30
31 pub fn with_capacity(size: usize) -> Self {
32 unsafe {
33 let mut vec = mem::zeroed::<igraph_vector_int_t>();
34 igraph_vector_int_init(&mut vec, size as i64);
35 vec
36 }
37 }
38
39 pub fn set(&mut self, index: usize, value: i64) {
40 unsafe {
41 igraph_vector_int_set(self, index as i64, value);
42 }
43 }
44
45 pub fn get(&self, index: usize) -> i64 {
46 unsafe { igraph_vector_int_get(self, index as i64) }
47 }
48}
49
50impl From<&[i64]> for igraph_vector_int_t {
51 fn from(vec: &[i64]) -> Self {
52 let mut igraph_vec = Self::with_capacity(vec.len());
53 for (i, &value) in vec.iter().enumerate() {
54 igraph_vec.set(i, value);
55 }
56 igraph_vec
57 }
58}
59
60impl Into<Vec<i64>> for igraph_vector_int_t {
61 fn into(self) -> Vec<i64> {
62 let size = self.size();
63 let mut vec = Vec::with_capacity(size);
64 for i in 0..size {
65 vec.push(self.get(i));
66 }
67 vec
68 }
69}
70
71pub enum edge_type_sw_t {
72 SIMPLE,
73 LOOPS,
74 MULTI,
75}
76
77impl igraph_rng_t {
78 pub fn get_integer(&mut self, min: i64, max: i64) -> i64 {
79 unsafe { igraph_rng_get_integer(self, min, max) }
80 }
81
82 pub fn get_unif(&mut self, min: f64, max: f64) -> f64 {
83 unsafe { igraph_rng_get_unif(self, min, max) }
84 }
85
86 pub fn seed<'a>(seed: u64) -> Option<&'a mut igraph_rng_t> {
87 unsafe {
88 let rng = igraph_rng_default();
89 igraph_rng_seed(rng, seed);
90 rng.as_mut()
91 }
92 }
93}
94
95impl igraph_t {
96 pub fn setup() {
97 unsafe {
98 igraph_setup();
99 }
100 }
101
102 /// In the `G(n, m)` Erdős-Rényi model, a graph with `n` vertices and `m` edges is generated uniformly at random;
103 /// for the sake of clarity, it binds the [igraph_erdos_renyi_game_gnm](https://igraph.org/c/html/latest/igraph-Games.html#igraph_erdos_renyi_game_gnm) function.
104 pub fn erdos_renyi_game_gnm(
105 num_vertices: usize,
106 num_edges: usize,
107 directed: bool,
108 mode: edge_type_sw_t,
109 edge_attr: bool,
110 ) -> Self {
111 unsafe {
112 let mut graph = Self::new(0, directed);
113
114 igraph_erdos_renyi_game_gnm(
115 &mut graph,
116 num_vertices as i64,
117 num_edges as i64,
118 directed,
119 match mode {
120 edge_type_sw_t::SIMPLE => IGRAPH_SIMPLE_SW,
121 edge_type_sw_t::LOOPS => IGRAPH_LOOPS_SW,
122 edge_type_sw_t::MULTI => IGRAPH_MULTI_SW,
123 },
124 edge_attr,
125 );
126 graph
127 }
128 }
129
130 pub fn new(num_vertices: usize, directed: bool) -> Self {
131 unsafe {
132 let mut graph = mem::zeroed::<igraph_t>();
133 igraph_empty(&mut graph, num_vertices as i64, directed);
134 graph
135 }
136 }
137
138 pub fn num_vertices(&self) -> i64 {
139 unsafe { igraph_vcount(self) }
140 }
141
142 pub fn num_edges(&self) -> i64 {
143 unsafe { igraph_ecount(self) }
144 }
145
146 pub fn is_directed(&self) -> bool {
147 unsafe { igraph_is_directed(self) }
148 }
149
150 pub fn add_vertices(&mut self, n: i64) {
151 unsafe {
152 igraph_add_vertices(self, n, std::ptr::null());
153 }
154 }
155
156 pub fn add_edge(&mut self, from: i64, to: i64) {
157 unsafe {
158 igraph_add_edge(self, from, to);
159 }
160 }
161
162 pub fn add_edges_from_slice(&mut self, edges_slice: &[(i64, i64)]) {
163 unsafe {
164 let mut edges = igraph_vector_int_t::with_capacity(edges_slice.len() * 2);
165 let mut i = 0;
166 for (from, to) in edges_slice.iter() {
167 edges.set(i, *from);
168 i += 1;
169 edges.set(i, *to);
170 i += 1;
171 }
172 igraph_add_edges(self, &edges, std::ptr::null());
173 }
174 }
175
176 pub fn add_edges_from_vector(&mut self, edges: &igraph_vector_int_t) {
177 unsafe {
178 igraph_add_edges(self, edges, std::ptr::null());
179 }
180 }
181
182 /// [Calculates the diameter of a graph (longest geodesic)](https://igraph.org/c/html/0.10.2/igraph-Structural.html#igraph_diameter):
183 ///
184 /// The diameter of a graph is the length of the longest shortest path it has.
185 /// This function computes both the diameter, as well as the corresponding path.
186 /// The diameter of the null graph is considered be infinity by convention.
187 /// If the graph has no vertices, IGRAPH_NAN is returned.
188 pub fn diameter(&self) -> f64 {
189 let mut diameter = 0.0;
190 unsafe {
191 igraph_diameter(
192 self,
193 std::ptr::null(),
194 &mut diameter,
195 std::ptr::null_mut(),
196 std::ptr::null_mut(),
197 std::ptr::null_mut(),
198 std::ptr::null_mut(),
199 self.is_directed(),
200 true,
201 );
202 }
203 diameter
204 }
205
206 pub fn mean_degree(&self, loops: bool) -> f64 {
207 let mut mean_degree = 0.0;
208 unsafe {
209 igraph_mean_degree(self, &mut mean_degree, loops);
210 }
211 mean_degree
212 }
213
214 pub fn community_multilevel(&self, resolution: f64) -> Vec<i64> {
215 unsafe {
216 let mut membership = igraph_vector_int_t::with_capacity(self.num_vertices() as usize);
217 igraph_community_multilevel(
218 self,
219 std::ptr::null(),
220 resolution,
221 &mut membership,
222 std::ptr::null_mut(),
223 std::ptr::null_mut(),
224 );
225 membership.into()
226 }
227 }
228}
229
230/// # Introduction
231///
232/// A simple test that creates a random graph and computes its diameter and mean degree.
233/// It is a translation of the first example from the igraph C library documentation,
234/// that can be found [in the first lesson](https://igraph.org/c/html/latest/igraph-Tutorial.html#tut-lesson-1).
235///
236/// # C code
237///
238/// ```c
239/// #include <igraph.h>
240///
241/// int main(void) {
242/// igraph_int_t num_vertices = 1000;
243/// igraph_int_t num_edges = 1000;
244/// igraph_real_t diameter, mean_degree;
245/// igraph_t graph;
246///
247/// /* Initialize the library. */
248/// igraph_setup();
249///
250/// /* Ensure identical results across runs. */
251/// igraph_rng_seed(igraph_rng_default(), 42);
252///
253/// igraph_erdos_renyi_game_gnm(
254/// &graph, num_vertices, num_edges,
255/// IGRAPH_UNDIRECTED, IGRAPH_SIMPLE_SW, IGRAPH_EDGE_UNLABELED);
256///
257/// igraph_diameter(
258/// &graph, /* weights = */ NULL,
259/// &diameter,
260/// /* from = */ NULL, /* to = */ NULL,
261/// /* vertex_path = */ NULL, /* edge_path = */ NULL,
262/// IGRAPH_UNDIRECTED, /* unconn= */ true);
263///
264/// igraph_mean_degree(&graph, &mean_degree, IGRAPH_LOOPS);
265/// printf("Diameter of a random graph with average degree %g: %g\n",
266/// mean_degree, diameter);
267///
268/// igraph_destroy(&graph);
269///
270/// return 0;
271/// }
272/// ```
273fn example_1() {
274 let graph = igraph_t::erdos_renyi_game_gnm(1000, 1000, false, edge_type_sw_t::SIMPLE, false);
275
276 let diameter = graph.diameter();
277
278 let mean_degree = graph.mean_degree(true);
279
280 assert!(diameter == 23.0);
281 assert!(mean_degree == 2.0);
282}
283
284fn example_2() {
285 /*
286 int main(void) {
287 igraph_t graph;
288 igraph_vector_int_t dimvector;
289 igraph_vector_int_t edges;
290 igraph_vector_bool_t periodic;
291 igraph_real_t avg_path_len;
292
293 /* Initialize the library. */
294 igraph_setup();
295
296 igraph_vector_int_init(&dimvector, 2);
297 VECTOR(dimvector)[0] = 30;
298 VECTOR(dimvector)[1] = 30;
299
300 igraph_vector_bool_init(&periodic, 2);
301 igraph_vector_bool_fill(&periodic, true);
302 igraph_square_lattice(&graph, &dimvector, 0, IGRAPH_UNDIRECTED,
303 /* mutual= */ false, &periodic);
304
305 igraph_average_path_length(&graph, NULL, &avg_path_len, NULL,
306 IGRAPH_UNDIRECTED, /* unconn= */ true);
307 printf("Average path length (lattice): %g\n", (double) avg_path_len);
308
309 /* Seed the RNG to ensure identical results across runs. */
310 igraph_rng_seed(igraph_rng_default(), 42);
311
312 igraph_vector_int_init(&edges, 20);
313 for (igraph_int_t i = 0; i < igraph_vector_int_size(&edges); i++) {
314 VECTOR(edges)[i] = RNG_INTEGER(0, igraph_vcount(&graph) - 1);
315 }
316
317 igraph_add_edges(&graph, &edges, NULL);
318 igraph_average_path_length(&graph, NULL, &avg_path_len, NULL,
319 IGRAPH_UNDIRECTED, /* unconn= */ true);
320 printf("Average path length (randomized lattice): %g\n", (double) avg_path_len);
321
322 igraph_vector_bool_destroy(&periodic);
323 igraph_vector_int_destroy(&dimvector);
324 igraph_vector_int_destroy(&edges);
325 igraph_destroy(&graph);
326
327 return 0;
328 }
329 */
330
331 unsafe {
332 let mut graph = mem::zeroed::<igraph_t>();
333 igraph_setup();
334 let mut dimvector = mem::zeroed::<igraph_vector_int_t>();
335 let mut periodic = mem::zeroed::<igraph_vector_bool_t>();
336 igraph_vector_int_init(&mut dimvector, 2);
337 igraph_vector_int_set(&mut dimvector, 0, 30);
338 igraph_vector_int_set(&mut dimvector, 1, 30);
339
340 igraph_vector_bool_init(&mut periodic, 2);
341 igraph_vector_bool_fill(&mut periodic, true);
342 igraph_square_lattice(
343 &mut graph,
344 &dimvector,
345 0,
346 IGRAPH_UNDIRECTED == 1,
347 false,
348 &periodic,
349 );
350
351 let mut avg_path_len = 0.0;
352 igraph_average_path_length(
353 &graph,
354 std::ptr::null(),
355 &mut avg_path_len,
356 std::ptr::null_mut(),
357 IGRAPH_UNDIRECTED == 1,
358 true,
359 );
360 println!("Average path length (lattice): {}", avg_path_len);
361
362 let rng = igraph_rng_default();
363 igraph_rng_seed(rng, 42);
364
365 let mut edges = mem::zeroed::<igraph_vector_int_t>();
366 igraph_vector_int_init(&mut edges, 20);
367 for i in 0..igraph_vector_int_size(&edges) {
368 let rand_vertex = igraph_rng_get_integer(rng, 0, igraph_vcount(&graph) - 1);
369 igraph_vector_int_set(&mut edges, i, rand_vertex);
370 }
371
372 igraph_add_edges(&mut graph, &edges, std::ptr::null());
373 igraph_average_path_length(
374 &graph,
375 std::ptr::null(),
376 &mut avg_path_len,
377 std::ptr::null_mut(),
378 IGRAPH_UNDIRECTED == 1,
379 true,
380 );
381 println!("Average path length (randomized lattice): {}", avg_path_len);
382
383 igraph_vector_bool_destroy(&mut periodic);
384 }
385}
386
387/// In our next example we will calculate various centrality measures in a friendship graph.
388/// The friendship graph is from the famous Zachary karate club study.
389/// (Do a web search on "Zachary karate" if you want to know more about this.)
390/// Centrality measures quantify how central is the position of individual vertices in the graph.
391///
392fn example_3() {
393 /*
394 int main(void) {
395 igraph_t graph;
396 igraph_vector_int_t result;
397 igraph_vector_t result_real;
398 igraph_int_t edges_array[] = {
399 0,1, 0,2, 0,3, 0,4, 0,5, 0,6, 0,7, 0,8,
400 0,10, 0,11, 0,12, 0,13, 0,17, 0,19, 0,21, 0,31,
401 1, 2, 1, 3, 1, 7, 1,13, 1,17, 1,19, 1,21, 1,30,
402 2, 3, 2, 7, 2,27, 2,28, 2,32, 2, 9, 2, 8, 2,13,
403 3, 7, 3,12, 3,13, 4, 6, 4,10, 5, 6, 5,10, 5,16,
404 6,16, 8,30, 8,32, 8,33, 9,33, 13,33, 14,32, 14,33,
405 15,32, 15,33, 18,32, 18,33, 19,33, 20,32, 20,33,
406 22,32, 22,33, 23,25, 23,27, 23,32, 23,33, 23,29,
407 24,25, 24,27, 24,31, 25,31, 26,29, 26,33, 27,33,
408 28,31, 28,33, 29,32, 29,33, 30,32, 30,33, 31,32,
409 31,33, 32,33
410 };
411 igraph_vector_int_t edges =
412 igraph_vector_int_view(edges_array, sizeof(edges_array) / sizeof(edges_array[0]));
413
414 /* Initialize the library. */
415 igraph_setup();
416
417 igraph_create(&graph, &edges, 0, IGRAPH_UNDIRECTED);
418
419 igraph_vector_int_init(&result, 0);
420 igraph_vector_init(&result_real, 0);
421
422 igraph_degree(&graph, &result, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
423 printf("Maximum degree is %10" IGRAPH_PRId ", vertex %2" IGRAPH_PRId ".\n",
424 igraph_vector_int_max(&result),
425 igraph_vector_int_which_max(&result));
426
427 igraph_closeness(&graph, &result_real, NULL, NULL, igraph_vss_all(),
428 IGRAPH_ALL, /* weights= */ NULL, /* normalized= */ false);
429 printf("Maximum closeness is %10g, vertex %2" IGRAPH_PRId ".\n",
430 (double) igraph_vector_max(&result_real),
431 igraph_vector_which_max(&result_real));
432
433 igraph_betweenness(&graph, /* weights= */ NULL, &result_real, igraph_vss_all(),
434 IGRAPH_UNDIRECTED, /* normalized= */ false);
435 printf("Maximum betweenness is %10g, vertex %2" IGRAPH_PRId ".\n",
436 (double) igraph_vector_max(&result_real),
437 igraph_vector_which_max(&result_real));
438
439 igraph_vector_int_destroy(&result);
440 igraph_vector_destroy(&result_real);
441 igraph_destroy(&graph);
442
443 return 0;
444 }
445 */
446
447 unsafe {
448 let mut graph = mem::zeroed::<igraph_t>();
449
450 let edges_array: [i64; 156] = [
451 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 10, 0, 11, 0, 12, 0, 13, 0, 17, 0,
452 19, 0, 21, 0, 31, 1, 2, 1, 3, 1, 7, 1, 13, 1, 17, 1, 19, 1, 21, 1, 30, 2, 3, 2, 7, 2,
453 27, 2, 28, 2, 32, 2, 9, 2, 8, 2, 13, 3, 7, 3, 12, 3, 13, 4, 6, 4, 10, 5, 6, 5, 10, 5,
454 16, 6, 16, 8, 30, 8, 32, 8, 33, 9, 33, 13, 33, 14, 32, 14, 33, 15, 32, 15, 33, 18, 32,
455 18, 33, 19, 33, 20, 32, 20, 33, 22, 32, 22, 33, 23, 25, 23, 27, 23, 32, 23, 33, 23, 29,
456 24, 25, 24, 27, 24, 31, 25, 31, 26, 29, 26, 33, 27, 33, 28, 31, 28, 33, 29, 32, 29, 33,
457 30, 32, 30, 33, 31, 32, 31, 33, 32, 33,
458 ];
459 let edges = igraph_vector_int_view(edges_array.as_ptr(), edges_array.len() as i64);
460
461 igraph_setup();
462
463 igraph_create(&mut graph, &edges, 0, IGRAPH_UNDIRECTED == 1);
464
465 let mut result = mem::zeroed::<igraph_vector_int_t>();
466 let mut result_real = mem::zeroed::<igraph_vector_t>();
467 igraph_vector_int_init(&mut result, 0);
468 igraph_vector_init(&mut result_real, 0);
469
470 igraph_degree(
471 &graph,
472 &mut result,
473 igraph_vss_all(),
474 igraph_neimode_t_IGRAPH_ALL,
475 IGRAPH_LOOPS_SW,
476 );
477 println!(
478 "Maximum degree is {:10}, vertex {:2}.",
479 igraph_vector_int_max(&result),
480 igraph_vector_int_which_max(&result),
481 );
482
483 igraph_closeness(
484 &graph,
485 &mut result_real,
486 std::ptr::null_mut(),
487 std::ptr::null_mut(),
488 igraph_vss_all(),
489 igraph_neimode_t_IGRAPH_ALL,
490 std::ptr::null(),
491 false,
492 );
493 println!(
494 "Maximum closeness is {:10}, vertex {:2}.",
495 igraph_vector_max(&result_real),
496 igraph_vector_which_max(&result_real)
497 );
498
499 igraph_betweenness(
500 &graph,
501 std::ptr::null(),
502 &mut result_real,
503 igraph_vss_all(),
504 IGRAPH_UNDIRECTED == 1,
505 false,
506 );
507 println!(
508 "Maximum betweenness is {:10}, vertex {:2}.",
509 igraph_vector_max(&result_real),
510 igraph_vector_which_max(&result_real)
511 );
512
513 igraph_vector_destroy(&mut result_real);
514 }
515}
516
517#[cfg(test)]
518mod tests {
519
520 use super::*;
521
522 #[test]
523 fn test_igraph_version() {
524 let major = IGRAPH_VERSION_MAJOR;
525 let minor = IGRAPH_VERSION_MINOR;
526 let patch = IGRAPH_VERSION_PATCH;
527 assert!(major == 1);
528 assert!(minor == 0);
529 assert!(patch == 0);
530 }
531
532 #[test]
533 fn test_igraph_tutorial() {
534 igraph_t::setup();
535 let _rng = igraph_rng_t::seed(42).unwrap();
536 example_1();
537 example_2();
538 // example_3();
539 }
540}