-
Notifications
You must be signed in to change notification settings - Fork 195
Create simple_paths_generator_with_score.rs #1284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
cb54aa0
096f239
295badd
11f4e55
5f0600c
8b691bd
0f494c4
c035b30
3f3577d
56feb61
311846c
0423f95
9c5a37b
59b4b59
5ba73bb
8ff5edf
b35e8dd
202edad
5b7708c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,368 @@ | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
| // not use this file except in compliance with the License. You may obtain | ||
| // a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
| // License for the specific language governing permissions and limitations | ||
| // under the License. | ||
|
|
||
| use crate::petgraph::algo::{Measure}; | ||
| use crate::petgraph::graph::{DiGraph, NodeIndex}; | ||
| use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable}; | ||
|
|
||
| use std::cmp::Ordering; | ||
| use std::collections::hash_map::Entry::{Occupied, Vacant}; | ||
| use std::collections::{BinaryHeap, HashMap}; | ||
| use std::fmt::Debug; | ||
| use std::hash::Hash; | ||
| use std::{f32, thread}; | ||
| // use rand::Rng; | ||
| /////////// | ||
| // SimplePath | ||
| // This is Structure which saves all the context about graph & iterating attributes | ||
| // Score : the total weightage of the current shortest path | ||
| // Path: Shorted path caulculated in this iteration | ||
| // index: used for iterating over edged to delete one and calculate path once again | ||
| // Source: to store the start point | ||
| // Target: to store goal of path | ||
| // graph: store the path to be used | ||
| // unique_path: stores all unique_paths to verify that we are not returning same path again after random edge removal | ||
| // switch : used for switching to next shortest path in case for one all possible paths are generated. | ||
| ///////////// | ||
|
|
||
| #[derive(Debug, Clone)] | ||
| pub struct SimplePath { | ||
ranjana-mishra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub Score: f32, | ||
| pub Path: Vec<NodeIndex>, | ||
| index: usize, | ||
| source: NodeIndex, | ||
| target: NodeIndex, | ||
| graph: DiGraph<(), f32>, | ||
ranjana-mishra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| unique_paths: Vec<Vec<NodeIndex>>, | ||
| switch: usize, | ||
| } | ||
|
|
||
| impl SimplePath { | ||
| fn new( | ||
| graph: &mut DiGraph<(), f32>, | ||
| source: NodeIndex, | ||
| target: NodeIndex, | ||
| ) -> Option<SimplePath> { | ||
| let s = SimplePath { | ||
| switch: 0, | ||
| unique_paths: vec![], | ||
| Score: 0.0, | ||
| Path: vec!(), | ||
| index: 0, | ||
| source: source, | ||
| target: target, | ||
| graph: graph.clone(), | ||
| }; | ||
| return Some(s); | ||
|
|
||
| } | ||
| } | ||
|
|
||
| impl Iterator for SimplePath { | ||
| type Item = SimplePath; | ||
| fn next(&mut self) -> Option<Self::Item> { | ||
|
|
||
| if self.unique_paths.len() == 0 { | ||
| let mut sim_path = get_simple_path(self); | ||
| match sim_path { | ||
| None => { | ||
| return None; | ||
| } | ||
| Some(mut s_path) => { | ||
| s_path.index = 0; | ||
| return Some(s_path) | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| let mut simple_graph = &self.unique_paths[self.switch]; | ||
| let mut index: usize = self.index; | ||
|
|
||
| if index + 1 == simple_graph.len() { | ||
| if self.switch < self.unique_paths.len() - 1 { | ||
| self.switch = self.switch + 1; | ||
| simple_graph = &self.unique_paths[self.switch]; | ||
| self.index = 0; | ||
| index = 0; | ||
| } else { | ||
| return None; | ||
| } | ||
| } | ||
|
|
||
| let edge = self.graph.find_edge(simple_graph[index], simple_graph[index + 1]); | ||
| match edge { | ||
| Some(edge) => { | ||
| let (s, t) = (simple_graph[index], simple_graph[index + 1]); | ||
| let Some(weight) = self.graph.edge_weight(edge) else { | ||
| return None; | ||
| }; | ||
| let weight = *weight; | ||
|
|
||
| println!("Removing edge {:?} {:?}",s,t); | ||
| { | ||
| let graph = &mut self.graph; | ||
| graph.remove_edge(edge); | ||
| } | ||
|
|
||
| let sim_path = get_simple_path(self); | ||
|
|
||
|
|
||
|
|
||
|
|
||
| match sim_path { | ||
| None => { | ||
| self.index = self.index + 1; | ||
| let graph = &mut self.graph; | ||
| graph.add_edge(s, t, weight); | ||
| return self.next(); | ||
| } | ||
| Some(mut s_path) => { | ||
| { | ||
| let graph = &mut s_path.graph; | ||
| graph.add_edge(s, t, weight); | ||
| } | ||
| return Some(s_path); | ||
| } | ||
| } | ||
| } | ||
| None => { | ||
| self.index = self.index + 1; | ||
| return self.next(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| // The code provides the shortest distance cost of all Nodes from the start Node | ||
| #[derive(Copy, Clone, Debug)] | ||
| struct MinScored<K, T>(pub K, pub T); | ||
|
|
||
| impl<K: PartialOrd, T> PartialEq for MinScored<K, T> { | ||
| #[inline] | ||
| fn eq(&self, other: &MinScored<K, T>) -> bool { | ||
| self.cmp(other) == Ordering::Equal | ||
| } | ||
| } | ||
|
|
||
| impl<K: PartialOrd, T> Eq for MinScored<K, T> {} | ||
|
|
||
| impl<K: PartialOrd, T> PartialOrd for MinScored<K, T> { | ||
| #[inline] | ||
| fn partial_cmp(&self, other: &MinScored<K, T>) -> Option<Ordering> { | ||
| Some(self.cmp(other)) | ||
| } | ||
| } | ||
|
|
||
| impl<K: PartialOrd, T> Ord for MinScored<K, T> { | ||
| #[inline] | ||
| fn cmp(&self, other: &MinScored<K, T>) -> Ordering { | ||
| let a = &self.0; | ||
| let b = &other.0; | ||
| if a == b { | ||
| Ordering::Equal | ||
| } else if a < b { | ||
| Ordering::Greater | ||
| } else if a > b { | ||
| Ordering::Less | ||
| } else if a.ne(a) && b.ne(b) { | ||
| // these are the NaN cases | ||
| Ordering::Equal | ||
| } else if a.ne(a) { | ||
| // Order NaN less, so that it is last in the MinScore order | ||
| Ordering::Less | ||
| } else { | ||
| Ordering::Greater | ||
| } | ||
| } | ||
| } | ||
ranjana-mishra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // This is mutation of petgraph dijkastra to get full path between source to target | ||
| fn dijkstra<G, F, K>( | ||
|
||
| graph: G, | ||
| start: G::NodeId, | ||
| goal: Option<G::NodeId>, | ||
| mut edge_cost: F, | ||
| ) -> (HashMap<G::NodeId, K>, HashMap<G::NodeId,G::NodeId>) | ||
| where | ||
| G: IntoEdges + Visitable, | ||
| G::NodeId: Eq + Hash, | ||
| F: FnMut(G::EdgeRef) -> K, | ||
| K: Measure + Copy, | ||
| <G>::NodeId: Debug, | ||
| { | ||
| let mut visited = graph.visit_map(); | ||
| let mut scores = HashMap::new(); | ||
| let mut visit_next = BinaryHeap::new(); | ||
| let zero_score = K::default(); | ||
| scores.insert(start, zero_score); | ||
| let mut tracing: HashMap<G::NodeId, G::NodeId> = HashMap::new(); | ||
| visit_next.push(MinScored(zero_score, start)); | ||
| while let Some(MinScored(node_score, node)) = visit_next.pop() { | ||
| if visited.is_visited(&node) { | ||
| continue; | ||
| } | ||
| if goal.as_ref() == Some(&node) { | ||
| break; | ||
| } | ||
| for edge in graph.edges(node) { | ||
| let next = edge.target(); | ||
| if visited.is_visited(&next) { | ||
| continue; | ||
| } | ||
| let next_score = node_score + edge_cost(edge); | ||
| match scores.entry(next) { | ||
| Occupied(ent) => { | ||
| if next_score < *ent.get() { | ||
| *ent.into_mut() = next_score; | ||
| visit_next.push(MinScored(next_score, next)); | ||
| if let Some(v) = tracing.get_mut(&next) { | ||
| *v = node; | ||
| } else { | ||
| tracing.insert(next, node); | ||
| todo!() | ||
| }; | ||
|
|
||
| } | ||
| } | ||
| Vacant(ent) => { | ||
| ent.insert(next_score); | ||
| visit_next.push(MinScored(next_score, next)); | ||
| tracing.insert(next, node); | ||
| } | ||
| } | ||
| } | ||
| visited.visit(node); | ||
| } | ||
| (scores, tracing) | ||
| } | ||
|
|
||
| // This function is private to this module, will call Dijkstra algo to get the possible path & Scores & returns a SimplePath as return value | ||
|
|
||
| fn get_simple_path(s: &mut SimplePath) -> Option<SimplePath> { | ||
| let (score, path) = dijkstra(&s.graph, s.source, Some(s.target), |e| *e.weight()); | ||
| let mut score_target: f32 = 0.0; | ||
| let mut unique_paths = s.unique_paths.clone(); | ||
| let mut paths :Vec<NodeIndex> = vec!(); | ||
|
|
||
| if score.contains_key(&s.target) { | ||
| score_target = *score.get(&s.target).expect("Error"); | ||
| } | ||
|
|
||
| if path.contains_key(&s.target) { | ||
| paths.push(s.target); | ||
| let mut node = &s.target; | ||
| loop { | ||
| let pre_node = path.get(node).expect("Error"); | ||
| paths.push(*pre_node); | ||
| if *pre_node == s.source { | ||
| break; | ||
| } | ||
| node = pre_node; | ||
| } | ||
|
||
| } | ||
|
|
||
| if paths.len() == 0 { | ||
| return None | ||
| } | ||
| paths.reverse(); | ||
| let contains_target = unique_paths.iter().any(|v| *v == paths.to_vec()); | ||
| if !contains_target { | ||
| unique_paths.push(paths.to_vec()); | ||
| let s = SimplePath { | ||
| switch: s.switch, | ||
| unique_paths: unique_paths, | ||
| Score: score_target, | ||
| Path: paths.to_vec(), | ||
| index: s.index + 1, | ||
| source: s.source, | ||
| target: s.target, | ||
| graph: s.graph.clone(), | ||
| }; | ||
| return Some(s); | ||
| } | ||
| None | ||
| } | ||
|
|
||
|
|
||
| // This function call get_simple_path for each graph after removing one of the edges in between. | ||
|
|
||
| // ------------------------------------------- | ||
| // INPUTS | ||
| // ------------------------------------------- | ||
| // you can call the function with Input Graph, Source Node, Target Node | ||
| // Create a SimplePath instance as - | ||
| // let path = SimplePath::new(&mut graph,source,target); | ||
| // Then iterate over it, as path.next() . | ||
| // The Return type is a Option, so you have to handle the None Part as the End of Iterator | ||
| //////////////////////////////////////////////// | ||
|
|
||
| ////////////////////////////////////////////// | ||
| // Testing Main function | ||
|
|
||
| //fn main() { | ||
| // let mut graph = DiGraph::new(); | ||
| // let nodes: Vec<NodeIndex> = (0..50000).map(|_| graph.add_node(())).collect(); | ||
| // let mut rng = rand::thread_rng(); | ||
| // for _ in 0..100000 { // Adjust the number of edges as desired | ||
| // let a = rng.gen_range(0..nodes.len()); | ||
| // let b = rng.gen_range(0..nodes.len()); | ||
| // let weight = rng.gen_range(1..100); // Random weight between 1 and 100 | ||
| // if a != b { // Prevent self-loops | ||
| // graph.add_edge(nodes[a], nodes[b], weight as f32); | ||
| // } | ||
| // } | ||
| // let source = nodes[10]; | ||
| // let target = nodes[800]; | ||
| // let mut result = SimplePath::new(&mut graph,source,target); | ||
| // | ||
| // while result.is_some() { | ||
| // let mut result_new = result.expect("REASON").next(); | ||
| // if result_new.is_none() { | ||
| // break; | ||
| // } | ||
| // println!("New Path & Score {:#?}, {:#?}",result_new.clone().unwrap().Score, result_new.clone().unwrap().Path); | ||
| // result = result_new; | ||
| // } | ||
| // } | ||
|
|
||
| // ---------------------------------------------- | ||
| // OUTPUT | ||
| // ---------------------------------------------- | ||
| // The function simple_paths_generator will return the Vector of Type SimplePath, which is a structure which contains { Score, Path } | ||
| // | ||
| // Example : | ||
| //New Path & Score 614.0, [ | ||
| // NodeIndex(10), | ||
| // NodeIndex(2636), | ||
| // NodeIndex(8612), | ||
| // NodeIndex(7513), | ||
| // NodeIndex(800), | ||
| //] | ||
| //New Path & Score 675.0, [ | ||
| // NodeIndex(10), | ||
| // NodeIndex(2636), | ||
| // NodeIndex(8612), | ||
| // NodeIndex(7513), | ||
| // NodeIndex(5367), | ||
| // NodeIndex(6520), | ||
| // NodeIndex(5590), | ||
| // NodeIndex(5745), | ||
| // NodeIndex(2596), | ||
| // NodeIndex(4981), | ||
| // NodeIndex(2837), | ||
| // NodeIndex(6319), | ||
| // NodeIndex(4025), | ||
| // NodeIndex(5631), | ||
| // NodeIndex(6935), | ||
| // NodeIndex(2784), | ||
| // NodeIndex(800), | ||
| //] | ||
ranjana-mishra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.