Skip to main content

osm_lump_ways/graph/
directed_graph.rs

1use super::*;
2use log::warn;
3use rayon::prelude::ParallelIterator;
4use smallvec::SmallVec;
5use std::collections::{BTreeMap, HashSet};
6use std::fmt::Debug;
7
8use crate::kosaraju;
9use itertools::Itertools;
10use std::iter;
11
12pub trait DirectedGraphTrait<V, E>: Send + Sync + Sized {
13    fn new() -> Self;
14
15    fn in_neighbours(&self, vertex: i64) -> impl Iterator<Item = i64>;
16    fn num_in_neighbours(&self, vertex: i64) -> Option<usize> {
17        if self.contains_vertex(&vertex) {
18            Some(self.in_neighbours(vertex).count())
19        } else {
20            None
21        }
22    }
23    /// Returns (a, to_vertex) where a is an in neighbour of to_vertex
24    fn in_edges(&self, vertex: i64) -> impl Iterator<Item = (i64, i64)> {
25        self.in_neighbours(vertex).map(move |nid0| (nid0, vertex))
26    }
27    fn out_neighbours(&self, vertex: i64) -> impl Iterator<Item = i64>;
28    fn out_neighbours_w_prop<'a>(&'a self, from_vertex: i64) -> impl Iterator<Item = (i64, &'a E)>
29    where
30        E: 'a;
31    fn num_out_neighbours(&self, vertex: i64) -> Option<usize> {
32        if self.contains_vertex(&vertex) {
33            Some(self.out_neighbours(vertex).count())
34        } else {
35            None
36        }
37    }
38
39    /// Returns (from_vertex, b) where b is an out neighbour of from_vertex
40    fn out_edges(&self, vertex: i64) -> impl Iterator<Item = (i64, i64)> {
41        self.out_neighbours(vertex).map(move |nid2| (vertex, nid2))
42    }
43
44    /// All edges that go to/from this vertex. No guarantee of order.
45    fn edges(&self, vertex: i64) -> impl Iterator<Item = (i64, i64)> {
46        self.in_edges(vertex).chain(self.out_edges(vertex))
47    }
48
49    // For an edge (defined by 2 vertexes), return all other edges which are connected to the first
50    // or last vertex (excl. this edge)
51    fn all_connected_edges(&self, edge: &(i64, i64)) -> impl Iterator<Item = (i64, i64)> {
52        self.in_neighbours(edge.0)
53            .map(|v0| (v0, edge.0))
54            .chain(self.out_neighbours(edge.0).map(|v2| (edge.0, v2)))
55            .chain(self.in_neighbours(edge.1).map(|v0| (v0, edge.1)))
56            .chain(self.out_neighbours(edge.1).map(|v2| (edge.1, v2)))
57            .filter(move |new_edge| new_edge != edge)
58    }
59
60    fn contains_edge(&self, from_vertex: impl Into<i64>, to_vertex: impl Into<i64>) -> bool {
61        let to_vertex = to_vertex.into();
62        self.out_neighbours(from_vertex.into())
63            .any(|v| v == to_vertex)
64    }
65
66    fn num_vertexes(&self) -> usize;
67    fn num_edges(&self) -> usize {
68        self.edges_iter().count()
69    }
70    /// True iff this vertex is in this graph
71    fn contains_vertex(&self, vid: &i64) -> bool;
72
73    /// Iterator over all edges
74    fn edges_iter(&self) -> impl Iterator<Item = (i64, i64)> + '_;
75    fn edges_par_iter(&self) -> impl ParallelIterator<Item = (i64, i64)>;
76
77    /// returns each vertex and the number of out edges
78    fn vertexes_and_num_outs(&self) -> impl Iterator<Item = (i64, usize)> + '_;
79
80    fn len(&self) -> (usize, usize) {
81        (self.num_vertexes(), self.num_edges())
82    }
83
84    fn is_empty(&self) -> bool {
85        self.num_vertexes() == 0
86    }
87
88    /// Iterator (in any order) of vertexes which are the destination of an edge
89    fn dest_vertexes_jumbled(&self) -> impl ParallelIterator<Item = i64> {
90        self.edges_par_iter().map(|(_src, dest)| dest)
91    }
92    /// Iterator (in any order) of vertexes which are the src of an edge
93    fn src_vertexes_jumbled(&self) -> impl Iterator<Item = i64> {
94        self.edges_iter().map(|(src, _dest)| src)
95    }
96
97    /// True iff this vertex has an outgoing edge
98    fn vertex_has_outgoing(&self, vid: &i64) -> bool {
99        self.out_neighbours(*vid).next().is_some()
100    }
101
102    fn detailed_size(&self) -> String;
103
104    /// True iff this vertex does not have ≥1 edges. this happens with zero in edges, or if the
105    /// edge doesn't exist
106    /// when doing topological sorting, we remove edges, which can remove the vertex when there are
107    /// no more incoming
108    fn num_ins_zero(&self, vid: &i64) -> bool {
109        self.num_in_neighbours(*vid) == Some(0)
110    }
111
112    /// returns each vertex and the number of in & out edges
113    fn vertexes_and_num_ins_outs(&self) -> impl Iterator<Item = (i64, usize, usize)> + '_;
114
115    /// Iterator (in any order, possibly with dupes) of vertexes which do not have outgoing edges
116    fn vertexes_wo_outgoing_jumbled(&self) -> impl ParallelIterator<Item = i64>
117    where
118        Self: Sync,
119    {
120        self.dest_vertexes_jumbled()
121            .filter(|v| !self.vertex_has_outgoing(v))
122    }
123
124    /// starting at point `nid`, follow all upstreams, in a DFS manner
125    fn all_in_edges_recursive(
126        &self,
127        nid: i64,
128        incl_nid: impl Fn(&i64) -> bool,
129        nodeid_pos: &impl NodeIdPosition,
130    ) -> impl Iterator<Item = Vec<(f64, f64)>> {
131        let mut frontier: SmallVec<[_; 1]> = smallvec::smallvec![];
132        let mut seen_vertexes = HashSet::new();
133        if incl_nid(&nid) {
134            frontier.push((nid, None));
135        }
136
137        // Somehow in this, nids are getting added to the frontier many times, and this is causing
138        // massive duplications of part of nodes
139
140        std::iter::from_fn(move || {
141            if frontier.is_empty() {
142                return None;
143            }
144
145            let (mut curr_point, opt_prev_point) = frontier.pop().unwrap();
146            let mut curr_latlng;
147            let mut curr_path = Vec::with_capacity(10);
148
149            if let Some(prev_point) = opt_prev_point {
150                curr_path.push(prev_point);
151            }
152            loop {
153                curr_latlng = nodeid_pos.get(&curr_point).unwrap();
154                curr_path.push(curr_latlng);
155                seen_vertexes.insert(curr_point);
156                let mut ins = self
157                    .in_neighbours(curr_point)
158                    .filter(|i| !seen_vertexes.contains(i));
159                match ins.next() {
160                    Some(nxt) => {
161                        // any other out neighbours of this point need to be visited later
162                        frontier.extend(
163                            ins.filter(|n| incl_nid(n))
164                                .map(|in_nid| (in_nid, Some(curr_latlng))),
165                        );
166
167                        curr_point = nxt;
168                        continue;
169                    }
170                    _ => {
171                        // no more neighbours here
172                        curr_path.reverse();
173                        return Some(curr_path);
174                    }
175                }
176            }
177        })
178    }
179    /// Vertex v exists, and has either in neighbours, xor out neighbours (but not both)
180    fn neighbors_in_xor_out(&mut self, v: &i64) -> bool {
181        (self.num_in_neighbours(*v) == Some(0)) ^ (self.num_out_neighbours(*v) == Some(0))
182    }
183    fn delete_edge(&mut self, vertex1: &i64, vertex2: &i64);
184
185    fn expand_edge(&self, vertex1: i64, vertex2: i64) -> impl Iterator<Item = i64> + '_ {
186        iter::once(vertex1).chain(iter::once(vertex2))
187    }
188
189    /// Removes this vertex (& associated edges) from this graph
190    fn delete_vertex(&mut self, vertex: &i64);
191
192    fn contract_vertex(&mut self, vertex: &i64, replacement: &i64);
193    /// Iterator over all vertexes
194    fn vertexes(&self) -> impl Iterator<Item = i64> + '_ {
195        self.vertexes_iter()
196    }
197    fn vertexes_iter(&self) -> impl Iterator<Item = i64> + '_;
198    fn vertexes_par_iter(&self) -> impl ParallelIterator<Item = i64>;
199
200    fn add_edge(&mut self, vertex1: i64, vertex2: i64) -> bool;
201    /// Add many vertexes & edges
202    fn add_edge_chain(&mut self, vertexes: &[i64]) -> bool {
203        // This could be speed up by keeping a reference to the current vertex edges and walking
204        // along. saved looking up the same vertex twice in the btreemap
205        if vertexes.len() < 2 {
206            return false;
207        }
208        let mut added = false;
209        for w in vertexes.windows(2) {
210            added |= self.add_edge(w[0], w[1]);
211        }
212        added
213    }
214
215    fn into_vertexes_topologically_sorted(self, sorting_nodes_bar: &ProgressBar) -> Vec<i64> {
216        let mut g = self;
217        let mut result = Vec::with_capacity(g.num_vertexes());
218        let mut frontier: Vec<i64> = Vec::new();
219
220        let mut others = SmallNidVec::new();
221        loop {
222            frontier.extend(
223                g.vertexes_and_num_ins_outs().filter_map(
224                    |(v, num_ins, _num_outs)| if num_ins == 0 { Some(v) } else { None },
225                ),
226            );
227            if frontier.is_empty() {
228                break;
229            }
230
231            while let Some(v) = frontier.pop() {
232                result.push(v);
233                sorting_nodes_bar.inc(1);
234
235                // have to save to another Vec to prevent lifetimes
236                others.truncate(0);
237                others.extend(g.out_neighbours(v));
238                for other in others.drain(..) {
239                    g.delete_edge(&v, &other);
240                    if g.num_ins_zero(&other) {
241                        frontier.push(other);
242                    }
243                }
244            }
245        }
246
247        assert!(
248            g.is_empty(),
249            "num_vertexes = {} ≠ 0, first remaining edge: {:?}",
250            g.num_vertexes(),
251            g.edges_iter().next().unwrap()
252        );
253
254        result
255    }
256
257    fn into_disconnected_graphs(self, progress_bar: &ProgressBar) -> impl Iterator<Item = Self>;
258
259    fn strongly_connected_components(
260        &self,
261        calc_components_bar: &ProgressBar,
262    ) -> Vec<Vec<[i64; 2]>> {
263        if self.is_empty() {
264            return vec![];
265        }
266        let component_for_vertex = kosaraju::kosaraju(self, calc_components_bar);
267
268        debug!(
269            "kosaraju alg finished. Have {} maps of root vertexes, for {} vertexes",
270            component_for_vertex.len(),
271            self.num_vertexes(),
272        );
273        let mut components: HashMap<i64, HashSet<i64>> = HashMap::new();
274        for (v, root_v) in component_for_vertex.iter() {
275            components
276                .entry(*root_v)
277                .or_insert_with(|| std::iter::once(*root_v).collect())
278                .insert(*v);
279        }
280
281        // Convert list of vertexes into linestrings
282        components
283            .into_values()
284            .map(|cycle| {
285                cycle
286                    .iter()
287                    .flat_map(|nid| self.out_neighbours(*nid).map(move |other| [*nid, other]))
288                    // Don't include a line segment to an outneighbour which isn't in the cycle. we
289                    // alrady know nids[0] is in the cycle
290                    .filter(|nids| cycle.contains(&nids[1]))
291                    // Expand the intermediate
292                    .flat_map(|nids| {
293                        self.expand_edge(nids[0], nids[1])
294                            .tuple_windows::<(i64, i64)>()
295                    })
296                    .map(|nid_tuple| [nid_tuple.0, nid_tuple.1])
297                    .collect()
298            })
299            .collect()
300    }
301
302    fn delete_vertex_if_unconnected(&mut self, vertex: &i64) {
303        if self.num_in_neighbours(*vertex) == Some(0) && self.num_out_neighbours(*vertex) == Some(0)
304        {
305            self.delete_vertex(vertex);
306        }
307    }
308
309    fn vertex_property(&self, vertex: &i64) -> Option<&V>;
310    fn vertex_property_unchecked(&self, vertex: &i64) -> &V;
311
312    fn set_vertex_property(&mut self, vertex: &i64, property: V);
313    fn vertex_property_mut(&mut self, vertex: &i64) -> &mut V;
314
315    fn edge_property(&self, edge: (i64, i64)) -> Option<&E>;
316    fn edge_property_unchecked(&self, edge: (i64, i64)) -> &E;
317
318    fn set_edge_property(&mut self, edge: (i64, i64), property: E);
319
320    fn edge_property_mut(&mut self, edge: (i64, i64)) -> &mut E;
321
322    fn add_edge_w_prop(&mut self, vertex1: i64, vertex2: i64, eprop: E);
323
324    fn add_vertex_w_prop(&mut self, vertex: i64, vprop: V);
325
326    /// Returns (from_vertex, b, E) where b is an out neighbour of from_vertex
327    fn out_edges_w_prop<'a>(&'a self, from_vertex: i64) -> impl Iterator<Item = (i64, i64, &'a E)>
328    where
329        E: 'a;
330    fn out_edges_w_prop_mut<'a>(
331        &'a mut self,
332        from_vertex: i64,
333    ) -> impl Iterator<Item = (i64, i64, &'a mut E)>
334    where
335        E: 'a;
336    fn in_edges_w_prop<'a>(&'a self, to_vertex: i64) -> impl Iterator<Item = (i64, i64, &'a E)>
337    where
338        E: 'a;
339
340    fn edges_iter_w_prop<'a>(&'a self) -> impl Iterator<Item = (i64, i64, &'a E)>
341    where
342        E: 'a;
343    fn edges_iter_w_prop_mut<'a>(&'a mut self) -> impl Iterator<Item = (i64, i64, &'a mut E)>
344    where
345        E: 'a;
346    fn edges_par_iter_w_prop<'a>(&'a self) -> impl ParallelIterator<Item = (i64, i64, &'a E)>
347    where
348        E: 'a;
349
350    fn edges_par_iter_w_prop_mut<'a>(
351        &'a mut self,
352    ) -> impl ParallelIterator<Item = (i64, i64, &'a mut E)>
353    where
354        E: 'a;
355
356    fn assert_consistancy(&self);
357
358    /// Remove this vertex, returning the
359    /// Any & all edges connected to this vertex are deleted.
360    fn remove_vertex(&mut self, vertex: &i64) -> Option<V>;
361
362    fn remove_edge(&mut self, vertex1: &i64, vertex2: &i64) -> Option<E>;
363
364    fn vertexes_w_prop<'a>(&'a self) -> impl Iterator<Item = (i64, &'a V)>
365    where
366        V: 'a;
367    fn vertexes_w_prop_par<'a>(&'a self) -> impl ParallelIterator<Item = (i64, &'a V)>
368    where
369        V: 'a;
370    fn vertexes_w_prop_par_mut<'a>(&'a mut self) -> impl ParallelIterator<Item = (i64, &'a mut V)>
371    where
372        V: 'a;
373
374    fn edges_w_prop_par_mut<'a>(
375        &'a mut self,
376    ) -> impl ParallelIterator<Item = ((i64, i64), &'a mut E)>
377    where
378        E: 'a;
379}
380
381#[derive(Default, Debug, Clone)]
382struct Vertex<V, E> {
383    vprop: V,
384    ins: SmallVec<[i64; 1]>,
385    outs: SmallVec<[(i64, E); 1]>,
386}
387
388impl<V, E> Vertex<V, E> {
389    #[allow(clippy::type_complexity)]
390    fn into_parts(self) -> (V, SmallVec<[i64; 1]>, SmallVec<[(i64, E); 1]>) {
391        (self.vprop, self.ins, self.outs)
392    }
393}
394
395/// A graph which stores a list of all incoming and outgoing edges
396#[derive(Default, Debug, Clone)]
397pub struct DirectedGraph<V, E>
398where
399    V: Send + Default + Clone + Sync + Debug,
400    E: Send + Default + Clone + Sync + Debug,
401{
402    // key is vertex id
403    edges: BTreeMap<i64, Vertex<V, E>>,
404}
405
406impl<V, E> DirectedGraph<V, E>
407where
408    V: Send + Default + Clone + Sync + Debug,
409    E: Send + Default + Clone + Sync + Debug,
410{
411}
412
413impl<V, E> DirectedGraphTrait<V, E> for DirectedGraph<V, E>
414where
415    V: Send + Default + Clone + Sync + Debug,
416    E: Send + Default + Clone + Sync + Debug,
417{
418    fn new() -> Self {
419        Default::default()
420    }
421    fn num_in_neighbours(&self, vertex: i64) -> Option<usize> {
422        self.edges.get(&vertex).map(|v| v.ins.len())
423    }
424    fn num_out_neighbours(&self, vertex: i64) -> Option<usize> {
425        self.edges.get(&vertex).map(|v| v.outs.len())
426    }
427
428    fn out_neighbours(&self, from_vertex: i64) -> impl Iterator<Item = i64> {
429        self.edges
430            .get(&from_vertex)
431            .into_iter()
432            .flat_map(|v| v.outs.iter().map(|(nid, _eprop)| nid))
433            .copied()
434    }
435    fn out_neighbours_w_prop<'a>(&'a self, from_vertex: i64) -> impl Iterator<Item = (i64, &'a E)>
436    where
437        E: 'a,
438    {
439        self.edges
440            .get(&from_vertex)
441            .into_iter()
442            .flat_map(|v| v.outs.iter())
443            .map(|(nid2, eprop)| (*nid2, eprop))
444    }
445    fn in_neighbours(&self, from_vertex: i64) -> impl Iterator<Item = i64> {
446        self.edges
447            .get(&from_vertex)
448            .into_iter()
449            .flat_map(|v| v.ins.iter())
450            .copied()
451    }
452
453    fn num_vertexes(&self) -> usize {
454        self.edges.len()
455    }
456    fn num_edges(&self) -> usize {
457        self.edges.values().map(|v| v.outs.len()).sum()
458    }
459    /// True iff this vertex is in this graph
460    fn contains_vertex(&self, vid: &i64) -> bool {
461        self.edges.contains_key(vid)
462    }
463
464    /// Iterator over all edges
465    fn edges_iter(&self) -> impl Iterator<Item = (i64, i64)> {
466        self.edges
467            .iter()
468            .flat_map(move |(nid, v)| v.outs.iter().map(move |(o, _eprop)| (*nid, *o)))
469    }
470    fn edges_par_iter(&self) -> impl ParallelIterator<Item = (i64, i64)> {
471        self.edges_iter().par_bridge()
472    }
473
474    /// returns each vertex and the number of out edges
475    fn vertexes_and_num_outs(&self) -> impl Iterator<Item = (i64, usize)> {
476        self.edges.iter().map(|(nid1, v)| (*nid1, v.outs.len()))
477    }
478
479    fn vertex_has_outgoing(&self, vid: &i64) -> bool {
480        self.edges.get(vid).is_some_and(|v| !v.outs.is_empty())
481    }
482
483    fn detailed_size(&self) -> String {
484        let s = format!(
485            "DirectedGraph: num_vertexes {} num_edges {}",
486            self.num_vertexes(),
487            self.num_edges(),
488        );
489        //s.push_str(&format!(
490        //    "\nSize of graph: {} = {} bytes.\nbytes/vertex = {:>.5}\nbytes/edge = {:>.5}",
491        //    self.get_size(),
492        //    self.get_size().to_formatted_string(&Locale::en),
493        //    self.get_size() as f64 / self.num_vertexes() as f64,
494        //    self.get_size() as f64 / self.num_edges() as f64,
495        //));
496
497        s
498    }
499
500    fn num_ins_zero(&self, vid: &i64) -> bool {
501        self.edges.get(vid).is_none_or(|v| v.ins.is_empty())
502    }
503
504    fn is_empty(&self) -> bool {
505        self.edges.is_empty()
506    }
507
508    fn vertexes_and_num_ins_outs(&self) -> impl Iterator<Item = (i64, usize, usize)> + '_ {
509        self.edges
510            .iter()
511            .map(|(nid, v)| (*nid, v.ins.len(), v.outs.len()))
512    }
513
514    fn neighbors_in_xor_out(&mut self, v: &i64) -> bool {
515        self.edges
516            .get(v)
517            .is_some_and(|v| !v.ins.is_empty() ^ !v.outs.is_empty())
518    }
519    fn delete_edge(&mut self, vertex1: &i64, vertex2: &i64) {
520        self.remove_edge(vertex1, vertex2);
521    }
522
523    fn delete_vertex(&mut self, vertex: &i64) {
524        self.remove_vertex(vertex);
525    }
526
527    fn contract_vertex(&mut self, vertex: &i64, replacement: &i64) {
528        if vertex == replacement {
529            warn!("Trying to contract a vertex with itself: {}", vertex);
530            return;
531        }
532        if !self.contains_vertex(vertex) && !self.contains_vertex(replacement) {
533            warn!(
534                "Trying to replace the vertex {vertex} with {replacement}, but neither are in the graph"
535            );
536            return;
537        }
538        assert!(
539            self.contains_vertex(vertex),
540            "Vertex to replace {vertex} doesn't exist"
541        );
542        assert!(
543            self.contains_vertex(replacement),
544            "Replacement vertex {replacement} doesn't exist"
545        );
546
547        let mut old = match self.edges.remove(vertex) {
548            None => {
549                return;
550            }
551            Some(old) => old,
552        };
553
554        self.set_vertex_property(replacement, old.vprop);
555
556        for (out_v, eprop) in old.outs.drain(..) {
557            self.edges
558                .get_mut(&out_v)
559                .unwrap()
560                .ins
561                .retain(|in_v| in_v != vertex);
562            self.add_edge_w_prop(*replacement, out_v, eprop);
563        }
564        for in_v in old.ins.iter() {
565            if let Some(eprop) = self.remove_edge(in_v, vertex) {
566                self.add_edge_w_prop(*in_v, *replacement, eprop);
567            }
568        }
569    }
570
571    fn vertexes_iter(&self) -> impl Iterator<Item = i64> + '_ {
572        self.edges.keys().copied()
573    }
574    fn vertexes_par_iter(&self) -> impl ParallelIterator<Item = i64> {
575        self.edges.par_iter().map(|(nid, _)| nid).copied()
576    }
577
578    /// Adds an edge between these 2, returning true iff the edge already existed
579    fn add_edge(&mut self, vertex1: i64, vertex2: i64) -> bool {
580        if vertex1 == vertex2 {
581            return false;
582        }
583        let from_v1 = &mut self.edges.entry(vertex1).or_default().outs;
584        if from_v1.iter().any(|(vid, _eprop)| vid == &vertex2) {
585            return true;
586        } else {
587            from_v1.push((vertex2, E::default()));
588        }
589
590        // assume we never get inconsistant
591        let other = self.edges.entry(vertex2).or_default();
592        other.ins.push(vertex1);
593        other.ins.sort();
594        false
595    }
596
597    fn into_disconnected_graphs(self, progress_bar: &ProgressBar) -> impl Iterator<Item = Self> {
598        dbg!("here");
599        let mut g = self;
600        let mut vertexes_to_look_at = Vec::new();
601
602        std::iter::from_fn(move || {
603            if g.is_empty() {
604                return None;
605            }
606            let mut new_graph: DirectedGraph<V, E> = DirectedGraph::new();
607            vertexes_to_look_at.truncate(0);
608            vertexes_to_look_at.push(g.vertexes().next().unwrap());
609            let mut num_vertexes = 0;
610
611            while let Some(vertex) = vertexes_to_look_at.pop() {
612                num_vertexes += 1;
613                if !g.contains_vertex(&vertex) {
614                    continue;
615                }
616
617                let (vprop, ins, outs) = g.edges.remove(&vertex).unwrap().into_parts();
618                new_graph.add_vertex_w_prop(vertex, vprop);
619
620                for (out_v, eprop) in outs.into_iter() {
621                    new_graph.add_edge_w_prop(vertex, out_v, eprop);
622                    vertexes_to_look_at.push(out_v);
623                }
624                vertexes_to_look_at.extend(ins.into_iter());
625            }
626
627            progress_bar.inc(num_vertexes as u64);
628            Some(new_graph)
629        })
630    }
631
632    fn vertex_property(&self, vertex: &i64) -> Option<&V> {
633        self.edges.get(vertex).map(|v| &v.vprop)
634    }
635    fn vertex_property_unchecked(&self, vertex: &i64) -> &V {
636        self.vertex_property(vertex).unwrap()
637    }
638
639    fn set_vertex_property(&mut self, vertex: &i64, property: V) {
640        self.edges.entry(*vertex).or_default().vprop = property;
641    }
642    fn vertex_property_mut(&mut self, vertex: &i64) -> &mut V {
643        &mut self.edges.entry(*vertex).or_default().vprop
644    }
645
646    fn edge_property(&self, edge: (i64, i64)) -> Option<&E> {
647        self.edges.get(&edge.0).map(|v| &v.outs).and_then(|outs| {
648            outs.iter()
649                .find(|(vid, _p)| *vid == edge.1)
650                .map(|(_vid, prop)| prop)
651        })
652    }
653    fn edge_property_unchecked(&self, edge: (i64, i64)) -> &E {
654        self.edge_property(edge).unwrap()
655    }
656
657    fn set_edge_property(&mut self, edge: (i64, i64), property: E) {
658        if edge.0 == edge.1 {
659            return;
660        }
661        *self.edge_property_mut(edge) = property;
662    }
663
664    fn edge_property_mut(&mut self, edge: (i64, i64)) -> &mut E {
665        let vertex = self.edges.get_mut(&edge.0).unwrap();
666        let outs = &mut vertex.outs;
667        if !outs.iter().any(|(oid, _eprop)| *oid == edge.1) {
668            outs.push((edge.1, E::default()));
669        }
670
671        outs.iter_mut()
672            .filter(|(oid, _)| *oid == edge.1)
673            .map(|(_, eprop)| eprop)
674            .next()
675            .unwrap()
676    }
677
678    fn add_edge_w_prop(&mut self, vertex1: i64, vertex2: i64, eprop: E) {
679        if vertex1 == vertex2 {
680            return;
681        }
682        self.add_edge(vertex1, vertex2);
683        self.set_edge_property((vertex1, vertex2), eprop);
684    }
685
686    fn add_vertex_w_prop(&mut self, vertex: i64, vprop: V) {
687        // TODO remove all clones
688        self.edges
689            .entry(vertex)
690            .and_modify(|o| o.vprop = vprop.clone())
691            .or_insert(Vertex {
692                vprop,
693                ..Default::default()
694            });
695    }
696
697    /// Returns (from_vertex, b, E) where b is an out neighbour of from_vertex
698    fn out_edges_w_prop<'a>(&'a self, from_vertex: i64) -> impl Iterator<Item = (i64, i64, &'a E)>
699    where
700        E: 'a,
701    {
702        self.edges.get(&from_vertex).into_iter().flat_map(move |v| {
703            v.outs
704                .iter()
705                .map(move |(nid2, eprop)| (from_vertex, *nid2, eprop))
706        })
707    }
708    /// Returns (from_vertex, b, E) where b is an out neighbour of from_vertex
709    fn out_edges_w_prop_mut<'a>(
710        &'a mut self,
711        from_vertex: i64,
712    ) -> impl Iterator<Item = (i64, i64, &'a mut E)>
713    where
714        E: 'a,
715    {
716        self.edges
717            .get_mut(&from_vertex)
718            .into_iter()
719            .flat_map(move |v| {
720                v.outs
721                    .iter_mut()
722                    .map(move |(nid2, eprop)| (from_vertex, *nid2, eprop))
723            })
724    }
725    fn in_edges_w_prop<'a>(&'a self, to_vertex: i64) -> impl Iterator<Item = (i64, i64, &'a E)>
726    where
727        E: 'a,
728    {
729        self.in_edges(to_vertex)
730            .map(|(nid1, nid2)| (nid1, nid2, self.edge_property_unchecked((nid1, nid2))))
731    }
732
733    fn edges_iter_w_prop<'a>(&'a self) -> impl Iterator<Item = (i64, i64, &'a E)>
734    where
735        E: 'a,
736    {
737        self.edges
738            .iter()
739            .flat_map(|(nid1, v)| v.outs.iter().map(|(nid2, eprop)| (*nid1, *nid2, eprop)))
740    }
741    fn edges_iter_w_prop_mut<'a>(&'a mut self) -> impl Iterator<Item = (i64, i64, &'a mut E)>
742    where
743        E: 'a,
744    {
745        self.edges
746            .iter_mut()
747            .flat_map(|(nid1, v)| v.outs.iter_mut().map(|(nid2, eprop)| (*nid1, *nid2, eprop)))
748    }
749    fn edges_par_iter_w_prop<'a>(&'a self) -> impl ParallelIterator<Item = (i64, i64, &'a E)>
750    where
751        E: 'a,
752    {
753        self.edges
754            .par_iter()
755            .flat_map(|(nid1, v)| v.outs.par_iter().map(|(nid2, eprop)| (*nid1, *nid2, eprop)))
756    }
757
758    fn edges_par_iter_w_prop_mut<'a>(
759        &'a mut self,
760    ) -> impl ParallelIterator<Item = (i64, i64, &'a mut E)>
761    where
762        E: 'a,
763    {
764        self.edges.par_iter_mut().flat_map(|(nid1, v)| {
765            v.outs
766                .par_iter_mut()
767                .map(|(nid2, eprop)| (*nid1, *nid2, eprop))
768        })
769    }
770
771    fn assert_consistancy(&self) {
772        for (nid1, v) in self.edges.iter() {
773            // no self loops
774            assert!(!v.ins.contains(nid1));
775            assert!(
776                !v.outs.iter().any(|(nid2, _)| nid1 == nid2),
777                "{:?} {:?}",
778                nid1,
779                v.outs
780            );
781
782            // if there's an in, there's an out
783            for in_v in v.ins.iter() {
784                assert!(
785                    self.edges.contains_key(in_v),
786                    "Node {nid1} has an in edge from {in_v}, but there is no data for that vertex {in_v}"
787                );
788                assert!(
789                    self.edges
790                        .get(in_v)
791                        .unwrap()
792                        .outs
793                        .iter()
794                        .any(|(otherv, _eprop)| otherv == nid1),
795                    "Graph Data inconsistancy. {nid1} has {in_v} as one of it's in edges, but there is no corresponding out edge from {in_v} to {nid1}"
796                );
797            }
798            // if there's an out, there's an in
799            for (out_v, _eprop) in v.outs.iter() {
800                assert!(
801                    self.edges.contains_key(out_v),
802                    "Node {nid1} has an out edge to {out_v}, but there is no data for that vertex {out_v}"
803                );
804                assert!(self.edges.get(out_v).unwrap().ins.contains(nid1));
805            }
806        }
807
808        assert_eq!(
809            self.edges
810                .par_iter()
811                .map(|(_nid2, v)| v.ins.len())
812                .sum::<usize>(),
813            self.edges
814                .par_iter()
815                .map(|(_nid2, v)| v.outs.len())
816                .sum::<usize>()
817        );
818    }
819
820    /// Remove this vertex, returning the
821    /// Any & all edges connected to this vertex are deleted.
822    fn remove_vertex(&mut self, vertex: &i64) -> Option<V> {
823        let (vprop, ins, outs) = self.edges.remove(vertex)?.into_parts();
824        for in_v in ins.iter() {
825            self.delete_edge(in_v, vertex);
826        }
827        for (out_v, _eprop) in outs.iter() {
828            self.delete_edge(vertex, out_v);
829        }
830        Some(vprop)
831    }
832
833    fn remove_edge(&mut self, vertex1: &i64, vertex2: &i64) -> Option<E> {
834        let outs = &mut self.edges.get_mut(vertex1)?.outs;
835        let idx = outs.iter().position(|(v, _eprop)| v == vertex2)?;
836        let (_v2, eprop) = outs.remove(idx);
837
838        // remove the corresponding in edge
839        if let Some(x) = self.edges.get_mut(vertex2) {
840            x.ins.retain(|v1| v1 != vertex1);
841        }
842
843        self.delete_vertex_if_unconnected(vertex1);
844        self.delete_vertex_if_unconnected(vertex2);
845
846        Some(eprop)
847    }
848
849    fn vertexes_w_prop<'a>(&'a self) -> impl Iterator<Item = (i64, &'a V)>
850    where
851        V: 'a,
852    {
853        self.edges.iter().map(|(nid, v)| (*nid, &v.vprop))
854    }
855
856    fn vertexes_w_prop_par_mut<'a>(&'a mut self) -> impl ParallelIterator<Item = (i64, &'a mut V)>
857    where
858        V: 'a,
859    {
860        self.edges
861            .par_iter_mut()
862            .map(|(nid, v)| (*nid, &mut v.vprop))
863    }
864
865    fn vertexes_w_prop_par<'a>(&'a self) -> impl ParallelIterator<Item = (i64, &'a V)>
866    where
867        V: 'a,
868    {
869        self.edges.par_iter().map(|(nid, v)| (*nid, &v.vprop))
870    }
871
872    fn edges_w_prop_par_mut<'a>(
873        &'a mut self,
874    ) -> impl ParallelIterator<Item = ((i64, i64), &'a mut E)>
875    where
876        E: 'a,
877    {
878        self.edges.par_iter_mut().flat_map(|(nid1, v)| {
879            v.outs
880                .par_iter_mut()
881                .map(|(nid2, eprop)| ((*nid1, *nid2), eprop))
882        })
883    }
884}