Skip to main content

igraph/
operators.rs

1//! Graph operators: unions, intersections, complements, subgraphs,
2//! simplification, rewiring and graph products (`igraph_operators.h`).
3//!
4//! This module turns the operators of igraph's
5//! [Graph Operators](https://igraph.org/c/html/latest/igraph-Operators.html)
6//! chapter into methods of [`Graph`]. Operators that *build a new graph*
7//! borrow their operands (`&self`) and return a fresh [`Graph`]; operators
8//! that igraph performs *in place* take `&mut self`
9//! ([`simplify`](Graph::simplify), [`contract_vertices`](Graph::contract_vertices),
10//! [`connect_neighborhood`](Graph::connect_neighborhood),
11//! [`reverse_edges`](Graph::reverse_edges), [`rewire`](Graph::rewire)). Clone the
12//! graph first if you need to keep the original.
13//!
14//! Operators working on *many* graphs at once (e.g.
15//! [`Graph::union_many`]) are associated functions accepting any iterator of
16//! graph references, such as `[&g1, &g2, &g3]` or `graphs.iter()`.
17//!
18//! As in igraph, vertex ids are never "matched by name": two graphs are
19//! combined by *identifying vertices with the same id*. Unless stated
20//! otherwise, the operands must have the same directedness, and graph,
21//! vertex and edge attributes are not handled by these wrappers.
22//!
23//! # Example
24//!
25//! ```
26//! use igraph::prelude::*;
27//!
28//! // A 4-cycle and a "diagonal" graph on the same vertex set.
29//! let square = Graph::ring(4, false, false, true).unwrap();
30//! let diagonals = Graph::from_edges(&[(0, 2), (1, 3)], 4, false).unwrap();
31//!
32//! // Their union is K4, the complement of the square is the diagonals.
33//! let k4 = square.union(&diagonals).unwrap();
34//! assert_eq!(k4, Graph::full(4, false, false).unwrap());
35//! assert_eq!(square.complementer(false).unwrap(), diagonals);
36//! assert_eq!(k4.difference(&square).unwrap(), diagonals);
37//!
38//! // Two disjoint copies of the square, then the subgraph induced by one of them.
39//! let two = square.disjoint_union(&square).unwrap();
40//! assert_eq!((two.vcount(), two.ecount()), (8, 8));
41//! let back = two.induced_subgraph(4..8, SubgraphImplementation::Auto).unwrap();
42//! assert_eq!(back, square);
43//!
44//! // The Cartesian product of two edges is a square (up to relabeling).
45//! let edge = Graph::full(2, false, false).unwrap();
46//! let prod = edge.product(&edge, Product::Cartesian).unwrap();
47//! assert!(prod.isomorphic(&square).unwrap());
48//! ```
49//!
50//! # Provided functionality
51//!
52//! | Rust | C function | What it does |
53//! |------|------------|--------------|
54//! | [`Graph::disjoint_union`] | `igraph_disjoint_union` | side-by-side copy of two graphs |
55//! | [`Graph::disjoint_union_many`] | `igraph_disjoint_union_many` | side-by-side copy of many graphs |
56//! | [`Graph::union`], [`Graph::union_map`] | `igraph_union` | edges in either graph (+ edge maps) |
57//! | [`Graph::union_many`], [`Graph::union_many_map`] | `igraph_union_many` | edges in any graph (+ edge maps) |
58//! | [`Graph::intersection`], [`Graph::intersection_map`] | `igraph_intersection` | edges in both graphs (+ edge maps) |
59//! | [`Graph::intersection_many`], [`Graph::intersection_many_map`] | `igraph_intersection_many` | edges in all graphs (+ edge maps) |
60//! | [`Graph::difference`] | `igraph_difference` | edges of the first graph missing from the second |
61//! | [`Graph::join`] | `igraph_join` | disjoint union plus all edges between the two parts |
62//! | [`Graph::complementer`] | `igraph_complementer` | complement graph |
63//! | [`Graph::compose`], [`Graph::compose_map`] | `igraph_compose` | composition of relations |
64//! | [`Graph::contract_vertices`] | `igraph_contract_vertices` | merge groups of vertices (in place) |
65//! | [`Graph::permute_vertices`] | `igraph_permute_vertices` | relabel vertices |
66//! | [`Graph::connect_neighborhood`] | `igraph_connect_neighborhood` | connect vertices within `k` steps (in place) |
67//! | [`Graph::graph_power`] | `igraph_graph_power` | the `k`-th power of a graph |
68//! | [`Graph::rewire`] | `igraph_rewire` | degree-preserving random edge switches (in place) |
69//! | [`Graph::simplify`] | `igraph_simplify` | remove multi-edges and/or loops (in place) |
70//! | [`Graph::induced_subgraph`] | `igraph_induced_subgraph` | subgraph induced by a vertex set |
71//! | [`Graph::induced_subgraph_map`] | `igraph_induced_subgraph_map` | same, with the vertex id maps |
72//! | [`Graph::induced_subgraph_edges`] | `igraph_induced_subgraph_edges` | ids of the edges inside a vertex set |
73//! | [`Graph::subgraph_from_edges`] | `igraph_subgraph_from_edges` | subgraph spanned by an edge set |
74//! | [`Graph::reverse_edges`] | `igraph_reverse_edges` | flip the direction of some edges (in place) |
75//! | [`Graph::product`] | `igraph_product` | Cartesian, lexicographic, strong, tensor, modular products |
76//! | [`Graph::rooted_product`] | `igraph_rooted_product` | rooted product |
77//! | [`Graph::mycielskian`] | `igraph_mycielskian` | iterated Mycielski construction |
78//!
79//! `igraph_add_edge`, also declared in this header, is wrapped by the core
80//! method [`Graph::add_edge`].
81//!
82//! # See also
83//!
84//! - Ready-made graphs to feed these operators: [`Graph::famous`],
85//!   [`Graph::full`], [`Graph::ring`], [`Graph::square_lattice`],
86//!   [`Graph::hypercube`], [`Graph::wheel`], [`Graph::mycielski_graph`]
87//!   (`constructors`) and [`Graph::full_bipartite`] (`bipartite`).
88//! - Comparing results: `==` compares *labelled* graphs
89//!   ([`Graph::is_same_graph`]); [`Graph::isomorphic`] and
90//!   [`Graph::canonical_permutation`] (`isomorphism`) compare structure up
91//!   to relabeling.
92//! - Other ways to cut a graph apart: [`Graph::delete_vertices`] (core),
93//!   [`Graph::decompose`] and [`Graph::neighborhood_graphs`] (`components`).
94//! - Other randomizations: [`Graph::rewire_edges`] and
95//!   [`Graph::degree_sequence_game`] (`games`).
96//! - Changing directedness rather than edges: [`Graph::to_directed`] and
97//!   [`Graph::to_undirected`] (`conversion`).
98
99use crate::{
100    constants::*,
101    error::{Error, Result},
102    ffi::*,
103    graph::{EdgeId, Graph, VertexId},
104    igraph_call,
105    list::VectorIntList,
106    selector::{EdgeSelector, VertexSelector},
107    vector::VectorInt,
108};
109use std::{ffi::c_void, mem::MaybeUninit, ptr};
110
111/// A graph produced by a binary operator, together with the edge maps that
112/// relate its edges to the edges of the two operands.
113///
114/// The meaning (and the length) of the maps depends on the operator: see
115/// [`Graph::union_map`], [`Graph::intersection_map`] and [`Graph::compose_map`].
116#[derive(Debug, Clone, PartialEq)]
117pub struct EdgeMapped {
118    /// The resulting graph.
119    pub graph: Graph,
120    /// Edge map relating the result to the first operand (`self`).
121    pub edge_map1: Vec<EdgeId>,
122    /// Edge map relating the result to the second operand.
123    pub edge_map2: Vec<EdgeId>,
124}
125
126/// A graph produced by an operator on many graphs, together with one edge
127/// map per operand (see [`Graph::union_many_map`] and
128/// [`Graph::intersection_many_map`]).
129#[derive(Debug, Clone, PartialEq)]
130pub struct EdgeMappedMany {
131    /// The resulting graph.
132    pub graph: Graph,
133    /// `edge_maps[i][e]` is the id, in [`graph`](Self::graph), of edge `e`
134    /// of the `i`-th operand, or `None` if that edge has no image.
135    pub edge_maps: Vec<Vec<Option<EdgeId>>>,
136}
137
138/// An induced subgraph together with the correspondence between its
139/// vertices and the vertices of the original graph (see
140/// [`Graph::induced_subgraph_map`]).
141#[derive(Debug, Clone, PartialEq)]
142pub struct InducedSubgraph {
143    /// The induced subgraph.
144    pub graph: Graph,
145    /// `map[v]` is the id in [`graph`](Self::graph) of the original vertex
146    /// `v`, or `None` if `v` was not selected. Its length is the vertex
147    /// count of the original graph.
148    pub map: Vec<Option<VertexId>>,
149    /// `invmap[w]` is the original id of vertex `w` of the subgraph. Its
150    /// length is the vertex count of the subgraph.
151    pub invmap: Vec<VertexId>,
152}
153
154/// Statistics of a [`Graph::rewire`] run (`igraph_rewiring_stats_t`).
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
156pub struct RewiringStats {
157    /// Number of rewiring trials that actually switched a pair of edges.
158    pub successful_swaps: usize,
159}
160
161/// An `igraph_vector_ptr_t` of *borrowed* graph pointers, destroyed (but
162/// without touching the graphs) on drop. The borrow keeps the graphs alive.
163struct GraphPtrs<'a> {
164    raw: igraph_vector_ptr_t,
165    _graphs: Vec<&'a Graph>,
166}
167
168impl<'a> GraphPtrs<'a> {
169    fn new(graphs: impl IntoIterator<Item = &'a Graph>) -> Result<Self> {
170        let graphs: Vec<&'a Graph> = graphs.into_iter().collect();
171        let mut raw = MaybeUninit::<igraph_vector_ptr_t>::uninit();
172        igraph_call!(igraph_vector_ptr_init(
173            raw.as_mut_ptr(),
174            graphs.len() as igraph_int_t
175        ))?;
176        let mut raw = unsafe { raw.assume_init() };
177        for (i, g) in graphs.iter().enumerate() {
178            // igraph only reads the graphs: the const-to-mut cast is harmless.
179            let p = *g as *const Graph as *mut c_void;
180            unsafe { igraph_vector_ptr_set(&mut raw, i as igraph_int_t, p) };
181        }
182        Ok(Self {
183            raw,
184            _graphs: graphs,
185        })
186    }
187
188    fn as_ptr(&self) -> *const igraph_vector_ptr_t {
189        &self.raw
190    }
191}
192
193impl Drop for GraphPtrs<'_> {
194    fn drop(&mut self) {
195        // No item destructor is set: only the pointer array is freed.
196        unsafe { igraph_vector_ptr_destroy(&mut self.raw) };
197    }
198}
199
200/// Runs `f` with the raw `igraph_vs_t` of `sel`.
201///
202/// Vertex lists are viewed in place (the view stays at a fixed address for
203/// the whole call, as `igraph_vss_vector` stores a pointer to it); other
204/// selectors go through [`VertexSelector::to_raw`].
205fn with_vs<R>(sel: VertexSelector<'_>, f: impl FnOnce(igraph_vs_t) -> Result<R>) -> Result<R> {
206    match &sel {
207        VertexSelector::List(list) => {
208            crate::error::ensure_init();
209            let view = VectorInt::view(list);
210            let vs = unsafe { igraph_vss_vector(view.as_ptr()) };
211            f(vs)
212        }
213        _ => {
214            let raw = sel.to_raw()?;
215            f(raw.get())
216        }
217    }
218}
219
220/// Runs `f` with the raw `igraph_es_t` of `sel` (see [`with_vs`]).
221fn with_es<R>(sel: EdgeSelector<'_>, f: impl FnOnce(igraph_es_t) -> Result<R>) -> Result<R> {
222    match &sel {
223        EdgeSelector::List(list) => {
224            crate::error::ensure_init();
225            let view = VectorInt::view(list);
226            let es = unsafe { igraph_ess_vector(view.as_ptr()) };
227            f(es)
228        }
229        _ => {
230            let raw = sel.to_raw()?;
231            f(raw.get())
232        }
233    }
234}
235
236/// Converts a Rust count into an `igraph_int_t`, rejecting values that do
237/// not fit (a plain `as` cast would turn them into negative numbers).
238fn to_int(n: usize, what: &str) -> Result<igraph_int_t> {
239    igraph_int_t::try_from(n).map_err(|_| Error::invalid(format!("{what} is too large: {n}")))
240}
241
242/// Converts igraph's `-1`-means-missing id vectors into `Option`s.
243fn optional_ids(ids: &[igraph_int_t]) -> Vec<Option<igraph_int_t>> {
244    ids.iter().map(|&i| (i >= 0).then_some(i)).collect()
245}
246
247impl igraph_t {
248    /// The disjoint union of two graphs.
249    ///
250    /// The vertices of `other` are relabeled so that the two vertex sets are
251    /// disjoint: vertex and edge ids of `self` are unchanged, while those of
252    /// `other` are shifted by the vertex and edge counts of `self`. The
253    /// result has `|V1|+|V2|` vertices and `|E1|+|E2|` edges.
254    ///
255    /// See also [`decompose`](Self::decompose), which splits a graph back
256    /// into its connected components.
257    ///
258    /// Binds [`igraph_disjoint_union`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_disjoint_union).
259    /// Time complexity: O(|V1|+|V2|+|E1|+|E2|).
260    ///
261    /// # Errors
262    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the two
263    /// graphs do not have the same directedness.
264    ///
265    /// # Examples
266    /// ```
267    /// use igraph::prelude::*;
268    /// let a = Graph::from_edges(&[(0, 1)], 2, false).unwrap();
269    /// let b = Graph::from_edges(&[(0, 1), (1, 2)], 3, false).unwrap();
270    /// let u = a.disjoint_union(&b).unwrap();
271    /// assert_eq!(u.edge_list(), vec![(0, 1), (2, 3), (3, 4)]);
272    /// ```
273    pub fn disjoint_union(&self, other: &Graph) -> Result<Graph> {
274        Graph::init_with(|res| unsafe { igraph_disjoint_union(res, self, other) })
275    }
276
277    /// The disjoint union of many graphs, laid side by side in the given
278    /// order (see [`disjoint_union`](Self::disjoint_union)).
279    ///
280    /// Vertex and edge ids of each operand are shifted by the total vertex
281    /// and edge counts of the operands before it. With no operand at all the
282    /// result is a *directed* graph with no vertices, as in igraph.
283    ///
284    /// Binds [`igraph_disjoint_union_many`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_disjoint_union_many).
285    /// Time complexity: O(|V|+|E|) of the result.
286    ///
287    /// # Errors
288    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the
289    /// graphs have mixed directedness.
290    ///
291    /// # Examples
292    /// ```
293    /// use igraph::prelude::*;
294    /// let triangle = Graph::from_edges(&[(0, 1), (1, 2), (2, 0)], 3, false).unwrap();
295    /// let three = Graph::disjoint_union_many([&triangle, &triangle, &triangle]).unwrap();
296    /// assert_eq!((three.vcount(), three.ecount()), (9, 9));
297    /// assert_eq!(three.edge(8).unwrap(), (6, 8));
298    /// ```
299    pub fn disjoint_union_many<'a>(graphs: impl IntoIterator<Item = &'a Graph>) -> Result<Graph> {
300        let ptrs = GraphPtrs::new(graphs)?;
301        Graph::init_with(|res| unsafe { igraph_disjoint_union_many(res, ptrs.as_ptr()) })
302    }
303
304    /// The union of two graphs on the same vertex ids: an edge is in the
305    /// result if it is in at least one of the operands.
306    ///
307    /// The result has as many vertices as the larger operand. Multi-edges are
308    /// handled by multiplicity: if `self` has `N` edges between `u` and `v`
309    /// and `other` has `M`, the union has `max(N, M)`. Use
310    /// [`union_map`](Self::union_map) to also learn where each edge went.
311    ///
312    /// Binds [`igraph_union`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_union).
313    /// Time complexity: O(|V|+|E|) of the result.
314    ///
315    /// # Errors
316    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the two
317    /// graphs do not have the same directedness.
318    ///
319    /// # Examples
320    /// ```
321    /// use igraph::prelude::*;
322    /// let a = Graph::from_edges(&[(0, 1), (1, 2)], 3, false).unwrap();
323    /// let b = Graph::from_edges(&[(2, 1), (2, 3)], 4, false).unwrap();
324    /// let u = a.union(&b).unwrap();
325    /// assert_eq!(u.vcount(), 4);
326    /// assert_eq!(u.edge_list(), vec![(0, 1), (1, 2), (2, 3)]);
327    /// ```
328    pub fn union(&self, other: &Graph) -> Result<Graph> {
329        Graph::init_with(|res| unsafe {
330            igraph_union(res, self, other, ptr::null_mut(), ptr::null_mut())
331        })
332    }
333
334    /// Like [`union`](Self::union), also returning the edge maps.
335    ///
336    /// In the returned [`EdgeMapped`], `edge_map1[e]` is the id in the union
337    /// of edge `e` of `self` (one entry per edge of `self`), and `edge_map2`
338    /// is the same for `other`.
339    ///
340    /// Binds [`igraph_union`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_union).
341    ///
342    /// # Examples
343    /// ```
344    /// use igraph::prelude::*;
345    /// let a = Graph::from_edges(&[(0, 1), (1, 2)], 3, true).unwrap();
346    /// let b = Graph::from_edges(&[(1, 2), (2, 0)], 3, true).unwrap();
347    /// let u = a.union_map(&b).unwrap();
348    /// assert_eq!(u.graph.edge_list(), vec![(0, 1), (1, 2), (2, 0)]);
349    /// assert_eq!(u.edge_map1, vec![0, 1]);
350    /// assert_eq!(u.edge_map2, vec![1, 2]); // the shared edge 1->2 is edge 1
351    /// ```
352    pub fn union_map(&self, other: &Graph) -> Result<EdgeMapped> {
353        let mut m1 = VectorInt::new();
354        let mut m2 = VectorInt::new();
355        let graph =
356            Graph::init_with(|res| unsafe { igraph_union(res, self, other, &mut m1, &mut m2) })?;
357        Ok(EdgeMapped {
358            graph,
359            edge_map1: m1.into(),
360            edge_map2: m2.into(),
361        })
362    }
363
364    /// The union of many graphs: an edge is in the result if it is in at
365    /// least one operand, with the *maximum* of the multiplicities.
366    ///
367    /// The result has as many vertices as the largest operand. With no
368    /// operand at all the result is a *directed* graph with no vertices.
369    ///
370    /// Binds [`igraph_union_many`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_union_many).
371    /// Time complexity: O(|V|+|E|), |V| the vertex count of the largest
372    /// graph and |E| the edge count of the result.
373    ///
374    /// # Errors
375    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the
376    /// graphs have mixed directedness.
377    ///
378    /// # Examples
379    /// ```
380    /// use igraph::prelude::*;
381    /// // The three "spokes" of a star, as three single-edge graphs.
382    /// let spokes: Vec<Graph> =
383    ///     (1..4).map(|i| Graph::from_edges(&[(0, i)], 0, false).unwrap()).collect();
384    /// let star = Graph::union_many(&spokes).unwrap();
385    /// let mut edges = star.edge_list();
386    /// edges.sort();
387    /// assert_eq!(edges, vec![(0, 1), (0, 2), (0, 3)]);
388    /// ```
389    pub fn union_many<'a>(graphs: impl IntoIterator<Item = &'a Graph>) -> Result<Graph> {
390        let ptrs = GraphPtrs::new(graphs)?;
391        Graph::init_with(|res| unsafe { igraph_union_many(res, ptrs.as_ptr(), ptr::null_mut()) })
392    }
393
394    /// Like [`union_many`](Self::union_many), also returning, for each
395    /// operand, the id in the union of each of its edges.
396    ///
397    /// Binds [`igraph_union_many`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_union_many).
398    pub fn union_many_map<'a>(
399        graphs: impl IntoIterator<Item = &'a Graph>,
400    ) -> Result<EdgeMappedMany> {
401        let ptrs = GraphPtrs::new(graphs)?;
402        let mut maps = VectorIntList::new();
403        let graph =
404            Graph::init_with(|res| unsafe { igraph_union_many(res, ptrs.as_ptr(), &mut maps) })?;
405        let edge_maps = maps.iter().map(|m| optional_ids(m)).collect();
406        Ok(EdgeMappedMany { graph, edge_maps })
407    }
408
409    /// The intersection of two graphs on the same vertex ids: an edge is in
410    /// the result if it is in both operands.
411    ///
412    /// The result has as many vertices as the larger operand. Multi-edges are
413    /// handled by multiplicity: if `self` has `N` edges between `u` and `v`
414    /// and `other` has `M`, the intersection has `min(N, M)`.
415    ///
416    /// Binds [`igraph_intersection`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_intersection).
417    /// Time complexity: O(|V|+|E|), |E| the edge count of the smaller graph.
418    ///
419    /// # Errors
420    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the two
421    /// graphs do not have the same directedness.
422    ///
423    /// # Examples
424    /// ```
425    /// use igraph::prelude::*;
426    /// let a = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 4, false).unwrap();
427    /// let b = Graph::from_edges(&[(2, 1), (3, 0), (3, 2)], 4, false).unwrap();
428    /// assert_eq!(a.intersection(&b).unwrap().edge_list(), vec![(1, 2), (2, 3)]);
429    /// ```
430    pub fn intersection(&self, other: &Graph) -> Result<Graph> {
431        Graph::init_with(|res| unsafe {
432            igraph_intersection(res, self, other, ptr::null_mut(), ptr::null_mut())
433        })
434    }
435
436    /// Like [`intersection`](Self::intersection), also returning the edge maps.
437    ///
438    /// Note the direction of the maps, which differs from
439    /// [`union_map`](Self::union_map): they are indexed by the edges of the
440    /// *result*, i.e. `edge_map1[e]` is the id in `self` of edge `e` of the
441    /// intersection, and `edge_map2[e]` its id in `other`. Both have as many
442    /// entries as the intersection has edges.
443    ///
444    /// Binds [`igraph_intersection`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_intersection).
445    ///
446    /// # Examples
447    /// Taken from igraph's `igraph_intersection.c` example:
448    /// ```
449    /// use igraph::prelude::*;
450    /// let left = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 0, true).unwrap();
451    /// let right = Graph::from_edges(&[(1, 0), (5, 4), (1, 2), (3, 2)], 0, true).unwrap();
452    /// let isec = left.intersection_map(&right).unwrap();
453    /// assert_eq!(isec.graph.edge_list(), vec![(1, 2)]);
454    /// assert_eq!((isec.edge_map1, isec.edge_map2), (vec![1], vec![2]));
455    /// ```
456    pub fn intersection_map(&self, other: &Graph) -> Result<EdgeMapped> {
457        let mut m1 = VectorInt::new();
458        let mut m2 = VectorInt::new();
459        let graph = Graph::init_with(|res| unsafe {
460            igraph_intersection(res, self, other, &mut m1, &mut m2)
461        })?;
462        Ok(EdgeMapped {
463            graph,
464            edge_map1: m1.into(),
465            edge_map2: m2.into(),
466        })
467    }
468
469    /// The intersection of many graphs: an edge is in the result if it is in
470    /// every operand, with the *minimum* of the multiplicities.
471    ///
472    /// The result has as many vertices as the largest operand. With no
473    /// operand at all the result is a *directed* graph with no vertices.
474    ///
475    /// Binds [`igraph_intersection_many`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_intersection_many).
476    /// Time complexity: O(|V|+|E|), |E| the edge count of the smallest graph.
477    ///
478    /// # Errors
479    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the
480    /// graphs have mixed directedness.
481    ///
482    /// # Examples
483    /// ```
484    /// use igraph::prelude::*;
485    /// let a = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 4, false).unwrap();
486    /// let b = Graph::from_edges(&[(0, 1), (1, 2)], 4, false).unwrap();
487    /// let c = Graph::from_edges(&[(1, 2), (0, 3)], 4, false).unwrap();
488    /// assert_eq!(Graph::intersection_many([&a, &b, &c]).unwrap().edge_list(), vec![(1, 2)]);
489    /// ```
490    pub fn intersection_many<'a>(graphs: impl IntoIterator<Item = &'a Graph>) -> Result<Graph> {
491        let ptrs = GraphPtrs::new(graphs)?;
492        Graph::init_with(|res| unsafe {
493            igraph_intersection_many(res, ptrs.as_ptr(), ptr::null_mut())
494        })
495    }
496
497    /// Like [`intersection_many`](Self::intersection_many), also returning,
498    /// for each operand, the id in the result of each of its edges (`None`
499    /// for edges that are not in the intersection).
500    ///
501    /// Unlike [`intersection_map`](Self::intersection_map), these maps are
502    /// indexed by the edges of the *operands*.
503    ///
504    /// Binds [`igraph_intersection_many`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_intersection_many).
505    pub fn intersection_many_map<'a>(
506        graphs: impl IntoIterator<Item = &'a Graph>,
507    ) -> Result<EdgeMappedMany> {
508        let ptrs = GraphPtrs::new(graphs)?;
509        let mut maps = VectorIntList::new();
510        let graph = Graph::init_with(|res| unsafe {
511            igraph_intersection_many(res, ptrs.as_ptr(), &mut maps)
512        })?;
513        let edge_maps = maps.iter().map(|m| optional_ids(m)).collect();
514        Ok(EdgeMappedMany { graph, edge_maps })
515    }
516
517    /// The difference of two graphs: the edges of `self` that are not in
518    /// `sub`, on the vertex set of `self`.
519    ///
520    /// Multi-edges are subtracted by multiplicity. The result always has the
521    /// same number of vertices as `self`.
522    ///
523    /// Binds [`igraph_difference`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_difference).
524    /// Time complexity: O(|V|+|E|), |V| the vertex count of the smaller graph
525    /// and |E| the edge count of the result.
526    ///
527    /// # Errors
528    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the two
529    /// graphs do not have the same directedness.
530    ///
531    /// # Examples
532    /// From igraph's `igraph_difference.c` example:
533    /// ```
534    /// use igraph::prelude::*;
535    /// let orig = Graph::from_edges(&[(0, 1), (1, 2), (2, 1), (4, 5), (8, 9)], 0, true).unwrap();
536    /// let sub = Graph::from_edges(&[(0, 1), (5, 4), (2, 1), (6, 7)], 0, true).unwrap();
537    /// let diff = orig.difference(&sub).unwrap();
538    /// assert_eq!(diff.vcount(), 10);
539    /// assert_eq!(diff.edge_list(), vec![(1, 2), (4, 5), (8, 9)]);
540    /// ```
541    pub fn difference(&self, sub: &Graph) -> Result<Graph> {
542        Graph::init_with(|res| unsafe { igraph_difference(res, self, sub) })
543    }
544
545    /// The join of two graphs: their [disjoint union](Self::disjoint_union)
546    /// plus an edge between every vertex of `self` and every vertex of
547    /// `other`.
548    ///
549    /// The result has `|V1|+|V2|` vertices and `|E1|+|E2|+|V1||V2|` edges;
550    /// for directed graphs both `(v, u)` and `(u, v)` are added, i.e.
551    /// `|E1|+|E2|+2|V1||V2|` edges. Vertex ids of `other` are shifted by
552    /// `|V1|`. For example, the join of an empty graph on `m` vertices and
553    /// one on `n` vertices is the complete bipartite graph `K(m,n)`.
554    ///
555    /// See also [`Graph::full_bipartite`] and [`Graph::wheel`], which build
556    /// the classic joins (`K(m,n)`, and a single vertex joined to a cycle)
557    /// directly.
558    ///
559    /// Binds [`igraph_join`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_join).
560    /// Time complexity: O(|V1||V2|+|E1|+|E2|).
561    ///
562    /// # Errors
563    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the two
564    /// graphs do not have the same directedness.
565    ///
566    /// # Examples
567    /// ```
568    /// use igraph::prelude::*;
569    /// // K(2,3) as the join of two edgeless graphs.
570    /// let k23 = Graph::new(2, false).join(&Graph::new(3, false)).unwrap();
571    /// assert_eq!(k23.ecount(), 6);
572    /// assert_eq!(k23.neighbors(0, NeighborMode::All).unwrap(), vec![2, 3, 4]);
573    /// assert_eq!(k23, Graph::full_bipartite(2, 3, false, NeighborMode::All).unwrap().graph);
574    /// ```
575    pub fn join(&self, other: &Graph) -> Result<Graph> {
576        Graph::init_with(|res| unsafe { igraph_join(res, self, other) })
577    }
578
579    /// The complement of the graph: all the edges that are *not* in `self`.
580    ///
581    /// With `loops = true` self-loops are added to every vertex that has
582    /// none. For directed graphs, edge directions are taken into account.
583    /// Multi-edges in the input are treated like single edges.
584    ///
585    /// See also [`Graph::full`]: the complement of the edgeless graph on `n`
586    /// vertices is the complete graph `K_n`.
587    ///
588    /// Binds [`igraph_complementer`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_complementer).
589    /// Time complexity: O(|V|+|E1|+|E2|), |E1| and |E2| the edge counts of
590    /// the graph and of its complement.
591    ///
592    /// # Examples
593    /// ```
594    /// use igraph::prelude::*;
595    /// // The path 0-1-2-3 is self-complementary: its complement is 2-0-3-1.
596    /// let p4 = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 4, false).unwrap();
597    /// let mut comp = p4.complementer(false).unwrap().edge_list();
598    /// comp.sort();
599    /// assert_eq!(comp, vec![(0, 2), (0, 3), (1, 3)]);
600    /// ```
601    pub fn complementer(&self, loops: bool) -> Result<Graph> {
602        Graph::init_with(|res| unsafe { igraph_complementer(res, self, loops) })
603    }
604
605    /// The composition `self ∘ other` of two graphs, seen as binary relations.
606    ///
607    /// The result contains an edge `(i, j)` for every vertex `k` such that
608    /// `self` has an edge `(i, k)` and `other` has an edge `(k, j)`: it may
609    /// thus contain multi-edges (one per such `k`) and self-loops (e.g.
610    /// `(i, i)` from `i -> k` in `self` and `k -> i` in `other`, which for
611    /// undirected graphs happens for every edge the two operands share at
612    /// `k`). The result has as many vertices as the larger operand.
613    ///
614    /// Binds [`igraph_compose`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_compose).
615    /// Time complexity: O(|V| d1 d2), d1 and d2 the average degrees.
616    ///
617    /// # Errors
618    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the two
619    /// graphs do not have the same directedness.
620    ///
621    /// # Examples
622    /// ```
623    /// use igraph::prelude::*;
624    /// // "parent of" composed with itself is "grandparent of".
625    /// let parent = Graph::from_edges(&[(0, 1), (1, 2), (1, 3), (3, 4)], 5, true).unwrap();
626    /// let mut grandparent = parent.compose(&parent).unwrap().edge_list();
627    /// grandparent.sort();
628    /// assert_eq!(grandparent, vec![(0, 2), (0, 3), (1, 4)]);
629    /// ```
630    pub fn compose(&self, other: &Graph) -> Result<Graph> {
631        Graph::init_with(|res| unsafe {
632            igraph_compose(res, self, other, ptr::null_mut(), ptr::null_mut())
633        })
634    }
635
636    /// Like [`compose`](Self::compose), also returning the edge maps:
637    /// `edge_map1[e]` is the edge `(i, k)` of `self`, and `edge_map2[e]` the
638    /// edge `(k, j)` of `other`, that generated edge `e` of the result.
639    ///
640    /// Binds [`igraph_compose`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_compose).
641    pub fn compose_map(&self, other: &Graph) -> Result<EdgeMapped> {
642        let mut m1 = VectorInt::new();
643        let mut m2 = VectorInt::new();
644        let graph =
645            Graph::init_with(|res| unsafe { igraph_compose(res, self, other, &mut m1, &mut m2) })?;
646        Ok(EdgeMapped {
647            graph,
648            edge_map1: m1.into(),
649            edge_map2: m2.into(),
650        })
651    }
652
653    /// Merges groups of vertices into single vertices, in place.
654    ///
655    /// `mapping[v]` is the id, in the contracted graph, of the original
656    /// vertex `v` (so `mapping` must have one entry per vertex). To avoid
657    /// isolated "orphan" vertices, the new ids should be the consecutive
658    /// integers `0..k`; the contracted graph has `max(mapping) + 1`
659    /// vertices. No edge is removed: edges inside a group become self-loops
660    /// and parallel connections between groups become multi-edges; call
661    /// [`simplify`](Self::simplify) afterwards to clean them up. Vertex
662    /// attributes are discarded (edge and graph attributes are kept): use
663    /// [`contract_vertices_with_attributes`](Self::contract_vertices_with_attributes)
664    /// to combine the vertex attributes of each group instead.
665    ///
666    /// A typical `mapping` is a community membership vector, e.g. from
667    /// [`community_multilevel`](Self::community_multilevel), which contracts
668    /// every community to a single vertex. See also
669    /// [`induced_subgraph`](Self::induced_subgraph) to zoom *into* a group
670    /// instead.
671    ///
672    /// Binds [`igraph_contract_vertices`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_contract_vertices).
673    /// Time complexity: O(|V|+|E|).
674    ///
675    /// # Errors
676    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if
677    /// `mapping` does not have one entry per vertex or contains negative ids
678    /// or [`VertexId::MAX`] (the vertex count `max(mapping) + 1` would
679    /// overflow).
680    ///
681    /// # Examples
682    /// ```
683    /// use igraph::prelude::*;
684    /// // Two triangles joined by an edge, contracted to two "super-vertices".
685    /// let mut g = Graph::from_edges(
686    ///     &[(0, 1), (1, 2), (2, 0), (3, 4), (4, 5), (5, 3), (2, 3)], 6, false,
687    /// ).unwrap();
688    /// g.contract_vertices(&[0, 0, 0, 1, 1, 1]).unwrap();
689    /// assert_eq!((g.vcount(), g.ecount()), (2, 7));
690    /// g.simplify(true, true).unwrap();
691    /// assert_eq!(g.edge_list(), vec![(0, 1)]);
692    /// ```
693    pub fn contract_vertices(&mut self, mapping: &[VertexId]) -> Result<()> {
694        if mapping.len() != self.vcount() {
695            return Err(Error::invalid(format!(
696                "the mapping has {} entries but the graph has {} vertices",
697                mapping.len(),
698                self.vcount()
699            )));
700        }
701        // Negative ids index out of bounds in C, and igraph computes the new
702        // vertex count as `max + 1`, which overflows for `VertexId::MAX`.
703        if let Some(&bad) = mapping.iter().find(|&&m| !(0..VertexId::MAX).contains(&m)) {
704            return Err(Error::invalid(format!(
705                "the mapping contains the invalid vertex id {bad}"
706            )));
707        }
708        let m = VectorInt::view(mapping);
709        igraph_call!(igraph_contract_vertices(self, m.as_ptr(), ptr::null()))
710    }
711
712    /// Relabels the vertices according to a permutation, returning a new
713    /// graph.
714    ///
715    /// `permutation[i]` is the id, *in the original graph*, of the vertex
716    /// that becomes vertex `i` of the result. Edge ids are unchanged. Use it
717    /// e.g. with a canonical permutation to obtain the canonical form of a
718    /// graph.
719    ///
720    /// See also [`canonical_permutation`](Self::canonical_permutation) and
721    /// [`canonical_form`](Self::canonical_form) (`isomorphism`), which
722    /// compute such a permutation and apply it.
723    ///
724    /// Binds [`igraph_permute_vertices`](https://igraph.org/c/html/latest/igraph-Isomorphism.html#igraph_permute_vertices).
725    /// Time complexity: O(|V|+|E|).
726    ///
727    /// # Errors
728    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if
729    /// `permutation` is not a permutation of `0..vcount`.
730    ///
731    /// # Examples
732    /// ```
733    /// use igraph::prelude::*;
734    /// let g = Graph::from_edges(&[(0, 1), (1, 2)], 3, true).unwrap();
735    /// // New vertex 0 is old vertex 2, new 1 is old 0, new 2 is old 1.
736    /// let h = g.permute_vertices(&[2, 0, 1]).unwrap();
737    /// assert_eq!(h.edge_list(), vec![(1, 2), (2, 0)]);
738    ///
739    /// // Relabeled copies share the same canonical form.
740    /// let canon = |g: &Graph| g.permute_vertices(&g.canonical_permutation(None).unwrap()).unwrap();
741    /// assert_eq!(canon(&g), canon(&h));
742    /// ```
743    pub fn permute_vertices(&self, permutation: &[VertexId]) -> Result<Graph> {
744        let p = VectorInt::view(permutation);
745        Graph::init_with(|res| unsafe { igraph_permute_vertices(self, res, p.as_ptr()) })
746    }
747
748    /// Connects every vertex to all the vertices reachable from it in at
749    /// most `order` steps, in place.
750    ///
751    /// Existing connections are not duplicated, and for undirected graphs a
752    /// single edge is added per pair. For directed graphs `mode` tells how to
753    /// search: with [`NeighborMode::Out`] each vertex `u` gets an edge
754    /// `u -> v` to every `v` it reaches along directed paths; with
755    /// [`NeighborMode::In`] every `v` reaching `u` gets an edge `v -> u` (so
756    /// the new edges still follow the paths: the same set of edges is added
757    /// as with `Out`, possibly in another order); [`NeighborMode::All`]
758    /// ignores directions and adds a single edge `u -> v` with `u < v` per
759    /// newly connected pair. Orders below 2 leave the graph unchanged. See [`graph_power`](Self::graph_power) for a
760    /// non-mutating variant that also simplifies.
761    ///
762    /// See also [`neighborhood`](Self::neighborhood) (`components`), which
763    /// lists the vertices within `order` steps without changing the graph.
764    ///
765    /// Binds [`igraph_connect_neighborhood`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_connect_neighborhood).
766    /// Time complexity: O(|V| d^k), d the average degree and k the order.
767    ///
768    /// # Errors
769    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if
770    /// `order` does not fit in an `igraph_int_t`.
771    ///
772    /// # Examples
773    /// ```
774    /// use igraph::prelude::*;
775    /// // A ring of 6 vertices where everybody also knows the neighbors' neighbors.
776    /// let edges: Vec<(i64, i64)> = (0..6).map(|i| (i, (i + 1) % 6)).collect();
777    /// let mut g = Graph::from_edges(&edges, 6, false).unwrap();
778    /// g.connect_neighborhood(2, NeighborMode::All).unwrap();
779    /// assert_eq!(g.ecount(), 12);
780    /// assert_eq!(g.degree(.., NeighborMode::All, Loops::Twice).unwrap(), vec![4; 6]);
781    /// ```
782    pub fn connect_neighborhood(&mut self, order: usize, mode: NeighborMode) -> Result<()> {
783        let order = to_int(order, "the order")?;
784        // igraph builds an IGRAPH_NO_MULTIPLE adjacency list in `mode`, which
785        // trusts the cached "has multi-edges" flag: for a directed graph in
786        // `All` mode that flag must not be stale (see
787        // `Graph::with_fresh_multi_cache`). The graph is borrowed mutably, so
788        // the cache is simply dropped before and after the call.
789        self.invalidate_cache();
790        let res = igraph_call!(igraph_connect_neighborhood(self, order, mode.into()));
791        self.invalidate_cache();
792        res
793    }
794
795    /// The `order`-th power of the graph.
796    ///
797    /// It is a simple graph on the same vertices where `u` is connected to
798    /// `v` if `v` is reachable from `u` in at most `order` steps. The zeroth
799    /// power has no edges; the first power is the graph with multi-edges and
800    /// loops removed. With `directed = false` edge directions are ignored and
801    /// the result is undirected. Graph and vertex attributes are kept, edge
802    /// attributes are discarded.
803    ///
804    /// For directed inputs this wrapper clears igraph's cached graph
805    /// properties around the call, working around an igraph 1.0.1 bug that
806    /// could otherwise return a double edge for a mutual pair `u -> v`,
807    /// `v -> u` when directions are ignored, or abort the process on a later
808    /// call (see the source for details). The result is always simple.
809    ///
810    /// Binds [`igraph_graph_power`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_graph_power).
811    /// Time complexity: O(|V| d^k), d the average degree and k the order.
812    ///
813    /// # Errors
814    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if
815    /// `order` does not fit in an `igraph_int_t`.
816    ///
817    /// # Examples
818    /// ```
819    /// use igraph::prelude::*;
820    /// // The square of the path 0-1-2-3.
821    /// let p4 = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 4, false).unwrap();
822    /// let sq = p4.graph_power(2, false).unwrap();
823    /// assert_eq!(sq.ecount(), 5); // everything but (0, 3)
824    /// assert_eq!(sq.get_eid(0, 3, false).unwrap(), None);
825    /// ```
826    pub fn graph_power(&self, order: usize, directed: bool) -> Result<Graph> {
827        let order = to_int(order, "the order")?;
828        // igraph bug (1.0.0 and 1.0.1): `igraph_graph_power` builds an
829        // adjacency list with `igraph_adjlist_init(.., IGRAPH_NO_MULTIPLE)`,
830        // which trusts and updates the graph's cached "has multi-edges" flag.
831        // With directions ignored (mode ALL), a mutual pair `u -> v`,
832        // `v -> u` of a *directed* graph looks like a multi-edge, so:
833        // - if "no multi-edges" was already cached (e.g. by `is_simple`),
834        //   the deduplication is skipped and the result gets a double edge;
835        // - otherwise "has multi-edges" is cached, which is wrong for the
836        //   directed graph, and a later check that finds none (e.g. a
837        //   directed `graph_power`) fails an igraph assertion and aborts
838        //   the process.
839        // Dropping the cache of a directed input before the call (whoever
840        // wrote it) and after an undirected-mode call (which may have
841        // written a wrong value) avoids both; it only costs recomputation.
842        let guard = self.is_directed();
843        if guard {
844            self.invalidate_cache();
845        }
846        let res = Graph::init_with(|res| unsafe { igraph_graph_power(self, res, order, directed) });
847        if guard && !directed {
848            self.invalidate_cache();
849        }
850        res
851    }
852
853    /// Randomly rewires the graph in place, preserving its degree sequence.
854    ///
855    /// Performs `trials` degree-preserving *edge switches*: two edges
856    /// `(a, b)` and `(c, d)` are picked uniformly at random and replaced by
857    /// `(a, d)` and `(c, b)`, provided the result respects `allowed`:
858    /// [`EdgeTypeSw::Simple`] forbids loops and multi-edges,
859    /// [`EdgeTypeSw::Loops`] allows (single) self-loops. Multigraphs
860    /// ([`EdgeTypeSw::Multi`]) are not supported yet by igraph. For directed
861    /// graphs both in- and out-degrees are preserved. All attributes are lost.
862    ///
863    /// Draws from the calling thread's default random number generator
864    /// (each thread has its own): seed it with
865    /// [`rng::seed`](crate::rng::seed), or install a private generator with
866    /// [`Rng::scoped`](crate::rng::Rng::scoped), for reproducible results.
867    /// Returns the number of switches actually performed.
868    ///
869    /// See also [`rewire_edges`](Self::rewire_edges), which rewires edge
870    /// endpoints with a given probability (not preserving degrees), and
871    /// [`degree_sequence_game`](Self::degree_sequence_game), which samples
872    /// a new graph with a prescribed degree sequence (`games`).
873    ///
874    /// Binds [`igraph_rewire`](https://igraph.org/c/html/latest/igraph-Games.html#igraph_rewire).
875    ///
876    /// Graphs with fewer than two edges cannot be rewired: they are left
877    /// unchanged and zero swaps are reported.
878    ///
879    /// # Errors
880    /// [`ErrorKind::Unimplemented`](crate::ErrorKind::Unimplemented) for
881    /// [`EdgeTypeSw::Multi`], which igraph does not support yet;
882    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if
883    /// `trials` does not fit in an `igraph_int_t`.
884    ///
885    /// # Examples
886    /// ```
887    /// use igraph::prelude::*;
888    /// rng::seed(42).unwrap();
889    /// let edges: Vec<(i64, i64)> = (0..10).map(|i| (i, (i + 1) % 10)).collect();
890    /// let mut g = Graph::from_edges(&edges, 10, false).unwrap();
891    /// let stats = g.rewire(100, EdgeTypeSw::Simple).unwrap();
892    /// assert!(stats.successful_swaps > 0);
893    /// // Still 2-regular.
894    /// assert_eq!(g.degree(.., NeighborMode::All, Loops::Twice).unwrap(), vec![2; 10]);
895    /// ```
896    pub fn rewire(&mut self, trials: usize, allowed: EdgeTypeSw) -> Result<RewiringStats> {
897        let mut stats = igraph_rewiring_stats_t {
898            successful_swaps: 0,
899            unused1_: 0,
900            unused2_: 0,
901            unused3_: 0,
902        };
903        let trials = to_int(trials, "the number of trials")?;
904        // igraph leaves `stats` untouched when the graph has fewer than two
905        // edges: the zero initialization above is then the right answer.
906        igraph_call!(igraph_rewire(self, trials, allowed.into(), &mut stats))?;
907        Ok(RewiringStats {
908            successful_swaps: stats.successful_swaps.max(0) as usize,
909        })
910    }
911
912    /// Removes multi-edges and/or self-loops, in place.
913    ///
914    /// With `remove_multiple`, parallel edges are merged into one; with
915    /// `remove_loops`, self-loops are deleted. The edge order may change,
916    /// even if the graph was already simple.
917    ///
918    /// With the [attribute handler](crate::attributes::enable) on, graph and
919    /// vertex attributes are always kept. Edge attributes are discarded
920    /// whenever igraph rebuilds the edge set to merge multi-edges, i.e. when
921    /// `remove_multiple` is `true` and igraph does not already know (from
922    /// its property cache) that the graph has no multi-edges, even if no
923    /// edge actually gets merged. When only loops are removed (or there is
924    /// nothing to do) the remaining edges keep their attributes. Use
925    /// [`simplify_with_attributes`](Self::simplify_with_attributes) to
926    /// combine the attributes of the merged edges instead (e.g. summing
927    /// their weights), and
928    /// [`contract_vertices_with_attributes`](Self::contract_vertices_with_attributes)
929    /// for the analogous vertex operation.
930    ///
931    /// See also [`is_simple`](Self::is_simple),
932    /// [`has_multiple`](Self::has_multiple) and
933    /// [`count_multiple`](Self::count_multiple) (`structural`) to inspect
934    /// a graph before simplifying it.
935    ///
936    /// Binds [`igraph_simplify`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_simplify).
937    /// Time complexity: O(|V|+|E|).
938    ///
939    /// # Examples
940    /// ```
941    /// use igraph::prelude::*;
942    /// let mut g = Graph::from_edges(&[(0, 1), (1, 0), (1, 1), (1, 2), (1, 2)], 3, false).unwrap();
943    /// let mut keep_loops = g.clone();
944    /// keep_loops.simplify(true, false).unwrap();
945    /// assert_eq!(keep_loops.edge_list(), vec![(0, 1), (1, 1), (1, 2)]);
946    /// g.simplify(true, true).unwrap();
947    /// assert_eq!(g.edge_list(), vec![(0, 1), (1, 2)]);
948    /// ```
949    pub fn simplify(&mut self, remove_multiple: bool, remove_loops: bool) -> Result<()> {
950        igraph_call!(igraph_simplify(
951            self,
952            remove_multiple,
953            remove_loops,
954            ptr::null()
955        ))
956    }
957
958    /// The subgraph induced by the selected vertices: those vertices and all
959    /// the edges among them.
960    ///
961    /// Duplicate vertices in the selector are considered once and the
962    /// selection order is ignored: the subgraph keeps the vertices in
963    /// increasing order of their original ids (so vertex `i` of the subgraph
964    /// is the `i`-th smallest selected id). `implementation` picks the
965    /// strategy: [`SubgraphImplementation::CopyAndDelete`] is best when
966    /// keeping most of the graph, [`SubgraphImplementation::CreateFromScratch`]
967    /// when extracting a small part; [`SubgraphImplementation::Auto`] chooses
968    /// based on the ratio of the sizes. Use
969    /// [`induced_subgraph_map`](Self::induced_subgraph_map) to get the id
970    /// correspondence.
971    ///
972    /// See also [`delete_vertices`](Self::delete_vertices) (the in-place
973    /// complement of this operation),
974    /// [`neighborhood_graphs`](Self::neighborhood_graphs) and
975    /// [`decompose`](Self::decompose) (`components`).
976    ///
977    /// Binds [`igraph_induced_subgraph`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_induced_subgraph).
978    /// Time complexity: O(|V|+|E|) of the original graph.
979    ///
980    /// # Errors
981    /// [`ErrorKind::InvalidVertexId`](crate::ErrorKind::InvalidVertexId) for
982    /// invalid vertex ids.
983    ///
984    /// # Examples
985    /// ```
986    /// use igraph::prelude::*;
987    /// let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0), (0, 2)], 4, false).unwrap();
988    /// let tri = g.induced_subgraph(&[2, 0, 1], SubgraphImplementation::Auto).unwrap();
989    /// assert_eq!(tri.edge_list(), vec![(0, 1), (1, 2), (0, 2)]);
990    /// ```
991    pub fn induced_subgraph<'a>(
992        &self,
993        vids: impl Into<VertexSelector<'a>>,
994        implementation: SubgraphImplementation,
995    ) -> Result<Graph> {
996        with_vs(vids.into(), |vs| {
997            Graph::init_with(|res| unsafe {
998                igraph_induced_subgraph(self, res, vs, implementation.into())
999            })
1000        })
1001    }
1002
1003    /// Like [`induced_subgraph`](Self::induced_subgraph), also returning the
1004    /// maps between the original vertex ids and the subgraph's.
1005    ///
1006    /// Binds [`igraph_induced_subgraph_map`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_induced_subgraph_map).
1007    ///
1008    /// # Examples
1009    /// ```
1010    /// use igraph::prelude::*;
1011    /// let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 4)], 5, false).unwrap();
1012    /// let sub = g.induced_subgraph_map(&[3, 1, 2], SubgraphImplementation::CreateFromScratch).unwrap();
1013    /// assert_eq!(sub.invmap, vec![1, 2, 3]);
1014    /// assert_eq!(sub.map, vec![None, Some(0), Some(1), Some(2), None]);
1015    /// assert_eq!(sub.graph.edge_list(), vec![(0, 1), (1, 2)]);
1016    /// ```
1017    pub fn induced_subgraph_map<'a>(
1018        &self,
1019        vids: impl Into<VertexSelector<'a>>,
1020        implementation: SubgraphImplementation,
1021    ) -> Result<InducedSubgraph> {
1022        let mut map = VectorInt::new();
1023        let mut invmap = VectorInt::new();
1024        let graph = with_vs(vids.into(), |vs| {
1025            Graph::init_with(|res| unsafe {
1026                igraph_induced_subgraph_map(
1027                    self,
1028                    res,
1029                    vs,
1030                    implementation.into(),
1031                    &mut map,
1032                    &mut invmap,
1033                )
1034            })
1035        })?;
1036        Ok(InducedSubgraph {
1037            graph,
1038            map: optional_ids(&map),
1039            invmap: invmap.into(),
1040        })
1041    }
1042
1043    /// Ids of the edges of the subgraph induced by the selected vertices,
1044    /// i.e. of the edges having both endpoints in the selection.
1045    ///
1046    /// Binds [`igraph_induced_subgraph_edges`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_induced_subgraph_edges).
1047    /// Time complexity: O(mv log(nv)), nv the number of selected vertices and
1048    /// mv the sum of their degrees.
1049    ///
1050    /// # Errors
1051    /// [`ErrorKind::InvalidVertexId`](crate::ErrorKind::InvalidVertexId) for
1052    /// invalid vertex ids.
1053    ///
1054    /// # Examples
1055    /// ```
1056    /// use igraph::prelude::*;
1057    /// let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0), (0, 2)], 4, false).unwrap();
1058    /// let mut inside = g.induced_subgraph_edges(&[0, 1, 2]).unwrap();
1059    /// inside.sort();
1060    /// assert_eq!(inside, vec![0, 1, 4]);
1061    /// ```
1062    pub fn induced_subgraph_edges<'a>(
1063        &self,
1064        vids: impl Into<VertexSelector<'a>>,
1065    ) -> Result<Vec<EdgeId>> {
1066        let mut res = VectorInt::new();
1067        with_vs(vids.into(), |vs| {
1068            igraph_call!(igraph_induced_subgraph_edges(self, vs, &mut res))
1069        })?;
1070        Ok(res.into())
1071    }
1072
1073    /// The subgraph made of the selected edges (and their endpoints).
1074    ///
1075    /// Edge ids are reassigned consecutively, keeping the original order.
1076    /// With `delete_vertices = true`, vertices not incident to any selected
1077    /// edge are removed as well (and vertex ids reassigned in increasing
1078    /// order); otherwise the subgraph keeps all the vertices of `self`.
1079    /// Attributes are preserved.
1080    ///
1081    /// Binds [`igraph_subgraph_from_edges`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_subgraph_from_edges).
1082    /// Time complexity: O(|V|+|E|) of the original graph.
1083    ///
1084    /// # Errors
1085    /// [`ErrorKind::InvalidEdgeId`](crate::ErrorKind::InvalidEdgeId) for
1086    /// invalid edge ids.
1087    ///
1088    /// # Examples
1089    /// ```
1090    /// use igraph::prelude::*;
1091    /// let g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 4)], 5, false).unwrap();
1092    /// let kept = g.subgraph_from_edges(&[1, 2], true).unwrap();
1093    /// assert_eq!((kept.vcount(), kept.edge_list()), (3, vec![(0, 1), (1, 2)]));
1094    /// let spanning = g.subgraph_from_edges(&[1, 2], false).unwrap();
1095    /// assert_eq!((spanning.vcount(), spanning.edge_list()), (5, vec![(1, 2), (2, 3)]));
1096    /// ```
1097    pub fn subgraph_from_edges<'a>(
1098        &self,
1099        eids: impl Into<EdgeSelector<'a>>,
1100        delete_vertices: bool,
1101    ) -> Result<Graph> {
1102        with_es(eids.into(), |es| {
1103            Graph::init_with(|res| unsafe {
1104                igraph_subgraph_from_edges(self, res, es, delete_vertices)
1105            })
1106        })
1107    }
1108
1109    /// Reverses the direction of the selected edges, in place.
1110    ///
1111    /// Attributes and the order of vertices and edges are preserved. Pass
1112    /// `..` to reverse all edges (this is O(1)); it is rarely needed, since
1113    /// most functions accept [`NeighborMode::In`] to walk edges backwards.
1114    /// Undirected graphs are left unchanged (and `eids` is then not even
1115    /// validated). An edge listed twice is reversed twice, i.e. it ends up
1116    /// with its original direction.
1117    ///
1118    /// Binds [`igraph_reverse_edges`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_reverse_edges).
1119    /// Time complexity: O(1) for all edges, O(|E|) otherwise.
1120    ///
1121    /// # Errors
1122    /// [`ErrorKind::InvalidEdgeId`](crate::ErrorKind::InvalidEdgeId) for
1123    /// invalid edge ids.
1124    ///
1125    /// # Examples
1126    /// ```
1127    /// use igraph::prelude::*;
1128    /// let mut g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 4, true).unwrap();
1129    /// g.reverse_edges(1).unwrap();
1130    /// assert_eq!(g.edge_list(), vec![(0, 1), (2, 1), (2, 3)]);
1131    /// g.reverse_edges(..).unwrap();
1132    /// assert_eq!(g.edge_list(), vec![(1, 0), (1, 2), (3, 2)]);
1133    /// ```
1134    pub fn reverse_edges<'a>(&mut self, eids: impl Into<EdgeSelector<'a>>) -> Result<()> {
1135        with_es(eids.into(), |es| {
1136            igraph_call!(igraph_reverse_edges(self, es))
1137        })
1138    }
1139
1140    /// A graph product of `self` and `other` (*experimental* in igraph).
1141    ///
1142    /// The vertices of the product are the pairs `(u, v)` with `u` in `self`
1143    /// and `v` in `other`, numbered `u * |V2| + v`. Writing `u ~ u'` for
1144    /// adjacency, `(u, v)` is connected to `(u', v')` when:
1145    ///
1146    /// | [`Product`] | condition | edges (undirected) |
1147    /// |---|---|---|
1148    /// | [`Cartesian`](Product::Cartesian) | `u = u'` and `v ~ v'`, or `u ~ u'` and `v = v'` | `\|V1\|\|E2\| + \|V2\|\|E1\|` |
1149    /// | [`Lexicographic`](Product::Lexicographic) | `u = u'` and `v ~ v'`, or `u ~ u'` | `\|V1\|\|E2\| + \|V2\|²\|E1\|` |
1150    /// | [`Strong`](Product::Strong) | Cartesian or tensor condition | `\|V1\|\|E2\| + \|V2\|\|E1\| + 2\|E1\|\|E2\|` |
1151    /// | [`Tensor`](Product::Tensor) | `u ~ u'` and `v ~ v'` | `2\|E1\|\|E2\|` |
1152    /// | [`Modular`](Product::Modular) | both adjacent or both non-adjacent (simple graphs only) | `2\|E1\|\|E2\| + 2\|E1'\|\|E2'\|` |
1153    ///
1154    /// In the directed case the factor 2 disappears. All these products are
1155    /// associative; the lexicographic one is not commutative.
1156    ///
1157    /// See also [`Graph::square_lattice`] and [`Graph::hypercube`]: grids
1158    /// and hypercubes are iterated Cartesian products of paths, cycles and
1159    /// `K2`, built directly.
1160    ///
1161    /// Binds [`igraph_product`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_product).
1162    ///
1163    /// # Errors
1164    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if the two
1165    /// graphs have different directedness, or are not simple for the modular
1166    /// product.
1167    ///
1168    /// # Examples
1169    /// ```
1170    /// use igraph::prelude::*;
1171    /// // The 3x4 grid is the Cartesian product of two paths.
1172    /// let p3 = Graph::from_edges(&[(0, 1), (1, 2)], 3, false).unwrap();
1173    /// let p4 = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 4, false).unwrap();
1174    /// let grid = p3.product(&p4, Product::Cartesian).unwrap();
1175    /// assert_eq!((grid.vcount(), grid.ecount()), (12, 3 * 3 + 4 * 2));
1176    /// let lattice = Graph::square_lattice(&[4, 3], 1, false, false, None).unwrap();
1177    /// assert!(grid.isomorphic(&lattice).unwrap());
1178    /// ```
1179    pub fn product(&self, other: &Graph, kind: Product) -> Result<Graph> {
1180        Graph::init_with(|res| unsafe { igraph_product(res, self, other, kind.into()) })
1181    }
1182
1183    /// The rooted product of `self` and `other` with root `root` in `other`
1184    /// (*experimental* in igraph).
1185    ///
1186    /// A copy of `other` is attached to every vertex `u` of `self`, glued at
1187    /// its root: `(u, v)` is connected to `(u', v')` if `u = u'` and
1188    /// `v ~ v'`, or `u ~ u'` and `v = v' = root`. Vertex ids follow the same
1189    /// `u * |V2| + v` convention as [`product`](Self::product); the result
1190    /// has `|V1||E2| + |E1|` edges.
1191    ///
1192    /// Binds [`igraph_rooted_product`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_rooted_product).
1193    /// Time complexity: O(|V1||V2| + |V1||E2| + |E1|).
1194    ///
1195    /// # Errors
1196    /// [`ErrorKind::InvalidVertexId`](crate::ErrorKind::InvalidVertexId) if
1197    /// `root` is not a vertex of `other`;
1198    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) for mixed
1199    /// directedness.
1200    ///
1201    /// # Examples
1202    /// ```
1203    /// use igraph::prelude::*;
1204    /// // A "comb": a path with a pendant edge hanging from each vertex.
1205    /// let spine = Graph::from_edges(&[(0, 1), (1, 2)], 3, false).unwrap();
1206    /// let tooth = Graph::from_edges(&[(0, 1)], 2, false).unwrap();
1207    /// let comb = spine.rooted_product(&tooth, 0).unwrap();
1208    /// assert_eq!((comb.vcount(), comb.ecount()), (6, 5));
1209    /// assert_eq!(comb.degree(.., NeighborMode::All, Loops::Twice).unwrap(), vec![2, 1, 3, 1, 2, 1]);
1210    /// ```
1211    pub fn rooted_product(&self, other: &Graph, root: VertexId) -> Result<Graph> {
1212        Graph::init_with(|res| unsafe { igraph_rooted_product(res, self, other, root) })
1213    }
1214
1215    /// The `k`-times iterated Mycielskian of the graph (*experimental* in igraph).
1216    ///
1217    /// Mycielski's construction increases the chromatic number by one while
1218    /// keeping the graph triangle-free. From `G` with vertices `v_1..v_n` it
1219    /// builds `M(G)`: `G` itself, a copy `u_i` of every `v_i`, and a new
1220    /// vertex `w`; each `u_i` is joined to `w` and, for every edge
1221    /// `(v_i, v_j)`, the edges `(u_i, v_j)` and `(v_i, u_j)` are added. So
1222    /// `M(G)` has `2n + 1` vertices and `3m + n` edges; after `k` iterations
1223    /// there are `(n + 1) 2^k - 1` vertices. The Mycielskian of the null
1224    /// graph is the singleton and that of the singleton is the 2-path, so
1225    /// that iterating from them yields the connected Mycielski graphs
1226    /// (the Grötzsch graph after 4 steps from the null graph).
1227    ///
1228    /// See also [`Graph::mycielski_graph`], which builds the Mycielski graphs
1229    /// `M_k` directly; `M_k` is the `(k - 2)`-times iterated Mycielskian of
1230    /// `K2`, up to relabeling.
1231    ///
1232    /// Binds [`igraph_mycielskian`](https://igraph.org/c/html/latest/igraph-Operators.html#igraph_mycielskian).
1233    /// Time complexity: O(|V| 2^k + |E| 3^k).
1234    ///
1235    /// # Errors
1236    /// [`ErrorKind::InvalidValue`](crate::ErrorKind::InvalidValue) if `k`
1237    /// does not fit in an `igraph_int_t`, and
1238    /// [`ErrorKind::Overflow`](crate::ErrorKind::Overflow) if the result would
1239    /// be too large.
1240    ///
1241    /// # Examples
1242    /// ```
1243    /// use igraph::prelude::*;
1244    /// // M(K2) is the 5-cycle, M(C5) is the Grötzsch graph.
1245    /// let k2 = Graph::from_edges(&[(0, 1)], 2, false).unwrap();
1246    /// let c5 = k2.mycielskian(1).unwrap();
1247    /// assert_eq!((c5.vcount(), c5.ecount()), (5, 5));
1248    /// let grotzsch = k2.mycielskian(2).unwrap();
1249    /// assert_eq!((grotzsch.vcount(), grotzsch.ecount()), (11, 20));
1250    /// assert!(grotzsch.isomorphic(&Graph::famous("Grotzsch").unwrap()).unwrap());
1251    /// assert_eq!(grotzsch.girth().unwrap(), Some(4)); // still triangle-free
1252    /// ```
1253    pub fn mycielskian(&self, k: usize) -> Result<Graph> {
1254        let k = to_int(k, "the number of iterations")?;
1255        Graph::init_with(|res| unsafe { igraph_mycielskian(self, res, k) })
1256    }
1257}