From cb54aa06544386f2f06d16e7d853ecbaa74745ba Mon Sep 17 00:00:00 2001 From: ranjana-mishra Date: Fri, 20 Sep 2024 17:36:22 +0530 Subject: [PATCH 01/16] Create simple_paths_generator_with_score.rs It uses Dijkstra Algo to generate all possible paths , by deleting one edge at a time, and gives the paths with their score. --- .../src/simple_paths_generator_with_score.rs | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 rustworkx-core/src/simple_paths_generator_with_score.rs diff --git a/rustworkx-core/src/simple_paths_generator_with_score.rs b/rustworkx-core/src/simple_paths_generator_with_score.rs new file mode 100644 index 000000000..7168a43fb --- /dev/null +++ b/rustworkx-core/src/simple_paths_generator_with_score.rs @@ -0,0 +1,280 @@ +// 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::graph::{DiGraph, NodeIndex}; +use crate::petgraph::algo::Measure; +use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable}; + +use std::collections::{HashMap, BinaryHeap}; +use std::{f32,thread}; +use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::hash::Hash; +use std::cmp::Ordering; +use std::fmt::Debug; +// use rand::Rng; + + + +#[derive(Debug,Clone)] +pub struct SimplePath { + Score: f32, + Path : Vec, +} + +// The code provides the shortest distance cost of all Nodes from the start Node +#[derive(Copy, Clone, Debug)] struct MinScored(pub K, pub T); + +impl PartialEq for MinScored { + #[inline] + fn eq(&self, other: &MinScored) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Eq for MinScored {} + +impl PartialOrd for MinScored { + #[inline] + fn partial_cmp(&self, other: &MinScored) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for MinScored { + #[inline] + fn cmp(&self, other: &MinScored) -> 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 + } + } +} + +// This is mutation of petgraph dijkastra to get full path between source to target +fn dijkstra( + graph: G, + start: G::NodeId, + goal: Option, + mut edge_cost: F, + +) -> (HashMap,HashMap>) +where + G: IntoEdges + Visitable, + G::NodeId: Eq + Hash, + F: FnMut(G::EdgeRef) -> K, + K: Measure + Copy,::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> = 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)); + let Some(v) = tracing.get_mut(&next) else { tracing.insert(next,vec!()) ; todo!() }; + v.push(node); + } + } + Vacant(ent) => { + ent.insert(next_score); + visit_next.push(MinScored(next_score, next)); + tracing.insert(next,vec!()); + if tracing.contains_key(&node) { + let Some(previous_path) = tracing.get(&node) else { todo!() }; + let old_v = previous_path.clone(); + let Some(v) = tracing.get_mut(&next) else { todo!() }; + for path in old_v { + v.push(path); + } + } + + let Some(v) = tracing.get_mut(&next) else { todo!() }; + v.push(node); + } + } + + } + visited.visit(node); + + } + (scores,tracing) +} + +// This function is private to this module, will call Dijkstra algo to get all possible path & Scores & returns a Simple{Score, Path} as return value + +fn get_simple_path(graph: & DiGraph<(), f32>, source : NodeIndex, target : NodeIndex) -> Option{ + let (score,mut path)=dijkstra(&*graph, source, Some(target),|e| *e.weight()) ; + let mut score_target :f32 = 0.0; + if score.contains_key(&target) { + score_target = *score.get(&target).expect("Error"); + } + for (node,paths) in &mut path{ + if *node == target { + paths.push(*node); + let s = SimplePath{ Score: score_target, Path: paths.to_vec()} ; + return Some(s); + } + } + None +} + +// This function call get_simple_path for each graph after removing one of the edges in between. + +pub fn simple_paths_generator(graph: &mut DiGraph<(), f32>, source : NodeIndex, target : NodeIndex ) -> Vec { + let mut result : Vec = Vec::new(); + let mut count =0; + let mut threads = vec!(); + for edge in graph.edge_indices() { + if count == 0 { + let value_graph = graph.clone(); + let t1 = thread::spawn( move || + { + get_simple_path(&value_graph, source, target) + }); + threads.push(t1); + } + + if let Some((s,t)) = graph.edge_endpoints(edge) { + if s >= source { + let Some(weight) = graph.edge_weight(edge) else {panic!("No weigh found")}; + let weight = *weight; + graph.remove_edge(edge); + let value_graph = graph.clone(); + let t1 = thread::spawn( move || { + get_simple_path(&value_graph, source, target) + }); + threads.push(t1); + graph.add_edge(s,t,weight); + + } + } + count=count+1; + } + for t in threads { + + match t.join() { + Ok(Some(path)) => { + let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); + if ! contains_target { + let s = SimplePath{ Score: path.Score, Path: path.Path.to_vec()} ; + result.push(s); + } + + + }, + _ => {} , + } + } + + result +} + +// ------------------------------------------- +// INPUTS +// ------------------------------------------- +// you can call the function with Input Graph, Source Node, Target Node +// path_finder(&mut graph,source,target); + +// Testing Main function +// fn main() { +// let mut graph = DiGraph::new(); +// let nodes: Vec = (0..1000).map(|_| graph.add_node(())).collect(); +// let mut rng = rand::thread_rng(); +// for _ in 0..5000 { // 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[880]; +// let result = simple_paths_generator(&mut graph,source,target); +// println!("{:#?}",result) ; +// } + +// ---------------------------------------------- +// OUTPUT +// ---------------------------------------------- +// The function simple_paths_generator will return the Vector of Type SimplePath, which is a structure which contains { Score, Path } +// +// Example : +// [ +// SimplePath { +// Score: 154.0, +// Path: [ +// NodeIndex(10), +// NodeIndex(49), +// NodeIndex(844), +// NodeIndex(83), +// NodeIndex(879), +// NodeIndex(477), +// NodeIndex(530), +// NodeIndex(318), +// NodeIndex(179), +// NodeIndex(433), +// NodeIndex(466), +// NodeIndex(629), +// NodeIndex(880), +// ], +// }, +// SimplePath { +// Score: 154.0, +// Path: [ +// NodeIndex(10), +// NodeIndex(871), +// NodeIndex(792), +// NodeIndex(449), +// NodeIndex(356), +// NodeIndex(169), +// NodeIndex(457), +// NodeIndex(642), +// NodeIndex(588), +// NodeIndex(189), +// NodeIndex(629), +// NodeIndex(880), +// ], +// }, +// ] From 096f23992a5130f8e53ec6b4a00dcbb482b7e6be Mon Sep 17 00:00:00 2001 From: ranjana-mishra Date: Fri, 20 Sep 2024 17:38:58 +0530 Subject: [PATCH 02/16] Update simple_paths_generator_with_score.rs --- .../src/simple_paths_generator_with_score.rs | 223 +++++++++--------- 1 file changed, 117 insertions(+), 106 deletions(-) diff --git a/rustworkx-core/src/simple_paths_generator_with_score.rs b/rustworkx-core/src/simple_paths_generator_with_score.rs index 7168a43fb..2f1c497be 100644 --- a/rustworkx-core/src/simple_paths_generator_with_score.rs +++ b/rustworkx-core/src/simple_paths_generator_with_score.rs @@ -10,28 +10,26 @@ // License for the specific language governing permissions and limitations // under the License. -use crate::petgraph::graph::{DiGraph, NodeIndex}; use crate::petgraph::algo::Measure; +use crate::petgraph::graph::{DiGraph, NodeIndex}; use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable}; -use std::collections::{HashMap, BinaryHeap}; -use std::{f32,thread}; -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::hash::Hash; use std::cmp::Ordering; +use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::collections::{BinaryHeap, HashMap}; use std::fmt::Debug; -// use rand::Rng; - - +use std::hash::Hash; +use std::{f32, thread}; -#[derive(Debug,Clone)] -pub struct SimplePath { +#[derive(Debug, Clone)] +pub struct SimplePath { Score: f32, - Path : Vec, + Path: Vec, } -// The code provides the shortest distance cost of all Nodes from the start Node -#[derive(Copy, Clone, Debug)] struct MinScored(pub K, pub T); +// The code provides the shortest distance cost of all Nodes from the start Node +#[derive(Copy, Clone, Debug)] +struct MinScored(pub K, pub T); impl PartialEq for MinScored { #[inline] @@ -74,86 +72,99 @@ impl Ord for MinScored { // This is mutation of petgraph dijkastra to get full path between source to target fn dijkstra( - graph: G, - start: G::NodeId, - goal: Option, - mut edge_cost: F, - -) -> (HashMap,HashMap>) + graph: G, + start: G::NodeId, + goal: Option, + mut edge_cost: F, +) -> (HashMap, HashMap>) where - G: IntoEdges + Visitable, - G::NodeId: Eq + Hash, - F: FnMut(G::EdgeRef) -> K, - K: Measure + Copy,::NodeId: Debug + G: IntoEdges + Visitable, + G::NodeId: Eq + Hash, + F: FnMut(G::EdgeRef) -> K, + K: Measure + Copy, + ::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> = 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)); - let Some(v) = tracing.get_mut(&next) else { tracing.insert(next,vec!()) ; todo!() }; - v.push(node); - } - } - Vacant(ent) => { - ent.insert(next_score); + 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> = 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)); - tracing.insert(next,vec!()); - if tracing.contains_key(&node) { - let Some(previous_path) = tracing.get(&node) else { todo!() }; - let old_v = previous_path.clone(); - let Some(v) = tracing.get_mut(&next) else { todo!() }; - for path in old_v { - v.push(path); - } - } - - let Some(v) = tracing.get_mut(&next) else { todo!() }; + let Some(v) = tracing.get_mut(&next) else { + tracing.insert(next, vec![]); + todo!() + }; v.push(node); - } - } + } + } + Vacant(ent) => { + ent.insert(next_score); + visit_next.push(MinScored(next_score, next)); + tracing.insert(next, vec![]); + if tracing.contains_key(&node) { + let Some(previous_path) = tracing.get(&node) else { + todo!() + }; + let old_v = previous_path.clone(); + let Some(v) = tracing.get_mut(&next) else { + todo!() + }; + for path in old_v { + v.push(path); + } + } - } - visited.visit(node); - - } - (scores,tracing) + let Some(v) = tracing.get_mut(&next) else { + todo!() + }; + v.push(node); + } + } + } + visited.visit(node); + } + (scores, tracing) } // This function is private to this module, will call Dijkstra algo to get all possible path & Scores & returns a Simple{Score, Path} as return value -fn get_simple_path(graph: & DiGraph<(), f32>, source : NodeIndex, target : NodeIndex) -> Option{ - let (score,mut path)=dijkstra(&*graph, source, Some(target),|e| *e.weight()) ; - let mut score_target :f32 = 0.0; +fn get_simple_path( + graph: &DiGraph<(), f32>, + source: NodeIndex, + target: NodeIndex, +) -> Option { + let (score, mut path) = dijkstra(&*graph, source, Some(target), |e| *e.weight()); + let mut score_target: f32 = 0.0; if score.contains_key(&target) { score_target = *score.get(&target).expect("Error"); } - for (node,paths) in &mut path{ + for (node, paths) in &mut path { if *node == target { paths.push(*node); - let s = SimplePath{ Score: score_target, Path: paths.to_vec()} ; - return Some(s); + let s = SimplePath { + Score: score_target, + Path: paths.to_vec(), + }; + return Some(s); } } None @@ -161,49 +172,49 @@ fn get_simple_path(graph: & DiGraph<(), f32>, source : NodeIndex, target : NodeI // This function call get_simple_path for each graph after removing one of the edges in between. -pub fn simple_paths_generator(graph: &mut DiGraph<(), f32>, source : NodeIndex, target : NodeIndex ) -> Vec { - let mut result : Vec = Vec::new(); - let mut count =0; - let mut threads = vec!(); +pub fn simple_paths_generator( + graph: &mut DiGraph<(), f32>, + source: NodeIndex, + target: NodeIndex, +) -> Vec { + let mut result: Vec = Vec::new(); + let mut count = 0; + let mut threads = vec![]; for edge in graph.edge_indices() { if count == 0 { - let value_graph = graph.clone(); - let t1 = thread::spawn( move || - { - get_simple_path(&value_graph, source, target) - }); + let value_graph = graph.clone(); + let t1 = thread::spawn(move || get_simple_path(&value_graph, source, target)); threads.push(t1); } - - if let Some((s,t)) = graph.edge_endpoints(edge) { + + if let Some((s, t)) = graph.edge_endpoints(edge) { if s >= source { - let Some(weight) = graph.edge_weight(edge) else {panic!("No weigh found")}; + let Some(weight) = graph.edge_weight(edge) else { + panic!("No weigh found") + }; let weight = *weight; graph.remove_edge(edge); - let value_graph = graph.clone(); - let t1 = thread::spawn( move || { - get_simple_path(&value_graph, source, target) - }); + let value_graph = graph.clone(); + let t1 = thread::spawn(move || get_simple_path(&value_graph, source, target)); threads.push(t1); - graph.add_edge(s,t,weight); - + graph.add_edge(s, t, weight); } } - count=count+1; + count = count + 1; } for t in threads { - match t.join() { Ok(Some(path)) => { let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); - if ! contains_target { - let s = SimplePath{ Score: path.Score, Path: path.Path.to_vec()} ; + if !contains_target { + let s = SimplePath { + Score: path.Score, + Path: path.Path.to_vec(), + }; result.push(s); } - - - }, - _ => {} , + } + _ => {} } } @@ -240,7 +251,7 @@ pub fn simple_paths_generator(graph: &mut DiGraph<(), f32>, source : NodeIndex, // ---------------------------------------------- // The function simple_paths_generator will return the Vector of Type SimplePath, which is a structure which contains { Score, Path } // -// Example : +// Example : // [ // SimplePath { // Score: 154.0, From 295badd741b0c0bf43eb7c957129ff1384755dcc Mon Sep 17 00:00:00 2001 From: ranjana-mishra Date: Fri, 20 Sep 2024 17:39:17 +0530 Subject: [PATCH 03/16] Update simple_paths_generator_with_score.rs --- rustworkx-core/src/simple_paths_generator_with_score.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rustworkx-core/src/simple_paths_generator_with_score.rs b/rustworkx-core/src/simple_paths_generator_with_score.rs index 2f1c497be..d49577b55 100644 --- a/rustworkx-core/src/simple_paths_generator_with_score.rs +++ b/rustworkx-core/src/simple_paths_generator_with_score.rs @@ -20,6 +20,7 @@ use std::collections::{BinaryHeap, HashMap}; use std::fmt::Debug; use std::hash::Hash; use std::{f32, thread}; +// use rand::Rng; #[derive(Debug, Clone)] pub struct SimplePath { From 11f4e557c8e1b8d66b26ca6a5eea6826c44feaed Mon Sep 17 00:00:00 2001 From: ranjana-mishra Date: Fri, 20 Sep 2024 18:05:11 +0530 Subject: [PATCH 04/16] Rename simple_paths_generator_with_score.rs to simple_paths_generator_with_score_multithreading.rs --- ...ore.rs => simple_paths_generator_with_score_multithreading.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rustworkx-core/src/{simple_paths_generator_with_score.rs => simple_paths_generator_with_score_multithreading.rs} (100%) diff --git a/rustworkx-core/src/simple_paths_generator_with_score.rs b/rustworkx-core/src/simple_paths_generator_with_score_multithreading.rs similarity index 100% rename from rustworkx-core/src/simple_paths_generator_with_score.rs rename to rustworkx-core/src/simple_paths_generator_with_score_multithreading.rs From 5f0600cb73706d4be329c5d4fbbd66ab5728bfcb Mon Sep 17 00:00:00 2001 From: Ranjana Date: Fri, 20 Sep 2024 18:24:22 +0530 Subject: [PATCH 05/16] updated without multithreading also --- .../simple_paths_generator_with_score.rs | 300 ++++++++++++++++++ ...ths_generator_with_score_multithreading.rs | 2 +- 2 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 rustworkx-core/src/generators/simple_paths_generator_with_score.rs rename rustworkx-core/src/{ => generators}/simple_paths_generator_with_score_multithreading.rs (99%) diff --git a/rustworkx-core/src/generators/simple_paths_generator_with_score.rs b/rustworkx-core/src/generators/simple_paths_generator_with_score.rs new file mode 100644 index 000000000..b95e7fdbd --- /dev/null +++ b/rustworkx-core/src/generators/simple_paths_generator_with_score.rs @@ -0,0 +1,300 @@ +// 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 rand::Rng; +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}; + +#[derive(Debug, Clone)] +pub struct SimplePath { + Score: f32, + Path: Vec, +} + +// The code provides the shortest distance cost of all Nodes from the start Node +#[derive(Copy, Clone, Debug)] +struct MinScored(pub K, pub T); + +impl PartialEq for MinScored { + #[inline] + fn eq(&self, other: &MinScored) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl Eq for MinScored {} + +impl PartialOrd for MinScored { + #[inline] + fn partial_cmp(&self, other: &MinScored) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for MinScored { + #[inline] + fn cmp(&self, other: &MinScored) -> 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 + } + } +} + +// This is mutation of petgraph dijkastra to get full path between source to target +fn dijkstra( + graph: G, + start: G::NodeId, + goal: Option, + mut edge_cost: F, +) -> (HashMap, HashMap>) +where + G: IntoEdges + Visitable, + G::NodeId: Eq + Hash, + F: FnMut(G::EdgeRef) -> K, + K: Measure + Copy, + ::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> = 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)); + let Some(v) = tracing.get_mut(&next) else { + tracing.insert(next, vec![]); + todo!() + }; + v.push(node); + } + } + Vacant(ent) => { + ent.insert(next_score); + visit_next.push(MinScored(next_score, next)); + tracing.insert(next, vec![]); + if tracing.contains_key(&node) { + let Some(previous_path) = tracing.get(&node) else { + todo!() + }; + let old_v = previous_path.clone(); + let Some(v) = tracing.get_mut(&next) else { + todo!() + }; + for path in old_v { + v.push(path); + } + } + + let Some(v) = tracing.get_mut(&next) else { + todo!() + }; + v.push(node); + } + } + } + visited.visit(node); + } + (scores, tracing) +} + +// This function is private to this module, will call Dijkstra algo to get all possible path & Scores & returns a Simple{Score, Path} as return value + +fn get_simple_path( + graph: &DiGraph<(), f32>, + source: NodeIndex, + target: NodeIndex, +) -> Option { + let (score, mut path) = dijkstra(&*graph, source, Some(target), |e| *e.weight()); + let mut score_target: f32 = 0.0; + if score.contains_key(&target) { + score_target = *score.get(&target).expect("Error"); + } + for (node, paths) in &mut path { + if *node == target { + paths.push(*node); + let s = SimplePath { + Score: score_target, + Path: paths.to_vec(), + }; + return Some(s); + } + } + None +} + +// This function call get_simple_path for each graph after removing one of the edges in between. + +pub fn simple_paths_generator( + graph: &mut DiGraph<(), f32>, + source: NodeIndex, + target: NodeIndex, +) -> Vec { + let mut result: Vec = Vec::new(); + let mut count = 0; + for edge in graph.edge_indices() { + if count == 0 { + let sim_path = get_simple_path(&graph, source, target); + match sim_path { + Some(path) => { + let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); + if !contains_target { + let s = SimplePath { + Score: path.Score, + Path: path.Path.to_vec(), + }; + result.push(s); + } + } + None => {} + } + } + + if let Some((s, t)) = graph.edge_endpoints(edge) { + if s >= source { + let Some(weight) = graph.edge_weight(edge) else { + panic!("No weigh found") + }; + let weight = *weight; + graph.remove_edge(edge); + let sim_path = get_simple_path(&graph, source, target); + match sim_path { + Some(path) => { + let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); + if !contains_target { + let s = SimplePath { + Score: path.Score, + Path: path.Path.to_vec(), + }; + result.push(s); + } + } + None => {} + } + + graph.add_edge(s, t, weight); + } + } + count = count + 1; + } + + result +} + +// ------------------------------------------- +// INPUTS +// ------------------------------------------- +// you can call the function with Input Graph, Source Node, Target Node +// path_finder(&mut graph,source,target); + +// Testing Main function +// fn main() { +// let mut graph = DiGraph::new(); +// let nodes: Vec = (0..10000).map(|_| graph.add_node(())).collect(); +// let mut rng = rand::thread_rng(); +// for _ in 0..50000 { // 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[8670]; +// let result = simple_paths_generator(&mut graph,source,target); +// println!("{:#?}",result) ; +// } + +// ---------------------------------------------- +// OUTPUT +// ---------------------------------------------- +// The function simple_paths_generator will return the Vector of Type SimplePath, which is a structure which contains { Score, Path } +// Consumes less memory but more time +// +// Example : +// [ +// SimplePath { +// Score: 154.0, +// Path: [ +// NodeIndex(10), +// NodeIndex(49), +// NodeIndex(844), +// NodeIndex(83), +// NodeIndex(879), +// NodeIndex(477), +// NodeIndex(530), +// NodeIndex(318), +// NodeIndex(179), +// NodeIndex(433), +// NodeIndex(466), +// NodeIndex(629), +// NodeIndex(880), +// ], +// }, +// SimplePath { +// Score: 154.0, +// Path: [ +// NodeIndex(10), +// NodeIndex(871), +// NodeIndex(792), +// NodeIndex(449), +// NodeIndex(356), +// NodeIndex(169), +// NodeIndex(457), +// NodeIndex(642), +// NodeIndex(588), +// NodeIndex(189), +// NodeIndex(629), +// NodeIndex(880), +// ], +// }, +// ] diff --git a/rustworkx-core/src/simple_paths_generator_with_score_multithreading.rs b/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs similarity index 99% rename from rustworkx-core/src/simple_paths_generator_with_score_multithreading.rs rename to rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs index d49577b55..f63f98fd7 100644 --- a/rustworkx-core/src/simple_paths_generator_with_score_multithreading.rs +++ b/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs @@ -251,7 +251,7 @@ pub fn simple_paths_generator( // OUTPUT // ---------------------------------------------- // The function simple_paths_generator will return the Vector of Type SimplePath, which is a structure which contains { Score, Path } -// +// Consume High memory because of Many threads running at same. // Example : // [ // SimplePath { From 8b691bdbf5c68aed93fa1c1424763704e26ab0e7 Mon Sep 17 00:00:00 2001 From: Ranjana Date: Mon, 23 Sep 2024 11:02:06 +0530 Subject: [PATCH 06/16] updated code --- .../simple_paths_generator_with_score.rs | 84 ++++++++++-------- ...ths_generator_with_score_multithreading.rs | 87 ++++++++++++------- 2 files changed, 101 insertions(+), 70 deletions(-) diff --git a/rustworkx-core/src/generators/simple_paths_generator_with_score.rs b/rustworkx-core/src/generators/simple_paths_generator_with_score.rs index b95e7fdbd..6f58418ea 100644 --- a/rustworkx-core/src/generators/simple_paths_generator_with_score.rs +++ b/rustworkx-core/src/generators/simple_paths_generator_with_score.rs @@ -179,53 +179,61 @@ pub fn simple_paths_generator( target: NodeIndex, ) -> Vec { let mut result: Vec = Vec::new(); - let mut count = 0; - for edge in graph.edge_indices() { - if count == 0 { - let sim_path = get_simple_path(&graph, source, target); - match sim_path { - Some(path) => { - let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); - if !contains_target { - let s = SimplePath { - Score: path.Score, - Path: path.Path.to_vec(), - }; - result.push(s); - } - } - None => {} - } - } + let sim_path = get_simple_path(&graph, source, target); - if let Some((s, t)) = graph.edge_endpoints(edge) { - if s >= source { - let Some(weight) = graph.edge_weight(edge) else { - panic!("No weigh found") + match sim_path { + Some(path) => { + println!("Path - {:#?}", path.Path); + let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); + if !contains_target { + let s = SimplePath { + Score: path.Score, + Path: path.Path.to_vec(), }; - let weight = *weight; - graph.remove_edge(edge); - let sim_path = get_simple_path(&graph, source, target); - match sim_path { - Some(path) => { - let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); - if !contains_target { - let s = SimplePath { - Score: path.Score, - Path: path.Path.to_vec(), - }; - result.push(s); + result.push(s); + } + let simple_graph = &path.Path; + + for index in 0..path.Path.len() - 1 { + println!( + "Executing without edge {:#?} {:#?}", + simple_graph[index], + simple_graph[index + 1] + ); + let edge_option = graph.find_edge(simple_graph[index], simple_graph[index + 1]); + match edge_option { + Some(edge) => { + let (s, t) = (simple_graph[index], simple_graph[index + 1]); + + let Some(weight) = graph.edge_weight(edge) else { + panic!("No weigh found") + }; + let weight = *weight; + graph.remove_edge(edge); + let sim_path = get_simple_path(&graph, source, target); + match sim_path { + Some(path) => { + let contains_target = + result.iter().any(|v| v.Path == path.Path.to_vec()); + if !contains_target { + let s = SimplePath { + Score: path.Score, + Path: path.Path.to_vec(), + }; + result.push(s); + } + } + None => {} } + + graph.add_edge(s, t, weight); } None => {} } - - graph.add_edge(s, t, weight); } } - count = count + 1; + None => {} } - result } diff --git a/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs b/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs index f63f98fd7..0c31bd61c 100644 --- a/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs +++ b/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs @@ -179,44 +179,67 @@ pub fn simple_paths_generator( target: NodeIndex, ) -> Vec { let mut result: Vec = Vec::new(); - let mut count = 0; + let sim_path = get_simple_path(&graph, source, target); let mut threads = vec![]; - for edge in graph.edge_indices() { - if count == 0 { - let value_graph = graph.clone(); - let t1 = thread::spawn(move || get_simple_path(&value_graph, source, target)); - threads.push(t1); - } - if let Some((s, t)) = graph.edge_endpoints(edge) { - if s >= source { - let Some(weight) = graph.edge_weight(edge) else { - panic!("No weigh found") + match sim_path { + Some(path) => { + let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); + if !contains_target { + let s = SimplePath { + Score: path.Score, + Path: path.Path.to_vec(), }; - let weight = *weight; - graph.remove_edge(edge); - let value_graph = graph.clone(); - let t1 = thread::spawn(move || get_simple_path(&value_graph, source, target)); - threads.push(t1); - graph.add_edge(s, t, weight); + result.push(s); } - } - count = count + 1; - } - for t in threads { - match t.join() { - Ok(Some(path)) => { - let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); - if !contains_target { - let s = SimplePath { - Score: path.Score, - Path: path.Path.to_vec(), - }; - result.push(s); + let simple_graph = &path.Path; + let mut thread_count = 0; + + for index in 0..path.Path.len() - 1 { + let edge_option = graph.find_edge(simple_graph[index], simple_graph[index + 1]); + match edge_option { + Some(edge) => { + let (s, t) = (simple_graph[index], simple_graph[index + 1]); + + let Some(weight) = graph.edge_weight(edge) else { + panic!("No weigh found") + }; + let weight = *weight; + graph.remove_edge(edge); + let value_graph = graph.clone(); + thread_count = thread_count + 1; + if thread_count < 10 { + let t1 = thread::spawn(move || { + get_simple_path(&value_graph, source, target) + }); + threads.push(t1); + } else { + thread_count = 0; + for t in threads { + match t.join() { + Ok(Some(path)) => { + let contains_target = + result.iter().any(|v| v.Path == path.Path.to_vec()); + if !contains_target { + let s = SimplePath { + Score: path.Score, + Path: path.Path.to_vec(), + }; + result.push(s); + } + } + _ => {} + } + } + threads = vec![]; + } + graph.add_edge(s, t, weight); + } + None => {} } } - _ => {} } + None => {} } result @@ -251,7 +274,7 @@ pub fn simple_paths_generator( // OUTPUT // ---------------------------------------------- // The function simple_paths_generator will return the Vector of Type SimplePath, which is a structure which contains { Score, Path } -// Consume High memory because of Many threads running at same. +// Consume High memory because of Many threads running at same. // Example : // [ // SimplePath { From 0f494c46cfc99040dd575af3024dd56857cc55f7 Mon Sep 17 00:00:00 2001 From: Ranjana Date: Mon, 23 Sep 2024 11:11:59 +0530 Subject: [PATCH 07/16] removed println lines --- .../src/generators/simple_paths_generator_with_score.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rustworkx-core/src/generators/simple_paths_generator_with_score.rs b/rustworkx-core/src/generators/simple_paths_generator_with_score.rs index 6f58418ea..a226a0a41 100644 --- a/rustworkx-core/src/generators/simple_paths_generator_with_score.rs +++ b/rustworkx-core/src/generators/simple_paths_generator_with_score.rs @@ -183,7 +183,6 @@ pub fn simple_paths_generator( match sim_path { Some(path) => { - println!("Path - {:#?}", path.Path); let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); if !contains_target { let s = SimplePath { @@ -195,11 +194,6 @@ pub fn simple_paths_generator( let simple_graph = &path.Path; for index in 0..path.Path.len() - 1 { - println!( - "Executing without edge {:#?} {:#?}", - simple_graph[index], - simple_graph[index + 1] - ); let edge_option = graph.find_edge(simple_graph[index], simple_graph[index + 1]); match edge_option { Some(edge) => { From c035b301fd464f21ad60c607314d49e09b260d5d Mon Sep 17 00:00:00 2001 From: Ranjana Date: Mon, 23 Sep 2024 15:23:46 +0530 Subject: [PATCH 08/16] updated the code as iterator --- ...ths_generator_with_score_multithreading.rs | 315 ------------------ ...with_score.rs => simple_paths_iterator.rs} | 227 ++++++++----- 2 files changed, 146 insertions(+), 396 deletions(-) delete mode 100644 rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs rename rustworkx-core/src/generators/{simple_paths_generator_with_score.rs => simple_paths_iterator.rs} (58%) diff --git a/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs b/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs deleted file mode 100644 index 0c31bd61c..000000000 --- a/rustworkx-core/src/generators/simple_paths_generator_with_score_multithreading.rs +++ /dev/null @@ -1,315 +0,0 @@ -// 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; - -#[derive(Debug, Clone)] -pub struct SimplePath { - Score: f32, - Path: Vec, -} - -// The code provides the shortest distance cost of all Nodes from the start Node -#[derive(Copy, Clone, Debug)] -struct MinScored(pub K, pub T); - -impl PartialEq for MinScored { - #[inline] - fn eq(&self, other: &MinScored) -> bool { - self.cmp(other) == Ordering::Equal - } -} - -impl Eq for MinScored {} - -impl PartialOrd for MinScored { - #[inline] - fn partial_cmp(&self, other: &MinScored) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for MinScored { - #[inline] - fn cmp(&self, other: &MinScored) -> 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 - } - } -} - -// This is mutation of petgraph dijkastra to get full path between source to target -fn dijkstra( - graph: G, - start: G::NodeId, - goal: Option, - mut edge_cost: F, -) -> (HashMap, HashMap>) -where - G: IntoEdges + Visitable, - G::NodeId: Eq + Hash, - F: FnMut(G::EdgeRef) -> K, - K: Measure + Copy, - ::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> = 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)); - let Some(v) = tracing.get_mut(&next) else { - tracing.insert(next, vec![]); - todo!() - }; - v.push(node); - } - } - Vacant(ent) => { - ent.insert(next_score); - visit_next.push(MinScored(next_score, next)); - tracing.insert(next, vec![]); - if tracing.contains_key(&node) { - let Some(previous_path) = tracing.get(&node) else { - todo!() - }; - let old_v = previous_path.clone(); - let Some(v) = tracing.get_mut(&next) else { - todo!() - }; - for path in old_v { - v.push(path); - } - } - - let Some(v) = tracing.get_mut(&next) else { - todo!() - }; - v.push(node); - } - } - } - visited.visit(node); - } - (scores, tracing) -} - -// This function is private to this module, will call Dijkstra algo to get all possible path & Scores & returns a Simple{Score, Path} as return value - -fn get_simple_path( - graph: &DiGraph<(), f32>, - source: NodeIndex, - target: NodeIndex, -) -> Option { - let (score, mut path) = dijkstra(&*graph, source, Some(target), |e| *e.weight()); - let mut score_target: f32 = 0.0; - if score.contains_key(&target) { - score_target = *score.get(&target).expect("Error"); - } - for (node, paths) in &mut path { - if *node == target { - paths.push(*node); - let s = SimplePath { - Score: score_target, - Path: paths.to_vec(), - }; - return Some(s); - } - } - None -} - -// This function call get_simple_path for each graph after removing one of the edges in between. - -pub fn simple_paths_generator( - graph: &mut DiGraph<(), f32>, - source: NodeIndex, - target: NodeIndex, -) -> Vec { - let mut result: Vec = Vec::new(); - let sim_path = get_simple_path(&graph, source, target); - let mut threads = vec![]; - - match sim_path { - Some(path) => { - let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); - if !contains_target { - let s = SimplePath { - Score: path.Score, - Path: path.Path.to_vec(), - }; - result.push(s); - } - let simple_graph = &path.Path; - let mut thread_count = 0; - - for index in 0..path.Path.len() - 1 { - let edge_option = graph.find_edge(simple_graph[index], simple_graph[index + 1]); - match edge_option { - Some(edge) => { - let (s, t) = (simple_graph[index], simple_graph[index + 1]); - - let Some(weight) = graph.edge_weight(edge) else { - panic!("No weigh found") - }; - let weight = *weight; - graph.remove_edge(edge); - let value_graph = graph.clone(); - thread_count = thread_count + 1; - if thread_count < 10 { - let t1 = thread::spawn(move || { - get_simple_path(&value_graph, source, target) - }); - threads.push(t1); - } else { - thread_count = 0; - for t in threads { - match t.join() { - Ok(Some(path)) => { - let contains_target = - result.iter().any(|v| v.Path == path.Path.to_vec()); - if !contains_target { - let s = SimplePath { - Score: path.Score, - Path: path.Path.to_vec(), - }; - result.push(s); - } - } - _ => {} - } - } - threads = vec![]; - } - graph.add_edge(s, t, weight); - } - None => {} - } - } - } - None => {} - } - - result -} - -// ------------------------------------------- -// INPUTS -// ------------------------------------------- -// you can call the function with Input Graph, Source Node, Target Node -// path_finder(&mut graph,source,target); - -// Testing Main function -// fn main() { -// let mut graph = DiGraph::new(); -// let nodes: Vec = (0..1000).map(|_| graph.add_node(())).collect(); -// let mut rng = rand::thread_rng(); -// for _ in 0..5000 { // 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[880]; -// let result = simple_paths_generator(&mut graph,source,target); -// println!("{:#?}",result) ; -// } - -// ---------------------------------------------- -// OUTPUT -// ---------------------------------------------- -// The function simple_paths_generator will return the Vector of Type SimplePath, which is a structure which contains { Score, Path } -// Consume High memory because of Many threads running at same. -// Example : -// [ -// SimplePath { -// Score: 154.0, -// Path: [ -// NodeIndex(10), -// NodeIndex(49), -// NodeIndex(844), -// NodeIndex(83), -// NodeIndex(879), -// NodeIndex(477), -// NodeIndex(530), -// NodeIndex(318), -// NodeIndex(179), -// NodeIndex(433), -// NodeIndex(466), -// NodeIndex(629), -// NodeIndex(880), -// ], -// }, -// SimplePath { -// Score: 154.0, -// Path: [ -// NodeIndex(10), -// NodeIndex(871), -// NodeIndex(792), -// NodeIndex(449), -// NodeIndex(356), -// NodeIndex(169), -// NodeIndex(457), -// NodeIndex(642), -// NodeIndex(588), -// NodeIndex(189), -// NodeIndex(629), -// NodeIndex(880), -// ], -// }, -// ] diff --git a/rustworkx-core/src/generators/simple_paths_generator_with_score.rs b/rustworkx-core/src/generators/simple_paths_iterator.rs similarity index 58% rename from rustworkx-core/src/generators/simple_paths_generator_with_score.rs rename to rustworkx-core/src/generators/simple_paths_iterator.rs index a226a0a41..32c922d6a 100644 --- a/rustworkx-core/src/generators/simple_paths_generator_with_score.rs +++ b/rustworkx-core/src/generators/simple_paths_iterator.rs @@ -14,20 +14,121 @@ use crate::petgraph::algo::Measure; use crate::petgraph::graph::{DiGraph, NodeIndex}; use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable}; -use rand::Rng; 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 { - Score: f32, - Path: Vec, + pub Score: f32, + pub Path: Vec, + index: usize, + source: NodeIndex, + target: NodeIndex, + graph: DiGraph<(), f32>, + unique_paths: Vec>, + switch: usize, +} + +impl SimplePath { + fn new( + graph: &mut DiGraph<(), f32>, + source: NodeIndex, + target: NodeIndex, + ) -> Option { + let mut unique_paths: Vec> = vec![]; + let (score, mut path) = dijkstra(&*graph, source, Some(target), |e| *e.weight()); + let mut score_target: f32 = 0.0; + if score.contains_key(&target) { + score_target = *score.get(&target).expect("Error"); + } + for (node, paths) in &mut path { + if *node == target { + paths.push(*node); + unique_paths.push(paths.to_vec()); + let s = SimplePath { + switch: 0, + unique_paths: unique_paths, + Score: score_target, + Path: paths.to_vec(), + index: 0, + source: source, + target: target, + graph: graph.clone(), + }; + return Some(s); + } + } + None + } } +impl Iterator for SimplePath { + type Item = SimplePath; + fn next(&mut self) -> Option { + let mut simple_graph = &self.unique_paths[self.switch]; + let mut index: usize = self.index; + let mut graph = self.graph.clone(); + + 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 = 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) = graph.edge_weight(edge) else { + return None; + }; + let weight = *weight; + graph.remove_edge(edge); + index = index + 1; + + let sim_path = get_simple_path(&mut graph, self); + graph.add_edge(s, t, weight); + + match sim_path { + None => { + self.index = self.index + 1; + return self.next(); + } + _ => { + return sim_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(pub K, pub T); @@ -143,100 +244,56 @@ where } visited.visit(node); } + (scores, tracing) } -// This function is private to this module, will call Dijkstra algo to get all possible path & Scores & returns a Simple{Score, Path} as return value +// This function is private to this module, will call Dijkstra algo to get all possible path & Scores & returns a Simple as return value -fn get_simple_path( - graph: &DiGraph<(), f32>, - source: NodeIndex, - target: NodeIndex, -) -> Option { - let (score, mut path) = dijkstra(&*graph, source, Some(target), |e| *e.weight()); +fn get_simple_path(graph: &mut DiGraph<(), f32>, s: &mut SimplePath) -> Option { + let (score, mut path) = dijkstra(&*graph, s.source, Some(s.target), |e| *e.weight()); let mut score_target: f32 = 0.0; - if score.contains_key(&target) { - score_target = *score.get(&target).expect("Error"); + let mut unique_paths = s.unique_paths.clone(); + + if score.contains_key(&s.target) { + score_target = *score.get(&s.target).expect("Error"); } for (node, paths) in &mut path { - if *node == target { + if *node == s.target { paths.push(*node); - let s = SimplePath { - Score: score_target, - Path: paths.to_vec(), - }; - return Some(s); - } - } - None -} - -// This function call get_simple_path for each graph after removing one of the edges in between. - -pub fn simple_paths_generator( - graph: &mut DiGraph<(), f32>, - source: NodeIndex, - target: NodeIndex, -) -> Vec { - let mut result: Vec = Vec::new(); - let sim_path = get_simple_path(&graph, source, target); - - match sim_path { - Some(path) => { - let contains_target = result.iter().any(|v| v.Path == path.Path.to_vec()); + let contains_target = unique_paths.iter().any(|v| *v == paths.to_vec()); if !contains_target { + unique_paths.push(paths.to_vec()); let s = SimplePath { - Score: path.Score, - Path: path.Path.to_vec(), + 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: graph.clone(), }; - result.push(s); - } - let simple_graph = &path.Path; - - for index in 0..path.Path.len() - 1 { - let edge_option = graph.find_edge(simple_graph[index], simple_graph[index + 1]); - match edge_option { - Some(edge) => { - let (s, t) = (simple_graph[index], simple_graph[index + 1]); - - let Some(weight) = graph.edge_weight(edge) else { - panic!("No weigh found") - }; - let weight = *weight; - graph.remove_edge(edge); - let sim_path = get_simple_path(&graph, source, target); - match sim_path { - Some(path) => { - let contains_target = - result.iter().any(|v| v.Path == path.Path.to_vec()); - if !contains_target { - let s = SimplePath { - Score: path.Score, - Path: path.Path.to_vec(), - }; - result.push(s); - } - } - None => {} - } - - graph.add_edge(s, t, weight); - } - None => {} - } + return Some(s); } } - None => {} } - result + 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 -// path_finder(&mut graph,source,target); +// 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(); @@ -251,16 +308,24 @@ pub fn simple_paths_generator( // } // } // let source = nodes[10]; -// let target = nodes[8670]; -// let result = simple_paths_generator(&mut graph,source,target); -// println!("{:#?}",result) ; -// } +// let target = nodes[800]; +// let mut result = SimplePath::new(&mut graph,source,target); +// println!("New Path {:#?}",result.clone().unwrap().Path); +// +// 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 } -// Consumes less memory but more time // // Example : // [ From 3f3577d50303b91668bace12f3542c8d25c66408 Mon Sep 17 00:00:00 2001 From: Ranjana Date: Mon, 23 Sep 2024 15:27:18 +0530 Subject: [PATCH 09/16] updated fmt --- rustworkx-core/src/generators/simple_paths_iterator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustworkx-core/src/generators/simple_paths_iterator.rs b/rustworkx-core/src/generators/simple_paths_iterator.rs index 32c922d6a..42e554ca4 100644 --- a/rustworkx-core/src/generators/simple_paths_iterator.rs +++ b/rustworkx-core/src/generators/simple_paths_iterator.rs @@ -248,7 +248,7 @@ where (scores, tracing) } -// This function is private to this module, will call Dijkstra algo to get all possible path & Scores & returns a Simple as return value +// 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(graph: &mut DiGraph<(), f32>, s: &mut SimplePath) -> Option { let (score, mut path) = dijkstra(&*graph, s.source, Some(s.target), |e| *e.weight()); From 56feb61ef5f5fe79254f8f4a2229c79561d30608 Mon Sep 17 00:00:00 2001 From: Ranjana Date: Mon, 23 Sep 2024 15:32:03 +0530 Subject: [PATCH 10/16] update output section --- .../src/generators/simple_paths_iterator.rs | 65 ++++++++----------- 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/rustworkx-core/src/generators/simple_paths_iterator.rs b/rustworkx-core/src/generators/simple_paths_iterator.rs index 42e554ca4..c559010f0 100644 --- a/rustworkx-core/src/generators/simple_paths_iterator.rs +++ b/rustworkx-core/src/generators/simple_paths_iterator.rs @@ -310,7 +310,7 @@ fn get_simple_path(graph: &mut DiGraph<(), f32>, s: &mut SimplePath) -> Option, s: &mut SimplePath) -> Option Date: Wed, 25 Sep 2024 10:17:32 +0530 Subject: [PATCH 11/16] update iterator func --- .../src/generators/simple_paths_iterator.rs | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/rustworkx-core/src/generators/simple_paths_iterator.rs b/rustworkx-core/src/generators/simple_paths_iterator.rs index c559010f0..97c04c46a 100644 --- a/rustworkx-core/src/generators/simple_paths_iterator.rs +++ b/rustworkx-core/src/generators/simple_paths_iterator.rs @@ -53,39 +53,41 @@ impl SimplePath { source: NodeIndex, target: NodeIndex, ) -> Option { - let mut unique_paths: Vec> = vec![]; - let (score, mut path) = dijkstra(&*graph, source, Some(target), |e| *e.weight()); - let mut score_target: f32 = 0.0; - if score.contains_key(&target) { - score_target = *score.get(&target).expect("Error"); - } - for (node, paths) in &mut path { - if *node == target { - paths.push(*node); - unique_paths.push(paths.to_vec()); - let s = SimplePath { + let s = SimplePath { switch: 0, - unique_paths: unique_paths, - Score: score_target, - Path: paths.to_vec(), + unique_paths: vec![], + Score: 0.0, + Path: vec!(), index: 0, source: source, target: target, - graph: graph.clone(), - }; - return Some(s); - } - } - None + graph: graph.clone(), + }; + return Some(s); + } } impl Iterator for SimplePath { type Item = SimplePath; fn next(&mut self) -> Option { + let mut graph = self.graph.clone(); + if self.unique_paths.len() == 0 { + let sim_path = get_simple_path(& graph, self); + match sim_path { + None => { + self.index = self.index + 1; + return self.next(); + } + _ => { + return sim_path; + } + } + + } + let mut simple_graph = &self.unique_paths[self.switch]; let mut index: usize = self.index; - let mut graph = self.graph.clone(); if index + 1 == simple_graph.len() { if self.switch < self.unique_paths.len() + 1 { @@ -107,9 +109,8 @@ impl Iterator for SimplePath { }; let weight = *weight; graph.remove_edge(edge); - index = index + 1; - let sim_path = get_simple_path(&mut graph, self); + let sim_path = get_simple_path(& graph, self); graph.add_edge(s, t, weight); match sim_path { @@ -250,7 +251,7 @@ where // 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(graph: &mut DiGraph<(), f32>, s: &mut SimplePath) -> Option { +fn get_simple_path(graph: & DiGraph<(), f32>, s: &mut SimplePath) -> Option { let (score, mut path) = dijkstra(&*graph, s.source, Some(s.target), |e| *e.weight()); let mut score_target: f32 = 0.0; let mut unique_paths = s.unique_paths.clone(); @@ -310,7 +311,6 @@ fn get_simple_path(graph: &mut DiGraph<(), f32>, s: &mut SimplePath) -> Option Date: Wed, 25 Sep 2024 14:49:04 +0530 Subject: [PATCH 12/16] updated to store only previos node , not full path dijkastra --- ...s_iterator.rs => simple_shortest_paths.rs} | 126 +++++++++--------- 1 file changed, 60 insertions(+), 66 deletions(-) rename rustworkx-core/src/generators/{simple_paths_iterator.rs => simple_shortest_paths.rs} (77%) diff --git a/rustworkx-core/src/generators/simple_paths_iterator.rs b/rustworkx-core/src/generators/simple_shortest_paths.rs similarity index 77% rename from rustworkx-core/src/generators/simple_paths_iterator.rs rename to rustworkx-core/src/generators/simple_shortest_paths.rs index 97c04c46a..f2192b83a 100644 --- a/rustworkx-core/src/generators/simple_paths_iterator.rs +++ b/rustworkx-core/src/generators/simple_shortest_paths.rs @@ -14,14 +14,13 @@ use crate::petgraph::algo::Measure; use crate::petgraph::graph::{DiGraph, NodeIndex}; use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable}; +use rand::Rng; 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 @@ -43,7 +42,7 @@ pub struct SimplePath { source: NodeIndex, target: NodeIndex, graph: DiGraph<(), f32>, - unique_paths: Vec>, + pub unique_paths: Vec>, switch: usize, } @@ -53,18 +52,17 @@ impl SimplePath { source: NodeIndex, target: NodeIndex, ) -> Option { - let s = SimplePath { - switch: 0, - unique_paths: vec![], - Score: 0.0, - Path: vec!(), - index: 0, - source: source, - target: target, - graph: graph.clone(), + 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); - } } @@ -73,24 +71,22 @@ impl Iterator for SimplePath { fn next(&mut self) -> Option { let mut graph = self.graph.clone(); if self.unique_paths.len() == 0 { - let sim_path = get_simple_path(& graph, self); + let sim_path = get_simple_path(&graph, self); match sim_path { None => { - self.index = self.index + 1; - return self.next(); + return None; } _ => { return sim_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 { + if self.switch < self.unique_paths.len() - 1 { self.switch = self.switch + 1; simple_graph = &self.unique_paths[self.switch]; self.index = 0; @@ -110,7 +106,7 @@ impl Iterator for SimplePath { let weight = *weight; graph.remove_edge(edge); - let sim_path = get_simple_path(& graph, self); + let sim_path = get_simple_path(&graph, self); graph.add_edge(s, t, weight); match sim_path { @@ -179,7 +175,7 @@ fn dijkstra( start: G::NodeId, goal: Option, mut edge_cost: F, -) -> (HashMap, HashMap>) +) -> (HashMap, HashMap) where G: IntoEdges + Visitable, G::NodeId: Eq + Hash, @@ -192,7 +188,7 @@ where let mut visit_next = BinaryHeap::new(); let zero_score = K::default(); scores.insert(start, zero_score); - let mut tracing: HashMap> = HashMap::new(); + let mut tracing: HashMap = HashMap::new(); visit_next.push(MinScored(zero_score, start)); while let Some(MinScored(node_score, node)) = visit_next.pop() { if visited.is_visited(&node) { @@ -212,73 +208,70 @@ where if next_score < *ent.get() { *ent.into_mut() = next_score; visit_next.push(MinScored(next_score, next)); - let Some(v) = tracing.get_mut(&next) else { - tracing.insert(next, vec![]); + if let Some(v) = tracing.get_mut(&next) { + *v = node; + } else { + tracing.insert(next, node); todo!() }; - v.push(node); } } Vacant(ent) => { ent.insert(next_score); visit_next.push(MinScored(next_score, next)); - tracing.insert(next, vec![]); - if tracing.contains_key(&node) { - let Some(previous_path) = tracing.get(&node) else { - todo!() - }; - let old_v = previous_path.clone(); - let Some(v) = tracing.get_mut(&next) else { - todo!() - }; - for path in old_v { - v.push(path); - } - } - - let Some(v) = tracing.get_mut(&next) else { - todo!() - }; - v.push(node); + 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(graph: & DiGraph<(), f32>, s: &mut SimplePath) -> Option { - let (score, mut path) = dijkstra(&*graph, s.source, Some(s.target), |e| *e.weight()); +fn get_simple_path(graph: &DiGraph<(), f32>, s: &mut SimplePath) -> Option { + let (score, path) = dijkstra(&*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 = vec![]; if score.contains_key(&s.target) { score_target = *score.get(&s.target).expect("Error"); } - for (node, paths) in &mut path { - if *node == s.target { - paths.push(*node); - 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: graph.clone(), - }; - return Some(s); + + 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: graph.clone(), + }; + return Some(s); + } None } @@ -296,11 +289,12 @@ fn get_simple_path(graph: & DiGraph<(), f32>, s: &mut SimplePath) -> Option = (0..10000).map(|_| graph.add_node(())).collect(); + +//fn main() { +// let mut graph = DiGraph::new(); +// let nodes: Vec = (0..50000).map(|_| graph.add_node(())).collect(); // let mut rng = rand::thread_rng(); -// for _ in 0..50000 { // Adjust the number of edges as desired +// 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 From 9c5a37b6dd00a58d4cd4cccc070ab467fba9ba92 Mon Sep 17 00:00:00 2001 From: Ranjana Date: Wed, 25 Sep 2024 15:20:05 +0530 Subject: [PATCH 13/16] updated with better memory management --- .../src/generators/simple_shortest_paths.rs | 114 ++++++++++-------- 1 file changed, 66 insertions(+), 48 deletions(-) diff --git a/rustworkx-core/src/generators/simple_shortest_paths.rs b/rustworkx-core/src/generators/simple_shortest_paths.rs index f2192b83a..1b53ceea9 100644 --- a/rustworkx-core/src/generators/simple_shortest_paths.rs +++ b/rustworkx-core/src/generators/simple_shortest_paths.rs @@ -10,17 +10,17 @@ // License for the specific language governing permissions and limitations // under the License. -use crate::petgraph::algo::Measure; +use crate::petgraph::algo::{Measure}; use crate::petgraph::graph::{DiGraph, NodeIndex}; use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable}; -use rand::Rng; 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 @@ -42,7 +42,7 @@ pub struct SimplePath { source: NodeIndex, target: NodeIndex, graph: DiGraph<(), f32>, - pub unique_paths: Vec>, + unique_paths: Vec>, switch: usize, } @@ -52,34 +52,37 @@ impl SimplePath { source: NodeIndex, target: NodeIndex, ) -> Option { - let s = SimplePath { - switch: 0, - unique_paths: vec![], - Score: 0.0, - Path: vec![], - index: 0, - source: source, - target: target, - graph: graph.clone(), + 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 { - let mut graph = self.graph.clone(); + if self.unique_paths.len() == 0 { - let sim_path = get_simple_path(&graph, self); + let mut sim_path = get_simple_path(self); match sim_path { None => { return None; } - _ => { - return sim_path; + Some(mut s_path) => { + s_path.index = 0; + return Some(s_path) } } + } let mut simple_graph = &self.unique_paths[self.switch]; @@ -96,26 +99,39 @@ impl Iterator for SimplePath { } } - let edge = graph.find_edge(simple_graph[index], simple_graph[index + 1]); + 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) = graph.edge_weight(edge) else { + 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); + - let sim_path = get_simple_path(&graph, self); - graph.add_edge(s, t, weight); + match sim_path { None => { self.index = self.index + 1; + let graph = &mut self.graph; + graph.add_edge(s, t, weight); return self.next(); } - _ => { - return sim_path; + Some(mut s_path) => { + { + let graph = &mut s_path.graph; + graph.add_edge(s, t, weight); + } + return Some(s_path); } } } @@ -175,7 +191,7 @@ fn dijkstra( start: G::NodeId, goal: Option, mut edge_cost: F, -) -> (HashMap, HashMap) +) -> (HashMap, HashMap) where G: IntoEdges + Visitable, G::NodeId: Eq + Hash, @@ -214,6 +230,7 @@ where tracing.insert(next, node); todo!() }; + } } Vacant(ent) => { @@ -230,50 +247,51 @@ where // 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(graph: &DiGraph<(), f32>, s: &mut SimplePath) -> Option { - let (score, path) = dijkstra(&*graph, s.source, Some(s.target), |e| *e.weight()); +fn get_simple_path(s: &mut SimplePath) -> Option { + 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 = vec![]; + let mut paths :Vec = vec!(); if score.contains_key(&s.target) { score_target = *score.get(&s.target).expect("Error"); } - - if path.contains_key(&s.target) { + + if path.contains_key(&s.target) { paths.push(s.target); let mut node = &s.target; - loop { + loop { let pre_node = path.get(node).expect("Error"); paths.push(*pre_node); - if *pre_node == s.source { + if *pre_node == s.source { break; } node = pre_node; - } + } } if paths.len() == 0 { - return None; + 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: graph.clone(), - }; - return Some(s); + 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 } - None -} + // This function call get_simple_path for each graph after removing one of the edges in between. From 59b4b5950dff256d94e350c5962d9bdb0929abfc Mon Sep 17 00:00:00 2001 From: Ranjana Date: Fri, 4 Oct 2024 17:20:49 +0530 Subject: [PATCH 14/16] update for all issues raised before --- .../src/generators/simple_shortest_paths.rs | 396 ++++++------------ 1 file changed, 138 insertions(+), 258 deletions(-) diff --git a/rustworkx-core/src/generators/simple_shortest_paths.rs b/rustworkx-core/src/generators/simple_shortest_paths.rs index 1b53ceea9..b2246b383 100644 --- a/rustworkx-core/src/generators/simple_shortest_paths.rs +++ b/rustworkx-core/src/generators/simple_shortest_paths.rs @@ -11,193 +11,97 @@ // under the License. use crate::petgraph::algo::{Measure}; -use crate::petgraph::graph::{DiGraph, NodeIndex}; -use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable}; +use crate::petgraph::graph::{Graph, NodeIndex}; +use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable, IntoEdgeReferences}; +use crate::petgraph::EdgeType; use std::cmp::Ordering; +use std::vec::IntoIter; 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. -///////////// +use std::f32; +use crate::min_scored::MinScored; -#[derive(Debug, Clone)] -pub struct SimplePath { - pub Score: f32, - pub Path: Vec, - index: usize, - source: NodeIndex, - target: NodeIndex, - graph: DiGraph<(), f32>, - unique_paths: Vec>, - switch: usize, -} -impl SimplePath { - fn new( - graph: &mut DiGraph<(), f32>, - source: NodeIndex, - target: NodeIndex, - ) -> Option { - 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); +// Call dijkastra to get shortest path for a graph, by ignore some edges from the all unique_shortest_paths. +// Returns the score of new path, & the full Path - } -} +fn get_simple_paths(graph: &mut Graph,source:NodeIndex,target: NodeIndex,unique_paths: &mut Vec>,ignore_edges: &mut Vec<(NodeIndex, NodeIndex)>, index: &mut usize, switch: &mut usize) -> Option<(P,Vec)> +where N: EdgeType, +P: Copy + std::cmp::PartialOrd + std::default::Default + std::ops::Add + std::fmt::Debug { + if *index != 0 || *switch != 0 { -impl Iterator for SimplePath { - type Item = SimplePath; - fn next(&mut self) -> Option { - - 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; + let mut path = &unique_paths[*switch]; + if *index >= path.len() -1{ + if *switch < unique_paths.len() - 1 { + *switch = *switch + 1; + path = &unique_paths[*switch]; + *index = 1; } else { return None; } } + ignore_edges.push((path[*index-1], path[*index])); + } + + + let (score, path) = dijkstra(&*graph,source, Some(target), |e| *e.weight(), ignore_edges.clone()); + let mut score_target= P::default(); + let mut paths :Vec = vec!(); - 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); - } - } + if score.contains_key(&target) { + score_target = *score.get(&target).expect("Error"); + } + + if path.contains_key(&target) { + paths.push(target); + let mut node = ⌖ + loop { + let pre_node = path.get(node).expect("Error"); + paths.push(*pre_node); + // if you have reached to source from target , then exit, no need to backtrack + if *pre_node == source { + break; } - None => { - self.index = self.index + 1; - return self.next(); + node = pre_node; } - } } -} -// The code provides the shortest distance cost of all Nodes from the start Node -#[derive(Copy, Clone, Debug)] -struct MinScored(pub K, pub T); -impl PartialEq for MinScored { - #[inline] - fn eq(&self, other: &MinScored) -> bool { - self.cmp(other) == Ordering::Equal + if paths.len() == 0 { + *index = *index + 1; + return get_simple_paths(graph,source,target,unique_paths,ignore_edges,index,switch); } -} - -impl Eq for MinScored {} + paths.reverse(); -impl PartialOrd for MinScored { - #[inline] - fn partial_cmp(&self, other: &MinScored) -> Option { - Some(self.cmp(other)) + let contains_target = unique_paths.iter().any(|v| *v == paths.to_vec()); + if !contains_target { + unique_paths.push(paths.clone()); + *index = *index +1; + return Some((score_target,paths.clone())); + } else { + *index = *index + 1; + return get_simple_paths(graph,source,target,unique_paths,ignore_edges,index,switch); } -} -impl Ord for MinScored { - #[inline] - fn cmp(&self, other: &MinScored) -> 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 - } - } } -// This is mutation of petgraph dijkastra to get full path between source to target +// This is mutation of petgraph dijkastra to get full path between source to target and to ignore some edges while computing shorest path. + fn dijkstra( graph: G, start: G::NodeId, goal: Option, - mut edge_cost: F, + mut edge_cost: F, ignore_edges : Vec<(G::NodeId,G::NodeId)> ) -> (HashMap, HashMap) where G: IntoEdges + Visitable, G::NodeId: Eq + Hash, F: FnMut(G::EdgeRef) -> K, K: Measure + Copy, - ::NodeId: Debug, + ::NodeId: Debug, ::EdgeRef: PartialEq { let mut visited = graph.visit_map(); let mut scores = HashMap::new(); @@ -215,6 +119,10 @@ where } for edge in graph.edges(node) { let next = edge.target(); + let edge_to_check = (node,next); + if ignore_edges.iter().any(|&edge| edge == edge_to_check ){ + continue; + } if visited.is_visited(&next) { continue; } @@ -245,124 +153,96 @@ where (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 +// This is the public function to call all possible paths, then N shortest out of them. -fn get_simple_path(s: &mut SimplePath) -> Option { - 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 = vec!(); - if score.contains_key(&s.target) { - score_target = *score.get(&s.target).expect("Error"); - } +pub fn get_shortest_paths(graph: &mut Graph,source: NodeIndex,target: NodeIndex,shortest_path_get : usize) -> IntoIter>> +where N: EdgeType, +P: Copy + std::cmp::PartialOrd + std::default::Default + std::ops::Add + std::fmt::Debug{ + let mut scores :Vec

