diff --git a/src/graph.rs b/src/graph.rs index 30dcc02..045a647 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -1,18 +1,20 @@ -use self::matrix::clone; +use matrix::{clone, dfs_bridges, mult}; + +use self::matrix::dfs_articulations; pub mod matrix; -pub fn calculate_distanz_matrix(adjazenz_matrix: &Vec>) -> Vec> { - let mut distanz_matrix: Vec> = vec![vec![]; adjazenz_matrix.len()]; +pub fn calculate_distanz_matrix(adjazenz_matrix: &Vec>) -> Vec> { + let mut distanz_matrix: Vec> = vec![vec![]; adjazenz_matrix.len()]; let mut potenz_matrix = clone(adjazenz_matrix); - for k in 1..(adjazenz_matrix.len() + 1) { - potenz_matrix = matrix::mult(&potenz_matrix, adjazenz_matrix); + for k in 1..=adjazenz_matrix.len() { + potenz_matrix = mult(&potenz_matrix, adjazenz_matrix); for i in 0..adjazenz_matrix.len() { for j in 0..adjazenz_matrix.len() { if k != 1 { - if potenz_matrix[i][j] != 0 && distanz_matrix[i][j] == u8::MAX { - distanz_matrix[i][j] = u8::try_from(k).unwrap(); + if potenz_matrix[i][j] != 0 && distanz_matrix[i][j] == usize::MAX { + distanz_matrix[i][j] = k; } continue; } @@ -21,7 +23,7 @@ pub fn calculate_distanz_matrix(adjazenz_matrix: &Vec>) -> Vec> } else if adjazenz_matrix[i][j] == 1 { distanz_matrix[i].push(1); } else { - distanz_matrix[i].push(u8::MAX); + distanz_matrix[i].push(usize::MAX); } } } @@ -29,12 +31,12 @@ pub fn calculate_distanz_matrix(adjazenz_matrix: &Vec>) -> Vec> distanz_matrix } -pub fn calculate_weg_matrix(adjazenz_matrix: &Vec>) -> Vec> { - let mut weg_matrix: Vec> = vec![vec![]; adjazenz_matrix.len()]; +pub fn calculate_weg_matrix(adjazenz_matrix: &Vec>) -> Vec> { + let mut weg_matrix: Vec> = vec![vec![]; adjazenz_matrix.len()]; let mut potenz_matrix = clone(adjazenz_matrix); - for k in 1..(adjazenz_matrix.len() + 1) { - potenz_matrix = matrix::mult(&potenz_matrix, adjazenz_matrix); + for k in 1..=adjazenz_matrix.len() { + potenz_matrix = mult(&potenz_matrix, adjazenz_matrix); for i in 0..adjazenz_matrix.len() { for j in 0..adjazenz_matrix.len() { if k != 1 { @@ -54,15 +56,15 @@ pub fn calculate_weg_matrix(adjazenz_matrix: &Vec>) -> Vec> { weg_matrix } -pub fn calculate_exzentrizitaeten(distanz_matrix: Vec>) -> Vec { - let mut exzentrizitaeten: Vec = vec![]; - let mut exzentrizitaet: u8; +pub fn calculate_exzentrizitaeten(distanz_matrix: Vec>) -> Vec { + let mut exzentrizitaeten = vec![]; + let mut exzentrizitaet: usize; for vector in distanz_matrix { exzentrizitaet = 0; for value in vector { - if value == u8::MAX { + if value == usize::MAX { continue; } exzentrizitaet = exzentrizitaet.max(value); @@ -72,23 +74,23 @@ pub fn calculate_exzentrizitaeten(distanz_matrix: Vec>) -> Vec { exzentrizitaeten } -pub fn calculate_properties(exzentrizitaeten: &[u8]) -> (u8, u8, Vec, bool) { - let mut radius = u8::MAX; - let mut diameter: u8 = 0; - let mut centre: Vec = vec![]; - let mut connected: bool = true; +pub fn calculate_properties(exzentrizitaeten: &[usize]) -> (usize, usize, Vec, bool) { + let mut radius = usize::MAX; + let mut diameter = 0; + let mut centre = vec![]; + let mut connected = true; for (index, value) in exzentrizitaeten.iter().enumerate() { if value > &diameter { diameter = *value; } if value == &radius { - centre.push(u8::try_from(index + 1).unwrap()); + centre.push(index + 1); } if value < &radius { radius = *value; centre.clear(); - centre.push(u8::try_from(index + 1).unwrap()); + centre.push(index + 1); } if value == &0 { connected = false; @@ -97,15 +99,15 @@ pub fn calculate_properties(exzentrizitaeten: &[u8]) -> (u8, u8, Vec, bool) (radius, diameter, centre, connected) } -pub fn find_components(weg_matrix: Vec>) -> Vec> { - let mut components: Vec> = vec![]; - let mut component: Vec; +pub fn find_components(weg_matrix: Vec>) -> Vec> { + let mut components: Vec> = vec![]; + let mut component: Vec; for array in weg_matrix { component = vec![]; for (index, value) in array.iter().enumerate() { if value == &1 { - component.push(u8::try_from(index + 1).unwrap()); + component.push(index + 1); } } if !components.contains(&component) { @@ -115,46 +117,56 @@ pub fn find_components(weg_matrix: Vec>) -> Vec> { components } -pub fn find_articulations_and_bridges( - adjazenz_matrix: &mut Vec>, - components: &Vec>, -) -> (Vec, Vec>) { - let mut bridges: Vec> = vec![]; - let mut articulations: Vec = vec![]; - let mut temp_matrix = adjazenz_matrix.clone(); +pub fn find_bridges(adjazenz_matrix: &Vec>) -> Vec> { + let size = adjazenz_matrix.len(); + let mut bridges: Vec> = vec![]; + let mut visited = vec![false; size]; + let mut discovery_time = vec![0; size]; + let mut low_time = vec![0; size]; + let time = 0; - for n in 0..temp_matrix.len() { - for i in 0..temp_matrix.len() { - for j in 0..temp_matrix.len() { - temp_matrix[i][n] = 0; - temp_matrix[n][j] = 0; - - if n != 0 { - continue; - } - let bridge = vec![ - u8::try_from(usize::min(i + 1, j + 1)).unwrap(), - u8::try_from(usize::max(i + 1, j + 1)).unwrap(), - ]; - let prev_value = adjazenz_matrix[i][j]; - adjazenz_matrix[i][j] = 0; - adjazenz_matrix[j][i] = 0; - - if find_components(calculate_weg_matrix(adjazenz_matrix)).len() > components.len() - && !bridges.contains(&bridge) - { - bridges.push(bridge); - } - adjazenz_matrix[i][j] = prev_value; - adjazenz_matrix[j][i] = prev_value; - } + for i in 0..size { + if !visited[i] { + dfs_bridges( + &mut bridges, + adjazenz_matrix, + &mut visited, + &mut discovery_time, + &mut low_time, + time, + i, + usize::MAX, + ); } - - if find_components(calculate_weg_matrix(&temp_matrix)).len() > (components.len() + 1) { - articulations.push(u8::try_from(n + 1).unwrap()); - } - temp_matrix = adjazenz_matrix.clone(); } - (articulations, bridges) + bridges +} + +pub fn find_articulations(adjazenz_matrix: &Vec>) -> Vec { + let size = adjazenz_matrix.len(); + let mut ariculations = vec![]; + let mut is_articulation = vec![false; size]; + let mut visited = vec![false; size]; + let mut discovery_time = vec![0; size]; + let mut low_time = vec![0; size]; + let time = 0; + + for i in 0..size { + if !visited[i] { + dfs_articulations( + &mut ariculations, + &mut is_articulation, + adjazenz_matrix, + &mut visited, + &mut discovery_time, + &mut low_time, + time, + i, + usize::MAX, + ); + } + } + + ariculations } diff --git a/src/graph/matrix.rs b/src/graph/matrix.rs index 99d398a..f209ac1 100644 --- a/src/graph/matrix.rs +++ b/src/graph/matrix.rs @@ -1,33 +1,26 @@ -use csv::ReaderBuilder; +pub fn fill_with_random(size: usize) -> Vec> { + let mut matrix = vec![vec![0; size]; size]; + let mut random_value: usize; -pub fn fill_with_random(size: usize) -> Vec> { - assert!( - (size < u8::MAX.into() && size > 0), - "fill_with_random: size must not be bigger than 255 or smaller than 1, size was: {size}" - ); - - let mut matrix: Vec> = vec![]; for i in 0..size { - matrix.push(vec![]); for j in 0..size { - if i == j { - matrix[i].push(0); - continue; - } - matrix[i].push(fastrand::u8(0..2)); + random_value = fastrand::usize(0..=1); + matrix[i][j] = random_value; + matrix[j][i] = random_value; + matrix[i][i] = 0; } } matrix } -pub fn mult(matrix1: &Vec>, matrix2: &Vec>) -> Vec> { - let mut product: Vec> = vec![vec![]; matrix2.len()]; +pub fn mult(matrix1: &Vec>, matrix2: &Vec>) -> Vec> { + let mut product = vec![vec![]; matrix2.len()]; let mut vector: Vec; for (index, k) in (0..matrix1.len()).enumerate() { vector = vec![]; for array in matrix2 { - vector.push(array[index].into()); + vector.push(array[index]); } for array in matrix1 { product[k].push(array.iter().zip(vector.iter()).map(|(x, y)| x * y).sum()); @@ -36,20 +29,115 @@ pub fn mult(matrix1: &Vec>, matrix2: &Vec>) -> Vec product } -pub fn clone(matrix: &Vec>) -> Vec> { +pub fn dfs_bridges( + bridges: &mut Vec>, + adjazenz_matrix: &Vec>, + visited: &mut Vec, + discovery_time: &mut Vec, + low_time: &mut Vec, + time: usize, + vertex: usize, + parent: usize, +) { + let time = time + 1; + visited[vertex] = true; + discovery_time[vertex] = time; + low_time[vertex] = time; + + for neighbor in 0..adjazenz_matrix.len() { + if adjazenz_matrix[vertex][neighbor] != 1 || visited[neighbor] { + continue; + } + if neighbor != parent { + low_time[vertex] = usize::min(low_time[vertex], discovery_time[neighbor]); + } + + dfs_bridges( + bridges, + adjazenz_matrix, + visited, + discovery_time, + low_time, + time, + neighbor, + vertex, + ); + + low_time[vertex] = usize::min(low_time[vertex], low_time[neighbor]); + + if discovery_time[vertex] < low_time[neighbor] { + bridges.push(vec![vertex + 1, neighbor + 1]); + } + } +} + +pub fn dfs_articulations( + articulations: &mut Vec, + is_articulation: &mut Vec, + adjazenz_matrix: &Vec>, + visited: &mut Vec, + discovery_time: &mut Vec, + low_time: &mut Vec, + time: usize, + vertex: usize, + parent: usize, +) { + let time = time + 1; + visited[vertex] = true; + discovery_time[vertex] = time; + low_time[vertex] = time; + let mut child_count: usize = 0; + let mut articulation = false; + + for neighbor in 0..adjazenz_matrix.len() { + if visited[neighbor] || neighbor == parent || parent == usize::MAX { + continue; + } + + child_count += 1; + dfs_articulations( + articulations, + is_articulation, + adjazenz_matrix, + visited, + discovery_time, + low_time, + time, + vertex, + parent, + ); + + low_time[vertex] = usize::min(low_time[vertex], low_time[neighbor]); + + if discovery_time[vertex] <= low_time[neighbor] { + articulation = true; + } + } + + if parent != usize::MAX && child_count > 1 { + articulation = true; + } + + if articulation { + is_articulation[vertex] = true; + articulations.push(vertex + 1); + } +} + +pub fn clone(matrix: &Vec>) -> Vec> { let mut new_matrix: Vec> = vec![]; for i in 0..matrix.len() { new_matrix.push(vec![]); for j in 0..matrix.len() { - new_matrix[i].push(matrix[i][j].into()); + new_matrix[i].push(matrix[i][j]); } } new_matrix } -pub fn show(matrix: &Vec>) { +pub fn show(matrix: &Vec>) { for vector in matrix { for value in vector { print!("{value} "); @@ -58,10 +146,10 @@ pub fn show(matrix: &Vec>) { } } -pub fn read_csv(file_name: &str) -> Vec> { - let mut matrix: Vec> = vec![]; +pub fn read_csv(file_name: &str) -> Vec> { + let mut matrix: Vec> = vec![]; let dir: String = "/home/rene/projects/Java/graphprogram/csv/".into(); - let mut csv = ReaderBuilder::new() + let mut csv = csv::ReaderBuilder::new() .has_headers(false) .delimiter(b';') .from_path(dir + file_name) diff --git a/src/lib.rs b/src/lib.rs index 57c77a8..e4bc40a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ mod tests { #[test] fn graph() { - let mut adjazenz_matrix = read_csv("art-brck.csv"); + let adjazenz_matrix = read_csv("art-brck.csv"); let distanz_matrix = calculate_distanz_matrix(&adjazenz_matrix); let weg_matrix = calculate_weg_matrix(&adjazenz_matrix); @@ -44,7 +44,8 @@ mod tests { let exzentrizitaeten = calculate_exzentrizitaeten(distanz_matrix); let properties = calculate_properties(&exzentrizitaeten); let components = find_components(weg_matrix); - let result = find_articulations_and_bridges(&mut adjazenz_matrix, &components); + let bridges = find_bridges(&adjazenz_matrix); + let articulations = find_articulations(&adjazenz_matrix); assert_eq!(exzentrizitaeten, vec![2, 2, 2, 1, 2]); assert_eq!(properties.0, 1); @@ -52,8 +53,8 @@ mod tests { assert_eq!(properties.2, vec![4]); assert_eq!(properties.3, true); assert_eq!(components, vec![vec![1, 2, 3, 4, 5]]); - assert_eq!(result.1, vec![vec![4, 5]]); - assert_eq!(result.0, vec![4]); + assert_eq!(bridges, vec![vec![4, 5]]); + assert_eq!(articulations, vec![4]); } #[test] diff --git a/src/main.rs b/src/main.rs index 3ffe3e7..66d3bfb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,13 +7,13 @@ use crate::graph::{ pub mod graph; pub fn main() { - //let file_name = "50n.csv"; - //let mut adjazenz_matrix = read_csv(file_name); - let mut adjazenz_matrix = fill_with_random(1); // with 48 verteces, it runs in about 10.2 seconds (run on the 2023-06-03 at 12:36) + let file_name = "24n.csv"; + let adjazenz_matrix = read_csv(file_name); + //let adjazenz_matrix = fill_with_random(320); // with 320 verteces, it runs in about 10 seconds on an Intel i5-10300H @4.3 GHz (2023-06-05 15:48) let distanz_matrix = calculate_distanz_matrix(&adjazenz_matrix); let weg_matrix = calculate_weg_matrix(&adjazenz_matrix); - println!("adjazen matrix:"); + println!("adjazenz matrix:"); show(&adjazenz_matrix); println!("\ndistanz matrix:"); show(&distanz_matrix); @@ -37,7 +37,6 @@ pub fn main() { let components = find_components(weg_matrix); println!("components: {components:?}"); - let result = find_articulations_and_bridges(&mut adjazenz_matrix, &components); - println!("bridges: {:?}", result.1); - println!("articulations: {:?}", result.0); + println!("bridges: {:?}", find_bridges(&adjazenz_matrix)); + println!("articulations: {:?}", find_articulations(&adjazenz_matrix)); }