Shortest path via bidirectional BFS. `max_visited` caps the combined forward+backward visited set to prevent supernode fan-out explosion. Pass [`DEFAULT_MAX_VISITED`] for the standard limit. `frontier_bitmap`: when `Some`, only nodes whose surrogate is present in the bitmap are eligible for expansion. Start and end nodes are not gated.
(
&self,
src: &str,
dst: &str,
label_filter: Option<&str>,
max_depth: usize,
max_visited: usize,
frontier_bitmap: Option<&nodedb_types::Surrogat
| 178 | /// `frontier_bitmap`: when `Some`, only nodes whose surrogate is present in the |
| 179 | /// bitmap are eligible for expansion. Start and end nodes are not gated. |
| 180 | pub fn shortest_path( |
| 181 | &self, |
| 182 | src: &str, |
| 183 | dst: &str, |
| 184 | label_filter: Option<&str>, |
| 185 | max_depth: usize, |
| 186 | max_visited: usize, |
| 187 | frontier_bitmap: Option<&nodedb_types::SurrogateBitmap>, |
| 188 | ) -> Option<Vec<String>> { |
| 189 | let src_id = *self.node_to_id.get(src)?; |
| 190 | let dst_id = *self.node_to_id.get(dst)?; |
| 191 | if src_id == dst_id { |
| 192 | return Some(vec![src.to_string()]); |
| 193 | } |
| 194 | |
| 195 | let label_id = label_filter.and_then(|l| self.label_id(l)); |
| 196 | let mut fwd_parent: HashMap<u32, u32> = HashMap::new(); |
| 197 | let mut bwd_parent: HashMap<u32, u32> = HashMap::new(); |
| 198 | fwd_parent.insert(src_id, src_id); |
| 199 | bwd_parent.insert(dst_id, dst_id); |
| 200 | |
| 201 | let mut fwd_frontier: Vec<u32> = vec![src_id]; |
| 202 | let mut bwd_frontier: Vec<u32> = vec![dst_id]; |
| 203 | |
| 204 | for _depth in 0..max_depth { |
| 205 | if fwd_parent.len() + bwd_parent.len() >= max_visited { |
| 206 | break; |
| 207 | } |
| 208 | |
| 209 | let mut next_fwd = Vec::new(); |
| 210 | for &node in &fwd_frontier { |
| 211 | self.record_access(node); |
| 212 | for (lid, neighbor) in self.dense_iter_out(node) { |
| 213 | if label_id.is_none_or(|f| f == lid) |
| 214 | && frontier_bitmap.is_none_or(|bm| { |
| 215 | bm.contains(nodedb_types::Surrogate::new( |
| 216 | self.node_surrogate_raw(neighbor), |
| 217 | )) |
| 218 | }) |
| 219 | { |
| 220 | if let Entry::Vacant(e) = fwd_parent.entry(neighbor) { |
| 221 | e.insert(node); |
| 222 | next_fwd.push(neighbor); |
| 223 | } |
| 224 | if bwd_parent.contains_key(&neighbor) { |
| 225 | return Some(self.reconstruct_path(neighbor, &fwd_parent, &bwd_parent)); |
| 226 | } |
| 227 | } |
| 228 | } |
| 229 | } |
| 230 | fwd_frontier = next_fwd; |
| 231 | |
| 232 | let mut next_bwd = Vec::new(); |
| 233 | for &node in &bwd_frontier { |
| 234 | self.record_access(node); |
| 235 | for (lid, neighbor) in self.dense_iter_in(node) { |
| 236 | if label_id.is_none_or(|f| f == lid) |
| 237 | && frontier_bitmap.is_none_or(|bm| { |