uni_algo/algo/algorithms/
all_simple_paths.rs1use crate::algo::GraphProjection;
10use crate::algo::algorithms::Algorithm;
11use uni_common::core::id::Vid;
12
13pub struct AllSimplePaths;
14
15#[derive(Debug, Clone)]
16pub struct AllSimplePathsConfig {
17 pub source: Vid,
18 pub target: Vid,
19 pub min_depth: usize,
20 pub max_depth: usize,
21 pub limit: usize, }
23
24impl Default for AllSimplePathsConfig {
25 fn default() -> Self {
26 Self {
27 source: Vid::from(0),
28 target: Vid::from(0),
29 min_depth: 0,
30 max_depth: 5,
31 limit: 100,
32 }
33 }
34}
35
36pub struct AllSimplePathsResult {
37 pub paths: Vec<Vec<Vid>>,
38}
39
40impl Algorithm for AllSimplePaths {
41 type Config = AllSimplePathsConfig;
42 type Result = AllSimplePathsResult;
43
44 fn name() -> &'static str {
45 "all_simple_paths"
46 }
47
48 fn run(graph: &GraphProjection, config: Self::Config) -> Self::Result {
49 let source_slot = match graph.to_slot(config.source) {
50 Some(s) => s,
51 None => return AllSimplePathsResult { paths: Vec::new() },
52 };
53 let target_slot = match graph.to_slot(config.target) {
54 Some(s) => s,
55 None => return AllSimplePathsResult { paths: Vec::new() },
56 };
57
58 let mut paths = Vec::new();
59 let mut current_path = Vec::with_capacity(config.max_depth + 1);
60 let mut visited = vec![false; graph.vertex_count()];
61
62 current_path.push(source_slot);
63 visited[source_slot as usize] = true;
64
65 dfs(
66 graph,
67 source_slot,
68 target_slot,
69 &config,
70 &mut current_path,
71 &mut visited,
72 &mut paths,
73 );
74
75 let mapped_paths = paths
76 .into_iter()
77 .map(|path| path.into_iter().map(|idx| graph.to_vid(idx)).collect())
78 .collect();
79
80 AllSimplePathsResult {
81 paths: mapped_paths,
82 }
83 }
84}
85
86fn dfs(
87 graph: &GraphProjection,
88 u: u32,
89 target: u32,
90 config: &AllSimplePathsConfig,
91 path: &mut Vec<u32>,
92 visited: &mut [bool],
93 paths: &mut Vec<Vec<u32>>,
94) {
95 if paths.len() >= config.limit {
96 return;
97 }
98
99 let depth = path.len() - 1; if depth > config.max_depth {
101 return;
102 }
103
104 if u == target {
105 if depth >= config.min_depth {
106 paths.push(path.clone());
107 }
108 return;
114 }
115
116 for &v in graph.out_neighbors(u) {
117 if !visited[v as usize] {
118 visited[v as usize] = true;
119 path.push(v);
120 dfs(graph, v, target, config, path, visited, paths);
121 path.pop();
122 visited[v as usize] = false;
123 }
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::algo::test_utils::build_test_graph;
131
132 #[test]
133 fn test_simple_paths_diamond() {
134 let vids = vec![Vid::from(0), Vid::from(1), Vid::from(2), Vid::from(3)];
136 let edges = vec![
137 (Vid::from(0), Vid::from(1)),
138 (Vid::from(1), Vid::from(3)),
139 (Vid::from(0), Vid::from(2)),
140 (Vid::from(2), Vid::from(3)),
141 ];
142 let graph = build_test_graph(vids, edges);
143
144 let config = AllSimplePathsConfig {
145 source: Vid::from(0),
146 target: Vid::from(3),
147 max_depth: 5,
148 limit: 10,
149 ..Default::default()
150 };
151
152 let result = AllSimplePaths::run(&graph, config);
153 assert_eq!(result.paths.len(), 2);
154 }
155}