= vec!(); + let mut paths :Vec>> = vec!(); + let mut shortest_paths :Vec>> = vec!(); + let mut ignore_edges : Vec<(NodeIndex, NodeIndex)> =vec!(); - 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; - } + let mut index : usize = 0; + let mut switch : usize =0 ; + let mut unique_paths: Vec> = vec!(); + while let Some((score,path)) = get_simple_paths(graph,source,target,&mut unique_paths,&mut ignore_edges,&mut index,&mut switch) { + scores.push(score); + paths.push(Some(path)); } - - 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); + for i in 0..scores.len(){ + let mut min_score_index :usize = i; + for j in i+1..scores.len(){ + if scores[j] < scores[min_score_index] { + min_score_index =j; } - None + } + shortest_paths.push(paths[min_score_index].clone()); + if i == shortest_path_get -1 { + break; + } } + // println!("Scores & Paths {:#?} {:#?}", scores, paths); + return shortest_paths.into_iter() +} -// This function call get_simple_path for each graph after removing one of the edges in between. // ------------------------------------------- -// INPUTS +// TEST CASES // ------------------------------------------- -// 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 +// Testing function -//fn main() { -// let mut graph = DiGraph::new(); -// let nodes: Vec = (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; -// } -// } +#[cfg(test)] +mod tests { + use crate::get_shortest_paths; + use petgraph::Graph; + use petgraph::graph::DiGraph; + + #[test] + fn test_shortest_paths() { + + let mut g = Graph::new_undirected(); + let a = g.add_node("A"); + let b = g.add_node("B"); + let c = g.add_node("C"); + let d = g.add_node("D"); + let e = g.add_node("E"); + let f = g.add_node("F"); + g.add_edge(a, b, 7); + g.add_edge(c, a, 9); + g.add_edge(a, d, 14); + g.add_edge(b, c, 10); + g.add_edge(d, c, 2); + g.add_edge(d, e, 9); + g.add_edge(b, f, 15); + g.add_edge(c, f, 11); + g.add_edge(e, f, 6); + let source = a; + let target = f; + let mut path1 = [ + a, + c, + f, + ]; + + let path2 = [ + a, + b, + f, + ]; + + for path in get_shortest_paths( &mut g,source,target,2){ + match path { + Some(p) => assert_eq!(p, path1), + None => panic!("Not matched"), + } + path1 = path2; + } + +} +} -// ---------------------------------------------- -// 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), -//] From 5ba73bb2500c48de48b777a12ffe6ed34c04af25 Mon Sep 17 00:00:00 2001 From: Ranjana Date: Mon, 7 Oct 2024 21:16:25 +0530 Subject: [PATCH 15/16] updated new simple_shortest_path generation function --- .../shortest_path/simple_shortest_paths.rs | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 rustworkx-core/src/shortest_path/simple_shortest_paths.rs diff --git a/rustworkx-core/src/shortest_path/simple_shortest_paths.rs b/rustworkx-core/src/shortest_path/simple_shortest_paths.rs new file mode 100644 index 000000000..24764979b --- /dev/null +++ b/rustworkx-core/src/shortest_path/simple_shortest_paths.rs @@ -0,0 +1,265 @@ +use crate::petgraph::algo::{Measure}; +use crate::petgraph::graph::{Graph, Node, NodeIndex}; +use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable, IntoEdgeReferences}; +use crate::petgraph::EdgeType; +use min_scored::MinScored; + +use std::cmp::Ordering; +use std::vec::IntoIter; +use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::collections::{BinaryHeap, HashMap}; + +use std::fmt::Debug; +use std::hash::Hash; +use std::f32; +use rand::Rng; + + +/// This is mutation of petgraph dijkastra to get all possible parents_nodes for a target instead of shortest only +/// Returns the default score Hashmap also a set of (parent_node, node, score) vector. + +fn dijkstra( + graph: G, + start: G::NodeId, + goal: Option, + mut edge_cost: F, +) -> (HashMap, Vec<(G::NodeId, G::NodeId,K)>) +where + G: IntoEdges + Visitable, + G::NodeId: Eq + Hash, + F: FnMut(G::EdgeRef) -> K, + K: Measure + Copy, + ::NodeId: Debug, ::EdgeRef: PartialEq +{ + 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: Vec<(G::NodeId, G::NodeId,K)> = vec!(); + 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)); + tracing.push((next, node,next_score)); + } + else { + tracing.push((next, node, next_score)); + } + } + Vacant(ent) => { + ent.insert(next_score); + visit_next.push(MinScored(next_score, next)); + tracing.push((next, node,next_score)); + } + } + } + visited.visit(node); + } + (scores, tracing) +} + +/// To return next possible target for the path. +/// if all possible nodes are traced, then it picks the shortest endpoint and pick the nodes of next nodes. + +fn get_smallest_k_element

