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}