igraph/graph.rs
1//! The [`Graph`] type and igraph's basic interface (`igraph_interface.h`).
2//!
3//! [`Graph`] is the C struct `igraph_t` itself, made Rusty: it owns its data
4//! (destroyed on [`Drop`]), it is [`Clone`] (via `igraph_copy`) and [`Send`],
5//! and its methods return [`Result`]s instead of error codes. Vertices and
6//! edges are identified by consecutive integer ids starting from zero, as in
7//! igraph; ids are `i64` (`igraph_int_t`) while counts are `usize`.
8//!
9//! This module contains the fundamental operations: construction, adding
10//! and removing vertices and edges, and queries about the structure.
11//! Algorithms live in the other modules of the crate, most of them as further
12//! methods of [`Graph`].
13//!
14//! ```
15//! use igraph::prelude::*;
16//!
17//! // A directed triangle plus a pendant vertex.
18//! let mut g = Graph::from_edges(&[(0, 1), (1, 2), (2, 0)], 4, true).unwrap();
19//! g.add_edge(2, 3).unwrap();
20//! assert_eq!((g.vcount(), g.ecount()), (4, 4));
21//! assert_eq!(g.neighbors(2, NeighborMode::Out).unwrap(), vec![0, 3]);
22//! assert_eq!(g.edge(3).unwrap(), (2, 3));
23//! assert_eq!(g.get_eid(1, 2, true).unwrap(), Some(1));
24//! assert_eq!(g.get_eid(2, 1, true).unwrap(), None);
25//!
26//! let h = g.clone();
27//! g.delete_vertices(3).unwrap();
28//! assert_eq!((g.vcount(), h.vcount()), (3, 4));
29//! ```
30//!
31//! The functions of `igraph_interface.h` map as follows:
32//!
33//! | C function | Rust |
34//! |------------|------|
35//! | `igraph_empty`, `igraph_create` | [`Graph::new`], [`Graph::empty`], [`Graph::from_edges`], [`Graph::from_flat_edges`] |
36//! | `igraph_empty_attrs` | [`Graph::empty`] followed by [`set_graph_attr`](Graph::set_graph_attr) (see [`attributes`](crate::attributes)) |
37//! | `igraph_copy`, `igraph_destroy` | [`Clone`], [`Graph::try_clone`], [`Drop`] |
38//! | `igraph_add_vertices`, `igraph_add_edge(s)` | [`add_vertices`](Graph::add_vertices), [`add_vertex`](Graph::add_vertex), [`add_edge`](Graph::add_edge), [`add_edge_id`](Graph::add_edge_id), [`add_edges`](Graph::add_edges), [`add_edges_from_slice`](Graph::add_edges_from_slice), [`add_edges_from_vector`](Graph::add_edges_from_vector) |
39//! | `igraph_delete_vertices(_map)`, `igraph_delete_edges` | [`delete_vertices`](Graph::delete_vertices), [`delete_vertices_map`](Graph::delete_vertices_map), [`delete_edges`](Graph::delete_edges) |
40//! | `igraph_vcount`, `igraph_ecount`, `igraph_is_directed` | [`vcount`](Graph::vcount), [`ecount`](Graph::ecount), [`num_vertices`](Graph::num_vertices), [`num_edges`](Graph::num_edges), [`vertices`](Graph::vertices), [`edge_ids`](Graph::edge_ids), [`is_directed`](Graph::is_directed) |
41//! | `igraph_neighbors`, `igraph_incident` | [`neighbors`](Graph::neighbors), [`neighbors_with`](Graph::neighbors_with), [`incident`](Graph::incident) |
42//! | `igraph_degree(_1)` | [`degree`](Graph::degree), [`degree_of`](Graph::degree_of) |
43//! | `igraph_edge(s)` | [`edge`](Graph::edge), [`edges`](Graph::edges), [`edges_flat`](Graph::edges_flat), [`edge_list`](Graph::edge_list), [`edges_iter`](Graph::edges_iter) |
44//! | `IGRAPH_FROM`, `IGRAPH_TO`, `IGRAPH_OTHER` | [`edge_from`](Graph::edge_from), [`edge_to`](Graph::edge_to), [`other_endpoint`](Graph::other_endpoint) |
45//! | `igraph_get_eid(s)`, `igraph_get_all_eids_between` | [`get_eid`](Graph::get_eid), [`has_edge`](Graph::has_edge), [`get_eids`](Graph::get_eids), [`get_eids_opt`](Graph::get_eids_opt), [`get_all_eids_between`](Graph::get_all_eids_between) |
46//! | `igraph_is_same_graph` | [`is_same_graph`](Graph::is_same_graph), [`PartialEq`] |
47//! | `igraph_invalidate_cache` | [`invalidate_cache`](Graph::invalidate_cache) |
48//! | `igraph_vs_*`, `igraph_es_*` (`igraph_iterators.h`) | [`select_vertices`](Graph::select_vertices), [`select_edges`](Graph::select_edges), [`vs_size`](Graph::vs_size), [`es_size`](Graph::es_size), [`adjacent_vertices`](Graph::adjacent_vertices), [`incident_edges`](Graph::incident_edges) |
49//!
50//! For raw FFI users, [`Graph::init_with`] turns any C function that
51//! initializes an `igraph_t` into a `Result<Graph>`, and [`Graph::setup`]
52//! initializes igraph for the calling thread (every safe wrapper does it
53//! automatically, see [`crate::error::ensure_init`]).
54//!
55//! `Graph` is [`Send`] (it can be moved to another thread) but not [`Sync`]:
56//! igraph lazily caches properties inside the graph even through `const`
57//! pointers.
58//!
59//! # Where to go next
60//!
61//! Most graphs are not built edge by edge:
62//!
63//! - deterministic graphs (rings, lattices, trees, the named graphs of
64//! [`Graph::famous`], ...) are in [`constructors`](crate::constructors),
65//! random graph models in [`games`](crate::games), and file readers and
66//! writers in [`foreign`](crate::foreign);
67//! - conversions to and from matrices and edge lists are in
68//! [`conversion`](crate::conversion) (e.g. [`Graph::get_adjacency`]) and
69//! [`constructors`](crate::constructors) (e.g. [`Graph::adjacency`]);
70//! - structural queries beyond degrees (strength, simplicity, multi-edges,
71//! density, ...) are in [`structural`](crate::structural), subgraphs and
72//! simplification in [`operators`](crate::operators), and vertex, edge and
73//! graph attributes in [`attributes`](crate::attributes);
74//! - for repeated neighborhood queries, [`adjlist`](crate::adjlist) builds
75//! adjacency and incidence lists once.
76//!
77//! ```
78//! use igraph::prelude::*;
79//!
80//! // Zachary's karate club, one of igraph's named graphs.
81//! let club = Graph::famous("Zachary").unwrap();
82//! assert_eq!((club.vcount(), club.ecount()), (34, 78));
83//! let degree = club.degree(.., NeighborMode::All, Loops::Twice).unwrap();
84//! // The handshake lemma: every edge has two endpoints.
85//! assert_eq!(degree.iter().sum::<i64>(), 2 * 78);
86//! // The instructor (0) and the administrator (33) are the hubs.
87//! assert_eq!((degree[0], degree[33]), (16, 17));
88//! assert_eq!(club.maxdegree(.., NeighborMode::All, Loops::Twice).unwrap(), 17);
89//! ```
90
91use crate::{
92 constants::*,
93 error::{Error, Result, ensure_init},
94 ffi::*,
95 igraph_call,
96 selector::{EdgeSelector, VertexSelector},
97 vector::VectorInt,
98};
99use std::{fmt, mem::MaybeUninit, ops::Range};
100
101/// An igraph graph (`igraph_t`), see the [module docs](self).
102pub type Graph = igraph_t;
103
104/// Vertex identifier (`igraph_int_t`).
105pub type VertexId = igraph_int_t;
106/// Edge identifier (`igraph_int_t`).
107pub type EdgeId = igraph_int_t;
108
109impl Drop for igraph_t {
110 /// Destroys the graph with `igraph_destroy`.
111 fn drop(&mut self) {
112 // A zeroed (never initialized) graph has null storage: nothing to free.
113 if !self.from.stor_begin.is_null() {
114 unsafe { igraph_destroy(self) };
115 }
116 }
117}
118
119impl Clone for igraph_t {
120 /// Deep copy with `igraph_copy`.
121 fn clone(&self) -> Self {
122 Self::init_with(|g| unsafe { igraph_copy(g, self) }).expect("igraph failed to copy a graph")
123 }
124}
125
126// A graph owns its data; the (lazily filled) property cache is mutated even
127// through `&Graph`, hence `Send` but not `Sync`.
128unsafe impl Send for igraph_t {}
129
130impl fmt::Display for igraph_t {
131 /// A one-line summary, e.g. `Undirected graph with 3 vertices and 2 edges`.
132 ///
133 /// The alternate form (`{:#}`) appends the edge list, one edge per line,
134 /// as `from -> to` (directed) or `from -- to` (undirected):
135 ///
136 /// ```
137 /// use igraph::prelude::*;
138 /// let g = Graph::from_edges(&[(0, 1), (1, 2)], 3, false).unwrap();
139 /// assert_eq!(g.to_string(), "Undirected graph with 3 vertices and 2 edges");
140 /// assert_eq!(format!("{g:#}"), "Undirected graph with 3 vertices and 2 edges\n0 -- 1\n1 -- 2");
141 /// ```
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 write!(
144 f,
145 "{} graph with {} vertices and {} edges",
146 if self.is_directed() {
147 "Directed"
148 } else {
149 "Undirected"
150 },
151 self.vcount(),
152 self.ecount()
153 )?;
154 if f.alternate() {
155 let arrow = if self.is_directed() { "->" } else { "--" };
156 for (from, to) in self.edge_list() {
157 write!(f, "\n{from} {arrow} {to}")?;
158 }
159 }
160 Ok(())
161 }
162}
163
164impl PartialEq for igraph_t {
165 /// Two graphs are equal when they are the same *labelled* graph: same
166 /// directedness, vertex count and multiset of edges written in terms of
167 /// vertex ids (the order of the edges, and of the endpoints of undirected
168 /// edges, does not matter), see [`is_same_graph`](Graph::is_same_graph).
169 /// Use the isomorphism functions to compare structure up to relabeling.
170 fn eq(&self, other: &Self) -> bool {
171 self.is_same_graph(other).unwrap_or(false)
172 }
173}
174
175impl igraph_t {
176 /// Initializes igraph for the calling thread (see [`crate::error::ensure_init`]).
177 ///
178 /// Calling it is optional: every safe wrapper does it automatically.
179 pub fn setup() {
180 ensure_init();
181 }
182
183 /// Creates a graph by running an igraph *constructor*, i.e. a C function
184 /// that initializes the `igraph_t` pointed to by its argument.
185 ///
186 /// This is the building block of all the wrappers returning new graphs,
187 /// and it is useful to call raw constructors not wrapped by this crate.
188 /// `f` must either fail or fully initialize the graph; if it reports
189 /// success without initializing it, [`ErrorKind::Internal`](crate::error::ErrorKind::Internal)
190 /// is returned:
191 ///
192 /// ```
193 /// use igraph::{ffi, prelude::*};
194 /// let ring = Graph::init_with(|g| unsafe { ffi::igraph_ring(g, 5, false, false, true) }).unwrap();
195 /// assert_eq!(ring.ecount(), 5);
196 /// ```
197 pub fn init_with(f: impl FnOnce(*mut igraph_t) -> igraph_error_t) -> Result<Self> {
198 // Like `igraph_call!`: initializes the thread, forgets any stale
199 // error record, and refuses to nest too deeply inside callbacks.
200 crate::error::prepare_call()?;
201 // Zeroed storage is safe to drop (see `Drop`), should `f` fail early.
202 let mut graph = MaybeUninit::<igraph_t>::zeroed();
203 crate::error::check(f(graph.as_mut_ptr()))?;
204 // On failure igraph has already released whatever it allocated. On
205 // success, make sure the closure really initialized the graph: a
206 // (safe) closure returning `IGRAPH_SUCCESS` without calling a
207 // constructor would otherwise hand out a graph with null storage.
208 let graph = unsafe { graph.assume_init() };
209 if graph.from.stor_begin.is_null() {
210 return Err(Error::new(
211 crate::error::ErrorKind::Internal,
212 "the constructor passed to Graph::init_with did not initialize the graph",
213 ));
214 }
215 Ok(graph)
216 }
217
218 /// Creates a graph with `num_vertices` isolated vertices ([`igraph_empty`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_empty)).
219 ///
220 /// # Panics
221 /// If igraph fails to allocate the graph, like [`Vec`] does, or if
222 /// `num_vertices` exceeds igraph's maximum vertex count (see
223 /// [`empty`](Self::empty) for the fallible version).
224 pub fn new(num_vertices: usize, directed: bool) -> Self {
225 Self::empty(num_vertices, directed).expect("igraph failed to create a graph")
226 }
227
228 /// Creates a graph with `num_vertices` isolated vertices ([`igraph_empty`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_empty)).
229 ///
230 /// # Errors
231 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) if
232 /// `num_vertices` does not fit in an `i64`;
233 /// [`ErrorKind::Range`](crate::error::ErrorKind::Range) if it exceeds
234 /// igraph's maximum vertex count, or
235 /// [`ErrorKind::OutOfMemory`](crate::error::ErrorKind::OutOfMemory).
236 pub fn empty(num_vertices: usize, directed: bool) -> Result<Self> {
237 let n = count_arg(num_vertices, "number of vertices")?;
238 Self::init_with(|g| unsafe { igraph_empty(g, n, directed) })
239 }
240
241 /// Creates a graph from a list of `(from, to)` edges
242 /// ([`igraph_create`](https://igraph.org/c/html/latest/igraph-Generators.html#igraph_create)).
243 ///
244 /// The graph has `max(num_vertices, largest id + 1)` vertices; in an
245 /// undirected graph `(a, b)` and `(b, a)` denote the same edge. Multi-edges
246 /// and loops are kept; edge `i` is the `i`-th pair. See
247 /// [`constructors`](crate::constructors) for ready-made graphs, and
248 /// [`Graph::read_graph_edgelist_from_str`] to parse an edge list.
249 ///
250 /// ```
251 /// use igraph::prelude::*;
252 /// let g = Graph::from_edges(&[(0, 1), (1, 2)], 5, true).unwrap();
253 /// assert_eq!((g.vcount(), g.ecount()), (5, 2));
254 /// // The vertex count grows to fit the largest id.
255 /// let h = Graph::from_edges(&[(0, 7)], 0, false).unwrap();
256 /// assert_eq!(h.vcount(), 8);
257 /// ```
258 ///
259 /// # Errors
260 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for negative ids.
261 pub fn from_edges(
262 edges: &[(VertexId, VertexId)],
263 num_vertices: usize,
264 directed: bool,
265 ) -> Result<Self> {
266 let flat: VectorInt = edges.iter().flat_map(|&(a, b)| [a, b]).collect();
267 Self::from_flat_edges(&flat, num_vertices, directed)
268 }
269
270 /// Creates a graph from a flat edge list `[from0, to0, from1, to1, ...]`
271 /// ([`igraph_create`](https://igraph.org/c/html/latest/igraph-Generators.html#igraph_create)).
272 ///
273 /// # Errors
274 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) for an odd length
275 /// or a `num_vertices` that does not fit in an `i64`,
276 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for negative ids.
277 pub fn from_flat_edges(
278 edges: &[VertexId],
279 num_vertices: usize,
280 directed: bool,
281 ) -> Result<Self> {
282 if !edges.len().is_multiple_of(2) {
283 return Err(Error::invalid(
284 "the flat edge list must have an even length",
285 ));
286 }
287 let n = count_arg(num_vertices, "number of vertices")?;
288 let view = VectorInt::view(edges);
289 Self::init_with(|g| unsafe { igraph_create(g, view.as_ptr(), n, directed) })
290 }
291
292 /// Number of vertices ([`igraph_vcount`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_vcount)), O(1).
293 pub fn vcount(&self) -> usize {
294 unsafe { igraph_vcount(self) as usize }
295 }
296
297 /// Number of edges ([`igraph_ecount`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_ecount)), O(1).
298 pub fn ecount(&self) -> usize {
299 unsafe { igraph_ecount(self) as usize }
300 }
301
302 /// Number of vertices; alias of [`vcount`](Self::vcount).
303 pub fn num_vertices(&self) -> usize {
304 self.vcount()
305 }
306
307 /// Number of edges; alias of [`ecount`](Self::ecount).
308 pub fn num_edges(&self) -> usize {
309 self.ecount()
310 }
311
312 /// Whether the graph is directed ([`igraph_is_directed`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_is_directed)).
313 pub fn is_directed(&self) -> bool {
314 unsafe { igraph_is_directed(self) }
315 }
316
317 /// The range of all vertex ids, `0..vcount`.
318 pub fn vertices(&self) -> Range<VertexId> {
319 0..self.vcount() as VertexId
320 }
321
322 /// The range of all edge ids, `0..ecount`.
323 pub fn edge_ids(&self) -> Range<EdgeId> {
324 0..self.ecount() as EdgeId
325 }
326
327 /// Adds `n` isolated vertices, with ids `vcount..vcount + n`
328 /// ([`igraph_add_vertices`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_add_vertices)).
329 ///
330 /// # Errors
331 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) if
332 /// `n` does not fit in an `i64`;
333 /// [`ErrorKind::Overflow`](crate::error::ErrorKind::Overflow) or
334 /// [`ErrorKind::Range`](crate::error::ErrorKind::Range) if the new vertex
335 /// count would overflow or exceed igraph's maximum vertex count.
336 pub fn add_vertices(&mut self, n: usize) -> Result<()> {
337 let n = count_arg(n, "number of vertices to add")?;
338 igraph_call!(igraph_add_vertices(self, n, std::ptr::null()))
339 }
340
341 /// Adds a single edge ([`igraph_add_edge`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_add_edge)); for many edges
342 /// [`add_edges`](Self::add_edges) is much faster.
343 ///
344 /// # Errors
345 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) if an endpoint does not exist.
346 pub fn add_edge(&mut self, from: VertexId, to: VertexId) -> Result<()> {
347 igraph_call!(igraph_add_edge(self, from, to))
348 }
349
350 /// Adds the given `(from, to)` edges, with ids `ecount..` in order
351 /// ([`igraph_add_edges`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_add_edges)).
352 ///
353 /// # Errors
354 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) if an endpoint does not
355 /// exist (then no edge is added).
356 pub fn add_edges(&mut self, edges: &[(VertexId, VertexId)]) -> Result<()> {
357 let flat: VectorInt = edges.iter().flat_map(|&(a, b)| [a, b]).collect();
358 self.add_edges_from_vector(&flat)
359 }
360
361 /// Adds the given `(from, to)` edges; alias of [`add_edges`](Self::add_edges).
362 pub fn add_edges_from_slice(&mut self, edges: &[(VertexId, VertexId)]) -> Result<()> {
363 self.add_edges(edges)
364 }
365
366 /// Adds the edges of a flat list `[from0, to0, from1, to1, ...]` ([`igraph_add_edges`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_add_edges)).
367 ///
368 /// # Errors
369 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) for an odd length,
370 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for missing vertices.
371 pub fn add_edges_from_vector(&mut self, edges: &[VertexId]) -> Result<()> {
372 if !edges.len().is_multiple_of(2) {
373 return Err(Error::invalid(
374 "the flat edge list must have an even length",
375 ));
376 }
377 let view = VectorInt::view(edges);
378 igraph_call!(igraph_add_edges(self, view.as_ptr(), std::ptr::null()))
379 }
380
381 /// Removes the selected edges ([`igraph_delete_edges`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_delete_edges)); the
382 /// remaining edges keep their relative order and are renumbered to stay
383 /// consecutive.
384 ///
385 /// # Errors
386 /// [`ErrorKind::InvalidEdgeId`](crate::error::ErrorKind::InvalidEdgeId) for invalid edges.
387 pub fn delete_edges<'a>(&mut self, edges: impl Into<EdgeSelector<'a>>) -> Result<()> {
388 let es = edges.into().to_raw()?;
389 igraph_call!(igraph_delete_edges(self, es.get()))
390 }
391
392 /// Removes the selected vertices and their incident edges
393 /// ([`igraph_delete_vertices`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_delete_vertices)); the remaining vertices and edges are
394 /// renumbered to stay consecutive (see
395 /// [`delete_vertices_map`](Self::delete_vertices_map) for the mapping).
396 /// To keep the original graph, build the complementary
397 /// [`Graph::induced_subgraph`] instead.
398 ///
399 /// # Errors
400 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
401 pub fn delete_vertices<'a>(&mut self, vertices: impl Into<VertexSelector<'a>>) -> Result<()> {
402 let vs = vertices.into().to_raw()?;
403 igraph_call!(igraph_delete_vertices(self, vs.get()))
404 }
405
406 /// Removes the selected vertices and their incident edges, returning
407 /// `(map, invmap)`
408 /// ([`igraph_delete_vertices_map`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_delete_vertices_map)):
409 /// `map[old]` is the new id of vertex `old`, or `-1` if it was deleted,
410 /// and `invmap[new]` is the old id of vertex `new`.
411 ///
412 /// ```
413 /// use igraph::prelude::*;
414 /// let mut g = Graph::from_edges(&[(0, 1), (1, 2), (2, 3)], 4, false).unwrap();
415 /// let (map, invmap) = g.delete_vertices_map(&[1]).unwrap();
416 /// assert_eq!(map, vec![0, -1, 1, 2]);
417 /// assert_eq!(invmap, vec![0, 2, 3]);
418 /// assert_eq!(g.edge_list(), vec![(1, 2)]);
419 /// ```
420 ///
421 /// # Errors
422 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
423 pub fn delete_vertices_map<'a>(
424 &mut self,
425 vertices: impl Into<VertexSelector<'a>>,
426 ) -> Result<(Vec<VertexId>, Vec<VertexId>)> {
427 let vs = vertices.into().to_raw()?;
428 let mut map = VectorInt::new();
429 let mut invmap = VectorInt::new();
430 igraph_call!(igraph_delete_vertices_map(
431 self,
432 vs.get(),
433 &mut map,
434 &mut invmap
435 ))?;
436 Ok((map.into(), invmap.into()))
437 }
438
439 /// Neighbors of a vertex, sorted, counting loop edges twice and keeping
440 /// multi-edges, so that the result has as many entries as the degree
441 /// ([`igraph_neighbors`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_neighbors) with `IGRAPH_LOOPS_TWICE`
442 /// and `IGRAPH_MULTIPLE`); see [`neighbors_with`](Self::neighbors_with)
443 /// for other conventions.
444 ///
445 /// For many queries on the same graph, an
446 /// [`AdjList`](crate::adjlist::AdjList) is faster; for the vertices
447 /// within a given distance, see [`Graph::neighborhood`].
448 ///
449 /// ```
450 /// use igraph::prelude::*;
451 /// let star = Graph::star(4, StarMode::Undirected, 0).unwrap();
452 /// assert_eq!(star.neighbors(0, NeighborMode::All).unwrap(), vec![1, 2, 3]);
453 /// assert_eq!(star.neighbors(2, NeighborMode::All).unwrap(), vec![0]);
454 /// ```
455 ///
456 /// # Errors
457 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for an invalid vertex.
458 pub fn neighbors(&self, vertex: VertexId, mode: NeighborMode) -> Result<Vec<VertexId>> {
459 self.neighbors_with(vertex, mode, Loops::Twice, true)
460 }
461
462 /// Neighbors of a vertex with full control over loops and multi-edges
463 /// ([`igraph_neighbors`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_neighbors)). The result is sorted.
464 ///
465 /// `mode` selects out-, in- or all neighbors in directed graphs (it is
466 /// ignored for undirected ones); `loops` says whether a loop edge makes
467 /// the vertex its own neighbor zero, one or two times; with
468 /// `multiple = false` each neighbor appears once however many parallel
469 /// edges lead to it.
470 ///
471 /// ```
472 /// use igraph::prelude::*;
473 /// let g = Graph::from_edges(&[(0, 0), (0, 1), (0, 1)], 2, false).unwrap();
474 /// assert_eq!(g.neighbors_with(0, NeighborMode::All, Loops::Twice, true).unwrap(), vec![0, 0, 1, 1]);
475 /// assert_eq!(g.neighbors_with(0, NeighborMode::All, Loops::None, false).unwrap(), vec![1]);
476 /// ```
477 ///
478 /// # Errors
479 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for an invalid vertex.
480 pub fn neighbors_with(
481 &self,
482 vertex: VertexId,
483 mode: NeighborMode,
484 loops: Loops,
485 multiple: bool,
486 ) -> Result<Vec<VertexId>> {
487 let mut res = VectorInt::new();
488 igraph_call!(igraph_neighbors(
489 self,
490 &mut res,
491 vertex,
492 mode.into(),
493 loops.into(),
494 multiple
495 ))?;
496 Ok(res.into())
497 }
498
499 /// Ids of the edges incident to a vertex, ordered like the neighbors
500 /// of [`neighbors_with`](Self::neighbors_with) ([`igraph_incident`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_incident)).
501 ///
502 /// # Errors
503 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for an invalid vertex.
504 pub fn incident(
505 &self,
506 vertex: VertexId,
507 mode: NeighborMode,
508 loops: Loops,
509 ) -> Result<Vec<EdgeId>> {
510 let mut res = VectorInt::new();
511 igraph_call!(igraph_incident(
512 self,
513 &mut res,
514 vertex,
515 mode.into(),
516 loops.into()
517 ))?;
518 Ok(res.into())
519 }
520
521 /// Degrees of the selected vertices, in selector order
522 /// ([`igraph_degree`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_degree)); `loops` says whether a loop edge counts zero,
523 /// one or two times (two is the convention of the handshake lemma).
524 /// `mode` selects out-, in- or total degrees in directed graphs.
525 ///
526 /// See also [`Graph::strength`] (weighted degrees), [`Graph::maxdegree`]
527 /// and [`Graph::mean_degree`].
528 ///
529 /// ```
530 /// use igraph::prelude::*;
531 /// // A loop at 0 and a double edge 0 - 1.
532 /// let g = Graph::from_edges(&[(0, 0), (0, 1), (0, 1)], 2, false).unwrap();
533 /// assert_eq!(g.degree(.., NeighborMode::All, Loops::Twice).unwrap(), vec![4, 2]);
534 /// assert_eq!(g.degree(.., NeighborMode::All, Loops::Once).unwrap(), vec![3, 2]);
535 /// assert_eq!(g.degree(&[0], NeighborMode::All, Loops::None).unwrap(), vec![2]);
536 /// ```
537 ///
538 /// # Errors
539 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
540 pub fn degree<'a>(
541 &self,
542 vertices: impl Into<VertexSelector<'a>>,
543 mode: NeighborMode,
544 loops: Loops,
545 ) -> Result<Vec<igraph_int_t>> {
546 let vs = vertices.into().to_raw()?;
547 let mut res = VectorInt::new();
548 igraph_call!(igraph_degree(
549 self,
550 &mut res,
551 vs.get(),
552 mode.into(),
553 loops.into()
554 ))?;
555 Ok(res.into())
556 }
557
558 /// Degree of a single vertex, with the conventions of
559 /// [`degree`](Self::degree) but faster (O(1) when loops count twice,
560 /// O(degree) otherwise)
561 /// ([`igraph_degree_1`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_degree_1)).
562 ///
563 /// ```
564 /// use igraph::prelude::*;
565 /// let wheel = Graph::wheel(6, WheelMode::Undirected, 0).unwrap();
566 /// assert_eq!(wheel.degree_of(0, NeighborMode::All, Loops::Twice).unwrap(), 5);
567 /// assert_eq!(wheel.degree_of(3, NeighborMode::All, Loops::Twice).unwrap(), 3);
568 /// assert!(wheel.degree_of(6, NeighborMode::All, Loops::Twice).is_err());
569 /// ```
570 ///
571 /// # Errors
572 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for an invalid vertex.
573 pub fn degree_of(
574 &self,
575 vertex: VertexId,
576 mode: NeighborMode,
577 loops: Loops,
578 ) -> Result<igraph_int_t> {
579 // igraph 1.0.0 and 1.0.1 do not validate `vid` in `igraph_degree_1`
580 // (it indexes the graph's index vectors directly): check it here.
581 if !self.vertices().contains(&vertex) {
582 return Err(Error::new(
583 crate::error::ErrorKind::InvalidVertexId,
584 format!(
585 "vertex {vertex} is not in the graph (it has {} vertices)",
586 self.vcount()
587 ),
588 ));
589 }
590 let mut deg = 0;
591 igraph_call!(igraph_degree_1(
592 self,
593 &mut deg,
594 vertex,
595 mode.into(),
596 loops.into()
597 ))?;
598 Ok(deg)
599 }
600
601 /// Endpoints `(from, to)` of an edge ([`igraph_edge`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_edge)); for
602 /// undirected graphs `from <= to`.
603 ///
604 /// # Errors
605 /// [`ErrorKind::InvalidEdgeId`](crate::error::ErrorKind::InvalidEdgeId) for an invalid edge.
606 pub fn edge(&self, edge: EdgeId) -> Result<(VertexId, VertexId)> {
607 let (mut from, mut to) = (0, 0);
608 igraph_call!(igraph_edge(self, edge, &mut from, &mut to))?;
609 Ok((from, to))
610 }
611
612 /// Endpoints of the selected edges, in selector order ([`igraph_edges`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_edges)).
613 ///
614 /// # Errors
615 /// [`ErrorKind::InvalidEdgeId`](crate::error::ErrorKind::InvalidEdgeId) for invalid edges.
616 pub fn edges<'a>(
617 &self,
618 edges: impl Into<EdgeSelector<'a>>,
619 ) -> Result<Vec<(VertexId, VertexId)>> {
620 let es = edges.into().to_raw()?;
621 let mut res = VectorInt::new();
622 igraph_call!(igraph_edges(self, es.get(), &mut res, false))?;
623 Ok(res
624 .as_chunks::<2>()
625 .0
626 .iter()
627 .map(|&[a, b]| (a, b))
628 .collect())
629 }
630
631 /// All the edges as `(from, to)` pairs, in edge id order (for
632 /// undirected graphs `from <= to`).
633 ///
634 /// See [`edges_flat`](Self::edges_flat) and [`Graph::get_edgelist`] for
635 /// a flat list, and [`Graph::write_graph_edgelist_to_string`] for the
636 /// text format.
637 pub fn edge_list(&self) -> Vec<(VertexId, VertexId)> {
638 self.edges(EdgeSelector::All)
639 .expect("listing all edges cannot fail")
640 }
641
642 /// Id of an edge between two vertices, or `None` if they are not
643 /// connected ([`igraph_get_eid`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_get_eid)). With `directed = false`, edge
644 /// directions are ignored in directed graphs. With multi-edges, any one
645 /// of them may be returned.
646 ///
647 /// # Errors
648 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
649 pub fn get_eid(&self, from: VertexId, to: VertexId, directed: bool) -> Result<Option<EdgeId>> {
650 let mut eid = -1;
651 igraph_call!(igraph_get_eid(self, &mut eid, from, to, directed, false))?;
652 Ok((eid >= 0).then_some(eid))
653 }
654
655 /// Ids of the edges connecting the given vertex pairs ([`igraph_get_eids`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_get_eids));
656 /// see [`get_eids_opt`](Self::get_eids_opt) to tolerate missing edges.
657 ///
658 /// # Errors
659 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) if some pair is not
660 /// connected, [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
661 pub fn get_eids(&self, pairs: &[(VertexId, VertexId)], directed: bool) -> Result<Vec<EdgeId>> {
662 let flat: VectorInt = pairs.iter().flat_map(|&(a, b)| [a, b]).collect();
663 let mut res = VectorInt::new();
664 igraph_call!(igraph_get_eids(self, &mut res, &flat, directed, true))?;
665 Ok(res.into())
666 }
667
668 /// Ids of all the (multi-)edges between two vertices
669 /// ([`igraph_get_all_eids_between`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_get_all_eids_between)).
670 ///
671 /// # Errors
672 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
673 pub fn get_all_eids_between(
674 &self,
675 from: VertexId,
676 to: VertexId,
677 directed: bool,
678 ) -> Result<Vec<EdgeId>> {
679 let mut res = VectorInt::new();
680 igraph_call!(igraph_get_all_eids_between(
681 self, &mut res, from, to, directed
682 ))?;
683 Ok(res.into())
684 }
685
686 /// Whether two graphs are the same labelled graph: same directedness,
687 /// same number of vertices and precisely the same edges, regardless of
688 /// their order ([`igraph_is_same_graph`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_is_same_graph)).
689 /// It is what `==` on graphs computes. To compare graphs up to a
690 /// relabeling of their vertices, use [`Graph::isomorphic`].
691 ///
692 /// ```
693 /// use igraph::prelude::*;
694 /// let a = Graph::from_edges(&[(0, 1), (2, 1)], 3, false).unwrap();
695 /// let b = Graph::from_edges(&[(1, 2), (0, 1)], 3, false).unwrap();
696 /// let c = Graph::from_edges(&[(0, 2), (1, 2)], 3, false).unwrap(); // isomorphic only
697 /// assert!(a.is_same_graph(&b).unwrap());
698 /// assert!(!a.is_same_graph(&c).unwrap());
699 /// ```
700 pub fn is_same_graph(&self, other: &Self) -> Result<bool> {
701 let mut res = false;
702 igraph_call!(igraph_is_same_graph(self, other, &mut res))?;
703 Ok(res)
704 }
705
706 /// Resolves a vertex selector into the list of vertex ids it denotes
707 /// (`igraph_vs_as_vector`, undocumented in `igraph_iterators.h`).
708 ///
709 /// # Errors
710 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) (or
711 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) for ranges) if the selector names
712 /// missing vertices.
713 pub fn select_vertices<'a>(
714 &self,
715 vertices: impl Into<VertexSelector<'a>>,
716 ) -> Result<Vec<VertexId>> {
717 let vs = vertices.into().to_raw()?;
718 let mut res = VectorInt::new();
719 igraph_call!(igraph_vs_as_vector(self, vs.get(), &mut res))?;
720 Ok(res.into())
721 }
722
723 /// Resolves an edge selector into the list of edge ids it denotes
724 /// ([`igraph_es_as_vector`](https://igraph.org/c/html/latest/igraph-Iterators.html#igraph_es_as_vector)).
725 ///
726 /// # Errors
727 /// [`ErrorKind::InvalidEdgeId`](crate::error::ErrorKind::InvalidEdgeId) for missing edges, and
728 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) for vertex pairs that are not connected.
729 pub fn select_edges<'a>(&self, edges: impl Into<EdgeSelector<'a>>) -> Result<Vec<EdgeId>> {
730 let es = edges.into().to_raw()?;
731 let mut res = VectorInt::new();
732 igraph_call!(igraph_es_as_vector(self, es.get(), &mut res))?;
733 Ok(res.into())
734 }
735
736 /// Invalidates igraph's internal cache of graph properties
737 /// ([`igraph_invalidate_cache`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_invalidate_cache)); only needed after unsafe raw mutation.
738 pub fn invalidate_cache(&self) {
739 unsafe { igraph_invalidate_cache(self) }
740 }
741
742 /// Runs `f` (typically one igraph call) so that igraph's property cache
743 /// cannot corrupt an adjacency list built in `IGRAPH_ALL` mode with
744 /// `IGRAPH_NO_MULTIPLE`.
745 ///
746 /// In igraph 1.0.0 and 1.0.1, `igraph_adjlist_init` and
747 /// `igraph_lazy_adjlist_init` skip the removal of duplicate neighbors when
748 /// the cache says the graph has no multi-edges. For a *directed* graph
749 /// with a mutual pair `u -> v`, `v -> u` that is wrong in `IGRAPH_ALL`
750 /// mode (each endpoint lists the other twice), and algorithms that rely
751 /// on distinct neighbors then fail assertions or corrupt memory;
752 /// `igraph_adjlist_init` may even cache a wrong `HAS_MULTI = true`.
753 /// Affected C functions include cliques, independent sets, coloring,
754 /// girth, chordality, triangles and transitivity, `igraph_ecc`,
755 /// eccentricity/radius/center/pseudo-diameter, simple paths, local scan,
756 /// Jaccard/Dice similarity, graph power and Reingold–Tilford.
757 ///
758 /// For directed graphs the cache is dropped before `f` and again after
759 /// it, even if `f` panics; undirected graphs are unaffected and `f` runs
760 /// directly. It only costs recomputing cached properties. `Graph` is
761 /// `Send` but not `Sync`, so no other thread observes the cache meanwhile.
762 pub(crate) fn with_fresh_multi_cache<T>(&self, f: impl FnOnce() -> T) -> T {
763 struct Invalidate<'a>(&'a igraph_t);
764 impl Drop for Invalidate<'_> {
765 fn drop(&mut self) {
766 self.0.invalidate_cache();
767 }
768 }
769 if !self.is_directed() {
770 return f();
771 }
772 self.invalidate_cache();
773 let _after = Invalidate(self);
774 f()
775 }
776
777 /// A deep copy of the graph, reporting allocation failures as an
778 /// error instead of panicking like [`Clone::clone`]
779 /// ([`igraph_copy`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_copy)).
780 pub fn try_clone(&self) -> Result<Self> {
781 Self::init_with(|g| unsafe { igraph_copy(g, self) })
782 }
783
784 /// Adds one isolated vertex and returns its id
785 /// ([`igraph_add_vertices`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_add_vertices)).
786 ///
787 /// ```
788 /// use igraph::prelude::*;
789 /// let mut g = Graph::new(2, false);
790 /// let v = g.add_vertex().unwrap();
791 /// g.add_edge(0, v).unwrap();
792 /// assert_eq!((v, g.vcount()), (2, 3));
793 /// ```
794 pub fn add_vertex(&mut self) -> Result<VertexId> {
795 let id = self.vcount() as VertexId;
796 self.add_vertices(1)?;
797 Ok(id)
798 }
799
800 /// Adds an edge and returns its id (edges are appended, so the new id
801 /// is the previous edge count)
802 /// ([`igraph_add_edge`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_add_edge)).
803 pub fn add_edge_id(&mut self, from: VertexId, to: VertexId) -> Result<EdgeId> {
804 let id = self.ecount() as EdgeId;
805 self.add_edge(from, to)?;
806 Ok(id)
807 }
808
809 /// Whether some edge connects `from` and `to` (in this direction if
810 /// `directed` is true and the graph is directed)
811 /// ([`igraph_get_eid`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_get_eid)).
812 ///
813 /// # Errors
814 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
815 pub fn has_edge(&self, from: VertexId, to: VertexId, directed: bool) -> Result<bool> {
816 Ok(self.get_eid(from, to, directed)?.is_some())
817 }
818
819 /// Ids of the edges connecting the given vertex pairs, with `None` for
820 /// the pairs that are not connected
821 /// ([`igraph_get_eids`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_get_eids)
822 /// with `error = false`).
823 ///
824 /// ```
825 /// use igraph::prelude::*;
826 /// let g = Graph::from_edges(&[(0, 1), (1, 2)], 3, false).unwrap();
827 /// assert_eq!(g.get_eids_opt(&[(2, 1), (0, 2)], true).unwrap(), vec![Some(1), None]);
828 /// ```
829 ///
830 /// # Errors
831 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for invalid vertices.
832 pub fn get_eids_opt(
833 &self,
834 pairs: &[(VertexId, VertexId)],
835 directed: bool,
836 ) -> Result<Vec<Option<EdgeId>>> {
837 let flat: VectorInt = pairs.iter().flat_map(|&(a, b)| [a, b]).collect();
838 let mut res = VectorInt::new();
839 igraph_call!(igraph_get_eids(self, &mut res, &flat, directed, false))?;
840 Ok(res.iter().map(|&e| (e >= 0).then_some(e)).collect())
841 }
842
843 /// Endpoints of the selected edges as a flat list; with `bycol = false`
844 /// it is `[from0, to0, from1, to1, ...]`, with `bycol = true` it is
845 /// `[from0, from1, ..., to0, to1, ...]`
846 /// ([`igraph_edges`](https://igraph.org/c/html/latest/igraph-Basic.html#igraph_edges)).
847 pub fn edges_flat<'a>(
848 &self,
849 edges: impl Into<EdgeSelector<'a>>,
850 bycol: bool,
851 ) -> Result<Vec<VertexId>> {
852 let es = edges.into().to_raw()?;
853 let mut res = VectorInt::new();
854 igraph_call!(igraph_edges(self, es.get(), &mut res, bycol))?;
855 Ok(res.into())
856 }
857
858 /// The source vertex of an edge (`IGRAPH_FROM`).
859 ///
860 /// # Errors
861 /// [`ErrorKind::InvalidEdgeId`](crate::error::ErrorKind::InvalidEdgeId) for an invalid edge.
862 pub fn edge_from(&self, edge: EdgeId) -> Result<VertexId> {
863 Ok(self.edge(edge)?.0)
864 }
865
866 /// The target vertex of an edge (`IGRAPH_TO`).
867 ///
868 /// # Errors
869 /// [`ErrorKind::InvalidEdgeId`](crate::error::ErrorKind::InvalidEdgeId) for an invalid edge.
870 pub fn edge_to(&self, edge: EdgeId) -> Result<VertexId> {
871 Ok(self.edge(edge)?.1)
872 }
873
874 /// The endpoint of `edge` opposite to `vertex` (`IGRAPH_OTHER`); for a
875 /// loop edge it is `vertex` itself.
876 ///
877 /// # Errors
878 /// [`ErrorKind::InvalidEdgeId`](crate::error::ErrorKind::InvalidEdgeId) for an invalid edge, and
879 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) if `vertex` is not an
880 /// endpoint of `edge`.
881 pub fn other_endpoint(&self, edge: EdgeId, vertex: VertexId) -> Result<VertexId> {
882 let (from, to) = self.edge(edge)?;
883 if to == vertex {
884 Ok(from)
885 } else if from == vertex {
886 Ok(to)
887 } else {
888 Err(Error::invalid(format!(
889 "vertex {vertex} is not an endpoint of edge {edge}"
890 )))
891 }
892 }
893
894 /// Number of vertices in a vertex selector for this graph
895 /// ([`igraph_vs_size`](https://igraph.org/c/html/latest/igraph-Iterators.html#igraph_vs_size)).
896 ///
897 /// This only *counts*, it does not validate: lists and ranges are
898 /// counted by their length (duplicates included) even if they name
899 /// missing vertices, and a single missing vertex counts as `0`. Only
900 /// the adjacent and non-adjacent selectors query the graph, and fail for
901 /// a missing center.
902 /// Use [`select_vertices`](Self::select_vertices) to resolve and
903 /// validate a selector.
904 ///
905 /// ```
906 /// use igraph::prelude::*;
907 /// let g = Graph::ring(5, false, false, true).unwrap();
908 /// assert_eq!(g.vs_size(..).unwrap(), 5);
909 /// assert_eq!(g.vs_size(&[1, 1, 4]).unwrap(), 3);
910 /// assert_eq!(g.vs_size(VertexSelector::non_adjacent(0, NeighborMode::All)).unwrap(), 3);
911 /// assert_eq!(g.vs_size(9).unwrap(), 0); // not validated
912 /// assert!(g.select_vertices(9).is_err());
913 /// ```
914 ///
915 /// # Errors
916 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId)
917 /// for an adjacent or non-adjacent selector around a missing vertex.
918 pub fn vs_size<'a>(&self, vertices: impl Into<VertexSelector<'a>>) -> Result<usize> {
919 let vs = vertices.into().to_raw()?;
920 let mut n = 0;
921 igraph_call!(igraph_vs_size(self, vs.as_ptr(), &mut n))?;
922 Ok(n as usize)
923 }
924
925 /// Number of edges in an edge selector for this graph
926 /// ([`igraph_es_size`](https://igraph.org/c/html/latest/igraph-Iterators.html#igraph_es_size)).
927 ///
928 /// Like [`vs_size`](Self::vs_size), lists and ranges are counted by
929 /// their length without validation (and a single missing edge counts as
930 /// `0`); incident, pair, path and all-between selectors query the graph.
931 /// Use [`select_edges`](Self::select_edges) to resolve and validate a
932 /// selector.
933 ///
934 /// # Errors
935 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId)
936 /// for selectors around missing vertices,
937 /// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) for
938 /// pairs that are not connected.
939 pub fn es_size<'a>(&self, edges: impl Into<EdgeSelector<'a>>) -> Result<usize> {
940 let es = edges.into().to_raw()?;
941 let mut n = 0;
942 igraph_call!(igraph_es_size(self, es.as_ptr(), &mut n))?;
943 Ok(n as usize)
944 }
945
946 /// Neighbors of the vertex through an adjacency *selector*
947 /// ([`igraph_vs_adj`](https://igraph.org/c/html/latest/igraph-Iterators.html#igraph_vs_adj) resolved with
948 /// `igraph_vs_as_vector`, which is undocumented in `igraph_iterators.h`), with full control of
949 /// loops and multi-edges; the result equals
950 /// [`neighbors_with`](Self::neighbors_with) with the same arguments.
951 /// Unlike [`VertexSelector::Adjacent`], which always ignores loops and
952 /// multi-edges, the conventions are configurable.
953 ///
954 /// # Errors
955 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for an invalid vertex.
956 pub fn adjacent_vertices(
957 &self,
958 vertex: VertexId,
959 mode: NeighborMode,
960 loops: Loops,
961 multiple: bool,
962 ) -> Result<Vec<VertexId>> {
963 ensure_init();
964 let mut vs = MaybeUninit::<igraph_vs_t>::uninit();
965 igraph_call!(igraph_vs_adj(
966 vs.as_mut_ptr(),
967 vertex,
968 mode.into(),
969 loops.into(),
970 multiple
971 ))?;
972 // Adjacency selectors own no memory: no `igraph_vs_destroy` needed.
973 let vs = unsafe { vs.assume_init() };
974 let mut res = VectorInt::new();
975 igraph_call!(igraph_vs_as_vector(self, vs, &mut res))?;
976 Ok(res.into())
977 }
978
979 /// Incident edges of the vertex with the given loop handling, in
980 /// selector order ([`igraph_es_incident`](https://igraph.org/c/html/latest/igraph-Iterators.html#igraph_es_incident) resolved
981 /// with [`igraph_es_as_vector`](https://igraph.org/c/html/latest/igraph-Iterators.html#igraph_es_as_vector)); unlike
982 /// [`EdgeSelector::Incident`], which lists every loop once, the loop
983 /// counting mode is configurable. The result equals
984 /// [`incident`](Self::incident) with the same arguments.
985 ///
986 /// # Errors
987 /// [`ErrorKind::InvalidVertexId`](crate::error::ErrorKind::InvalidVertexId) for an invalid vertex.
988 pub fn incident_edges(
989 &self,
990 vertex: VertexId,
991 mode: NeighborMode,
992 loops: Loops,
993 ) -> Result<Vec<EdgeId>> {
994 ensure_init();
995 let mut es = MaybeUninit::<igraph_es_t>::uninit();
996 igraph_call!(igraph_es_incident(
997 es.as_mut_ptr(),
998 vertex,
999 mode.into(),
1000 loops.into()
1001 ))?;
1002 let mut es = unsafe { es.assume_init() };
1003 let mut res = VectorInt::new();
1004 let r = igraph_call!(igraph_es_as_vector(self, std::ptr::read(&es), &mut res));
1005 unsafe { igraph_es_destroy(&mut es) };
1006 r?;
1007 Ok(res.into())
1008 }
1009
1010 /// Iterates over the edges as `(id, from, to)` triples, in id order.
1011 ///
1012 /// ```
1013 /// use igraph::prelude::*;
1014 /// let g = Graph::from_edges(&[(0, 1), (1, 2)], 3, true).unwrap();
1015 /// let e: Vec<_> = g.edges_iter().collect();
1016 /// assert_eq!(e, vec![(0, 0, 1), (1, 1, 2)]);
1017 /// ```
1018 pub fn edges_iter(&self) -> impl Iterator<Item = (EdgeId, VertexId, VertexId)> + '_ {
1019 // `from`/`to` are igraph's edge arrays (see `IGRAPH_FROM`/`IGRAPH_TO`);
1020 // like `igraph_edge`, report undirected edges as `(smaller, larger)`,
1021 // igraph stores them the other way around.
1022 let directed = self.is_directed();
1023 self.from
1024 .iter()
1025 .zip(self.to.iter())
1026 .enumerate()
1027 .map(move |(e, (&a, &b))| {
1028 if directed {
1029 (e as EdgeId, a, b)
1030 } else {
1031 (e as EdgeId, b, a)
1032 }
1033 })
1034 }
1035}
1036
1037/// Converts a count given as `usize` into an `igraph_int_t`, reporting an
1038/// [`ErrorKind::InvalidValue`](crate::error::ErrorKind::InvalidValue) error
1039/// (instead of wrapping around to a negative number) when it does not fit.
1040fn count_arg(n: usize, what: &str) -> Result<igraph_int_t> {
1041 igraph_int_t::try_from(n)
1042 .map_err(|_| Error::invalid(format!("{what} ({n}) does not fit in an igraph_int_t")))
1043}