(scores : & HashMap , visited : &mut Vec) -> +Option where P: Copy + std::cmp::PartialOrd + std::default::Default + std::ops::Add + std::fmt::Debug{ + if scores.len() == 1 { + for (node,_score) in scores { + return Some(node.clone()); + } + } + else { + let mut score_vec: Vec<_> = scores.iter().collect(); + score_vec.sort_by(|&(_, &score1), &(_, &score2)| { + score1.partial_cmp(&score2).unwrap_or(std::cmp::Ordering::Equal) + }); + let mut count = 0; + for (node,_score) in &score_vec { + if ! visited.contains(node) { + visited.push(**node); + return Some(**node); + } + count = count + 1; + if count == score_vec.len() { + return Some(*score_vec[0].0); + } + } + + } + return None; +} + +/// pubic function to get all possible paths +/// The dijkastra returns values like - +/// (parent_node, node , total_score_to_reach__from_root_through_) +/// Using these values for each we extract and store a Hashmap of . +/// then we backtrack from target till source to get the path. by picking one of the parent_nodes. +/// the last step is done for all possible paths. +/// For visiting all nodes of a parent_node, it only consider the shortest path of the from -> . + +pub fn get_shortest_paths(graph: &mut Graph,source: NodeIndex,target: NodeIndex, number_of_paths: Option) -> IntoIter>> +where N: EdgeType, +P: Copy + std::cmp::PartialOrd + std::default::Default + std::ops::Add + std::fmt::Debug { + + let mut final_paths : HashMap> = HashMap::new(); + let mut all_paths : HashMap, P> = HashMap::new(); + let mut visited : Vec = vec!(); + let mut shortest_paths : Vec>> = vec!(); + let mut paths : Vec = vec!(); + + let (score_new, path) = dijkstra(&*graph,source, Some(target), |e| *e.weight()); + if ! score_new.contains_key(&target) { + shortest_paths.push(None); + return shortest_paths.into_iter(); + } + + for (node ,next,score) in path { + if let Some(v) = final_paths.get_mut(&node) { + v.insert(next,score); + } else { + final_paths.insert(node,HashMap::new()); + let Some(v) = final_paths.get_mut(&node)else { todo!() }; + v.insert(next, score); + }; + } + + loop { + paths.push(target); + let mut node=target ; + let mut total_score_path: P = P::default(); + loop { + let pre_node = get_smallest_k_element(&final_paths[&node] ,&mut visited); + match pre_node { + Some(s) => { + paths.push(s); + let edge = graph.find_edge(pre_node.expect("REASON"),node); + let mut weight : P = P::default(); + match edge { + Some(edge) => { + weight = *graph.edge_weight(edge).unwrap(); + }, + None => {}, + + }; + + total_score_path = total_score_path + weight; + if source == s { + // If you have already reach to source from target, the path is complete. + break; + } + node = s; + } + None => { + break; + } + } + + } + paths.reverse(); + + if all_paths.contains_key(&paths) { + break; + } + all_paths.insert(paths,total_score_path); + paths = vec!(); + total_score_path = P::default(); + } + + let mut score_vec: Vec<_> = all_paths.iter().collect::>().clone(); + score_vec.sort_by(|&(_, &score1), &(_, &score2)| { + score1.partial_cmp(&score2).unwrap_or(std::cmp::Ordering::Equal) + }); + + let mut count = 0; + let mut total_paths = 0; + match number_of_paths { + Some(K) => total_paths = K, + None => total_paths = score_vec.len() as i32, + + } + + for (k,v ) in score_vec { + // println!("Path {:#?} Score {:#?}",k,v); + shortest_paths.push(Some(k.clone())); + count = count +1; + if count >= total_paths { + break; + } + } + + return shortest_paths.into_iter(); +} + +/// Test Function +/// the graph can Directed or Undirected. +/// weight is must , pass 1 as weight for each edge if no weight is there for the graph. +/// It verifies all 2 paths generated for the graph. + +#[cfg(test)] +mod tests { + use crate::get_shortest_paths; + use petgraph::Graph; + + #[test] + fn test_shortest_paths() { + + let mut g = Graph::new_undirected(); + let a = g.add_node("A"); + let b = g.add_node("B"); + let c = g.add_node("C"); + let d = g.add_node("D"); + let e = g.add_node("E"); + let f = g.add_node("F"); + g.add_edge(a, b, 7); + g.add_edge(a, c, 9); + g.add_edge(a, d, 14); + g.add_edge(b, c, 10); + g.add_edge(d, c, 2); + g.add_edge(d, e, 9); + g.add_edge(b, f, 15); + g.add_edge(c, f, 11); + g.add_edge(e, f, 6); + let source = a; + let target = f; + let mut path1 = [ + a, + c, + f, + ]; + + let path2 = [ + a, + b, + f, + ]; + + // You should pass None for parameter number_of_paths if you want all possible shortest paths + + for path in get_shortest_paths( &mut g,source,target,Some(2)){ + println!("{:#?}",path); + match path { + Some(p) => assert_eq!(p, path1), + None => panic!("Not matched"), + } + path1 = path2; + } + +} +} + From 8ff5edfd0e403dbc3e0ab3e9a17e5d7253243324 Mon Sep 17 00:00:00 2001 From: Ranjana Date: Mon, 7 Oct 2024 21:18:49 +0530 Subject: [PATCH 16/16] updated for shortest paths code --- .../src/generators/simple_shortest_paths.rs | 248 ------------------ rustworkx-core/src/shortest_path/mod.rs | 2 + .../shortest_path/simple_shortest_paths.rs | 12 + 3 files changed, 14 insertions(+), 248 deletions(-) delete mode 100644 rustworkx-core/src/generators/simple_shortest_paths.rs diff --git a/rustworkx-core/src/generators/simple_shortest_paths.rs b/rustworkx-core/src/generators/simple_shortest_paths.rs deleted file mode 100644 index b2246b383..000000000 --- a/rustworkx-core/src/generators/simple_shortest_paths.rs +++ /dev/null @@ -1,248 +0,0 @@ -// 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::{Graph, NodeIndex}; -use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable, IntoEdgeReferences}; -use crate::petgraph::EdgeType; - -use std::cmp::Ordering; -use std::vec::IntoIter; -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::collections::{BinaryHeap, HashMap}; - -use std::fmt::Debug; -use std::hash::Hash; -use std::f32; -use crate::min_scored::MinScored; - - -// Call dijkastra to get shortest path for a graph, by ignore some edges from the all unique_shortest_paths. -// Returns the score of new path, & the full Path - -fn get_simple_paths(graph: &mut Graph,source:NodeIndex,target: NodeIndex,unique_paths: &mut Vec>,ignore_edges: &mut Vec<(NodeIndex, NodeIndex)>, index: &mut usize, switch: &mut usize) -> Option<(P,Vec)> -where N: EdgeType, -P: Copy + std::cmp::PartialOrd + std::default::Default + std::ops::Add + std::fmt::Debug { - if *index != 0 || *switch != 0 { - - let mut path = &unique_paths[*switch]; - if *index >= path.len() -1{ - if *switch < unique_paths.len() - 1 { - *switch = *switch + 1; - path = &unique_paths[*switch]; - *index = 1; - } else { - return None; - } - } - ignore_edges.push((path[*index-1], path[*index])); - } - - - let (score, path) = dijkstra(&*graph,source, Some(target), |e| *e.weight(), ignore_edges.clone()); - let mut score_target= P::default(); - let mut paths :Vec = vec!(); - - if score.contains_key(&target) { - score_target = *score.get(&target).expect("Error"); - } - - if path.contains_key(&target) { - paths.push(target); - let mut node = ⌖ - loop { - let pre_node = path.get(node).expect("Error"); - paths.push(*pre_node); - // if you have reached to source from target , then exit, no need to backtrack - if *pre_node == source { - break; - } - node = pre_node; - } - } - - if paths.len() == 0 { - *index = *index + 1; - return get_simple_paths(graph,source,target,unique_paths,ignore_edges,index,switch); - } - paths.reverse(); - - let contains_target = unique_paths.iter().any(|v| *v == paths.to_vec()); - if !contains_target { - unique_paths.push(paths.clone()); - *index = *index +1; - return Some((score_target,paths.clone())); - } else { - *index = *index + 1; - return get_simple_paths(graph,source,target,unique_paths,ignore_edges,index,switch); - } - -} - -// This is mutation of petgraph dijkastra to get full path between source to target and to ignore some edges while computing shorest path. - -fn dijkstra( - graph: G, - start: G::NodeId, - goal: Option, - mut edge_cost: F, ignore_edges : Vec<(G::NodeId,G::NodeId)> -) -> (HashMap, HashMap) -where - G: IntoEdges + Visitable, - G::NodeId: Eq + Hash, - F: FnMut(G::EdgeRef) -> K, - K: Measure + Copy, - ::NodeId: Debug, ::EdgeRef: PartialEq -{ - 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 = 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(); - let edge_to_check = (node,next); - if ignore_edges.iter().any(|&edge| edge == edge_to_check ){ - continue; - } - 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 is the public function to call all possible paths, then N shortest out of them. - - -pub fn get_shortest_paths(graph: &mut Graph,source: NodeIndex,target: NodeIndex,shortest_path_get : usize) -> IntoIter>> -where N: EdgeType, -P: Copy + std::cmp::PartialOrd + std::default::Default + std::ops::Add + std::fmt::Debug{ - let mut scores :Vec

