checkpoint 2025-08-27

This commit is contained in:
2025-08-27 00:06:12 +02:00
parent 5e064c73ed
commit 5b67d74b31
11 changed files with 81 additions and 93 deletions

View File

@@ -92,3 +92,10 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread '<unnamed>' panicked at src/algorithms/goldberg_tarjan.rs:109:238:
No distance label found
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
# Code erklären
- Graph generieren (random_generator.rs)
- GUI, Custom Layout (main.rs, layout.rs)
- Graph Hilfsfunktionen (graph.rs)
- Algorithmen (ford_fulkerson.rs, edmonds_karp.rs, dinic.rs, goldberg_tarjan.rs)

View File

@@ -82,7 +82,6 @@ impl Dinic {
visited.visit(neighbor);
let mut new_path = path.clone();
new_path.push(neighbor);
// TODO: is this right?
if neighbor == self.sink {
return Some(new_path);
} else {
@@ -113,15 +112,7 @@ impl MaxflowAlgorithm for Dinic {
// increase flow with bottleneck capacity along the augmenting path
for edge in edges {
// get source and target of edge
let (source, target) = self.residual_graph.edge_endpoints(edge).expect("edge not connected");
// increase flow of the forward edge with the calculated bottleneck value
let weight: &mut (u64, u64) = self.residual_graph.edge_weight_mut(edge).expect("edge not found");
(*weight).0 += bottleneck_capacity;
// increase capacity of the residual edge of the with the calculated bottleneck value
let residual_edge = self.residual_graph.find_edge(target, source).expect("residual edge not found");
let residual_weight: &mut (u64, u64) = self.residual_graph.edge_weight_mut(residual_edge).expect("edge not found");
(*residual_weight).1 += bottleneck_capacity;
self.residual_graph.add_flow(edge, bottleneck_capacity);
}
false
} else {

View File

@@ -65,15 +65,7 @@ impl MaxflowAlgorithm for EdmondsKarp {
// increase flow with bottleneck capacity along the augmenting path
for edge in edges {
// get source and target of edge
let (source, target) = self.residual_graph.edge_endpoints(edge).expect("edge not connected");
// increase flow of the forward edge with the calculated bottleneck value
let weight: &mut (u64, u64) = self.residual_graph.edge_weight_mut(edge).expect("edge not found");
(*weight).0 += bottleneck_capacity;
// increase capacity of the residual edge of the with the calculated bottleneck value
let residual_edge = self.residual_graph.find_edge(target, source).expect("residual edge not found");
let residual_weight: &mut (u64, u64) = self.residual_graph.edge_weight_mut(residual_edge).expect("edge not found");
(*residual_weight).1 += bottleneck_capacity;
self.residual_graph.add_flow(edge, bottleneck_capacity);
}
false
} else {

View File

@@ -37,7 +37,6 @@ impl FordFulkerson {
visited.visit(neighbor);
let mut new_path = path.clone();
new_path.push(neighbor);
// TODO: is this right?
if neighbor == self.sink {
return Some(new_path);
} else {
@@ -65,15 +64,7 @@ impl MaxflowAlgorithm for FordFulkerson {
// increase flow with bottleneck capacity along the augmenting path
for edge in edges {
// get source and target of edge
let (source, target) = self.residual_graph.edge_endpoints(edge).expect("edge not connected");
// increase flow of the forward edge with the calculated bottleneck value
let weight: &mut (u64, u64) = self.residual_graph.edge_weight_mut(edge).expect("edge not found");
(*weight).0 += bottleneck_capacity;
// increase capacity of the residual edge of the with the calculated bottleneck value
let residual_edge = self.residual_graph.find_edge(target, source).expect("residual edge not found");
let residual_weight: &mut (u64, u64) = self.residual_graph.edge_weight_mut(residual_edge).expect("edge not found");
(*residual_weight).1 += bottleneck_capacity;
self.residual_graph.add_flow(edge, bottleneck_capacity);
}
false
} else {

View File

@@ -80,8 +80,6 @@ pub trait FlowGraph {
fn valid_flow(&self, source: NodeIndex, sink: NodeIndex) -> bool;
fn saturated_cut(&self, source: NodeIndex, sink: NodeIndex) -> bool;
fn total_flow(&self, source: NodeIndex, sink: NodeIndex) -> u64;
fn available_capacity(&self, edge: EdgeIndex) -> u64;
@@ -198,22 +196,6 @@ impl FlowGraph for StableGraph<(f32, f32), (u64, u64)> {
true
}
// checks if there exists a saturated cut in the graph (a bip)
fn saturated_cut(&self, source: NodeIndex, sink: NodeIndex) -> bool {
let mut s = HashSet::new();
let mut t = HashSet::new();
for node in self.node_indices().into_iter().collect::<Vec<_>>() {
if has_path_connecting(self, source, node, None) {
s.insert(node);
} else {
t.insert(node);
}
}
return true;
}
fn total_flow(&self, source: NodeIndex, sink: NodeIndex) -> u64 {
let outgoing_flows_source: u64 = self.edges_directed(source, Direction::Outgoing).map(|e| e.weight().0).sum();
let incoming_flows_source: u64 = self.edges_directed(source, Direction::Incoming).map(|e| e.weight().0).sum();

View File

@@ -30,9 +30,9 @@ impl<E: Clone> From<EdgeProps<E>> for CustomEdgeShape {
label_text: props.label,
width: 1.,
tip_size: 10.,
tip_angle: std::f32::consts::TAU / 30.,
curve_size: 15.,
tip_size: 6.,
tip_angle: std::f32::consts::TAU / 20.,
curve_size: 10.,
loop_size: 3.,
}
}

View File

@@ -167,7 +167,6 @@ impl App for MaxflowApp {
ui.add(egui::DragValue::new(&mut self.node_count).range(2..=50));
ui.label("maximum capacity");
ui.add(egui::DragValue::new(&mut self.max_capacity).range(1..=100));
// TODO: add generation strategy (random, pseudo-random)
if ui.button("generate graph").clicked() {
self.problem = random_generator::MaxflowProblem::new_planar_graph(self.node_count, self.max_capacity);
self.reset_state();

View File

@@ -26,7 +26,7 @@ impl MaxflowProblem {
// check if node is too close to another node (distance < 40)
let mut too_close = true;
let (mut x, mut y) = (0.0, 0.0);
// this is a poor attempt at modeling a do..while look in Rust
// this is a poor attempt at modeling a do..while loop in Rust
while too_close {
too_close = false;
x = rng.gen_range(0.0..=400.0);
@@ -140,9 +140,4 @@ impl MaxflowProblem {
_ => false
}
}
fn intersects_poly(a: (f32, f32), b: (f32, f32), c: (f32, f32), d: (f32, f32)) -> bool {
let mut intersects = Self::intersects(a, b, c, d);
todo!();
}
}

View File

@@ -12,13 +12,7 @@ fn solve_problem_all_algos(problem: &MaxflowProblem) -> (f64, f64, f64, f64) {
let mut durations = vec![0.0; 4];
for (i,a) in instances.iter_mut().enumerate() {
let now = Instant::now();
match a {
MaxflowAlgorithmEnum::GoldbergTarjan(_) => { a.run(); },
_ => {
a.run();
}
}
//a.run();
a.run();
durations[i] = now.elapsed().as_secs_f64();
// check if the flow is valid
@@ -36,6 +30,7 @@ fn run_tests(test_tuples: Vec<(u64, u64, u64)>) -> String {
let mut response = String::new();
for (problem_count, nodes, capacity) in test_tuples {
println!("Running test: {} times, {} nodes, {} capacity", problem_count, nodes, capacity);
response += format!("=== Testing with problem_count={}, nodes={}, capacity={}\n", problem_count, nodes, capacity).as_str();
let mut problems: Vec<_> = Vec::new();
for _ in 0..problem_count {
@@ -60,10 +55,11 @@ pub fn run_small_tests() -> String {
let test_tuples = [
// (number of problems, number of nodes, max. capacity)
(10, 10, 10),
(10, 10, 100),
(10, 50, 10),
(10, 50, 100),
(10, 100, 10),
(10, 100, 100),
(10, 200, 10),
(10, 200, 100)
(10, 100, 100)
];
return run_tests(test_tuples.into());
}
@@ -74,13 +70,12 @@ pub fn run_large_tests() -> String {
(10, 100, 10),
(10, 100, 100),
(10, 100, 1000),
(10, 500, 10),
(10, 500, 100),
(10, 500, 1000),
(10, 1000, 10),
(10, 1000, 100),
(10, 1000, 1000),
(10, 10000, 10)
(10, 200, 10),
(10, 200, 100),
(10, 200, 1000),
(10, 300, 10),
(10, 300, 100),
(10, 300, 1000)
];
return run_tests(test_tuples.into());
}

54
tests.txt Normal file
View File

@@ -0,0 +1,54 @@
=== Testing with problem_count=10, nodes=100, capacity=10
Ford-Fulkerson: 0.00019723s
Edmonds-Karp: 0.00017104s
Dinic: 0.00114540s
Goldberg-Tarjan: 0.11118784s
=== Testing with problem_count=10, nodes=100, capacity=100
Ford-Fulkerson: 0.00044646s
Edmonds-Karp: 0.00030087s
Dinic: 0.00212037s
Goldberg-Tarjan: 0.15394399s
=== Testing with problem_count=10, nodes=100, capacity=1000
Ford-Fulkerson: 0.00028169s
Edmonds-Karp: 0.00017956s
Dinic: 0.00128019s
Goldberg-Tarjan: 0.11455003s
=== Testing with problem_count=10, nodes=200, capacity=10
Ford-Fulkerson: 0.00057035s
Edmonds-Karp: 0.00042638s
Dinic: 0.00270890s
Goldberg-Tarjan: 1.70483265s
=== Testing with problem_count=10, nodes=200, capacity=100
Ford-Fulkerson: 0.00121046s
Edmonds-Karp: 0.00045426s
Dinic: 0.00301752s
Goldberg-Tarjan: 1.48397911s
=== Testing with problem_count=10, nodes=200, capacity=1000
Ford-Fulkerson: 0.00183244s
Edmonds-Karp: 0.00062984s
Dinic: 0.00411386s
Goldberg-Tarjan: 1.49089764s
=== Testing with problem_count=10, nodes=300, capacity=10
Ford-Fulkerson: 0.00086230s
Edmonds-Karp: 0.00071712s
Dinic: 0.00423448s
Goldberg-Tarjan: 5.84010118s
=== Testing with problem_count=10, nodes=300, capacity=100
Ford-Fulkerson: 0.00164213s
Edmonds-Karp: 0.00040957s
Dinic: 0.00322493s
Goldberg-Tarjan: 1.97116912s
=== Testing with problem_count=10, nodes=300, capacity=1000
Ford-Fulkerson: 0.00362413s
Edmonds-Karp: 0.00094858s
Dinic: 0.00600265s
Goldberg-Tarjan: 5.16341617s

View File

@@ -23,24 +23,6 @@ fn generate_small_maxflow_example() -> (StableGraph<(f32, f32), (u64, u64)>, Sta
g.add_edge(four, three, (0,5)); // changed capacity to 5 to enforce a single optimal solution
g.add_edge(four, t, (0,10));
// TODO:
// let mut m: StableGraph<(f32, f32), (u64, u64)> = StableGraph::new();
// let s = m.add_node((0., 5.));
// let one = m.add_node((10., 0.));
// let two = m.add_node((10., 10.));
// let three = m.add_node((20., 0.));
// let four = m.add_node((20., 10.));
// let t = m.add_node((30., 5.));
// m.add_edge(s, one, (10, 10));
// m.add_edge(s, two, (9, 10));
// m.add_edge(one, three, (4, 4));
// m.add_edge(one, four, (6, 8));
// m.add_edge(one, two, (0,2));
// m.add_edge(two, four, (9,9));
// m.add_edge(three, t, (9,10));
// m.add_edge(four, three, (5,6));
// m.add_edge(four, t, (10,10));
let mut m = g.clone();
m.update_edge(s, one, (10, 10));
m.update_edge(s, two, (9, 10));