1use crate::symbolic::core::Expr;
9use crate::symbolic::graph::Graph;
10use crate::symbolic::simplify::as_f64;
11use crate::symbolic::simplify_dag::simplify;
12use ordered_float::OrderedFloat;
13use std::collections::{HashMap, HashSet, VecDeque};
14use std::fmt::Debug;
15use std::hash::Hash;
16pub fn dfs<V>(graph: &Graph<V>, start_node: usize) -> Vec<usize>
27where
28 V: Eq + Hash + Clone + std::fmt::Debug,
29{
30 let mut visited = HashSet::new();
31 let mut result = Vec::new();
32 dfs_recursive(graph, start_node, &mut visited, &mut result);
33 result
34}
35pub(crate) fn dfs_recursive<V>(
36 graph: &Graph<V>,
37 u: usize,
38 visited: &mut HashSet<usize>,
39 result: &mut Vec<usize>,
40) where
41 V: Eq + Hash + Clone + std::fmt::Debug,
42{
43 visited.insert(u);
44 result.push(u);
45 if let Some(neighbors) = graph.adj.get(u) {
46 for &(v, _) in neighbors {
47 if !visited.contains(&v) {
48 dfs_recursive(graph, v, visited, result);
49 }
50 }
51 }
52}
53pub fn bfs<V>(graph: &Graph<V>, start_node: usize) -> Vec<usize>
64where
65 V: Eq + Hash + Clone + std::fmt::Debug,
66{
67 let mut visited = HashSet::new();
68 let mut result = Vec::new();
69 let mut queue = VecDeque::new();
70 visited.insert(start_node);
71 queue.push_back(start_node);
72 while let Some(u) = queue.pop_front() {
73 result.push(u);
74 if let Some(neighbors) = graph.adj.get(u) {
75 for &(v, _) in neighbors {
76 if !visited.contains(&v) {
77 visited.insert(v);
78 queue.push_back(v);
79 }
80 }
81 }
82 }
83 result
84}
85pub fn connected_components<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
96 graph: &Graph<V>,
97) -> Vec<Vec<usize>> {
98 let mut visited = HashSet::new();
99 let mut components = Vec::new();
100 for node_id in 0..graph.nodes.len() {
101 if !visited.contains(&node_id) {
102 let component = bfs(graph, node_id);
103 for &visited_node in &component {
104 visited.insert(visited_node);
105 }
106 components.push(component);
107 }
108 }
109 components
110}
111pub fn is_connected<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(graph: &Graph<V>) -> bool {
122 connected_components(graph).len() == 1
123}
124pub fn strongly_connected_components<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
135 graph: &Graph<V>,
136) -> Vec<Vec<usize>> {
137 let mut scc = Vec::new();
138 let mut stack = Vec::new();
139 let mut on_stack = HashSet::new();
140 let mut discovery_times = HashMap::new();
141 let mut low_link = HashMap::new();
142 let mut time = 0;
143 for node_id in 0..graph.nodes.len() {
144 tarjan_scc_util(
145 graph,
146 node_id,
147 &mut time,
148 &mut discovery_times,
149 &mut low_link,
150 &mut stack,
151 &mut on_stack,
152 &mut scc,
153 );
154 }
155 scc
156}
157pub(crate) fn tarjan_scc_util<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
158 graph: &Graph<V>,
159 u: usize,
160 time: &mut usize,
161 disc: &mut HashMap<usize, usize>,
162 low: &mut HashMap<usize, usize>,
163 stack: &mut Vec<usize>,
164 on_stack: &mut HashSet<usize>,
165 scc: &mut Vec<Vec<usize>>,
166) {
167 disc.insert(u, *time);
168 low.insert(u, *time);
169 *time += 1;
170 stack.push(u);
171 on_stack.insert(u);
172 if let Some(neighbors) = graph.adj.get(u) {
173 for &(v, _) in neighbors {
174 if !disc.contains_key(&v) {
175 tarjan_scc_util(graph, v, time, disc, low, stack, on_stack, scc);
176 if let (Some(&low_u), Some(&low_v)) = (low.get(&u), low.get(&v)) {
177 low.insert(u, low_u.min(low_v));
178 }
179 } else if on_stack.contains(&v) {
180 if let (Some(&low_u), Some(&disc_v)) = (low.get(&u), disc.get(&v)) {
181 low.insert(u, low_u.min(disc_v));
182 }
183 }
184 }
185 }
186 if low.get(&u) == disc.get(&u) {
187 let mut component = Vec::new();
188 while let Some(top) = stack.pop() {
189 on_stack.remove(&top);
190 component.push(top);
191 if top == u {
192 break;
193 }
194 }
195 scc.push(component);
196 }
197}
198pub fn has_cycle<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(graph: &Graph<V>) -> bool {
209 let mut visited = HashSet::new();
210 if graph.is_directed {
211 let mut recursion_stack = HashSet::new();
212 for node_id in 0..graph.nodes.len() {
213 if !visited.contains(&node_id)
214 && has_cycle_directed_util(graph, node_id, &mut visited, &mut recursion_stack)
215 {
216 return true;
217 }
218 }
219 } else {
220 for node_id in 0..graph.nodes.len() {
221 if !visited.contains(&node_id)
222 && has_cycle_undirected_util(graph, node_id, &mut visited, None)
223 {
224 return true;
225 }
226 }
227 }
228 false
229}
230pub(crate) fn has_cycle_directed_util<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
231 graph: &Graph<V>,
232 u: usize,
233 visited: &mut HashSet<usize>,
234 rec_stack: &mut HashSet<usize>,
235) -> bool {
236 visited.insert(u);
237 rec_stack.insert(u);
238 if let Some(neighbors) = graph.adj.get(u) {
239 for &(v, _) in neighbors {
240 if !visited.contains(&v) {
241 if has_cycle_directed_util(graph, v, visited, rec_stack) {
242 return true;
243 }
244 } else if rec_stack.contains(&v) {
245 return true;
246 }
247 }
248 }
249 rec_stack.remove(&u);
250 false
251}
252pub(crate) fn has_cycle_undirected_util<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
253 graph: &Graph<V>,
254 u: usize,
255 visited: &mut HashSet<usize>,
256 parent: Option<usize>,
257) -> bool {
258 visited.insert(u);
259 if let Some(neighbors) = graph.adj.get(u) {
260 for &(v, _) in neighbors {
261 if !visited.contains(&v) {
262 if has_cycle_undirected_util(graph, v, visited, Some(u)) {
263 return true;
264 }
265 } else if Some(v) != parent {
266 return true;
267 }
268 }
269 }
270 false
271}
272pub fn find_bridges_and_articulation_points<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
285 graph: &Graph<V>,
286) -> (Vec<(usize, usize)>, Vec<usize>) {
287 let mut bridges = Vec::new();
288 let mut articulation_points = HashSet::new();
289 let mut visited = HashSet::new();
290 let mut discovery_times = HashMap::new();
291 let mut low_link = HashMap::new();
292 let mut time = 0;
293 for node_id in 0..graph.nodes.len() {
294 if !visited.contains(&node_id) {
295 b_and_ap_util(
296 graph,
297 node_id,
298 None,
299 &mut time,
300 &mut visited,
301 &mut discovery_times,
302 &mut low_link,
303 &mut bridges,
304 &mut articulation_points,
305 );
306 }
307 }
308 (bridges, articulation_points.into_iter().collect())
309}
310pub(crate) fn b_and_ap_util<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
311 graph: &Graph<V>,
312 u: usize,
313 parent: Option<usize>,
314 time: &mut usize,
315 visited: &mut HashSet<usize>,
316 disc: &mut HashMap<usize, usize>,
317 low: &mut HashMap<usize, usize>,
318 bridges: &mut Vec<(usize, usize)>,
319 ap: &mut HashSet<usize>,
320) {
321 visited.insert(u);
322 disc.insert(u, *time);
323 low.insert(u, *time);
324 *time += 1;
325 let mut children = 0;
326 if let Some(neighbors) = graph.adj.get(u) {
327 for &(v, _) in neighbors {
328 if Some(v) == parent {
329 continue;
330 }
331 if visited.contains(&v) {
332 if let (Some(&low_u), Some(&disc_v)) = (low.get(&u), disc.get(&v)) {
333 low.insert(u, low_u.min(disc_v));
334 }
335 } else {
336 children += 1;
337 b_and_ap_util(graph, v, Some(u), time, visited, disc, low, bridges, ap);
338 if let (Some(&low_u), Some(&low_v)) = (low.get(&u), low.get(&v)) {
339 low.insert(u, low_u.min(low_v));
340 }
341 if parent.is_some() {
342 if let (Some(&low_v), Some(&disc_u)) = (low.get(&v), disc.get(&u)) {
343 if low_v >= disc_u {
344 ap.insert(u);
345 }
346 }
347 }
348 if let (Some(&low_v), Some(&disc_u)) = (low.get(&v), disc.get(&u)) {
349 if low_v > disc_u {
350 bridges.push((u, v));
351 }
352 }
353 }
354 }
355 }
356 if parent.is_none() && children > 1 {
357 ap.insert(u);
358 }
359}
360pub struct DSU {
362 parent: Vec<usize>,
363}
364impl DSU {
365 pub(crate) fn new(n: usize) -> Self {
366 DSU {
367 parent: (0..n).collect(),
368 }
369 }
370 pub(crate) fn find(&mut self, i: usize) -> usize {
371 if self.parent[i] == i {
372 return i;
373 }
374 self.parent[i] = self.find(self.parent[i]);
375 self.parent[i]
376 }
377 pub(crate) fn union(&mut self, i: usize, j: usize) {
378 let root_i = self.find(i);
379 let root_j = self.find(j);
380 if root_i != root_j {
381 self.parent[root_i] = root_j;
382 }
383 }
384}
385pub fn kruskal_mst<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
397 graph: &Graph<V>,
398) -> Vec<(usize, usize, Expr)> {
399 let mut edges = graph.get_edges();
400 edges.sort_by(|a, b| {
401 let weight_a = as_f64(&a.2).unwrap_or(f64::INFINITY);
402 let weight_b = as_f64(&b.2).unwrap_or(f64::INFINITY);
403 weight_a
404 .partial_cmp(&weight_b)
405 .unwrap_or(std::cmp::Ordering::Equal)
406 });
407 let mut dsu = DSU::new(graph.nodes.len());
408 let mut mst = Vec::new();
409 for (u, v, weight) in edges {
410 if dsu.find(u) != dsu.find(v) {
411 dsu.union(u, v);
412 mst.push((u, v, weight));
413 }
414 }
415 mst
416}
417pub fn edmonds_karp_max_flow<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
431 capacity_graph: &Graph<V>,
432 s: usize,
433 t: usize,
434) -> f64 {
435 let n = capacity_graph.nodes.len();
436 let mut residual_capacity = vec![vec![0.0; n]; n];
437 for u in 0..n {
438 if let Some(neighbors) = capacity_graph.adj.get(u) {
439 for &(v, ref cap) in neighbors {
440 residual_capacity[u][v] = as_f64(cap).unwrap_or(0.0);
441 }
442 }
443 }
444 let mut max_flow = 0.0;
445 loop {
446 let (parent, path_flow) = bfs_for_augmenting_path(&residual_capacity, s, t);
447 if path_flow == 0.0 {
448 break;
449 }
450 max_flow += path_flow;
451 let mut v = t;
452 while v != s {
453 if let Some(u) = parent[v] {
454 residual_capacity[u][v] -= path_flow;
455 residual_capacity[v][u] += path_flow;
456 v = u;
457 } else {
458 break;
459 }
460 }
461 }
462 max_flow
463}
464pub(crate) fn bfs_for_augmenting_path(
466 capacity: &Vec<Vec<f64>>,
467 s: usize,
468 t: usize,
469) -> (Vec<Option<usize>>, f64) {
470 let n = capacity.len();
471 let mut parent = vec![None; n];
472 let mut queue = VecDeque::new();
473 let mut path_flow = vec![f64::INFINITY; n];
474 queue.push_back(s);
475 while let Some(u) = queue.pop_front() {
476 for v in 0..n {
477 if parent[v].is_none() && v != s && capacity[u][v] > 0.0 {
478 parent[v] = Some(u);
479 path_flow[v] = path_flow[u].min(capacity[u][v]);
480 if v == t {
481 return (parent, path_flow[t]);
482 }
483 queue.push_back(v);
484 }
485 }
486 }
487 (parent, 0.0)
488}
489pub fn dinic_max_flow<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
504 capacity_graph: &Graph<V>,
505 s: usize,
506 t: usize,
507) -> f64 {
508 let n = capacity_graph.nodes.len();
509 let mut residual_capacity = vec![vec![0.0; n]; n];
510 for u in 0..n {
511 if let Some(neighbors) = capacity_graph.adj.get(u) {
512 for &(v, ref cap) in neighbors {
513 residual_capacity[u][v] = as_f64(cap).unwrap_or(0.0);
514 }
515 }
516 }
517 let mut max_flow = 0.0;
518 let mut level = vec![0; n];
519 while dinic_bfs(&residual_capacity, s, t, &mut level) {
520 let mut ptr = vec![0; n];
521 while {
522 let pushed = dinic_dfs(
523 &mut residual_capacity,
524 s,
525 t,
526 f64::INFINITY,
527 &level,
528 &mut ptr,
529 );
530 if pushed > 0.0 {
531 max_flow += pushed;
532 true
533 } else {
534 false
535 }
536 } {}
537 }
538 max_flow
539}
540pub(crate) fn dinic_bfs(
541 capacity: &Vec<Vec<f64>>,
542 s: usize,
543 t: usize,
544 level: &mut Vec<i32>,
545) -> bool {
546 for l in level.iter_mut() {
547 *l = -1;
548 }
549 level[s] = 0;
550 let mut q = VecDeque::new();
551 q.push_back(s);
552 while let Some(u) = q.pop_front() {
553 for v in 0..capacity.len() {
554 if level[v] < 0 && capacity[u][v] > 0.0 {
555 level[v] = level[u] + 1;
556 q.push_back(v);
557 }
558 }
559 }
560 level[t] != -1
561}
562pub(crate) fn dinic_dfs(
563 cap: &mut Vec<Vec<f64>>,
564 u: usize,
565 t: usize,
566 pushed: f64,
567 level: &Vec<i32>,
568 ptr: &mut Vec<usize>,
569) -> f64 {
570 if pushed == 0.0 {
571 return 0.0;
572 }
573 if u == t {
574 return pushed;
575 }
576 while ptr[u] < cap.len() {
577 let v = ptr[u];
578 if level[v] != level[u] + 1 || cap[u][v] == 0.0 {
579 ptr[u] += 1;
580 continue;
581 }
582 let tr = dinic_dfs(cap, v, t, pushed.min(cap[u][v]), level, ptr);
583 if tr == 0.0 {
584 ptr[u] += 1;
585 continue;
586 }
587 cap[u][v] -= tr;
588 cap[v][u] += tr;
589 return tr;
590 }
591 0.0
592}
593pub fn bellman_ford<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
608 graph: &Graph<V>,
609 start_node: usize,
610) -> Result<(HashMap<usize, f64>, HashMap<usize, Option<usize>>), String> {
611 let n = graph.nodes.len();
612 let mut dist = HashMap::new();
613 let mut prev = HashMap::new();
614 for node_id in 0..graph.nodes.len() {
615 dist.insert(node_id, f64::INFINITY);
616 }
617 dist.insert(start_node, 0.0);
618 for _ in 1..n {
619 for u in 0..n {
620 if let Some(neighbors) = graph.adj.get(u) {
621 for &(v, ref weight) in neighbors {
622 let w = as_f64(weight).unwrap_or(f64::INFINITY);
623 if dist[&u] != f64::INFINITY && dist[&u] + w < dist[&v] {
624 dist.insert(v, dist[&u] + w);
625 prev.insert(v, Some(u));
626 }
627 }
628 }
629 }
630 }
631 for u in 0..n {
632 if let Some(neighbors) = graph.adj.get(u) {
633 for &(v, ref weight) in neighbors {
634 let w = as_f64(weight).unwrap_or(f64::INFINITY);
635 if dist[&u] != f64::INFINITY && dist[&u] + w < dist[&v] {
636 return Err("Graph contains a negative-weight cycle.".to_string());
637 }
638 }
639 }
640 }
641 Ok((dist, prev))
642}
643#[allow(unused_variables)]
657pub fn min_cost_max_flow<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
658 graph: &Graph<V>,
659 s: usize,
660 t: usize,
661) -> (f64, f64) {
662 let n = graph.nodes.len();
663 let mut capacity = vec![vec![0.0; n]; n];
664 let mut cost = vec![vec![0.0; n]; n];
665 for u in 0..n {
666 if let Some(neighbors) = graph.adj.get(u) {
667 for &(v, ref weight) in neighbors {
668 if let Expr::Tuple(t) = weight {
669 if t.len() == 2 {
670 capacity[u][v] = as_f64(&t[0]).unwrap_or(0.0);
671 cost[u][v] = as_f64(&t[1]).unwrap_or(0.0);
672 }
673 }
674 }
675 }
676 }
677 let mut flow = 0.0;
678 let mut total_cost = 0.0;
679 loop {
680 let mut dist = vec![f64::INFINITY; n];
681 let mut parent = vec![None; n];
682 dist[s] = 0.0;
683 for _ in 1..n {
684 for u in 0..n {
685 for v in 0..n {
686 if capacity[u][v] > 0.0
687 && dist[u] != f64::INFINITY
688 && dist[u] + cost[u][v] < dist[v]
689 {
690 dist[v] = dist[u] + cost[u][v];
691 parent[v] = Some(u);
692 }
693 }
694 }
695 }
696 if dist[t] == f64::INFINITY {
697 break;
698 }
699 let mut path_flow = f64::INFINITY;
700 let mut curr = t;
701 while let Some(prev) = parent[curr] {
702 path_flow = path_flow.min(capacity[prev][curr]);
703 curr = prev;
704 }
705 flow += path_flow;
706 total_cost += path_flow * dist[t];
707 let mut v = t;
708 while let Some(u) = parent[v] {
709 capacity[u][v] -= path_flow;
710 capacity[v][u] += path_flow;
711 v = u;
712 }
713 }
714 (0.0, 0.0)
715}
716pub fn is_bipartite<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
728 graph: &Graph<V>,
729) -> Option<Vec<i8>> {
730 let n = graph.nodes.len();
731 let mut colors = vec![-1; n];
732 for i in 0..n {
733 if colors[i] == -1 {
734 let mut queue = VecDeque::new();
735 queue.push_back(i);
736 colors[i] = 0;
737 while let Some(u) = queue.pop_front() {
738 if let Some(neighbors) = graph.adj.get(u) {
739 for &(v, _) in neighbors {
740 if colors[v] == -1 {
741 colors[v] = 1 - colors[u];
742 queue.push_back(v);
743 } else if colors[v] == colors[u] {
744 return None;
745 }
746 }
747 }
748 }
749 }
750 }
751 Some(colors)
752}
753pub fn bipartite_maximum_matching<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
766 graph: &Graph<V>,
767 partition: &[i8],
768) -> Vec<(usize, usize)> {
769 let n = graph.nodes.len();
770 let s = n;
771 let t = n + 1;
772 let mut flow_graph = Graph::new(true);
773 let mut u_nodes = Vec::new();
774 let mut v_nodes = Vec::new();
775 for i in 0..n {
776 if partition[i] == 0 {
777 u_nodes.push(i);
778 } else {
779 v_nodes.push(i);
780 }
781 }
782 for &u in &u_nodes {
783 flow_graph.add_edge(&s, &u, Expr::Constant(1.0));
784 if let Some(neighbors) = graph.adj.get(u) {
785 for &(v, _) in neighbors {
786 flow_graph.add_edge(&u, &v, Expr::Constant(1.0));
787 }
788 }
789 }
790 for &v in &v_nodes {
791 flow_graph.add_edge(&v, &t, Expr::Constant(1.0));
792 }
793 let _max_flow = edmonds_karp_max_flow(&flow_graph, s, t);
794 vec![]
795}
796pub fn prim_mst<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
809 graph: &Graph<V>,
810 start_node: usize,
811) -> Vec<(usize, usize, Expr)> {
812 let n = graph.nodes.len();
813 let mut mst = Vec::new();
814 let mut visited = vec![false; n];
815 let mut pq = std::collections::BinaryHeap::new();
816 visited[start_node] = true;
817 if let Some(neighbors) = graph.adj.get(start_node) {
818 for &(v, ref weight) in neighbors {
819 let cost = as_f64(weight).unwrap_or(f64::INFINITY);
820 pq.push((
821 ordered_float::OrderedFloat(-cost),
822 start_node,
823 v,
824 weight.clone(),
825 ));
826 }
827 }
828 while let Some((_, u, v, weight)) = pq.pop() {
829 if visited[v] {
830 continue;
831 }
832 visited[v] = true;
833 mst.push((u, v, weight));
834 if let Some(neighbors) = graph.adj.get(v) {
835 for &(next_v, ref next_weight) in neighbors {
836 if !visited[next_v] {
837 let cost = as_f64(next_weight).unwrap_or(f64::INFINITY);
838 pq.push((
839 ordered_float::OrderedFloat(-cost),
840 v,
841 next_v,
842 next_weight.clone(),
843 ));
844 }
845 }
846 }
847 }
848 mst
849}
850pub fn topological_sort_kahn<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
863 graph: &Graph<V>,
864) -> Result<Vec<usize>, String> {
865 if !graph.is_directed {
866 return Err("Topological sort is only defined for directed graphs.".to_string());
867 }
868 let n = graph.nodes.len();
869 let mut in_degree = vec![0; n];
870 for i in 0..n {
871 in_degree[i] = graph.in_degree(i);
872 }
873 let mut queue: VecDeque<usize> = (0..n).filter(|&i| in_degree[i] == 0).collect();
874 let mut sorted_order = Vec::new();
875 while let Some(u) = queue.pop_front() {
876 sorted_order.push(u);
877 if let Some(neighbors) = graph.adj.get(u) {
878 for &(v, _) in neighbors {
879 in_degree[v] -= 1;
880 if in_degree[v] == 0 {
881 queue.push_back(v);
882 }
883 }
884 }
885 }
886 if sorted_order.len() == n {
887 Ok(sorted_order)
888 } else {
889 Err("Graph has a cycle, topological sort is not possible.".to_string())
890 }
891}
892pub fn topological_sort_dfs<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
903 graph: &Graph<V>,
904) -> Vec<usize> {
905 let mut visited = HashSet::new();
906 let mut stack = Vec::new();
907 for node_id in 0..graph.nodes.len() {
908 if !visited.contains(&node_id) {
909 topo_dfs_util(graph, node_id, &mut visited, &mut stack);
910 }
911 }
912 stack.reverse();
913 stack
914}
915pub(crate) fn topo_dfs_util<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
916 graph: &Graph<V>,
917 u: usize,
918 visited: &mut HashSet<usize>,
919 stack: &mut Vec<usize>,
920) {
921 visited.insert(u);
922 if let Some(neighbors) = graph.adj.get(u) {
923 for &(v, _) in neighbors {
924 if !visited.contains(&v) {
925 topo_dfs_util(graph, v, visited, stack);
926 }
927 }
928 }
929 stack.push(u);
930}
931pub fn bipartite_minimum_vertex_cover<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
945 graph: &Graph<V>,
946 partition: &[i8],
947 matching: &[(usize, usize)],
948) -> Vec<usize> {
949 let mut u_nodes = HashSet::new();
950 let mut matched_nodes_u = HashSet::new();
951 for i in 0..partition.len() {
952 if partition[i] == 0 {
953 u_nodes.insert(i);
954 }
955 }
956 for &(u, v) in matching {
957 if u_nodes.contains(&u) {
958 matched_nodes_u.insert(u);
959 } else {
960 matched_nodes_u.insert(v);
961 }
962 }
963 let unmatched_u: Vec<_> = u_nodes.difference(&matched_nodes_u).copied().collect();
964 let mut visited = HashSet::new();
965 let mut queue = VecDeque::from(unmatched_u);
966 while let Some(u) = queue.pop_front() {
967 if visited.contains(&u) {
968 continue;
969 }
970 visited.insert(u);
971 if let Some(neighbors) = graph.adj.get(u) {
972 for &(v, _) in neighbors {
973 if !matching.contains(&(u, v))
974 && !matching.contains(&(v, u))
975 && !visited.contains(&v)
976 {
977 queue.push_back(v);
978 }
979 }
980 }
981 }
982 let mut cover = Vec::new();
983 for u in u_nodes {
984 if !visited.contains(&u) {
985 cover.push(u);
986 }
987 }
988 for i in 0..partition.len() {
989 if partition[i] == 1 && visited.contains(&i) {
990 cover.push(i);
991 }
992 }
993 cover
994}
995#[allow(unused_variables)]
1007pub fn hopcroft_karp_bipartite_matching<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
1008 graph: &Graph<V>,
1009 partition: &[i8],
1010) -> Vec<(usize, usize)> {
1011 let n = graph.nodes.len();
1012 let mut u_nodes = Vec::new();
1013 for i in 0..n {
1014 if partition[i] == 0 {
1015 u_nodes.push(i);
1016 }
1017 }
1018 let mut pair_u = vec![None; n];
1019 let mut pair_v = vec![None; n];
1020 let mut dist = vec![0; n];
1021 let mut matching = 0;
1022 while hopcroft_karp_bfs(graph, &u_nodes, &mut pair_u, &mut pair_v, &mut dist) {
1023 for &u in &u_nodes {
1024 if pair_u[u].is_none()
1025 && hopcroft_karp_dfs(graph, u, &mut pair_u, &mut pair_v, &mut dist)
1026 {
1027 matching += 1;
1028 }
1029 }
1030 }
1031 let mut result = Vec::new();
1032 for u in 0..n {
1033 if let Some(v) = pair_u[u] {
1034 result.push((u, v));
1035 }
1036 }
1037 result
1038}
1039pub(crate) fn hopcroft_karp_bfs<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
1040 graph: &Graph<V>,
1041 u_nodes: &[usize],
1042 pair_u: &mut [Option<usize>],
1043 pair_v: &mut [Option<usize>],
1044 dist: &mut [usize],
1045) -> bool {
1046 let mut queue = VecDeque::new();
1047 for &u in u_nodes {
1048 if pair_u[u].is_none() {
1049 dist[u] = 0;
1050 queue.push_back(u);
1051 } else {
1052 dist[u] = usize::MAX;
1053 }
1054 }
1055 let mut found_path = false;
1056 while let Some(u) = queue.pop_front() {
1057 if let Some(neighbors) = graph.adj.get(u) {
1058 for &(v, _) in neighbors {
1059 if let Some(next_u_opt) = pair_v.get(v) {
1060 if let Some(next_u) = next_u_opt {
1061 if dist[*next_u] == usize::MAX {
1062 dist[*next_u] = dist[u] + 1;
1063 queue.push_back(*next_u);
1064 }
1065 } else {
1066 found_path = true;
1067 }
1068 }
1069 }
1070 }
1071 }
1072 found_path
1073}
1074pub(crate) fn hopcroft_karp_dfs<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
1075 graph: &Graph<V>,
1076 u: usize,
1077 pair_u: &mut [Option<usize>],
1078 pair_v: &mut [Option<usize>],
1079 dist: &mut [usize],
1080) -> bool {
1081 if let Some(neighbors) = graph.adj.get(u) {
1082 for &(v, _) in neighbors {
1083 if let Some(next_u_opt) = pair_v.get(v) {
1084 if let Some(next_u) = next_u_opt {
1085 if dist[*next_u] == dist[u] + 1
1086 && hopcroft_karp_dfs(graph, *next_u, pair_u, pair_v, dist)
1087 {
1088 pair_v[v] = Some(u);
1089 pair_u[u] = Some(v);
1090 return true;
1091 }
1092 } else {
1093 pair_v[v] = Some(u);
1094 pair_u[u] = Some(v);
1095 return true;
1096 }
1097 }
1098 }
1099 }
1100 dist[u] = usize::MAX;
1101 false
1102}
1103#[allow(unused_variables)]
1115pub fn blossom_algorithm<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
1116 graph: &Graph<V>,
1117) -> Result<Vec<(usize, usize)>, String> {
1118 let n = graph.nodes.len();
1119 let mut matching = vec![None; n];
1120 let mut matches = 0;
1121 for i in 0..n {
1122 if matching[i].is_none() {
1123 let path = find_augmenting_path_with_blossoms(graph, i, &matching)?;
1124 if !path.is_empty() {
1125 matches += 1;
1126 let mut u = path[0];
1127 for &v in path.iter().skip(1) {
1128 matching[u] = Some(v);
1129 matching[v] = Some(u);
1130 u = v;
1131 }
1132 }
1133 }
1134 }
1135 let mut result = Vec::new();
1136 for u in 0..n {
1137 if let Some(v) = matching[u] {
1138 if u < v {
1139 result.push((u, v));
1140 }
1141 }
1142 }
1143 Ok(result)
1144}
1145pub(crate) fn find_augmenting_path_with_blossoms<
1146 V: Eq + std::hash::Hash + Clone + std::fmt::Debug,
1147>(
1148 graph: &Graph<V>,
1149 start_node: usize,
1150 matching: &[Option<usize>],
1151) -> Result<Vec<usize>, String> {
1152 let n = graph.nodes.len();
1153 let mut parent = vec![None; n];
1154 let mut origin = (0..n).collect::<Vec<_>>();
1155 let mut level = vec![-1; n];
1156 let mut queue = VecDeque::new();
1157 level[start_node] = 0;
1158 queue.push_back(start_node);
1159 while let Some(u) = queue.pop_front() {
1160 if let Some(neighbors) = graph.adj.get(u) {
1161 for &(v, _) in neighbors {
1162 if level[v] == -1 {
1163 if let Some(w) = matching[v] {
1164 parent[v] = Some(u);
1165 level[v] = 1;
1166 level[w] = 0;
1167 queue.push_back(w);
1168 } else {
1169 parent[v] = Some(u);
1170 let mut path = vec![v, u];
1171 let mut curr = u;
1172 while let Some(p) = parent[curr] {
1173 path.push(p);
1174 curr = p;
1175 }
1176 return Ok(path);
1177 }
1178 } else if level[v] == 0 {
1179 let base = find_common_ancestor(&origin, &parent, u, v)?;
1180 contract_blossom(
1181 base,
1182 u,
1183 v,
1184 &mut queue,
1185 &mut level,
1186 &mut origin,
1187 &mut parent,
1188 matching,
1189 );
1190 contract_blossom(
1191 base,
1192 v,
1193 u,
1194 &mut queue,
1195 &mut level,
1196 &mut origin,
1197 &mut parent,
1198 matching,
1199 );
1200 }
1201 }
1202 }
1203 }
1204 Ok(vec![])
1205}
1206pub(crate) fn find_common_ancestor(
1207 origin: &[usize],
1208 parent: &[Option<usize>],
1209 mut u: usize,
1210 mut v: usize,
1211) -> Result<usize, String> {
1212 let mut visited = vec![false; origin.len()];
1213 loop {
1214 u = origin[u];
1215 visited[u] = true;
1216 if let Some(p) = parent[u] {
1217 u = p;
1218 } else {
1219 break;
1220 }
1221 }
1222 loop {
1223 v = origin[v];
1224 if visited[v] {
1225 return Ok(v);
1226 }
1227 if let Some(p) = parent[v] {
1228 v = p;
1229 } else {
1230 return Err("Could not find a common ancestor in blossom algorithm.".to_string());
1231 }
1232 }
1233}
1234pub(crate) fn contract_blossom(
1235 base: usize,
1236 mut u: usize,
1237 v: usize,
1238 queue: &mut VecDeque<usize>,
1239 level: &mut Vec<i32>,
1240 origin: &mut [usize],
1241 parent: &mut Vec<Option<usize>>,
1242 matching: &[Option<usize>],
1243) {
1244 while origin[u] != base {
1245 parent[u] = Some(v);
1246 origin[u] = base;
1247 if let Some(w) = matching[u] {
1248 if level[w] == -1 {
1249 level[w] = 0;
1250 queue.push_back(w);
1251 }
1252 }
1253 if let Some(p) = parent[u] {
1254 u = p;
1255 } else {
1256 break;
1257 }
1258 }
1259}
1260pub fn shortest_path_unweighted<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
1273 graph: &Graph<V>,
1274 start_node: usize,
1275) -> HashMap<usize, (usize, Option<usize>)> {
1276 let mut distances = HashMap::new();
1277 let mut predecessors = HashMap::new();
1278 let mut queue = VecDeque::new();
1279 distances.insert(start_node, 0);
1280 predecessors.insert(start_node, None);
1281 queue.push_back(start_node);
1282 while let Some(u) = queue.pop_front() {
1283 let u_dist = if let Some(d) = distances.get(&u) {
1284 *d
1285 } else {
1286 continue;
1287 };
1288 if let Some(neighbors) = graph.adj.get(u) {
1289 for &(v, _) in neighbors {
1290 if let std::collections::hash_map::Entry::Vacant(e) = distances.entry(v) {
1291 e.insert(u_dist + 1);
1292 predecessors.insert(v, Some(u));
1293 queue.push_back(v);
1294 }
1295 }
1296 }
1297 }
1298 let mut result = HashMap::new();
1299 for (node, dist) in distances {
1300 result.insert(node, (dist, predecessors.get(&node).copied().flatten()));
1301 }
1302 result
1303}
1304pub fn dijkstra<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(
1317 graph: &Graph<V>,
1318 start_node: usize,
1319) -> HashMap<usize, (Expr, Option<usize>)> {
1320 let mut dist = HashMap::new();
1321 let mut prev = HashMap::new();
1322 let mut pq = std::collections::BinaryHeap::new();
1323 for node_id in 0..graph.nodes.len() {
1324 dist.insert(node_id, Expr::Infinity);
1325 }
1326 dist.insert(start_node, Expr::Constant(0.0));
1327 prev.insert(start_node, None);
1328 pq.push((OrderedFloat(0.0), start_node));
1329 while let Some((cost, u)) = pq.pop() {
1330 let cost = -cost.0;
1331 if cost > dist.get(&u).and_then(as_f64).unwrap_or(f64::INFINITY) {
1332 continue;
1333 }
1334 if let Some(neighbors) = graph.adj.get(u) {
1335 for &(v, ref weight) in neighbors {
1336 let new_dist = simplify(&Expr::new_add(Expr::Constant(cost), weight.clone()));
1337 if as_f64(&new_dist).unwrap_or(f64::INFINITY)
1338 < dist.get(&v).and_then(as_f64).unwrap_or(f64::INFINITY)
1339 {
1340 dist.insert(v, new_dist.clone());
1341 prev.insert(v, Some(u));
1342 if let Some(cost) = as_f64(&new_dist) {
1343 pq.push((OrderedFloat(-cost), v));
1344 }
1345 }
1346 }
1347 }
1348 }
1349 let mut result = HashMap::new();
1350 for (node, d) in dist {
1351 result.insert(node, (d, prev.get(&node).copied().flatten()));
1352 }
1353 result
1354}
1355pub fn floyd_warshall<V: Eq + std::hash::Hash + Clone + std::fmt::Debug>(graph: &Graph<V>) -> Expr {
1367 let n = graph.nodes.len();
1368 let mut dist = vec![vec![Expr::Infinity; n]; n];
1369 for i in 0..n {
1370 dist[i][i] = Expr::Constant(0.0);
1371 }
1372 for u in 0..n {
1373 if let Some(neighbors) = graph.adj.get(u) {
1374 for &(v, ref weight) in neighbors {
1375 dist[u][v] = weight.clone();
1376 }
1377 }
1378 }
1379 for k in 0..n {
1380 for i in 0..n {
1381 for j in 0..n {
1382 let new_dist = simplify(&Expr::new_add(dist[i][k].clone(), dist[k][j].clone()));
1383 if as_f64(&dist[i][j]).unwrap_or(f64::INFINITY)
1384 > as_f64(&new_dist).unwrap_or(f64::INFINITY)
1385 {
1386 dist[i][j] = new_dist;
1387 }
1388 }
1389 }
1390 }
1391 Expr::Matrix(dist)
1392}
1393pub fn spectral_analysis(matrix: &Expr) -> Result<(Expr, Expr), String> {
1407 crate::symbolic::matrix::eigen_decomposition(matrix)
1408}
1409pub fn algebraic_connectivity<V>(graph: &Graph<V>) -> Result<Expr, String>
1421where
1422 V: Clone,
1423 V: Debug,
1424 V: Eq,
1425 V: Hash,
1426{
1427 let laplacian = graph.to_laplacian_matrix();
1428 let (eigenvalues, _) = spectral_analysis(&laplacian)?;
1429 if let Expr::Matrix(eig_vec) = eigenvalues {
1430 if eig_vec.len() < 2 {
1431 return Err("Graph has fewer than 2 eigenvalues.".to_string());
1432 }
1433 let mut numerical_eigenvalues = Vec::new();
1434 for val_expr in eig_vec.iter().flatten() {
1435 if let Some(val) = as_f64(val_expr) {
1436 numerical_eigenvalues.push(val);
1437 } else {
1438 return Err("Eigenvalues are not all numerical, cannot sort.".to_string());
1439 }
1440 }
1441 numerical_eigenvalues.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
1442 Ok(Expr::Constant(numerical_eigenvalues[1]))
1443 } else {
1444 Err("Eigenvalue computation did not return a vector.".to_string())
1445 }
1446}