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}