icentral_graph_hash/
graph_hash.rs

1crate::ix!();
2
3//-------------------------------------------[icentral/src/graph_hash_t.cc]
4
5pub type BcMap = Arc<Mutex<BetweennessScores>>;
6
7/**
8  | graph with nodes having integral indices
9  | that shouldn't be between 0 and n-1 will
10  | be used to store MinimumUnionCycles and subgraphs
11  |
12  */
13pub struct GraphHash {
14
15    name:                   String,
16    nodes_map:              NeighborsMap,
17    edges:                  Edges,
18
19    /**
20      | structures to be used by algorithms
21      | they are here so they are built once
22      |
23      */
24    parents:                ParentsMap,
25    path_counts:            PathCounts,
26    new_path_counts:        PathCounts,
27    inc_path_counts:        PathCounts,
28    distances:              DistanceMap,
29    pair_dependencies:      PairDependencies,
30    new_pair_dependencies:  PairDependencies,
31    sigmas:                 SigmaMap,
32    new_sigmas:             SigmaMap,
33    visit_markers:          VisitMarkers,
34    stack:                  NodeIdStack,
35    queue:                  NodeIdQueue,
36    print_nodes:            AtomicBool,
37}
38
39delegate_to_parents!{GraphHash}
40delegate_to_distances!{GraphHash}
41delegate_to_sigmas!{GraphHash}
42delegate_to_sigmas!{GraphHash; new_sigmas}
43delegate_to_visit_markers!{GraphHash}
44delegate_to_bfs_queue!{GraphHash}
45delegate_to_bfs_stack!{GraphHash}
46delegate_to_pair_dependencies!{GraphHash}
47delegate_to_pair_dependencies!{GraphHash; new_pair_dependencies}
48delegate_to_path_counts!{GraphHash}
49delegate_to_path_counts!{GraphHash; new_path_counts}
50delegate_to_path_counts!{GraphHash; inc_path_counts}
51
52impl HasMapForNode for GraphHash {
53
54    delegate!{
55        to self.nodes_map {
56            fn has_map_for_node(&self, id: NodeId) -> bool;
57        }
58    }
59}
60
61impl GetNodeIdRange for GraphHash {
62
63    delegate!{
64        to self.nodes_map {
65            fn nodeid_range(&self) -> Vec<NodeId>;
66        }
67    }
68}
69
70impl PairDependencyForNode for GraphHash {
71
72    delegate!{ 
73        to self.pair_dependencies {
74            fn pair_dependency_for_node(&self, node: NodeId) -> f64;
75        }
76    }
77}
78
79impl ResetWith<GraphHash> for GraphHash {
80    fn reset_with(&mut self, g: &GraphHash) {
81        todo!();
82    }
83}
84
85impl SetPairDependencyForNode for GraphHash {
86
87    delegate!{ 
88        to self.pair_dependencies {
89            fn set_pair_dependency_for_node(&mut self, node: NodeId, val: f64);
90        }
91    }
92}
93
94impl PathCountForNode for GraphHash {
95
96    delegate!{
97
98        to self.path_counts {
99
100            fn path_count_for_node(&self, node: NodeId) -> usize;
101
102            fn path_count_for_node_ref(&self, node: NodeId) -> &usize;
103
104            fn path_count_for_node_mut(&mut self, node: NodeId) -> &mut usize;
105        }
106    }
107}
108
109impl HasEdge for GraphHash {
110
111    fn has_edge(&self, e: &Edge) -> bool {
112        self.edges.has_edge(e)
113    }
114}
115
116impl ParentsForNode for GraphHash {
117
118    fn parents_for_node(&self, v_n: NodeId) -> Vec<NodeId> {
119        self.parents.parents_for_node(v_n)
120    }
121}
122
123impl NumNodes for GraphHash {
124    fn num_nodes(&self) -> usize {
125        self.nodes_map.len()
126    }
127}
128
129impl NumEdges for GraphHash {
130    fn num_edges(&self) -> usize {
131        self.edges.len()
132    }
133}
134
135impl GetEdges for GraphHash {
136    fn edges(&self) -> &Edges {
137        &self.edges
138    }
139}
140
141impl MappedNodes for GraphHash {
142    fn mapped_nodes(&self) -> Vec<NodeId> {
143        self.nodes_map.mapped_nodes()
144    }
145}
146
147impl Named for GraphHash {
148
149    fn name(&self) -> Cow<'_,str> {
150        Cow::Borrowed(&self.name)
151    }
152}
153
154impl GraphHash {
155
156    delegate_to_neighbors_map!{}
157    delegate_to_edges!{}
158}
159
160impl<G> NewFromGraphRef<G> for GraphHash 
161where G: GetEdges
162{
163
164    fn new_from_graph_ref(graph: &G, name: &str) -> Self {
165
166        let mut x = GraphHash::empty(name);
167
168        for edge in graph.edges().iter() {
169            x.insert_edge(&edge);
170        }
171
172        x
173    }
174}
175
176impl NewFromCycleVec for GraphHash {
177
178    fn new_from_cycle_vec(cycle_vec: &Vec<Cycle>, name: &str) -> Self {
179
180        let mut x = GraphHash::empty(name);
181
182        for i in NodeIdRange::new(0,cycle_vec.len()) {
183            x.insert_node(i);
184        }
185
186        for i in 0..cycle_vec.len() {
187
188            for j in 0..cycle_vec.len() {
189
190                if i != j && shared_vertex(&cycle_vec[i], &cycle_vec[j]) 
191                {
192                    x.insert_edge(&Edge::new_with_ids(i, j));
193                }
194            }
195        }
196
197        x
198    }
199}
200
201impl fmt::Debug for GraphHash {
202
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204
205        let binding = f.debug_struct("GraphHash");
206
207        let mut builder = binding;
208
209        builder.field("edges",  &self.edges);
210
211        if self.print_nodes.load(atomic::Ordering::SeqCst) {
212
213            builder.field("nodes_map", &self.nodes_map);
214
215        } 
216
217        builder.finish()
218    }
219}
220
221impl SpawnScores for GraphHash {
222
223    fn spawn_scores(&self) -> BetweennessScores
224    {
225        let scores_name = name![self.name(), "scores"];
226
227        BetweennessScores::new_from_graph_ref(self, scores_name) 
228    }
229}
230
231impl BrandesIterInit for GraphHash {
232
233    fn brandes_iter_init(&mut self, s: NodeId)
234    {
235        self.reinit_maps();
236
237        self.stack.clear();
238
239        self.path_counts.set_path_count_for_node(s,1);
240
241        self.distances.set_distance_for_node(s,0.0);
242
243        self.enqueue(s);
244    }
245}
246
247impl BrandesIterUpdateDistancesAndPathForNeighbors for GraphHash {
248
249    fn brandes_iter_update_dist_and_path_for_neighbors(&mut self, s: NodeId)
250    {
251        while let Some(v) = self.dequeue() {
252
253            self.stack.push(v);
254
255            self.update_dist_and_path_for_neighbors(v);
256        }
257    }
258}
259
260impl BrandesIterUpdatePairDependenciesAndFill for GraphHash {
261
262    fn brandes_iter_update_pair_dependencies_and_fill(
263        &mut self, 
264        s:      NodeId, 
265        scores: &mut BetweennessScores) 
266    -> Result<(),BetweennessCentralityError> 
267    {
268        for i in (0..=self.stack.len() - 1).rev() {
269
270            let w: NodeId = self.stack_node_at_index(i);
271
272            self.update_parent_pair_dependencies_and_increment_score_for_node(w, s, scores);
273        }
274
275        Ok(())
276    }
277}
278
279impl SetPrintNodes for GraphHash {
280
281    fn set_print_nodes(&self, val: bool) {
282        self.print_nodes.store(val, atomic::Ordering::SeqCst);
283    }
284}
285
286impl GetPrintNodes for GraphHash {
287
288    fn get_print_nodes(&self) -> bool {
289        self.print_nodes.load(atomic::Ordering::SeqCst)
290    }
291}
292
293impl GetNeighborsForNode for GraphHash {
294
295    fn neighbors(&self, id: NodeId) 
296    -> Vec<NodeId>
297    {
298        self.nodes_map.neighbors(id)
299    }
300}
301
302impl ReinitMapsForNode for GraphHash {
303
304    fn reinit_maps_for_node(&mut self, k: NodeId)
305    {
306        self.parents.set_parents_for_node(k, vec![]);
307
308        self.path_counts.set_path_count_for_node(k, 0);
309        self.new_path_counts.set_path_count_for_node(k, 0);
310
311        self.distances.set_distance_for_node(k, -1.0);
312
313        self.pair_dependencies.set_pair_dependency_for_node(k, 0.0);
314        self.new_pair_dependencies.set_pair_dependency_for_node(k, 0.0);
315
316        self.set_sigma_value_for_node(k, 0.0);
317        self.new_sigmas_set_sigma_value_for_node(k, 0.0);
318
319        self.inc_path_counts.set_path_count_for_node(k, 0);
320
321        self.visit_markers.unvisit(k);
322    }
323}
324
325impl ReinitMaps for GraphHash {
326    
327    fn reinit_maps(&mut self)
328    {
329        for k in self.nodes_map.mapped_nodes() {
330            self.reinit_maps_for_node(k);
331        }
332    }
333}
334
335impl InsertNode for GraphHash {
336    
337    fn insert_node(&mut self, id: NodeId) 
338    {
339        self.nodes_map.add_isolated_node(id);
340    }
341}
342
343impl InsertEdge for GraphHash {
344    
345    fn insert_edge(&mut self, edge: &Edge)
346    -> Result<(),BetweennessCentralityError> 
347    {
348        let redge = edge.reversed();
349
350        if self.edges.has_edge(&edge)
351        || self.edges.has_edge(&redge)
352        {
353            return Ok(());
354
355        } else {
356
357            self.edges.insert_edge(*edge);
358        }
359
360        self.insert_node(edge.src);
361        self.insert_node(edge.dst);
362
363        self.nodes_map.add_edge(&edge);
364
365        Ok(())
366    }
367}
368
369impl RemoveEdge for GraphHash {
370
371    fn remove_edge(&mut self, edge: &Edge)
372    -> Result<(),BetweennessCentralityError> 
373    {
374        self.edges.remove_edge(&edge);
375
376        let redge = edge.reversed();
377
378        self.edges.remove_edge(&redge);
379
380        self.nodes_map.unlink_edge(edge);
381
382        Ok(())
383    }
384}
385
386impl GetConnectedComponentSizes for GraphHash {
387
388    /**
389      | the vector @out_vec will have sizes
390      | of the connected components in the graph
391      |
392      */
393    fn conn_comp_sizes(&self) 
394    -> Result<Vec<i32>,BetweennessCentralityError>
395    {
396        let mut out_vec = vec![];
397
398        let visited_map_name = name![
399            self.name(), 
400            "conn_comp_sizes::visited_map"
401        ];
402
403        let mut visited_map = VisitMarkers::new_from_nodes(
404            self.nodes_map.mapped_nodes(),
405            &visited_map_name
406        );
407
408        for id in visited_map.iter_unvisited() {
409
410            self.conn_comp_sizes_step(
411                &mut visited_map, 
412                id, 
413                &mut out_vec
414            );
415        }
416
417        Ok(out_vec)
418    }
419}
420    
421impl ExtendWith<GraphHash> for GraphHash {
422
423    type Error = BetweennessCentralityError;
424
425    fn extend_with(&mut self, other: &GraphHash) 
426        -> Result<(),Self::Error>
427    {
428        self.nodes_map.extend_with(
429            &other.nodes_map
430        );
431
432        self.edges.extend(
433            &other.edges
434        );
435
436        Ok(())
437    }
438}
439    
440impl InitDebugIteration for GraphHash {
441
442    fn init_dbg_iteration(&mut self, source: NodeId) {
443
444        self.reinit_maps();
445        self.path_counts.set_path_count_for_node(source,1);
446        self.distances.set_distance_for_node(source,0.0);
447        self.enqueue(source);
448    }
449}
450
451impl DebugIterationStep for GraphHash {
452
453    fn dbg_iteration_step(&mut self, v_s: &mut Vec<NodeId>) 
454    -> Result<(),BetweennessCentralityError> 
455    {
456        while let Some(v_i) = self.dequeue() {
457
458            v_s.push(v_i);
459
460            self.update_dist_and_path_for_neighbors(v_i);
461        }
462
463        Ok(())
464    }
465}
466
467impl RemoveBridges for GraphHash {
468
469     fn remove_bridges(&mut self, bridge_vec: Vec<Edge>) {
470
471        debug!("removing bridges...");
472
473        for bridge in bridge_vec.iter() {
474
475            self.remove_edge(&bridge);
476        }
477    }
478}
479
480impl FindConnectedComponents<GraphHash> for GraphHash {
481
482    type Error = BetweennessCentralityError;
483
484    fn find_conn_comp(&mut self) 
485    -> Result<Vec<GraphHash>,Self::Error> 
486    {
487        debug!("finding connected components...");
488
489        let mut out_vec = vec![];
490
491        let visited_map_name = name![self.name(), "find_conn_comp::visited_map"];
492
493        let mut visited_map = VisitMarkers::new_from_nodes(
494            self.nodes_map.mapped_nodes(),
495            visited_map_name
496        );
497
498        for id in self.nodes_map.mapped_nodes() {
499
500            if visited_map.unvisited(id) {
501
502                let gh_name = name![self.name(), format!("graphhash_for_id{}", id)];
503
504                let gh = GraphHash::new_via_bfs_from_id(
505                    gh_name,
506                    self,
507                    id,
508                    &mut visited_map
509                );
510
511                out_vec.push(gh);
512            }
513        }
514
515        Ok(out_vec)
516    }
517}
518
519impl CreateNamedEmpty for GraphHash {
520
521    fn empty(name: &str) -> Self {
522
523        let nodes_map_name             = name![name, "nodes_map"];
524        let edges_name                 = name![name, "edges"];
525        let parents_name               = name![name, "parents"];
526        let path_counts_name           = name![name, "path_counts"];
527        let new_path_counts_name       = name![name, "new_path_counts"];
528        let inc_path_counts_name       = name![name, "inc_path_counts"];
529        let distances_name             = name![name, "distances"];
530        let pair_dependencies_name     = name![name, "pair_dependencies"];
531        let new_pair_dependencies_name = name![name, "new_pair_dependencies"];
532        let sigmas_name                = name![name, "sigmas"];
533        let new_sigmas_name            = name![name, "new_sigmas"];
534        let visit_markers_name         = name![name, "visit_markers"];
535        let stack_name                 = name![name, "stack"];
536        let queue_name                 = name![name, "queue"];
537
538        Self {
539            name:                   name.to_owned(),
540            nodes_map:              NeighborsMap::empty_mapped(nodes_map_name),
541            edges:                  Edges::empty(edges_name),
542            parents:                ParentsMap::empty_mapped(parents_name),
543            path_counts:            PathCounts::empty_mapped(path_counts_name),
544            new_path_counts:        PathCounts::empty_mapped(new_path_counts_name),
545            inc_path_counts:        PathCounts::empty_mapped(inc_path_counts_name),
546            distances:              DistanceMap::empty_mapped(distances_name),
547            pair_dependencies:      PairDependencies::empty_mapped(pair_dependencies_name),
548            new_pair_dependencies:  PairDependencies::empty_mapped(new_pair_dependencies_name),
549            sigmas:                 SigmaMap::empty_mapped(sigmas_name),
550            new_sigmas:             SigmaMap::empty_mapped(new_sigmas_name),
551            visit_markers:          VisitMarkers::empty_mapped(visit_markers_name),
552            stack:                  NodeIdStack::empty(stack_name),
553            queue:                  NodeIdQueue::empty(queue_name),
554            print_nodes:            AtomicBool::new(false),
555        }
556    }
557}
558
559impl GraphHash {
560
561    /// do a BFS from id, count the number of
562    /// vertices, and mark the visited
563    ///
564    pub fn fill_edges_from_bfs(
565        &mut self,
566        parent:      &GraphHash, 
567        id:          NodeId, 
568        visited_map: &mut VisitMarkers)
569    {
570        let mut q = NodeIdQueue::empty("fill_edges_from_bfs::queue");
571
572        q.enqueue(id);
573
574        while let Some(node) = q.dequeue() {
575
576            let nbrs_vec = parent.nodes_map.neighbors(node);
577
578            for &nbr in nbrs_vec.iter() {
579
580                self.insert_edge(&Edge::new(node, nbr));
581
582                if visited_map.unvisited(nbr) {
583
584                    visited_map.visit(nbr);
585
586                    q.enqueue(nbr);
587                }
588            }
589        }
590    }
591
592    pub fn new_via_bfs_from_id(
593        name:        &str,
594        parent:      &GraphHash, 
595        id:          NodeId, 
596        visited_map: &mut VisitMarkers) -> Self {
597
598        let mut gh: GraphHash = GraphHash::empty(name);
599
600        visited_map.visit(id);
601
602        gh.insert_node(id);
603
604        gh.fill_edges_from_bfs(
605            parent,
606            id,
607            visited_map
608        );
609
610        gh
611    }
612
613    pub fn maybe_set_distance_for_neighbor(
614        &mut self,
615        w: NodeId,
616        v: NodeId)
617    {
618        if self.distances.is_infinite(w) {
619
620            self.enqueue(w);
621
622            self.distances.set_distance_for_node(
623                w, 
624                self.distance(v) + 1.0
625            );
626        }
627    }
628
629    pub fn maybe_increment_path_count_and_add_parent_for_neighbor(
630        &mut self,
631        w: NodeId,
632        v: NodeId)
633    {
634        if self.distances.is_one_step_away(w, v) {
635
636            self.path_counts.increment_path_count_for_node_from(w,v);
637
638            self.parents.add_parent(w, v);
639        }
640    }
641
642    pub fn update_dist_and_path_for_neighbors(
643        &mut self,
644        v: NodeId)
645    {
646        let nbr_vec = self.neighbors(v);
647
648        for &w in nbr_vec.iter() {
649
650            self.maybe_set_distance_for_neighbor(w, v);
651
652            self.maybe_increment_path_count_and_add_parent_for_neighbor(w, v);
653        }
654    }
655
656    pub fn update_pair_dependencies(&mut self, w: NodeId, v: NodeId) {
657
658        let v_paths = self.path_counts.path_count_for_node(v) as f64;
659        let w_paths = self.path_counts.path_count_for_node(w) as f64;
660
661        let paths_ratio = v_paths / w_paths;
662
663        let w_pair_dependencies = self.pair_dependencies.pair_dependency_for_node(w);
664
665        self.pair_dependencies.increment_pair_dependency_for_node(
666            v,
667            paths_ratio * (1.0 + w_pair_dependencies)
668        );
669    }
670
671    pub fn update_parent_pair_dependencies_and_increment_score_for_node(
672        &mut self, 
673        w:      NodeId,
674        s:      NodeId, 
675        scores: &mut BetweennessScores) 
676    {
677        let parents = self.parents.parents_for_node(w);
678
679        for v in parents {
680
681            self.update_pair_dependencies(w,v);
682        }
683
684        if w != s {
685
686            scores.increase_score_for_node(
687                w, 
688                self.pair_dependencies.pair_dependency_for_node(w)
689            );
690        }
691    }
692
693    pub fn conn_comp_sizes_step(&self, 
694        visited_map: &mut VisitMarkers, 
695        id:          NodeId, 
696        out_vec:     &mut Vec<i32>) 
697    {
698        visited_map.visit(id);
699
700        out_vec.push(1);
701
702        let queue_name = name![self.name(), "conn_comp_sizes_step::queue"];
703
704        // do a BFS from s, count the
705        // number of vertices, and mark
706        // the visited
707        //
708        let mut q = NodeIdQueue::empty(queue_name);
709
710        q.enqueue(id);
711
712        while let Some(node) = q.dequeue() {
713
714            let nbrs_vec = self.nodes_map.neighbors(node);
715
716            for &nbr in nbrs_vec.iter() {
717
718                if visited_map.unvisited(nbr) {
719
720                    visited_map.visit(nbr);
721
722                    q.enqueue(nbr);
723
724                    *out_vec.last_mut().unwrap() += 1;
725                }
726            }
727        }
728    }
729    
730    pub fn find_single_source_shortest_paths_step(
731        &self, 
732        v:                            NodeId, 
733        id:                           NodeId, 
734        single_source_shortest_paths: &mut DistanceMap,
735        queue:                        &mut NodeIdQueue) 
736    {
737        let nbr_vec = self.neighbors(v);
738
739        for &nbr in nbr_vec.iter() {
740
741            if single_source_shortest_paths.is_infinite(nbr) {
742
743                single_source_shortest_paths.set_distance_for_node(
744                    nbr, 
745                    single_source_shortest_paths.distance(v) + 1.0
746                );
747
748                queue.enqueue(nbr);
749            }
750        }
751    }
752}
753
754impl FindSingleSourceShortestPaths for GraphHash {
755
756    fn find_single_source_shortest_paths(&self, id: NodeId) 
757    -> Result<DistanceMap,BetweennessCentralityError>
758    {
759        let queue_name        = format!("sssp_queue_for_{}", id);
760        let distance_map_name = format!("sssp_distance_map_for_{}", id);
761
762        let mut single_source_shortest_paths = DistanceMap::new_from_nodes(
763            self.nodes_map.mapped_nodes(), 
764            &distance_map_name
765        );
766
767        let mut queue  = NodeIdQueue::new(id, &queue_name);
768
769        single_source_shortest_paths.set_distance_for_node(id,0.0);
770
771        while let Some(v) = queue.dequeue() {
772
773            self.find_single_source_shortest_paths_step(
774                v,
775                id,
776                &mut single_source_shortest_paths,
777                &mut queue
778            );
779        }
780
781        Ok(single_source_shortest_paths)
782    }
783}
784
785impl FindPruningCounts for GraphHash {
786
787    fn find_pruning_counts_exp(&mut self, 
788        src:    NodeId,
789        dst:    NodeId) 
790    -> Result<(i32,i32,i32),BetweennessCentralityError> 
791    {
792        let edge = Edge::new(src,dst);
793
794        // IMP: the edge (src, dst) must not be in
795        // the graph else doesn't make sense to
796        // count pruned BFS's
797        //
798        let insert: bool = self.has_edge(&edge);
799
800        self.remove_edge(&edge);
801
802        let src_distances = self.find_single_source_shortest_paths(edge.src)?;
803        let dst_distances = self.find_single_source_shortest_paths(edge.dst)?;
804
805        let mut d0 = 0;
806        let mut d1 = 0;
807        let mut d2 = 0;
808
809        for node in self.nodes_map.mapped_nodes() {
810
811            let src_dist = src_distances.distance(node);
812            let dst_dist = dst_distances.distance(node);
813
814            let diff:     f64 = src_dist - dst_dist;
815            let abs_diff: f64 = diff.abs();
816
817            match abs_diff {
818                0.0  => d0 += 1,
819                1.0  => d1 += 1,
820                _  => d2 += 1,
821            }
822        }
823
824        if insert {
825            self.insert_edge(&edge);
826        }
827
828        Ok((d0,d1,d2))
829    }
830}