From 5d81549ac0dffb45d3dce69e0668cb6a2f2bff55 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 19 Mar 2025 15:06:51 +0100 Subject: [PATCH] Implement Ford-Fulkerson --- src/algorithms.rs | 125 +++++++++++++++++++++++++++++++++++++++++++--- src/graph.rs | 33 ++++++++++++ src/main.rs | 21 ++++---- 3 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 src/graph.rs diff --git a/src/algorithms.rs b/src/algorithms.rs index 7748d78..20b208d 100644 --- a/src/algorithms.rs +++ b/src/algorithms.rs @@ -1,13 +1,126 @@ +use std::cmp::min; +use std::collections::VecDeque; + +use eframe::glow::FALSE; // Ford-Fulkerson mit DFS zur Berechnung des flusserhöhenden Pfades, // Edmonds-Karp (also Ford-Fulkerson mit BFS statt DFS), // Dinic // Goldberg-Tarjan (auch Preflow-Push oder Push-Relabel genannt). -use random_generator::MaxflowProblem; +use egui_graphs::{Graph, DefaultNodeShape, DefaultEdgeShape}; +use petgraph::adj::EdgeIndex; +use petgraph::data::Build; +use petgraph::{Directed, Direction}; +use petgraph::stable_graph::EdgeReference; +use petgraph::visit::{Dfs, EdgeRef, NodeRef, VisitMap, Visitable}; +use petgraph::stable_graph::{StableGraph, NodeIndex}; -mod random_generator; +use crate::random_generator::MaxflowProblem; +use crate::graph::{MaxflowNode, MaxflowEdge}; +//mod random_generator; -impl FordFulkerson { - fn solve(problem: MaxflowProblem) -> ???solution??? { - - } +fn available_capacity(edge: EdgeReference<'_, (u64, u64)>) -> u64 { + edge.weight().1 - edge.weight().0 } + +// Returns the first augmenting path +fn dfs(graph: &StableGraph<(f32, f32), (u64, u64)>, source: NodeIndex, destination: NodeIndex) -> Option> { + let mut visited = graph.visit_map(); + let mut queue = VecDeque::new(); + queue.push_back((source, vec![source])); + + // main priority queue + while let Some((node, path)) = queue.pop_front() { + let outgoing_edges = graph.edges_directed(node, Direction::Outgoing); + + // iterate over all outgoing edges + for edge in outgoing_edges { + let neighbor = edge.target(); + if !visited.is_visited(&neighbor) && available_capacity(edge) > 0 { + visited.visit(neighbor); + let mut new_path = path.clone(); + new_path.push(neighbor); + // TODO: is this right? + if neighbor == destination { + return Some(new_path); + } else { + queue.push_back((neighbor, new_path)); + } + }; + } + } + + None +} + +pub fn ford_fulkerson(mut graph: StableGraph<(f32, f32), (u64, u64)>, source: NodeIndex, sink: NodeIndex) -> StableGraph<(f32, f32), (u64, u64)> { + //let augmenting_path = dfs(graph, source, sink); + + // continue while there are augmenting paths + while let Some(path) = dfs(&graph, source, sink) { + // find all edges along the path + let edges: Vec = path.windows(2).map(|w| graph.find_edge(w[0], w[1]).expect("edge not found")).collect(); + // find bottleneck capacity along path + let increase_value = edges.iter().fold(u64::MAX, |m, x| { + let edge = graph.edge_weight(*x).expect("edge index not found"); + min(m, edge.1 - edge.0) + }); + + // increase flow with bottleneck capacity along the augmenting path + for edge in edges { + let weight = graph.edge_weight_mut(edge).expect("edge not found"); + (*weight).0 += increase_value; + } + } + + // return graph with augmented flows + graph +} + +pub struct FordFulkerson { + problem: MaxflowProblem, + flows: Graph<(), u64, Directed, u32, DefaultNodeShape, DefaultEdgeShape>, + // alertnatively, use a map from EdgeIndex to flow value + //dfs: Dfs, +} + +/* impl FordFulkerson { + fn new(problem: MaxflowProblem) -> S/elf { + Self { problem: problem, flows: Graph::new(StableGraph::default()) } + } + + fn graph(&mut self) -> &Graph { + &self.problem.g + } + + fn flows(&mut self) -> &Graph<(), u64> { + &self.flows + } + + fn dfs(&mut self, ni: NodeIndex) -> Vec>{ + // set own node to visited + self.problem.g.node_mut(ni).expect("node index not found").set_visited(true); + //self.graph().node_mut(ni).expect("node index not found").set_visited(true); + + let augmenting_paths: Vec> = Vec::new(); + let neighboring_edges = self.graph().edges_directed(ni, Direction::Outgoing); + + for edge in neighboring_edges { + //let neighbor = self.problem.g.node_mut(edge.target()).expect("node index not found"); + //if neighbor.visited() == false { + // println!("{:?}", edge.weight()); + //} + } + // iterate over all unvisited! neighbors. for each: + // - check if there is capacity left + // - if neighbor = target, return path + // - else, do dfs starting from neighbor + // - if neighbor returns augmenting path add it to own list & prepend own edge + // return list of augmenting paths + augmenting_paths + } + + fn step(&self) { + //self.dfs(self.problem.s); + } + +} */ diff --git a/src/graph.rs b/src/graph.rs new file mode 100644 index 0000000..52e2239 --- /dev/null +++ b/src/graph.rs @@ -0,0 +1,33 @@ +//use egui_graphs::{Node, Edge}; +use petgraph::graph::{Node, Edge}; + +pub trait MaxflowNode { + fn visited(&self) -> bool; + fn set_visited(&mut self, b: bool); +} + +pub trait MaxflowEdge { + fn remaining_capacity(&self) -> u64; + fn set_capacity(&mut self, c: u64); +} + +/* impl MaxflowNode for Node { + fn visited(&self) -> bool { + *self.() + } + + fn set_visited(&mut self, b: bool) { + let payload = self.payload_mut(); + *payload = b; + } +} */ + +impl MaxflowEdge for Edge<(u64, u64)> { + fn remaining_capacity(&self) -> u64 { + self.weight.1 - self.weight.0 + } + + fn set_capacity(&mut self, c: u64) { + self.weight.0 = c; + } +} diff --git a/src/main.rs b/src/main.rs index ac92314..3e49081 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,15 +2,14 @@ use eframe::{run_native, App, CreationContext, NativeOptions, Frame}; use egui::{CentralPanel, SidePanel, Context}; use egui_graphs::{GraphView, Graph, SettingsStyle, LayoutRandom, LayoutStateRandom}; +use algorithms::ford_fulkerson; use random_generator::MaxflowProblem; -use algorithms::{ford_fulk -//use petgraph::stable_graph::StableGraph; - mod random_generator; mod algorithms; +mod graph; pub struct MaxflowApp { - g: Graph<(), u64>, + g: Graph<(f32, f32), (u64, u64)>, p: MaxflowProblem, node_count: u64, max_capacity: u64, @@ -19,12 +18,13 @@ pub struct MaxflowApp { impl MaxflowApp { fn new(_: &CreationContext<'_>) -> Self { let problem = MaxflowProblem::new(10, 10); - Self { g: problem.g.clone(), p: problem, node_count: 10, max_capacity: 5 } + Self { g: problem.to_gui_graph(), p: problem, node_count: 10, max_capacity: 5 } } } impl App for MaxflowApp { fn update(&mut self, ctx: &Context, _: &mut Frame) { + ctx.set_theme(egui::Theme::Light); CentralPanel::default().show(ctx, |ui| { ui.add(&mut GraphView::<_, _, _, _, _, _, LayoutStateRandom, LayoutRandom>::new(&mut self.g).with_styles(&SettingsStyle::default().with_labels_always(true))); }); @@ -32,14 +32,17 @@ impl App for MaxflowApp { .min_width(200.) .show(ctx, |ui| { ui.label("node count"); - ui.add(egui::DragValue::new(&mut self.node_count).range(1..=1000)); + ui.add(egui::DragValue::new(&mut self.node_count).range(2..=1000)); ui.label("maximum capacity"); - ui.add(egui::DragValue::new(&mut self.max_capacity).range(1..=10)); + ui.add(egui::DragValue::new(&mut self.max_capacity).range(1..=100)); if ui.button("generate graph").clicked() { - let problem = random_generator::MaxflowProblem::new(self.node_count, self.max_capacity); - self.g = problem.g; + self.p = random_generator::MaxflowProblem::new(self.node_count, self.max_capacity); + self.g = self.p.to_gui_graph(); } if ui.button("run algorithm").clicked() { + let max_flow_graph = ford_fulkerson(self.p.g.clone(), self.p.s, self.p.t); + self.p = MaxflowProblem::from(max_flow_graph, self.p.s, self.p.t); + self.g = self.p.to_gui_graph(); } }); }