From e8a615111ca57e852c9a1c4c59e836b2d85f97e4 Mon Sep 17 00:00:00 2001 From: jacekpoz Date: Thu, 20 Jun 2024 13:36:52 +0200 Subject: [PATCH] l5 --- lab5/zad1/.gitignore | 4 + lab5/zad1/Cargo.lock | 273 ++++++++++++++++++++++++++++++++++++++++ lab5/zad1/Cargo.toml | 9 ++ lab5/zad1/src/main.rs | 283 ++++++++++++++++++++++++++++++++++++++++++ lab5/zad2/.gitignore | 4 + lab5/zad2/Cargo.lock | 273 ++++++++++++++++++++++++++++++++++++++++ lab5/zad2/Cargo.toml | 9 ++ lab5/zad2/src/main.rs | 264 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 1119 insertions(+) create mode 100644 lab5/zad1/.gitignore create mode 100644 lab5/zad1/Cargo.lock create mode 100644 lab5/zad1/Cargo.toml create mode 100644 lab5/zad1/src/main.rs create mode 100644 lab5/zad2/.gitignore create mode 100644 lab5/zad2/Cargo.lock create mode 100644 lab5/zad2/Cargo.toml create mode 100644 lab5/zad2/src/main.rs diff --git a/lab5/zad1/.gitignore b/lab5/zad1/.gitignore new file mode 100644 index 0000000..314941c --- /dev/null +++ b/lab5/zad1/.gitignore @@ -0,0 +1,4 @@ +target +results +times.gp +times.pdf diff --git a/lab5/zad1/Cargo.lock b/lab5/zad1/Cargo.lock new file mode 100644 index 0000000..0e27a7f --- /dev/null +++ b/lab5/zad1/Cargo.lock @@ -0,0 +1,273 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "zad1" +version = "0.1.0" +dependencies = [ + "dashmap", + "rand", + "rayon", +] diff --git a/lab5/zad1/Cargo.toml b/lab5/zad1/Cargo.toml new file mode 100644 index 0000000..c97c2a1 --- /dev/null +++ b/lab5/zad1/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "zad1" +version = "0.1.0" +edition = "2021" + +[dependencies] +rand = "0.8.5" +rayon = "1.10.0" +dashmap = "5.5.3" diff --git a/lab5/zad1/src/main.rs b/lab5/zad1/src/main.rs new file mode 100644 index 0000000..77c9eb2 --- /dev/null +++ b/lab5/zad1/src/main.rs @@ -0,0 +1,283 @@ +#![feature(exitcode_exit_method)] + +use std::{fmt::Display, fs::OpenOptions, io::{self, Write}, process::ExitCode, sync::Arc, time::Instant}; + +use dashmap::DashMap; +use rand::{thread_rng, Rng}; +use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; + +#[derive(Clone, Copy)] +pub struct Edge { + pub u: usize, + pub v: usize, + pub w: f64, +} + +pub struct Graph { + pub size: usize, + pub edges: Vec>, +} + +impl Graph { + pub fn new(size: usize) -> Self { + Self { + size, + edges: (0..size) + .map(|i| + (0..size) + .map(|j| + if i == j { 0.0 } + else { thread_rng().gen::() } + ) + .collect::>() + ) + .collect::>(), + } + } + + fn min(&self, key: &Vec, mst: &Vec) -> usize { + let mut min = f64::INFINITY; + let mut min_index = usize::MAX; + + for i in 0..self.size { + if mst[i] == false && key[i] < min { + min = key[i]; + min_index = i; + } + } + + min_index + } + + pub fn prim(&self) -> Vec { + let mut parent = vec![0; self.size]; + + let mut key = vec![f64::INFINITY; self.size]; + + let mut mst = vec![false; self.size]; + + key[0] = 0.0; + parent[0] = usize::MAX; + + for _ in 0..(self.size - 1) { + let u = self.min(&key, &mst); + mst[u] = true; + + for j in 0..self.size { + if self.edges[u][j] != 0.0 && mst[j] == false && self.edges[u][j] < key[j] { + parent[j] = u; + key[j] = self.edges[u][j]; + } + } + } + + (0..self.size) + .filter(|i| parent[*i] != usize::MAX) + .map(|i| Edge { + u: parent[i], + v: i, + w: self.edges[i][parent[i]], + }) + .collect() + } + + fn find_id(belongs: &mut Vec, i: usize) -> usize { + if belongs[i] != i { + belongs[i] = Self::find_id(belongs, belongs[i]); + } + + return belongs[i]; + } + + fn union(belongs: &mut Vec, rank: &mut Vec, x: usize, y: usize) { + let x_root = Self::find_id(belongs, x); + let y_root = Self::find_id(belongs, y); + + if rank[x_root] < rank[y_root] { + belongs[x_root] = y_root; + } else if rank[x_root] > rank[y_root] { + belongs[y_root] = x_root; + } else { + belongs[y_root] = x_root; + rank[x_root] += 1; + } + } + + pub fn kruskal(&self) -> Vec { + let mut edges = vec![]; + + for i in 0..self.size { + for j in 0..i { + if self.edges[i][j] != 0.0 { + edges.push(Edge { + u: i, + v: j, + w: self.edges[i][j], + }); + } + } + } + + edges.sort_by(|e1, e2| e1.w.total_cmp(&e2.w)); + + let mut belongs = (0..self.size).collect::>(); + let mut rank = vec![0; self.size]; + + let mut mst = Vec::with_capacity(self.size); + + for i in 0..edges.len() { + let a = Self::find_id(&mut belongs, edges[i].u); + let b = Self::find_id(&mut belongs, edges[i].v); + + if a != b { + mst.push(edges[i]); + + Self::union(&mut belongs, &mut rank, a, b); + } + } + + mst + } +} + +impl Display for Graph { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for i in 0..self.size { + for j in 0..self.size { + write!(f, "{weight:.6} ", weight = self.edges[i][j])?; + } + write!(f, "\n")?; + } + + Ok(()) + } +} + +fn print_mst(mst: &Vec) { + println!("vertex\t\tweight"); + + for edge in mst { + println!("{} - {}\t\t{:.6}", edge.u, edge.v, edge.w); + } +} + +fn time_avg(results_map: &DashMap>) -> DashMap { + results_map.iter() + .map(|ref_multi| { + let (i, results) = ref_multi.pair(); + (*i, (results.iter() + .sum::() as f64 / results.len() as f64)) + }) + .collect() +} + +fn test() { + let n_min = 1000usize; + let n_max = 10000usize; + let step = 1000usize; + let rep = 10usize; + + let prim_times: Arc>> = Arc::new(DashMap::new()); + let kruskal_times: Arc>> = Arc::new(DashMap::new()); + + let prim_times_clone = Arc::clone(&prim_times); + let kruskal_times_clone = Arc::clone(&kruskal_times); + + // step_by isn't implemented for the ..= iter :-( + (n_min..(n_max + 1)).into_par_iter().step_by(step).for_each(|n| { + prim_times_clone.insert(n, vec![]); + kruskal_times_clone.insert(n, vec![]); + println!("{n}: starting"); + (0..rep).into_par_iter().for_each(|k| { + println!("\t{n}: iteration {k}"); + let graph = Graph::new(n); + + let prim_timer = Instant::now(); + graph.prim(); + let prim_time = prim_timer.elapsed().as_millis(); + + prim_times_clone.get_mut(&n).unwrap().push(prim_time); + + let kruskal_timer = Instant::now(); + graph.kruskal(); + let kruskal_time = kruskal_timer.elapsed().as_millis(); + + kruskal_times_clone.get_mut(&n).unwrap().push(kruskal_time); + }); + println!("{n}: finished"); + }); + + let prim_time_averages = time_avg(&prim_times); + let kruskal_time_averages = time_avg(&kruskal_times); + + let mut results_file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open("./results") + .expect("can't open file"); + + for n in (n_min..=n_max).step_by(step) { + writeln!(results_file, "{n} {} {}", + prim_time_averages.get(&n).unwrap().value(), + kruskal_time_averages.get(&n).unwrap().value(), + ).expect("can't write to file"); + } +} + +fn show() { + let mut input = String::new(); + + print!("graph size: "); + _ = io::stdout().flush(); + + io::stdin() + .read_line(&mut input) + .expect("pass the graph size"); + + let size = input.trim() + .parse::() + .expect("graph size should be usize"); + + let graph = Graph::new(size); + + println!(); + println!("graph:"); + println!("{}", graph); + + println!("prim:"); + println!(); + let mst_prim = graph.prim(); + + print_mst(&mst_prim); + + println!(); + + println!("kruskal:"); + println!(); + let mst_kruskal = graph.kruskal(); + + print_mst(&mst_kruskal); +} + +fn main() { + match std::env::args().nth(1) { + Some(s) => { + match s.as_str() { + "--test" => { + test(); + ExitCode::SUCCESS.exit_process(); + }, + "--show" => { + show(); + ExitCode::SUCCESS.exit_process(); + }, + _ => {}, + } + }, + None => {}, + } + + eprintln!("pass either --test or --show"); + ExitCode::FAILURE.exit_process(); +} diff --git a/lab5/zad2/.gitignore b/lab5/zad2/.gitignore new file mode 100644 index 0000000..67412cd --- /dev/null +++ b/lab5/zad2/.gitignore @@ -0,0 +1,4 @@ +target/ +results +rounds.gp +rounds.pdf diff --git a/lab5/zad2/Cargo.lock b/lab5/zad2/Cargo.lock new file mode 100644 index 0000000..0c8c7c5 --- /dev/null +++ b/lab5/zad2/Cargo.lock @@ -0,0 +1,273 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "zad2" +version = "0.1.0" +dependencies = [ + "dashmap", + "rand", + "rayon", +] diff --git a/lab5/zad2/Cargo.toml b/lab5/zad2/Cargo.toml new file mode 100644 index 0000000..3a75ab6 --- /dev/null +++ b/lab5/zad2/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "zad2" +version = "0.1.0" +edition = "2021" + +[dependencies] +rand = "0.8.5" +rayon = "1.10.0" +dashmap = "5.5.3" diff --git a/lab5/zad2/src/main.rs b/lab5/zad2/src/main.rs new file mode 100644 index 0000000..45654e9 --- /dev/null +++ b/lab5/zad2/src/main.rs @@ -0,0 +1,264 @@ +#![feature(exitcode_exit_method)] + +use std::{fmt::Display, fs::OpenOptions, io::{self, Write}, process::ExitCode, sync::Arc}; + +use dashmap::DashMap; +use rand::{thread_rng, Rng}; +use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; + +#[derive(Clone, Copy)] +pub struct Edge { + pub u: usize, + pub v: usize, + pub w: f64, +} + +pub struct Graph { + pub size: usize, + pub edges: Vec>, +} + +impl Graph { + pub fn new(size: usize) -> Self { + Self { + size, + edges: (0..size) + .map(|i| + (0..size) + .map(|j| + if i == j { 0.0 } + else { thread_rng().gen::() } + ) + .collect::>() + ) + .collect::>(), + } + } + + fn min(&self, key: &Vec, mst: &Vec) -> usize { + let mut min = f64::INFINITY; + let mut min_index = usize::MAX; + + for i in 0..self.size { + if mst[i] == false && key[i] < min { + min = key[i]; + min_index = i; + } + } + + min_index + } + + pub fn prim(&self) -> Vec { + let mut parent = vec![0; self.size]; + + let mut key = vec![f64::INFINITY; self.size]; + + let mut mst = vec![false; self.size]; + + key[0] = 0.0; + parent[0] = usize::MAX; + + for _ in 0..(self.size - 1) { + let u = self.min(&key, &mst); + mst[u] = true; + + for j in 0..self.size { + if self.edges[u][j] != 0.0 && mst[j] == false && self.edges[u][j] < key[j] { + parent[j] = u; + key[j] = self.edges[u][j]; + } + } + } + + (0..self.size) + .filter(|i| parent[*i] != usize::MAX) + .map(|i| Edge { + u: parent[i], + v: i, + w: self.edges[i][parent[i]], + }) + .collect() + } + + fn make_round(&self, vertex_index: usize, visited: &mut Vec, mst: &Vec) -> u64 { + let mut children_rounds = vec![]; + visited[vertex_index] = true; + + let mut in_mst = vec![vec![false; self.size]; self.size]; + for e in mst { + in_mst[e.v][e.u] = true; + in_mst[e.u][e.v] = true; + } + + for i in 0..self.size { + if in_mst[vertex_index][i] == true { + if visited[i] == false { + let child_rounds = self.make_round(i, visited, mst); + children_rounds.push(child_rounds); + } + } + } + + if let Some(max) = children_rounds.iter().max() { + return max + 1; + } else { + return 1; + } + } + + fn calculate_rounds(&self, mst: &Vec) -> u64 { + let mut visited = vec![false; self.size]; + + let rand_vertex_index = thread_rng().gen_range(0..self.size); + + return self.make_round(rand_vertex_index, &mut visited, mst); + } +} + +impl Display for Graph { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for i in 0..self.size { + for j in 0..self.size { + write!(f, "{weight:.6} ", weight = self.edges[i][j])?; + } + write!(f, "\n")?; + } + + Ok(()) + } +} + +fn print_mst(mst: &Vec) { + println!("vertex\t\tweight"); + + for edge in mst { + println!("{} - {}\t\t{:.6}", edge.u, edge.v, edge.w); + } +} + +fn round_avg(results_map: &DashMap>) -> DashMap { + results_map.iter() + .map(|ref_multi| { + let (i, results) = ref_multi.pair(); + (*i, (results.iter() + .sum::() as f64 / results.len() as f64)) + }) + .collect() +} + +fn round_max(results_map: &DashMap>) -> DashMap { + results_map.iter() + .map(|ref_multi| { + let (i, results) = ref_multi.pair(); + (*i, (*results.iter().max().unwrap())) + }) + .collect() +} + +fn round_min(results_map: &DashMap>) -> DashMap { + results_map.iter() + .map(|ref_multi| { + let (i, results) = ref_multi.pair(); + (*i, (*results.iter().min().unwrap())) + }) + .collect() +} + +fn test() { + let n_min = 100usize; + let n_max = 2500usize; + let step = 100usize; + let rep = 10usize; + + let rounds: Arc>> = Arc::new(DashMap::new()); + + let rounds_clone = Arc::clone(&rounds); + + // step_by isn't implemented for the ..= iter :-( + (n_min..(n_max + 1)).into_par_iter().step_by(step).for_each(|n| { + rounds_clone.insert(n, vec![]); + println!("{n}: starting"); + (0..rep).into_par_iter().for_each(|k| { + println!("\t{n}: iteration {k}"); + let graph = Graph::new(n); + + let mst = graph.prim(); + + let rounds = graph.calculate_rounds(&mst); + + rounds_clone.get_mut(&n).unwrap().push(rounds); + }); + println!("{n}: finished"); + }); + + let round_averages = round_avg(&rounds); + let round_maxes = round_max(&rounds); + let round_mins = round_min(&rounds); + + let mut results_file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open("./results") + .expect("can't open file"); + + for n in (n_min..=n_max).step_by(step) { + writeln!(results_file, "{n} {} {} {}", + round_averages.get(&n).unwrap().value(), + round_maxes.get(&n).unwrap().value(), + round_mins.get(&n).unwrap().value(), + ).expect("can't write to file"); + } +} + +fn show() { + let mut input = String::new(); + + print!("graph size: "); + _ = io::stdout().flush(); + + io::stdin() + .read_line(&mut input) + .expect("pass the graph size"); + + let size = input.trim() + .parse::() + .expect("graph size should be usize"); + + let graph = Graph::new(size); + + println!(); + println!("graph:"); + println!("{}", graph); + + println!("prim:"); + println!(); + let mst_prim = graph.prim(); + + print_mst(&mst_prim); + + println!("rounds: {}", graph.calculate_rounds(&mst_prim)); +} + +fn main() { + match std::env::args().nth(1) { + Some(s) => { + match s.as_str() { + "--test" => { + test(); + ExitCode::SUCCESS.exit_process(); + }, + "--show" => { + show(); + ExitCode::SUCCESS.exit_process(); + }, + _ => {}, + } + }, + None => {}, + } + + eprintln!("pass either --test or --show"); + ExitCode::FAILURE.exit_process(); +}