= vec!(); - let mut paths :Vec>> = vec!(); - let mut shortest_paths :Vec>> = vec!(); - let mut ignore_edges : Vec<(NodeIndex, NodeIndex)> =vec!(); - - let mut index : usize = 0; - let mut switch : usize =0 ; - let mut unique_paths: Vec> = vec!(); - while let Some((score,path)) = get_simple_paths(graph,source,target,&mut unique_paths,&mut ignore_edges,&mut index,&mut switch) { - scores.push(score); - paths.push(Some(path)); - } - for i in 0..scores.len(){ - let mut min_score_index :usize = i; - for j in i+1..scores.len(){ - if scores[j] < scores[min_score_index] { - min_score_index =j; - } - } - shortest_paths.push(paths[min_score_index].clone()); - if i == shortest_path_get -1 { - break; - } - } - // println!("Scores & Paths {:#?} {:#?}", scores, paths); - return shortest_paths.into_iter() -} - - - -// ------------------------------------------- -// TEST CASES -// ------------------------------------------- - -////////////////////////////////////////////// -// Testing function - -#[cfg(test)] -mod tests { - use crate::get_shortest_paths; - use petgraph::Graph; - use petgraph::graph::DiGraph; - - #[test] - fn test_shortest_paths() { - - let mut g = Graph::new_undirected(); - let a = g.add_node("A"); - let b = g.add_node("B"); - let c = g.add_node("C"); - let d = g.add_node("D"); - let e = g.add_node("E"); - let f = g.add_node("F"); - g.add_edge(a, b, 7); - g.add_edge(c, a, 9); - g.add_edge(a, d, 14); - g.add_edge(b, c, 10); - g.add_edge(d, c, 2); - g.add_edge(d, e, 9); - g.add_edge(b, f, 15); - g.add_edge(c, f, 11); - g.add_edge(e, f, 6); - let source = a; - let target = f; - let mut path1 = [ - a, - c, - f, - ]; - - let path2 = [ - a, - b, - f, - ]; - - for path in get_shortest_paths( &mut g,source,target,2){ - match path { - Some(p) => assert_eq!(p, path1), - None => panic!("Not matched"), - } - path1 = path2; - } - -} -} - diff --git a/rustworkx-core/src/shortest_path/mod.rs b/rustworkx-core/src/shortest_path/mod.rs index 6203d8fba..c8c5fd77c 100644 --- a/rustworkx-core/src/shortest_path/mod.rs +++ b/rustworkx-core/src/shortest_path/mod.rs @@ -20,9 +20,11 @@ mod astar; mod bellman_ford; mod dijkstra; mod k_shortest_path; +mod simple_shortest_paths; pub use all_shortest_paths::all_shortest_paths; pub use astar::astar; pub use bellman_ford::{bellman_ford, negative_cycle_finder}; pub use dijkstra::dijkstra; pub use k_shortest_path::k_shortest_path; +pub use simple_shortest_paths::get_shortest_paths; diff --git a/rustworkx-core/src/shortest_path/simple_shortest_paths.rs b/rustworkx-core/src/shortest_path/simple_shortest_paths.rs index 24764979b..cd7a05d06 100644 --- a/rustworkx-core/src/shortest_path/simple_shortest_paths.rs +++ b/rustworkx-core/src/shortest_path/simple_shortest_paths.rs @@ -1,3 +1,15 @@ +// 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::{Graph, Node, NodeIndex}; use crate::petgraph::visit::{EdgeRef, IntoEdges, VisitMap, Visitable, IntoEdgeReferences};