From eb9ce313fa0e0bf717de9b26e4052f4152d65375 Mon Sep 17 00:00:00 2001 From: Julian Pollinger Date: Fri, 23 Feb 2024 22:04:04 +0100 Subject: [PATCH] feat(rust): nicer output and refactoring --- rust/Cargo.lock | 179 +++++++++++++++++- rust/Cargo.toml | 4 + rust/src/io/mod.rs | 4 +- rust/src/lib.rs | 5 +- rust/src/main.rs | 64 ++++++- .../src/{algorithm.rs => rism_classic/mod.rs} | 13 +- rust/src/types/mod.rs | 4 +- rust/src/types/{iteration.rs => results.rs} | 8 +- 8 files changed, 261 insertions(+), 20 deletions(-) rename rust/src/{algorithm.rs => rism_classic/mod.rs} (84%) rename rust/src/types/{iteration.rs => results.rs} (93%) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index f3a43ae..af83bc4 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -50,6 +50,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + [[package]] name = "cfg-if" version = "1.0.0" @@ -87,7 +93,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -102,6 +108,31 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "getrandom" version = "0.2.12" @@ -119,18 +150,93 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "papergrid" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad43c07024ef767f9160710b3a6773976194758c7919b17e63b863db0bdf7fb" +dependencies = [ + "bytecount", + "fnv", + "unicode-width", +] + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.78" @@ -184,7 +290,31 @@ name = "rism" version = "0.1.0" dependencies = [ "clap", + "console", + "indicatif", "rand", + "serde", + "tabled", +] + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", ] [[package]] @@ -193,6 +323,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.48" @@ -204,18 +345,54 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tabled" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c998b0c8b921495196a48aabaf1901ff28be0760136e31604f7967b0792050e" +dependencies = [ + "papergrid", + "tabled_derive", + "unicode-width", +] + +[[package]] +name = "tabled_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c138f99377e5d653a371cdad263615634cfc8467685dfe8e73e2b8e98f44b17" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2768239..d04880d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,3 +14,7 @@ path = "src/main.rs" [dependencies] clap = { version = "4.4.18", features = ["derive"] } rand = "0.8.5" +serde = { version = "1.0.197", features = ["derive"] } +indicatif = "0.17.8" +console = "0.15.8" +tabled = "0.15.0" diff --git a/rust/src/io/mod.rs b/rust/src/io/mod.rs index 865dacf..582212a 100644 --- a/rust/src/io/mod.rs +++ b/rust/src/io/mod.rs @@ -2,7 +2,7 @@ use std::fs; use crate::types::{Seminar, SeminarType, Student}; pub fn import_students(students_path: &str, seminars: &Vec) -> Vec { - println!("Importing students from {students_path}"); + // println!("Importing students from {students_path}"); let mut students: Vec = Vec::new(); let contents = fs::read_to_string(students_path) @@ -30,7 +30,7 @@ pub fn import_students(students_path: &str, seminars: &Vec) -> Vec Vec { - println!("Importing seminars from {seminars_path}"); + // println!("Importing seminars from {seminars_path}"); let mut seminars: Vec =Vec::new(); let contents = fs::read_to_string(seminars_path) .expect(&*format!("Could not read file {seminars_path}")); diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 896feff..faef6cd 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,4 +1,5 @@ pub mod io; pub mod types; -pub mod algorithm; -pub mod constants; \ No newline at end of file +pub mod constants; +pub mod rism_classic; +pub mod rism_model_checking; \ No newline at end of file diff --git a/rust/src/main.rs b/rust/src/main.rs index b7d6d04..1c90293 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,7 +1,23 @@ use clap::Parser; -use rism::algorithm::run_algorithm; +use serde::Serialize; +use rism::rism_classic::run_algorithm; use rism::constants::get_default_points; use rism::io::{import_students, import_seminars}; +use rism::rism_model_checking::run_model_check; +use console::style; +use tabled::{Table, Tabled}; +use tabled::settings::Style; + +#[derive( +clap::ValueEnum, Clone, Default, Debug, Serialize, PartialEq +)] +#[serde(rename_all = "kebab-case")] +enum ExecutionVariants { + #[default] + Classic, + + ModelChecking, +} #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -17,6 +33,18 @@ struct Args { /// Number of Iterations #[arg(short, long)] iterations: u32, + + /// Choose variant of calculation + #[clap(short, long, default_value_t, value_enum)] + variant: ExecutionVariants, +} + +#[derive(Tabled)] +struct PrintableStudent { + name: String, + points: u16, + w_seminar: String, + p_seminar: String, } fn main() { @@ -24,6 +52,36 @@ fn main() { let seminars = import_seminars(&args.seminars_path); let students = import_students(&args.students_path, &seminars); - let best_iteration = run_algorithm(&students, &seminars, args.iterations, get_default_points()); - print!("Points: {}", best_iteration.total_points()); + + let best_iteration = match args.variant { + ExecutionVariants::Classic => Some(run_algorithm(&students, &seminars, args.iterations, get_default_points())), + ExecutionVariants::ModelChecking => run_model_check(&students, &seminars, get_default_points(), 400) + }; + if let Some(bi_unwr) = best_iteration { + + let mut students_table_data = Vec::new(); + + for a in &bi_unwr.assignments { + let ps = PrintableStudent { + name: a.student.name.clone(), + points: a.points, + w_seminar: match a.w_seminar { + Some(s) => s.name.clone(), + None => "Null".to_string() + }, + p_seminar: match a.p_seminar { + Some(s) => s.name.clone(), + None => "Null".to_string() + }, + }; + students_table_data.push(ps); + } + + let mut table = Table::new(students_table_data); + table.with(Style::rounded()); + print!("{}\n", table.to_string()); + print!("Total points: {}\n", style(bi_unwr.total_points()).bold().green()); + } else { + print!("{} Try the classic variant or increase the max points.\n", style("No result was found!").bold().yellow()) + } } diff --git a/rust/src/algorithm.rs b/rust/src/rism_classic/mod.rs similarity index 84% rename from rust/src/algorithm.rs rename to rust/src/rism_classic/mod.rs index f340928..f3d5b5b 100644 --- a/rust/src/algorithm.rs +++ b/rust/src/rism_classic/mod.rs @@ -1,10 +1,11 @@ -use crate::types::{Assignment, Iteration, Seminar, Student}; +use crate::types::{Assignment, RismResult, Seminar, Student}; use rand::thread_rng; use rand::seq::SliceRandom; use crate::constants::Points; use std::cmp; +use indicatif::ProgressIterator; -fn find_possible_assignment<'a>(wishes: &'a Vec, points: &Points, iteration: &Iteration) -> (Option<&'a Seminar>, u16) { +fn find_possible_assignment<'a>(wishes: &'a Vec, points: &Points, iteration: &RismResult) -> (Option<&'a Seminar>, u16) { return if iteration.get_capacity(&wishes[0]) > 0 { (Some(&wishes[0]), points.first_selection) } else if iteration.get_capacity(&wishes[1]) > 0 { @@ -16,14 +17,14 @@ fn find_possible_assignment<'a>(wishes: &'a Vec, points: &Points, itera }; } -pub fn run_algorithm<'a>(students: &'a Vec, seminars: &'a Vec, iterations: u32, points: Points) -> Iteration<'a> { - let mut best_iteration: Option = None; +pub fn run_algorithm<'a>(students: &'a Vec, seminars: &'a Vec, iterations: u32, points: Points) -> RismResult<'a> { + let mut best_iteration: Option = None; - for _ in 0..iterations { + for _ in (0..iterations).progress() { let mut shuffled_indices: Vec = (0..students.len()).collect(); shuffled_indices.shuffle(&mut thread_rng()); - let mut iteration: Iteration = Iteration::new( + let mut iteration: RismResult = RismResult::new( students.iter().map(|s| Assignment::new(s)).collect(), &seminars, vec![None; seminars.len()]); diff --git a/rust/src/types/mod.rs b/rust/src/types/mod.rs index 1d9505d..57e45be 100644 --- a/rust/src/types/mod.rs +++ b/rust/src/types/mod.rs @@ -1,5 +1,5 @@ -mod iteration; -pub type Iteration<'b> = iteration::Iteration<'b>; +mod results; +pub type RismResult<'b> = results::RismResult<'b>; mod assignment; pub type Assignment<'a> = assignment::Assignment<'a>; diff --git a/rust/src/types/iteration.rs b/rust/src/types/results.rs similarity index 93% rename from rust/src/types/iteration.rs rename to rust/src/types/results.rs index c3ab334..b8532e4 100644 --- a/rust/src/types/iteration.rs +++ b/rust/src/types/results.rs @@ -2,14 +2,14 @@ use std::cmp::Ordering; use crate::types::{Assignment, Seminar, Student}; #[derive(Debug, PartialEq, Eq)] -pub struct Iteration<'a> { +pub struct RismResult<'a> { points: Option, pub assignments: Vec>, pub seminars: &'a Vec, pub capacities: Vec>, } -impl<'a> Iteration<'a> { +impl<'a> RismResult<'a> { pub fn get_capacity(&self, seminar: &Seminar) -> u16 { self.capacities.get(seminar.id as usize).unwrap().unwrap_or(seminar.capacity) } @@ -53,13 +53,13 @@ impl<'a> Iteration<'a> { } } -impl<'a> PartialOrd for Iteration<'a> { +impl<'a> PartialOrd for RismResult<'a> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl<'a> Ord for Iteration<'a>{ +impl<'a> Ord for RismResult<'a>{ fn cmp(&self, other: &Self) -> Ordering { self.total_points().cmp(&other.total_points()) }