1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
//! A powerful library for directed adjacency list graphs.
//!
//! Graph is a complex data structure where relations between nodes may often be cyclic which
//! doesn't go well with the Rust's type system. A typical approach to this is to refer to nodes and
//! edges in a graph using node and edge indices (sometimes called IDs or keys) which are **mapped**
//! to the actual nodes, edges and their weights instead of using references or pointers. Since
//! we're **mapping** indices anyway why not make the **maps** we use generic and allow custom
//! indices?
//!
//! `mapgraph` provides the generic [`Graph`] type that is based on two maps: one for nodes and
//! one for edges. By using the rich system of traits from the [`map`] submodule the [`Graph`] type
//! may borrow some capabilities of the maps it's based on. For example, using a [`HashMap`] as a
//! node map for a [`Graph`] makes it accept external indices for nodes, effectively making the
//! graph an index for its own nodes.
//!
//! # Library features and examples
//!
//! ## Internal node indices
//!
//! Let's imagine Alice and Bob are friends and often call each other. Sometimes they order pizza by
//! phone from a place where Luigi works, but they aren't friends with Luigi, so he never calls them
//! by himself.
//!
//! Here's one way to make a graph to represent their relations:
//!
//! ```
//! use mapgraph::aliases::SlotMapGraph;
//!
//! # fn main() -> Result<(), mapgraph::error::AddEdgeError> {
//! // we create a graph that uses SlotMaps for both nodes and edges
//! let mut graph = SlotMapGraph::<&'static str, ()>::default();
//!
//! // next we create a node for each person
//! let alice_index = graph.add_node("Alice");
//! let bob_index = graph.add_node("Bob");
//! let luigi_index = graph.add_node("Luigi");
//!
//! // let's ensure that the indices return us the right node weights
//! assert_eq!(graph.node_weight(alice_index).copied(), Some("Alice"));
//! assert_eq!(graph.node_weight(bob_index).copied(), Some("Bob"));
//! assert_eq!(graph.node_weight(luigi_index).copied(), Some("Luigi"));
//!
//! // finally let's connect them
//! graph.add_edge((), alice_index, bob_index)?;
//! graph.add_edge((), bob_index, alice_index)?;
//! graph.add_edge((), bob_index, luigi_index)?;
//! graph.add_edge((), alice_index, luigi_index)?;
//! # Ok(())
//! # }
//! ```
//!
//! Here [`SlotMapGraph`] is just an alias for [`Graph`] that uses [`SlotMap`]s for both nodes and
//! edges. We don't use edge weights, so we pass the unit type as the first parameter to
//! [`Graph::add_edge`].
//!
//! While this may not seem like much just yet, using [`SlotMap`]s gives [`Graph`] important
//! properties: removing nodes won't cause unrelated indices to be invalidated and key versioning
//! prevents older indices from pointing to newly added nodes that happen to be stored in place of
//! an older node.
//!
//! ## External node indices
//!
//! Now let's imagine we are telephone company employees who want to trace phone numbers to people
//! and their relations for data science purposes. The obvious way to do this would be to create a
//! separate index that maps phone numbers to graph indices, but that presents a challenge: the
//! index should be synchronised to the graph. Adding or removing nodes should update the index as
//! well as the graph itself. What if we used the phone numbers as node indices directly?
//!
//! Here's how we can do this:
//!
//! ```
//! use mapgraph::aliases::HashSlotMapGraph;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // we create a graph that uses a HashMap for nodes and a SlotMap for edges
//! let mut graph = HashSlotMapGraph::<&'static str, (), _>::default();
//!
//! // define some constants for simplicity
//! const ALICE_NUMBER: &'static str = "6661234";
//! const BOB_NUMBER: &'static str = "5553535";
//! const LUIGI_NUMBER: &'static str = "1001112";
//!
//! // next we create a node for each person
//! graph.try_add_node_at_index(ALICE_NUMBER, "Alice")?;
//! graph.try_add_node_at_index(BOB_NUMBER, "Bob")?;
//! graph.try_add_node_at_index(LUIGI_NUMBER, "Luigi")?;
//!
//! // let's ensure that the indices return us the right node weights
//! assert_eq!(graph.node_weight(ALICE_NUMBER).copied(), Some("Alice"));
//! assert_eq!(graph.node_weight(BOB_NUMBER).copied(), Some("Bob"));
//! assert_eq!(graph.node_weight(LUIGI_NUMBER).copied(), Some("Luigi"));
//!
//! // finally let's connect them
//! graph.add_edge((), ALICE_NUMBER, BOB_NUMBER)?;
//! graph.add_edge((), BOB_NUMBER, ALICE_NUMBER)?;
//! graph.add_edge((), BOB_NUMBER, LUIGI_NUMBER)?;
//! graph.add_edge((), ALICE_NUMBER, LUIGI_NUMBER)?;
//! # Ok(())
//! # }
//! ```
//!
//! We use a [`HashSlotMapGraph`] which is just an alias to a [`Graph`] like [`SlotMapGraph`] from
//! the previous example. The interface for adding nodes to a [`HashSlotMapGraph`] is, however,
//! different. The [`Graph::try_add_node_at_index`] method that accepts an external node index is
//! used rather than [`Graph::add_node`] which provides an index as its return value since
//! [`HashMap`] accepts keys provided externally unlike [`SlotMap`] which produces its keys
//! internally. The way your map treats indices is encoded by implementing either [`ExtKeyMap`] or
//! [`IntKeyMap`] trait. See documentation for the [`map`] module for more info on map traits and
//! the capabilities they expose.
//!
//! ## Ordered node indices
//!
//! For the last example let's pretend we also want to find people with particular area codes in
//! their phone numbers:
//!
//! ```
//! use mapgraph::aliases::BTreeSlotMapGraph;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // we create a graph that uses a BTreeMap for nodes and a SlotMap for edges
//! let mut graph = BTreeSlotMapGraph::<&'static str, (), _>::default();
//!
//! // define some constants for simplicity
//! const ALICE_NUMBER: &'static str = "6661234";
//! const BOB_NUMBER: &'static str = "5553535";
//! const LUIGI_NUMBER: &'static str = "1001112";
//!
//! // next we create a node for each person
//! graph.try_add_node_at_index(ALICE_NUMBER, "Alice")?;
//! graph.try_add_node_at_index(BOB_NUMBER, "Bob")?;
//! graph.try_add_node_at_index(LUIGI_NUMBER, "Luigi").unwrap();
//!
//! // we skip adding edges this time and just do a range query
//! let phones_and_names: Vec<_> = graph.nodes_range("5000000"..="7000000").collect();
//!
//! // check that the results match our expectations
//! assert_eq!(
//! &phones_and_names,
//! &[(BOB_NUMBER, &"Bob"), (ALICE_NUMBER, &"Alice")]
//! );
//! # Ok(())
//! # }
//! ```
//!
//! Here we use the capabilities of a [`BTreeMap`] that are lent to the graph using the
//! [`OrderedKeyMap`] trait.
//!
//! # More advanced features
//!
//! ## Frozen graphs
//!
//! This is a nice feature lent from the [`petgraph`] crate. [`FrozenGraph`] is a [`Graph`] with an
//! immutable structure. Having a mutable reference to a [`FrozenGraph`] means you can mutate
//! weights, but not add or remove nodes and edges. [`Graph`] and [`FrozenGraph`] can be freely
//! converted between each other, graph also implements [`Deref<Target=FrozenGraph>`]. See docs for
//! [`FrozenGraph`] for more info.
//!
//! ## Parallel iteration using [`rayon`]
//!
//! When the `rayon` crate feature is enabled, [`Graph`] exposes methods for parallel iteration of
//! nodes and edges in case the underlying maps expose this functionality through the [`ParIterMap`]
//! trait.
//!
//! ```
//! use mapgraph::aliases::HashSlotMapGraph;
//! use rayon::iter::ParallelIterator;
//!
//! let mut graph = HashSlotMapGraph::<i32, i32, &'static str>::default();
//!
//! // add nodes and edges...
//!
//! // add 1 to each node weight in parallel
//! graph
//! .par_iter_node_weights_mut()
//! .for_each(|(_, weight)| *weight += 1);
//! ```
//!
//! In case you need to mutably iterate nodes and edges in parallel or to walk over edges while
//! doing parallel iteration on nodes (or vice versa), a mutable reference to a [`Graph`] may be
//! split into a reference to [`Nodes`] and a reference to [`Edges`]:
//!
//! ```
//! use mapgraph::{aliases::HashSlotMapGraph, graph::iter::EdgesWalker};
//! use rayon::iter::ParallelIterator;
//!
//! let mut graph = HashSlotMapGraph::<i32, i32, &'static str>::default();
//!
//! // add nodes and edges...
//!
//! // split a reference to a graph
//! let (nodes, edges) = graph.as_nodes_mut_and_edges();
//!
//! nodes.par_iter_mut().for_each(|(_, node)| {
//! // let's sum all the weight of outgoing edges of that node
//! let mut outputs_walker = node.walk_outputs();
//! let mut sum = 0;
//! while let Some((_ei, edge)) = outputs_walker.walk_edges_next(edges) {
//! sum += *edge.weight();
//! }
//!
//! // add that sum to the node's weight
//! *node.weight_mut() += sum;
//! });
//! ```
//!
//! # Crate features
//!
//! * `std` - enables support for the [`HashMap`] type, provides implementations of
//! [`std::error::Error`] on error types, enables the `std` feature on the [`slotmap`] crate if the
//! `slotmap` feature is enabled. Requires the `alloc` feature.
//! * `alloc` - enables support for the [`alloc`] crate, in particular [`BTreeMap`] and [`BTreeSet`]
//! types.
//! * `slotmap` - enables integration with the [`slotmap`] crate.
//! * `indexmap` - enables integration with the [`indexmap`] crate.
//! * `algorithms` - enables the [`algo`] module which provides various algorithms to be run on
//! graphs.
//! * `serde` - enables serialization/deserialization using [`serde`]. Disabled by default.
//! * `rayon` - enables parallel iteration support using [`rayon`]. Disabled by default.
//!
//! [`petgraph`]: https://github.com/petgraph/petgraph
//! [`HashMap`]: std::collections::HashMap
//! [`BTreeMap`]: alloc::collections::BTreeMap
//! [`BTreeSet`]: alloc::collections::BTreeSet
//! [`SlotMap`]: slotmap::SlotMap
//! [`IndexMap`]: indexmap::IndexMap
//! [`SlotMapGraph`]: aliases::SlotMapGraph
//! [`HashSlotMapGraph`]: aliases::HashSlotMapGraph
//! [`Deref<Target=FrozenGraph>`]: std::ops::Deref
//! [`Nodes`]: graph::Nodes
//! [`Edges`]: graph::Edges
extern crate alloc;
extern crate std;
pub use ;
pub use ParIterMap;
pub use ;