diff --git a/.gitignore b/.gitignore index ea8c4bf..205ac3f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target +rustfmt.toml +/.vscode diff --git a/Cargo.lock b/Cargo.lock index 44991e9..017809a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,12 +190,10 @@ dependencies = [ "ndarray", "ndarray-rand", "ntest", - "num-traits", "pest", "pest_derive", "rand", "rayon", - "thiserror", ] [[package]] @@ -210,9 +208,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" @@ -298,9 +296,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "matrixmultiply" diff --git a/Cargo.toml b/Cargo.toml index e1406e5..59614fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,19 +5,33 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "cs220" +path = "src/lib.rs" + +[[bin]] +name = "calc" +path = "src/bin/calc.rs" +required-features = ["build-calc"] + +[[bin]] +name = "par_iter" +path = "src/bin/par_iter.rs" + +[features] +build-calc = ["clap"] + [dependencies] anyhow = "1.0.86" -clap = { version = "4.5.11", features = ["derive"] } +clap = { version = "4.5.11", features = ["derive"], optional = true } etrace = "1.1.1" itertools = "0.13.0" lazy_static = "1.5.0" pest = "2.7.11" pest_derive = "2.7.11" rayon = "1.10.0" -thiserror = "1.0.63" ntest = "0.9.3" approx = "0.5.1" -num-traits = "0.2.19" ndarray = "0.15.6" ndarray-rand = "0.14.0" rand = "0.8.5" diff --git a/README.md b/README.md index a9f871d..a5845a3 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ - Announcements: in [issue tracker](https://github.com/kaist-cp/cs220/issues?q=is%3Aissue+is%3Aopen+label%3Aannouncement) + We assume you read each announcement within 24 hours. + We strongly recommend you to watch the repository. -- TA: TBA +- TA: [Janggun Lee](https://cp.kaist.ac.kr/janggun.lee) + Office Hours: Fri 9:00-10:00, Rm. 4441, Bldg. E3-1. If you want to come, do so by 9:15. See [below](https://github.com/kaist-cp/cs220#rules) for the office hour policy. @@ -23,7 +23,7 @@ ## Course description -This course will equip you with the programming concepts needed to effectively communicate your ideas to computers. +This course will equip you with the programming concepts needed to effectively communicate your ideas to computers. For a detailed overview, please refer to the introduction in the Google Slides presentation. ### Outline @@ -162,7 +162,7 @@ Ensure you are proficient with the following development tools: - You can run the grading script with the following command: ```bash $ ./scripts/grade.sh - + # E.g. To grade `assignment09`, run the following command: $ ./scripts/grade.sh 9 ``` @@ -181,8 +181,8 @@ Ensure you are proficient with the following development tools: Laptops can also be borrowed from the School of Computing Administration Team. - We will use [Safe Exam Browser](https://safeexambrowser.org/) to prevent cheatings. - - You should have your laptop configured with Safe Exam Browser before the exam. - - TBA: Details will be announced later. + - You should have your laptop configured with Safe Exam Browser before the exam. + - TBA: Details will be announced later. ### Attendance (?%) diff --git a/assets/why3/assignment05/binary_search.mlw b/assets/why3/assignment05/binary_search.mlw index 92fb42d..9b53b1b 100644 --- a/assets/why3/assignment05/binary_search.mlw +++ b/assets/why3/assignment05/binary_search.mlw @@ -19,5 +19,5 @@ module BinarySearch = (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) 0 (* TODO *) - + end diff --git a/assets/why3/assignment05/max.mlw b/assets/why3/assignment05/max.mlw index ff04fa9..bd8c448 100644 --- a/assets/why3/assignment05/max.mlw +++ b/assets/why3/assignment05/max.mlw @@ -2,11 +2,11 @@ Given an array `a` of integers with length `n` greater than `0`, return `max_idx`, the index of the maximum element of that array. - + E.g. `max_idx [5, 12, 34, 10] 4` will return `2` E.g. `max_idx [4, 3, 2] 3` will return `0` E.g. `max_idx [1, 2, 3, 4] 4` will return `3` - + Prove the below program indeed follows the given specification, by giving an appropriate invariant. *) @@ -22,12 +22,13 @@ module Max requires { n = length a } ensures { 0 <= max_idx <= n-1 } ensures { forall i. 0 <= i <= n-1 -> a[i] <= a[max_idx] } - = + = let ref max_idx = 0 in for i = 0 to n-1 do invariant { 0 <= max_idx <= n-1 } (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) - invariant { true (* TODO: Replace `true` with your solution. Your solution MUST be a single line, at line number 30. DON'T add another line of codes. *) } + (* TODO: Replace `true` with your solution. Your solution MUST be a single line, at line 31. DON'T add more code above or below. *) + invariant { true } (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) if a[max_idx] < a[i] then max_idx <- i; done; diff --git a/assets/why3/assignment05/pascal.mlw b/assets/why3/assignment05/pascal.mlw index 4601099..3888270 100644 --- a/assets/why3/assignment05/pascal.mlw +++ b/assets/why3/assignment05/pascal.mlw @@ -17,9 +17,9 @@ module Pascal ensures { result >= 1 } = if k = 0 || k = n then 1 else comb (n-1) k + comb (n-1) (k-1) - (* Computes the Pascal's triangle and returns the `n`th row of it. *) + (* Computes Pascal's triangle and returns the `n`th row of it. *) (* Insert an appropriate invariant so that Why3 can verify this function. *) - (* You SHOULD understand the Pascal's triangle first to find good invariants. *) + (* You should understand Pascal's triangle first to find good invariants. *) let chooses (n : int) : array int requires { n > 0 } ensures { forall i: int. @@ -28,16 +28,17 @@ module Pascal let ref row = Array.make 1 1 in for r = 1 to n do invariant { length row = r } - invariant { forall c: int. 0 <= c < r -> row[c] = comb (r-1) c } + invariant { forall c: int. 0 <= c < r -> row[c] = comb (r-1) c } let new_row = Array.make (r+1) 1 in for c = 1 to r-1 do (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) - invariant { true (* TODO: Replace `true` with your solution. Your solution MUST be a single line, at line number 35. DON'T add another lines. *) } + (* TODO: Replace `true` with your solution. Your solution MUST be a single line, at line 36. DON'T add more code above or below. *) + invariant { true } (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) new_row[c] <- row[c-1] + row[c] done; row <- new_row done; row - + end diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a37cce5..85cb9e7 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] channel = "1.80.0" -components = [ "rustfmt", "clippy" ] +components = ["rustfmt", "clippy"] diff --git a/scripts/grade-utils.sh b/scripts/grade-utils.sh index 80a28dd..1aa4b5a 100755 --- a/scripts/grade-utils.sh +++ b/scripts/grade-utils.sh @@ -7,7 +7,7 @@ # * RUNNERS: array of "cargo[_asan | _tsan] [--release]" # * TIMEOUT: default 10s -rustup toolchain update stable nightly +rustup toolchain update stable echo_err() { echo "$@" 1>&2 @@ -37,27 +37,6 @@ run_linters() { } export -f run_linters -# usage: cargo_asan [SUBCOMMAND] [OPTIONS] [-- ...] -# example: cargo_asan test --release TEST_NAME -- --skip SKIPPED -# NOTE: sanitizer documentation at https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html -cargo_asan() { - local SUBCOMMAND=$1; shift - RUSTFLAGS="-Z sanitizer=address" \ - RUSTDOCFLAGS="-Z sanitizer=address" \ - cargo +nightly $SUBCOMMAND -Z build-std --target x86_64-unknown-linux-gnu "$@" -} -export -f cargo_asan - -cargo_tsan() { - local SUBCOMMAND=$1; shift - RUSTFLAGS="-Z sanitizer=thread" \ - TSAN_OPTIONS="suppressions=suppress_tsan.txt" \ - RUSTDOCFLAGS="-Z sanitizer=thread" \ - RUST_TEST_THREADS=1 \ - cargo +nightly $SUBCOMMAND -Z build-std --target x86_64-unknown-linux-gnu "$@" -} -export -f cargo_tsan - # usage: _run_tests_with CARGO [OPTIONS] # example: _run_tests_with cargo_tsan --release # Echos number of failed tests to stdout. @@ -80,7 +59,7 @@ _run_tests_with() { # local NUM_TESTS=$(echo $TESTS | wc -w) for TEST in ${TESTS[@]}; do local TEST_CMD="$CARGO test $* --lib -- $TEST" - # card_game in Assignment12 takes 20 seconds. + # card_game in Assignment12 takes 20 seconds. timeout ${TIMEOUT:-22s} bash -c "$TEST_CMD 2> /dev/null" 1>&2 case $? in 0) PASSED=$((PASSED + 1));; diff --git a/scripts/grade.sh b/scripts/grade.sh index 16d2c7f..6ef01ba 100755 --- a/scripts/grade.sh +++ b/scripts/grade.sh @@ -73,7 +73,6 @@ case $TEST_NAME in TESTS=( "assignments::assignment09::bigint_grade::test" "assignments::assignment09::small_exercises_grade::test" - "assignments::assignment09::matmul_grade::test" ) ;; TEST10) diff --git a/scripts/submit.sh b/scripts/submit.sh index ea13c51..4a50fb1 100755 --- a/scripts/submit.sh +++ b/scripts/submit.sh @@ -15,16 +15,6 @@ for i in {01..13} ; do zip -rj $BASEDIR/target/assignment05.zip $BASEDIR/assets/why3/assignment05 continue fi - - if [ $i -eq 13 ] - then - if [ -f $BASEDIR/target/assignment13.zip ]; then - rm $BASEDIR/target/assignment13.zip - fi - zip -rj $BASEDIR/target/assignment13.zip $BASEDIR/src/assignments/assignment13 $BASEDIR/src/assignments/assignment09/matmul.rs - continue - fi - if [ -f $BASEDIR/target/assignment$i.zip ]; then rm $BASEDIR/target/assignment$i.zip fi diff --git a/src/assignments/assignment01/mod.rs b/src/assignments/assignment01/mod.rs index 034f208..82f5f3b 100644 --- a/src/assignments/assignment01/mod.rs +++ b/src/assignments/assignment01/mod.rs @@ -1,10 +1,11 @@ //! Assignment 1: Preparing Rust Development Environment. //! -//! The primary goal of this assignment is bringing up SSH, VSCode, and all the other necessary tools to develop Rust programs. -//! Please make sure you're comfortable with developing Rust programs before moving on to the next assignments. +//! The primary goal of this assignment is bringing up SSH, VSCode, and all the other necessary +//! tools to develop Rust programs. Please make sure you're comfortable with developing Rust +//! programs before moving on to the next assignments. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 1` works fine. -//! See `assigment01/small_exercises_grade.rs` and `/scripts/grade.sh 1` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 1` works +//! fine. See `assigment01/small_exercises_grade.rs` and `/scripts/grade.sh 1` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment01/small_exercises.rs b/src/assignments/assignment01/small_exercises.rs index eaa5358..0095978 100644 --- a/src/assignments/assignment01/small_exercises.rs +++ b/src/assignments/assignment01/small_exercises.rs @@ -1,8 +1,8 @@ //! Assignment 1: Preparing Rust Development Environment. -//! Welcome to the CS220 course! +//! Welcome to CS220! //! -//! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade.sh 1` works fine. -//! See `small_problems_grade.rs` and `/scripts/grade.sh 1` for the test script. +//! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade.sh 1` +//! works fine. See `small_problems_grade.rs` and `/scripts/grade.sh 1` for the test script. //! //! Hint: diff --git a/src/assignments/assignment02/mod.rs b/src/assignments/assignment02/mod.rs index df4deb5..1d50680 100644 --- a/src/assignments/assignment02/mod.rs +++ b/src/assignments/assignment02/mod.rs @@ -1,10 +1,11 @@ //! Assignment 2: Mastering common programming concepts (1/2). //! -//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, especially those in the Rust Book chapters 3 and 5. -//! Please make sure you're comfortable with the concepts to proceed on to the next assignments. +//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, +//! especially those in the Rust Book chapters 3 and 5. Please make sure you're comfortable with the +//! concepts to proceed on to the next assignments. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 2` works fine. -//! See `assigment02/*_grade.rs` and `/scripts/grade.sh 2` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 2` works +//! fine. See `assigment02/*_grade.rs` and `/scripts/grade.sh 2` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment02/small_exercises.rs b/src/assignments/assignment02/small_exercises.rs index 8f962b7..bef4c5f 100644 --- a/src/assignments/assignment02/small_exercises.rs +++ b/src/assignments/assignment02/small_exercises.rs @@ -1,5 +1,7 @@ //! Small problems. +use std::iter; + const FAHRENHEIT_OFFSET: f64 = 32.0; const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0; @@ -18,29 +20,33 @@ pub fn sum_array(input: &[u64]) -> u64 { todo!() } -/// Given a non-negative integer, say `n`, return the smallest integer of the form `3^m` that's greater than or equal to `n`. +/// Given a non-negative integer, say `n`, return the smallest integer of the form `3^m` that's +/// greater than or equal to `n`. /// /// For instance, up3(6) = 9, up3(9) = 9, up3(10) = 27. (We assume the absence of integer overflow.) pub fn up3(n: u64) -> u64 { todo!() } -/// Returns the greatest common divisor (GCD) of two non-negative integers. (We assume the absence of integer overflow.) +/// Returns the greatest common divisor (GCD) of two non-negative integers. (We assume the absence +/// of integer overflow.) pub fn gcd(lhs: u64, rhs: u64) -> u64 { todo!() } -/// Returns the array of nC0, nC1, nC2, ..., nCn, where nCk = n! / (k! * (n-k)!). (We assume the absence of integer overflow.) +/// Returns the array of nC0, nC1, nC2, ..., nCn, where nCk = n! / (k! * (n-k)!). (We assume the +/// absence of integer overflow.) /// -/// Consult for computation of binomial coefficients without integer overflow. +/// Consult for computation of binomial +/// coefficients without integer overflow. pub fn chooses(n: u64) -> Vec { todo!() } /// Returns the "zip" of two vectors. /// -/// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`. -/// Here, `3` is ignored because it doesn't have a partner. +/// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`. Here, `3` is +/// ignored because it doesn't have a partner. pub fn zip(lhs: Vec, rhs: Vec) -> Vec<(u64, u64)> { todo!() } diff --git a/src/assignments/assignment02/vec_and_mat.rs b/src/assignments/assignment02/vec_and_mat.rs index 0054fff..b2b6321 100644 --- a/src/assignments/assignment02/vec_and_mat.rs +++ b/src/assignments/assignment02/vec_and_mat.rs @@ -2,6 +2,7 @@ //! //! You will implement simple operations on vectors and matrices. +use std::cmp::PartialEq; use std::ops::Mul; /// 2x2 matrix of the following configuration: @@ -112,13 +113,20 @@ impl FMat2 { /// /// # Example /// - /// ``` + /// ```ignore /// assert_eq!( - /// Mat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(), - /// Mat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0} + /// FMat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(), + /// FMat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0 } /// ); /// ``` pub fn inverse(self) -> Self { todo!() } } + +// Equivalence between two floating-point matrices, as element-wise equivalence +impl PartialEq for FMat2 { + fn eq(&self, other: &FMat2) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d + } +} diff --git a/src/assignments/assignment02/vec_and_mat_grade.rs b/src/assignments/assignment02/vec_and_mat_grade.rs index bf47fa7..add6982 100644 --- a/src/assignments/assignment02/vec_and_mat_grade.rs +++ b/src/assignments/assignment02/vec_and_mat_grade.rs @@ -16,14 +16,6 @@ mod test { assert_eq!(fibonacci(92), 12200160415121876738); } - // Equivalence between two floating-point matrices, as element-wise equivalence - use std::cmp::PartialEq; - impl PartialEq for FMat2 { - fn eq(&self, other: &FMat2) -> bool { - self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d - } - } - #[test] fn test_inverse() { assert_eq!( diff --git a/src/assignments/assignment03/custom_operators.rs b/src/assignments/assignment03/custom_operators.rs index 137547b..b1c7aea 100644 --- a/src/assignments/assignment03/custom_operators.rs +++ b/src/assignments/assignment03/custom_operators.rs @@ -16,7 +16,7 @@ pub enum MyOption { /// Converts an `MyOption` into an `MyOption`, consuming the original: /// /// ``` -/// use cs220::assignments::assignment03::{my_map, MyOption}; +/// use cs220::assignments::assignment03::custom_operators::*; /// /// fn len(s: String) -> usize { /// s.len() @@ -29,14 +29,15 @@ pub fn my_map U>(v: MyOption, f: F) -> MyOption { todo!() } -/// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and returns the result. +/// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and +/// returns the result. /// /// Some languages call this operation flatmap. /// /// # Examples /// /// ``` -/// use cs220::assignments::assignment03::{MyOption, my_and_then}; +/// use cs220::assignments::assignment03::custom_operators::*; /// /// fn pos_then_to_string(x: isize) -> MyOption { /// if x > 0 { @@ -54,21 +55,21 @@ pub fn my_and_then MyOption>(v: MyOption, f: F) -> M todo!() } -/// Custom operator: `option_op_or(v1, v2, f)` -/// If neither `v1` nor `v2` is `Some`, returns `None`. -/// If exactly one is `Some`, returns the same `Some` value. -/// If both are `Some`, apply the values inside `Some` to `f` and wrap the resulting value inside `Some`. +/// Custom operator: `option_op_or(v1, v2, f)`. If neither `v1` nor `v2` is `Some`, returns `None`. +/// If exactly one is `Some`, returns the same `Some` value. If both are `Some`, apply the values +/// inside `Some` to `f` and wrap the resulting value inside `Some`. /// /// # Examples /// /// ``` +/// use cs220::assignments::assignment03::custom_operators::*; /// fn product(a: i32, b: i32) -> i32 { /// a * b /// } /// -/// assert_eq!(option_op_or(None, None, product), None); -/// assert_eq!(option_op_or(Some(3), None, product), Some(3)); -/// assert_eq!(option_op_or(Some(3), Some(5), product), Some(15)); +/// assert_eq!(my_option_op_or(MyOption::MyNone, MyOption::MyNone, product), MyOption::MyNone); +/// assert_eq!(my_option_op_or(MyOption::MySome(3), MyOption::MyNone, product), MyOption::MySome(3)); +/// assert_eq!(my_option_op_or(MyOption::MySome(3), MyOption::MySome(5), product), MyOption::MySome(15)); /// ``` pub fn my_option_op_or T>( v1: MyOption, diff --git a/src/assignments/assignment03/custom_operators_grade.rs b/src/assignments/assignment03/custom_operators_grade.rs index c2dda4f..42eccd7 100644 --- a/src/assignments/assignment03/custom_operators_grade.rs +++ b/src/assignments/assignment03/custom_operators_grade.rs @@ -1,6 +1,7 @@ #[cfg(test)] mod test { - use crate::assignments::assignment03::custom_operators::{MyOption::*, *}; + use crate::assignments::assignment03::custom_operators::MyOption::*; + use crate::assignments::assignment03::custom_operators::*; #[test] fn test_my_map() { diff --git a/src/assignments/assignment03/mod.rs b/src/assignments/assignment03/mod.rs index 8128e3e..b0b411a 100644 --- a/src/assignments/assignment03/mod.rs +++ b/src/assignments/assignment03/mod.rs @@ -1,7 +1,7 @@ //! Assignment 3: Mastering common programming concepts (2/2) //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 3` works fine. -//! See `assignment03/*_grade.rs` and `/scripts/grade.sh 3` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 3` works +//! fine. See `assignment03/*_grade.rs` and `/scripts/grade.sh 3` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment03/parse_shell.rs b/src/assignments/assignment03/parse_shell.rs index 1016149..ed2d1f3 100644 --- a/src/assignments/assignment03/parse_shell.rs +++ b/src/assignments/assignment03/parse_shell.rs @@ -1,19 +1,22 @@ //! Parsing a shell command. //! //! Shell commands are text-based instructions that you can enter in a command-line interface (CLI) -//! to interact with operating systems (e.g. Linux) and others. -//! For example, you can use the `ls` command to list files in a directory. +//! to interact with operating systems (e.g. Linux) and others. For example, you can use the `ls` +//! command to list files in a directory. //! //! You will parse a given string consists of a small number of shell commands. /// Parse the string as a shell command. /// /// Usually, a shell command is whitespace-separated array of strings. +/// /// ```text /// cat file --> ["cat", "file"] /// ``` -/// But sometimes, you may want to include whitespaces in each argument. -/// In that case, you can use quotes. +/// +/// But sometimes, you may want to include whitespaces in each argument. In that case, you can use +/// quotes. +/// /// ```text /// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs'] /// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs'] diff --git a/src/assignments/assignment03/small_exercises.rs b/src/assignments/assignment03/small_exercises.rs index ed9d703..62a8381 100644 --- a/src/assignments/assignment03/small_exercises.rs +++ b/src/assignments/assignment03/small_exercises.rs @@ -55,16 +55,19 @@ pub fn median(values: Vec) -> Option { todo!() } -/// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash map will be helpful here). +/// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash +/// map will be helpful here). /// /// Returns `None` if the list is empty. pub fn mode(values: Vec) -> Option { todo!() } -/// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig Latin. +/// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig +/// Latin. /// -/// 1. If a word starts with a consonant and a vowel, move the first letter of the word at the end of the word and add "ay". +/// 1. If a word starts with a consonant and a vowel, move the first letter of the word at the end +/// of the word and add "ay". /// /// Example: "happy" -> "appyh" + "ay" -> "appyhay" /// @@ -99,7 +102,8 @@ pub fn piglatin(input: String) -> String { /// /// - The result is a map from department to the list of its employees. /// - An empty department should not appear in the result. -/// - There are three commands: "Add {person} to {department}", "Remove {person} from {department}", and "Move {person} from {department} to {department}". +/// - There are three commands: "Add {person} to {department}", "Remove {person} from {department}", +/// and "Move {person} from {department} to {department}". /// - If a command is not executable, then it's ignored. /// - There is no space in the name of the person and department. /// diff --git a/src/assignments/assignment04/context.rs b/src/assignments/assignment04/context.rs index 54c9632..62a7507 100644 --- a/src/assignments/assignment04/context.rs +++ b/src/assignments/assignment04/context.rs @@ -3,8 +3,9 @@ use std::collections::HashMap; use anyhow::*; +use etrace::*; -use super::syntax::{Command, Expression}; +use super::syntax::{BinOp, Command, Expression}; /// Calculator's context. #[derive(Debug, Default, Clone)] @@ -31,7 +32,8 @@ impl Context { /// Calculates the given command. (We assume the absence of overflow.) /// - /// If there is no variable lhs in the command (i.e. `command.variable = None`), its value should be stored at `$0`, `$1`, `$2`, ... respectively. + /// If there is no variable lhs in the command (i.e. `command.variable = None`), its value + /// should be stored at `$0`, `$1`, `$2`, ... respectively. /// /// # Example /// diff --git a/src/assignments/assignment04/mod.rs b/src/assignments/assignment04/mod.rs index a1857d2..cc7968f 100644 --- a/src/assignments/assignment04/mod.rs +++ b/src/assignments/assignment04/mod.rs @@ -1,8 +1,9 @@ //! Assignment 4: Designing a calculator. //! //! The primary goal of this assignment is twofold: -//! (1) understanding the `pest` third-party library from documentations; and -//! (2) using programming concepts you've learned so far to implement a simple arithmetic calculator. +//! - (1) understanding the `pest` third-party library from documentations; and +//! - (2) using programming concepts you've learned so far to implement a simple arithmetic +//! calculator. //! //! For `pest`, read the following documentations (that contain 90% of the solution): //! - @@ -11,8 +12,9 @@ //! //! For calculator, just reading `syntax.rs` would suffice for you to understand what to do. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 4` works fine. -//! See `assignment04/grade.rs` and `/scripts/grade.sh 4` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 4` works +//! fine. See `assignment04/grade.rs` and `/scripts/grade.sh 4` for the test script. +//! //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment04.zip` to . //! //! To submit, run diff --git a/src/assignments/assignment04/parser.rs b/src/assignments/assignment04/parser.rs index fbda622..4173270 100644 --- a/src/assignments/assignment04/parser.rs +++ b/src/assignments/assignment04/parser.rs @@ -2,8 +2,14 @@ //! Parser. +use anyhow::{bail, Result}; +use etrace::*; +use lazy_static::*; +use pest::iterators::{Pair, Pairs}; +use pest::prec_climber::*; +use pest::Parser; + use super::syntax::*; -use anyhow::Result; #[allow(missing_docs)] #[allow(missing_debug_implementations)] @@ -15,13 +21,16 @@ mod inner { pub(crate) struct SyntaxParser; } +use inner::*; + /// Parses command. /// /// ## Operator Associativty /// /// For associativity of each operator, please follow [here](https://docs.rs/pest/latest/pest/prec_climber/struct.PrecClimber.html#examples). /// -/// e.g. `1+2+3` should be parsed into `(1+2)+3`, not `1+(2+3)` because the associativity of plus("add" in our hw) operator is `Left`. +/// e.g. `1+2+3` should be parsed into `(1+2)+3`, not `1+(2+3)` because the associativity of +/// plus("add" in our hw) operator is `Left`. pub fn parse_command(line: &str) -> Result { todo!("fill here") } diff --git a/src/assignments/assignment06/mod.rs b/src/assignments/assignment06/mod.rs index 9d1f959..cc64fb2 100644 --- a/src/assignments/assignment06/mod.rs +++ b/src/assignments/assignment06/mod.rs @@ -2,8 +2,8 @@ //! //! The primary goal of this assignment is to understand generics, traits, and lifetimes. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 6` works fine. -//! See `assignment06/*_grade.rs` and `/scripts/grade.sh 6` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 6` works +//! fine. See `assignment06/*_grade.rs` and `/scripts/grade.sh 6` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment06/semiring.rs b/src/assignments/assignment06/semiring.rs index 57cb5bb..cc8c3d0 100644 --- a/src/assignments/assignment06/semiring.rs +++ b/src/assignments/assignment06/semiring.rs @@ -1,6 +1,9 @@ //! Semiring -use std::{collections::HashMap, fmt::Debug}; +use std::collections::HashMap; +use std::fmt::Debug; + +use itertools::Itertools; /// Semiring. /// @@ -147,10 +150,8 @@ impl From for Polynomial { /// /// Assumptions: /// - Each term is separated by ` + `. -/// - Each term is one of the following form: -/// `a`, `x`, `ax`, `x^n`, and `ax^n`, -/// where `a` is a `usize` number and `n` is a `u64` number. -/// This `a` should then be converted to a `C` type. +/// - Each term is one of the following form: `a`, `x`, `ax`, `x^n`, and `ax^n`, where `a` is a +/// `usize` number and `n` is a `u64` number. This `a` should then be converted to a `C` type. /// - In `a`, it is guaranteed that `a >= 1`. /// - In `ax` and `ax^n`, it is guaranteed that `a >= 2`. /// - In `x^n` and `ax^n`, it is guaranteed that `n >= 2`. diff --git a/src/assignments/assignment06/semiring_grade.rs b/src/assignments/assignment06/semiring_grade.rs index 3b553a6..2979fb8 100644 --- a/src/assignments/assignment06/semiring_grade.rs +++ b/src/assignments/assignment06/semiring_grade.rs @@ -1,8 +1,9 @@ #[cfg(test)] mod test { - use crate::assignments::assignment06::semiring::*; use ntest::assert_about_eq; + use crate::assignments::assignment06::semiring::*; + fn test_from_str(s: &str, f: impl Fn(i64) -> i64) { let poly = s.parse::>().unwrap(); for i in 0..10 { diff --git a/src/assignments/assignment06/symbolic_differentiation.rs b/src/assignments/assignment06/symbolic_differentiation.rs index f46c5fc..a109e40 100644 --- a/src/assignments/assignment06/symbolic_differentiation.rs +++ b/src/assignments/assignment06/symbolic_differentiation.rs @@ -5,10 +5,12 @@ use std::ops::*; /// Rational number represented by two isize, numerator and denominator. /// -/// Each Rational number should be normalized so that `demoninator` is nonnegative and `numerator` and `demoninator` are coprime. -/// See `normalize` for examples. As a corner case, 0 is represented by Rational { numerator: 0, demoninator: 0 }. +/// Each Rational number should be normalized so that `demoninator` is nonnegative and `numerator` +/// and `demoninator` are coprime. See `normalize` for examples. As a corner case, 0 is represented +/// by `Rational { numerator: 0, demoninator: 0 }`. /// -/// For "natural use", Rational also overloads standard arithmetic operations, i.e, `+`, `-`, `*`, `/`. +/// For "natural use", it also overloads standard arithmetic operations, i.e, `+`, `-`, `*`, and +/// `/`. /// /// See [here](https://doc.rust-lang.org/core/ops/index.html) for details. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -96,9 +98,9 @@ pub enum SingletonPolynomial { Const(Rational), /// Non-const polynomial. Polynomial { - /// coefficent of polynomial. Must be non-zero. + /// Coefficent of polynomial. Must be non-zero. coeff: Rational, - /// power of polynomial. Must be non-zero. + /// Power of polynomial. Must be non-zero. power: Rational, }, } @@ -156,7 +158,7 @@ pub enum Trignometric { /// Coefficent coeff: Rational, }, - /// Sine function. + /// Cosine function. Cosine { /// Coefficent coeff: Rational, diff --git a/src/assignments/assignment06/symbolic_differentiation_grade.rs b/src/assignments/assignment06/symbolic_differentiation_grade.rs index 3766e04..9842325 100644 --- a/src/assignments/assignment06/symbolic_differentiation_grade.rs +++ b/src/assignments/assignment06/symbolic_differentiation_grade.rs @@ -1,8 +1,9 @@ #[cfg(test)] mod test { - use crate::assignments::assignment06::symbolic_differentiation::*; use ntest::assert_about_eq; + use crate::assignments::assignment06::symbolic_differentiation::*; + // Constant rationals to use const TWO: Rational = Rational::new(2, 1); const FOUR: Rational = Rational::new(4, 1); @@ -172,7 +173,7 @@ mod test { // Mult // // d/dx (2x^4 * cos(x) * exp(x)) = - // 8x^3 * cos(x) * exp(x) - 2x^4 * sin(x) * exp(x) + 2x^4 * cos(x) * exp(x) + // 8x^2 * cos(x) * exp(x) - 2x^4 * sin(x) * exp(x) + 2x^4 * cos(x) * exp(x) let f1 = SingletonPolynomial::new_poly(TWO, FOUR); let f2 = Trignometric::new_cosine(ONE); let f3 = Exp::new(); diff --git a/src/assignments/assignment07/mod.rs b/src/assignments/assignment07/mod.rs index 19f264e..09e3cbc 100644 --- a/src/assignments/assignment07/mod.rs +++ b/src/assignments/assignment07/mod.rs @@ -2,8 +2,8 @@ //! //! The primary goal of this assignment is to understand generics, traits, and lifetimes. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 7` works fine. -//! See `assignment07/*_grade.rs` and `/scripts/grade.sh 7` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 7` works +//! fine. See `assignment07/*_grade.rs` and `/scripts/grade.sh 7` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment07/my_itertools.rs b/src/assignments/assignment07/my_itertools.rs index 9e2efcf..85dae05 100644 --- a/src/assignments/assignment07/my_itertools.rs +++ b/src/assignments/assignment07/my_itertools.rs @@ -1,9 +1,10 @@ //! Implement your own minimal `itertools` crate. +use std::collections::HashSet; use std::hash::Hash; /// Iterator that iterates over the given iterator and returns only unique elements. -#[allow(missing_debug_implementations)] +#[derive(Debug)] pub struct Unique { // TODO: remove `_marker` and add necessary fields as you want _marker: std::marker::PhantomData, @@ -21,7 +22,7 @@ where } /// Iterator that chains two iterators together. -#[allow(missing_debug_implementations)] +#[derive(Debug)] pub struct Chain { // TODO: remove `_marker` and add necessary fields as you want _marker: std::marker::PhantomData<(I1, I2)>, @@ -38,7 +39,7 @@ impl, I2: Iterator> Itera } /// Iterator that iterates over given iterator and enumerates each element. -#[allow(missing_debug_implementations)] +#[derive(Debug)] pub struct Enumerate { // TODO: remove `_marker` and add necessary fields as you want _marker: std::marker::PhantomData, @@ -56,7 +57,7 @@ impl Iterator for Enumerate { /// /// If one iterator is longer than the other one, the remaining elements for the longer element /// should be ignored. -#[allow(missing_debug_implementations)] +#[derive(Debug)] pub struct Zip { // TODO: remove `_marker` and add necessary fields as you want _marker: std::marker::PhantomData<(I1, I2)>, diff --git a/src/assignments/assignment07/small_exercises.rs b/src/assignments/assignment07/small_exercises.rs index e3fd530..4555360 100644 --- a/src/assignments/assignment07/small_exercises.rs +++ b/src/assignments/assignment07/small_exercises.rs @@ -47,7 +47,8 @@ where } /// Returns and iterator over the generic fibonacci sequence starting from `first` and `second`. -/// This is a generic version of `fibonacci` function, which works for any types that implements `std::ops::Add` trait. +/// This is a generic version of `fibonacci` function, which works for any types that implements +/// `std::ops::Add` trait. pub fn fib(first: T, second: T) -> impl Iterator where T: std::ops::Add + Copy, diff --git a/src/assignments/assignment08/church.rs b/src/assignments/assignment08/church.rs index 251fda4..1e99fa6 100644 --- a/src/assignments/assignment08/church.rs +++ b/src/assignments/assignment08/church.rs @@ -9,6 +9,7 @@ //! - //! - +use std::cell::RefCell; use std::rc::Rc; /// Church numerals are represented as higher-order functions that take a function `f` @@ -51,8 +52,9 @@ pub fn mult(n: Church, m: Church) -> Church { /// This is the Church numeral equivalent of the natural number operation of exponentiation. /// Given two natural numbers `n` and `m`, the function should return a Church numeral /// that represents `n` to the power of `m`. The key is to convert `n` and `m` to Church numerals, -/// and then apply the Church numeral for `m` (the exponent) to the Church numeral for `n` (the base). -/// Note: This function should be implemented *WITHOUT* using the `to_usize` or any `pow`-like method. +/// and then apply the Church numeral for `m` (the exponent) to the Church numeral for `n` (the +/// base). Note: This function should be implemented *WITHOUT* using the `to_usize` or any +/// `pow`-like method. pub fn exp(n: usize, m: usize) -> Church { // ACTION ITEM: Uncomment the following lines and replace `todo!()` with your code. // let n = from_usize(n); diff --git a/src/assignments/assignment08/mod.rs b/src/assignments/assignment08/mod.rs index 909844f..ea4c78d 100644 --- a/src/assignments/assignment08/mod.rs +++ b/src/assignments/assignment08/mod.rs @@ -2,8 +2,8 @@ //! //! The primary goal of this assignment is to get used to first-class functions. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 8` works fine. -//! See `assignment08/*_grade.rs` and `/scripts/grade.sh 8` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 8` works +//! fine. See `assignment08/*_grade.rs` and `/scripts/grade.sh 8` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment08/small_exercises.rs b/src/assignments/assignment08/small_exercises.rs index 829d5a7..2fb8860 100644 --- a/src/assignments/assignment08/small_exercises.rs +++ b/src/assignments/assignment08/small_exercises.rs @@ -15,7 +15,8 @@ pub fn repeat T>(n: usize, mut f: F) -> impl FnMut(T) -> T { /// /// Applies the given function `f` for `i` times for the `i`-th element of the given vector. /// -/// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), f(f(f(v3)))]`. +/// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), +/// f(f(f(v3)))]`. /// /// Refer `test_funny_map` in `assignment08_grade.rs` for detailed examples. pub fn funny_map T>(f: F, vs: Vec) -> Vec { @@ -24,9 +25,8 @@ pub fn funny_map T>(f: F, vs: Vec) -> Vec { /// Count Repeat /// -/// Returns the number of the elements of the set -/// {x, f(x), f(f(x)), f(f(f(x))), ...}. -/// You may assume that the answer is finite and small enough. +/// Returns the number of the elements in the set {`x`, `f(x)`, `f(f(x))`, `f(f(f(x)))`, ...}. You +/// may assume that the answer is finite and small enough. /// /// Refer `test_count_repeat` in `assignment08_grade.rs` for detailed examples. pub fn count_repeat T>(f: F, x: T) -> usize diff --git a/src/assignments/assignment09/bigint.rs b/src/assignments/assignment09/bigint.rs index b1a1f51..4df36fa 100644 --- a/src/assignments/assignment09/bigint.rs +++ b/src/assignments/assignment09/bigint.rs @@ -1,7 +1,8 @@ //! Big integer with infinite precision. use std::fmt; -use std::{iter::zip, ops::*}; +use std::iter::zip; +use std::ops::*; /// An signed integer with infinite precision implemented with an "carrier" vector of `u32`s. /// @@ -15,15 +16,17 @@ use std::{iter::zip, ops::*}; /// /// You will implement the `Add` and `Sub` trait for this type. /// -/// Unlike standard fix-sized intergers in Rust where overflow will panic, the carrier is extended to save the overflowed bit. -/// On the contrary, if the precision is too much (e.g, vec![0,0] is used to represent 0, where `vec![0]` is sufficent), the carrier is truncated. +/// Unlike standard fix-sized intergers in Rust where overflow will panic, the carrier is extended +/// to save the overflowed bit. On the contrary, if the precision is too much (e.g, vec![0,0] is +/// used to represent 0, where `vec![0]` is sufficent), the carrier is truncated. /// /// See [this section](https://en.wikipedia.org/wiki/Two%27s_complement#Arithmetic_operations) for a rouge guide on implementation, /// while keeping in mind that the carrier should be extended to deal with overflow. /// /// The `sign_extension()`, `two_complement()`, and `truncate()` are non-mandatory helper methods. /// -/// For testing and debugging pruposes, the `Display` trait is implemented for you, which shows the integer in hexadecimal form. +/// For testing and debugging pruposes, the `Display` trait is implemented for you, which shows the +/// integer in hexadecimal form. #[derive(Debug, Clone)] pub struct BigInt { /// The carrier for `BigInt`. @@ -39,6 +42,10 @@ impl BigInt { } /// Creates a new `BigInt` from a `Vec`. + /// + /// # Panic + /// + /// Panics if `carrier` is empty. pub fn new_large(carrier: Vec) -> Self { assert!(!carrier.is_empty()); todo!() diff --git a/src/assignments/assignment09/bigint_grade.rs b/src/assignments/assignment09/bigint_grade.rs index 02be492..e88ce01 100644 --- a/src/assignments/assignment09/bigint_grade.rs +++ b/src/assignments/assignment09/bigint_grade.rs @@ -43,7 +43,7 @@ mod test { #[test] #[should_panic] fn test_inf_prec_panic() { - let _ = BigInt::new_large(vec![]); + let _unused = BigInt::new_large(vec![]); } #[test] diff --git a/src/assignments/assignment09/matmul.rs b/src/assignments/assignment09/matmul.rs index 2675312..ec7c39a 100644 --- a/src/assignments/assignment09/matmul.rs +++ b/src/assignments/assignment09/matmul.rs @@ -7,7 +7,7 @@ use itertools::*; /// # Example /// /// ``` -/// use cs220::assignments::assignment09::vec_add; +/// use cs220::assignments::assignment09::matmul::*; /// /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; @@ -23,10 +23,10 @@ pub fn vec_add(lhs: &[f64], rhs: &[f64]) -> Vec { /// You don't know how to calculate dot product? /// See /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment09::dot_product; +/// use cs220::assignments::assignment09::matmul::*; /// /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; @@ -48,10 +48,10 @@ pub fn dot_product(lhs: &[f64], rhs: &[f64]) -> f64 { /// - rhs: (p, n) /// - output: (m, p) /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment09::matmul; +/// use cs220::assignments::assignment09::matmul::*; /// /// let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; /// let mat2 = vec![ diff --git a/src/assignments/assignment09/matmul_grade.rs b/src/assignments/assignment09/matmul_grade.rs index 83efd14..e7fe1db 100644 --- a/src/assignments/assignment09/matmul_grade.rs +++ b/src/assignments/assignment09/matmul_grade.rs @@ -1,11 +1,12 @@ #[cfg(test)] mod test { - use crate::assignments::assignment09::matmul::*; - use approx::*; use itertools::Itertools; use ndarray::prelude::*; - use ndarray_rand::{rand_distr::Uniform, RandomExt}; + use ndarray_rand::rand_distr::Uniform; + use ndarray_rand::RandomExt; + + use crate::assignments::assignment09::matmul::*; #[test] fn vec_add_test() { diff --git a/src/assignments/assignment09/mod.rs b/src/assignments/assignment09/mod.rs index a805834..9d5d5d5 100644 --- a/src/assignments/assignment09/mod.rs +++ b/src/assignments/assignment09/mod.rs @@ -2,8 +2,8 @@ //! //! The primary goal of this assignment is to get used to iterators. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 9` works fine. -//! See `assignment09/*_grade.rs` and `/scripts/grade.sh 9` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 9` works +//! fine. See `assignment09/*_grade.rs` and `/scripts/grade.sh 9` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment09/small_exercises.rs b/src/assignments/assignment09/small_exercises.rs index b2950a4..f0af504 100644 --- a/src/assignments/assignment09/small_exercises.rs +++ b/src/assignments/assignment09/small_exercises.rs @@ -2,14 +2,17 @@ use std::collections::HashMap; -/// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's first two terms. +use itertools::Itertools; + +/// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's +/// first two terms. /// /// Returns `true` if the length of sequence is less or equal than 2. /// /// # Exmample /// /// ``` -/// use cs220::assignments::assignment09::is_fibonacci; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 13].into_iter()), true); /// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter()), false); @@ -20,10 +23,10 @@ pub fn is_fibonacci(inner: impl Iterator) -> bool { /// Returns the sum of `f(v)` for all element `v` the given array. /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment09::sigma; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!(sigma([1, 2].into_iter(), |x| x + 2), 7); /// assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); @@ -39,7 +42,7 @@ pub fn sigma i64>(inner: impl Iterator, f: F) -> i64 { /// # Example /// /// ``` -/// use cs220::assignments::assignment09::interleave3; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!( /// interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), @@ -61,7 +64,7 @@ pub fn interleave3( /// # Example /// /// ``` -/// use cs220::assignments::assignment09::interleave_n; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!( /// interleave_n(&mut [[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]), @@ -80,7 +83,7 @@ pub fn interleave_n( /// # Example /// /// ``` -/// use cs220::assignments::assignment09::k_smallest_mean; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!( /// k_smallest_mean(vec![1, 3, 2].into_iter(), 2), @@ -97,10 +100,10 @@ pub fn k_smallest_mean(inner: impl Iterator, k: usize) -> f64 { /// Returns mean for each class. /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment09::calculate_mean; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!( /// calculate_mean( @@ -135,7 +138,7 @@ pub fn calculate_mean(inner: impl Iterator) -> HashMap>, n: i64) -> usize { todo!() } -/// Returns a new vector that contains the item that appears `n` times in the input vector in increasing order. +/// Returns a new vector that contains the item that appears `n` times in the input vector in +/// increasing order. /// /// # Example /// /// ``` -/// use cs220::assignments::assignment09::find_count_n; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!(find_count_n(vec![1, 2], 1), vec![1, 2]); /// assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); @@ -175,10 +179,10 @@ pub fn find_count_n(inner: Vec, n: usize) -> Vec { /// - If the list is empty, returns `None`. /// - If several elements are equally median, the position of the first of them is returned. /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment09::position_median; +/// use cs220::assignments::assignment09::small_exercises::*; /// /// assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); /// assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); @@ -191,6 +195,8 @@ pub fn position_median(inner: Vec) -> Option { /// /// # Example /// ``` +/// use cs220::assignments::assignment09::small_exercises::*; +/// /// assert_eq!( /// two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()), /// 21 @@ -202,8 +208,10 @@ pub fn two_dimensional_sum(inner: impl Iterator /// Returns whether the given string is palindrome or not. /// -/// A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward. -/// We consider the empty string is palindrome. +/// A palindrome is a word, number, phrase, or other sequence of characters which reads the same +/// backward as forward. +/// +/// We consider the empty string as a palindrome. /// /// Consult . pub fn is_palindrome(s: String) -> bool { diff --git a/src/assignments/assignment10/labyrinth.rs b/src/assignments/assignment10/labyrinth.rs index 0b9e8e1..5829748 100644 --- a/src/assignments/assignment10/labyrinth.rs +++ b/src/assignments/assignment10/labyrinth.rs @@ -1,11 +1,11 @@ //! Labyrinth //! -//! Look at the `labyrinth_grade.rs` below before you start. +//! Look at `labyrinth_grade.rs` below before you start. //! HINT: //! //! NOTE: You will have to implement a probabilistic algorithm, which means, the algorithm can fail -//! even if you have implemented the solution. We recommend running multiple times (at least 5 times) to check your -//! solution works well. +//! even if you have implemented the solution. We recommend running multiple times (at least 5 +//! times) to check your solution works well. use std::cell::RefCell; @@ -26,8 +26,8 @@ impl Husband { Strategy { husband: self } } - /// Based on the information about currently visited room number and someone's wife ID trapped inside, - /// what the husband should do next? + /// Based on the information about currently visited room number and someone's wife ID trapped + /// inside, what the husband should do next? pub fn carefully_checks_whos_inside(&self, room: usize, wife: usize) { todo!() } diff --git a/src/assignments/assignment10/labyrinth_grade.rs b/src/assignments/assignment10/labyrinth_grade.rs index 30ff287..87fdfb3 100644 --- a/src/assignments/assignment10/labyrinth_grade.rs +++ b/src/assignments/assignment10/labyrinth_grade.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod test { + use rand::seq::SliceRandom; use rand::thread_rng; @@ -38,12 +39,13 @@ mod test { (0..WIVES).all(|his_wife| { // A new husband steps into the labyrinth to rescue his wife...! - let husband = Box::new(Husband::seeking(his_wife /*👩*/)); + let husband = Box::new(Husband::seeking(his_wife /* 👩 */)); let strategy = Box::new(husband.has_devised_a_strategy()); - #[allow(clippy::all)] - /* The Minotaur🐂 will arrive in */ - (0..50) /* steps... */ + // (Allow for better storytelling.) + #[allow(clippy::search_is_some)] + // The Minotaur🐂 will arrive in + (0..50) // steps... .zip(strategy) .find(|(_, room)| { // The husband contemplates his next move... 🤔 diff --git a/src/assignments/assignment10/mod.rs b/src/assignments/assignment10/mod.rs index c7bc775..1ad1a6d 100644 --- a/src/assignments/assignment10/mod.rs +++ b/src/assignments/assignment10/mod.rs @@ -1,8 +1,8 @@ //! Assignment 10: Iterators (2/2). //! The primary goal of this assignment is to get used to iterators. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 10` works fine. -//! See `assignment10/*_grade.rs` and `/scripts/grade.sh 10` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 10` works +//! fine. See `assignment10/*_grade.rs` and `/scripts/grade.sh 10` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment10/small_exercises.rs b/src/assignments/assignment10/small_exercises.rs index 4cb8f74..6bc92e0 100644 --- a/src/assignments/assignment10/small_exercises.rs +++ b/src/assignments/assignment10/small_exercises.rs @@ -1,10 +1,13 @@ //! Small exercises. +use std::collections::HashSet; + use itertools::*; /// Returns the pairs of `(i, j)` where `i < j` and `inner[i] > inner[j]` in increasing order. /// -/// For example, the inversions of `[3, 5, 1, 2, 4]` is `[(0, 2), (0, 3), (1, 2), (1, 3), (1, 4)]` because as follows: +/// For example, the inversions of `[3, 5, 1, 2, 4]` is `[(0, 2), (0, 3), (1, 2), (1, 3), (1, 4)]` +/// because as follows: /// /// - `0 < 2`, `inner[0] = 3 > 1 = inner[2]` /// - `0 < 3`, `inner[0] = 3 > 2 = inner[3]` @@ -108,7 +111,8 @@ pub enum File { /// |__c (Data, size: 8) /// ``` /// -/// Output: `[("a1", 1), ("a2", 3), ("b1", 3), ("a", 4), ("c", 8), ("b2", 15), ("b", 18), ("root", 30)]` +/// Output: `[("a1", 1), ("a2", 3), ("b1", 3), ("a", 4), ("c", 8), ("b2", 15), ("b", 18), ("root", +/// 30)]` pub fn du_sort(root: &File) -> Vec<(&str, usize)> { todo!() } @@ -118,12 +122,11 @@ pub fn du_sort(root: &File) -> Vec<(&str, usize)> { /// of returning a new vector. /// /// # Example -/// ``` +/// ```ignore /// let mut vec = vec![1, 2, 3, 4, 5]; /// remove_even(&mut vec); /// assert_eq!(*vec, vec![1, 3, 5]); /// ``` -#[allow(clippy::ptr_arg)] pub fn remove_even(inner: &mut Vec) { todo!() } @@ -135,12 +138,11 @@ pub fn remove_even(inner: &mut Vec) { /// Also, note that the order does not matter. /// /// # Example -/// ``` +/// ```ignore /// let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7]; /// remove_duplicate(&mut vec); /// assert_eq!(*vec, vec![1, 2, 3, 7, 5]); /// ``` -#[allow(clippy::ptr_arg)] pub fn remove_duplicate(inner: &mut Vec) { todo!() } @@ -153,6 +155,7 @@ pub fn remove_duplicate(inner: &mut Vec) { /// /// # Example /// +/// ```text /// table1 table2 /// ---------------------- ---------------------- /// 20230001 | Jack 20230001 | CS @@ -165,11 +168,12 @@ pub fn remove_duplicate(inner: &mut Vec) { /// 20230001 | Jack | CS /// 20230001 | Jack | EE /// 20231234 | Mike | ME -/// +/// ``` pub fn natural_join(table1: Vec>, table2: Vec>) -> Vec> { todo!() } +/// You can freely add more fields. struct Pythagorean; impl Pythagorean { @@ -187,7 +191,8 @@ impl Iterator for Pythagorean { } /// Generates sequence of unique [primitive Pythagorean triples](https://en.wikipedia.org/wiki/Pythagorean_triple), -/// i.e. (a,b,c) such that a² + b² = c², a and b are coprimes, and a < b. Generate in the increasing order of c. +/// i.e. (a,b,c) such that a² + b² = c², a and b are coprimes, and a < b. Generate in the increasing +/// order of c. pub fn pythagorean() -> impl Iterator { Pythagorean::new() } diff --git a/src/assignments/assignment10/small_exercises_grade.rs b/src/assignments/assignment10/small_exercises_grade.rs index a382146..d3a024f 100644 --- a/src/assignments/assignment10/small_exercises_grade.rs +++ b/src/assignments/assignment10/small_exercises_grade.rs @@ -322,17 +322,11 @@ mod test { (68, 285, 293), ]; - let mut pythagorean_iter = pythagorean(); - for i in 0..1000 { - let t = pythagorean_iter.next(); - assert!(t.is_some()); - - let (a, b, c) = t.unwrap(); - assert_eq!(a * a + b * b, c * c); - + for (i, (a, b, c)) in pythagorean().enumerate().take(1000) { if i < pythagoreans.len() { assert_eq!(pythagoreans[i], (a, b, c)) } + assert_eq!(a * a + b * b, c * c); } } } diff --git a/src/assignments/assignment11/graph.rs b/src/assignments/assignment11/graph.rs index 08f8122..441b8a5 100644 --- a/src/assignments/assignment11/graph.rs +++ b/src/assignments/assignment11/graph.rs @@ -12,6 +12,10 @@ //! //! Refer `graph_grade.rs` for test cases. +use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; + #[derive(PartialEq, Eq, Debug)] enum VisitStatus { Unvisited, @@ -20,11 +24,12 @@ enum VisitStatus { } /// Handle to a graph node. +/// /// `NodeHandle` should implement `Clone`, which clones the handle without cloning the underlying /// node. That is, there can be multiple handles to the same node. /// The user can access the node through a handle if it does not violate Rust's aliasing rules. /// -/// TODO: You can freely add fields to this struct. +/// You can freely add fields to this struct. #[derive(Debug, Clone)] pub struct NodeHandle; @@ -34,7 +39,7 @@ pub struct GraphError; /// Subgraph /// -/// TODO: You can freely add fields to this struct. +/// You can freely add fields to this struct. #[derive(Debug)] pub struct SubGraph; @@ -45,23 +50,24 @@ impl NodeHandle { } /// Adds an edge to `to`. - /// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`. - /// Returns `Ok(true)` if the edge is successfully added. + /// If the modification cannot be done, e.g. because of aliasing issues, returns + /// `Err(GraphError)`. Returns `Ok(true)` if the edge is successfully added. /// Returns `Ok(false)` if an edge to `to` already exits. pub fn add_edge(&self, to: NodeHandle) -> Result { todo!() } /// Removes the edge to `to`. - /// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`. - /// Returns `Ok(true)` if the edge is successfully removed. + /// If the modification cannot be done, e.g. because of aliasing issues, returns + /// `Err(GraphError)`. Returns `Ok(true)` if the edge is successfully removed. /// Returns `Ok(false)` if an edge to `to` does not exist. pub fn remove_edge(&self, to: &NodeHandle) -> Result { todo!() } /// Removes all edges. - /// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`. + /// If the modification cannot be done, e.g. because of aliasing issues, returns + /// `Err(GraphError)`. pub fn clear_edges(&self) -> Result<(), GraphError> { todo!() } @@ -84,7 +90,7 @@ impl SubGraph { todo!() } - /// Removes a node from the subgraph. Returns true iff the node is successfully removed. + /// Adds a node to the subgraph. Returns true iff the node is successfully removed. pub fn remove_node(&mut self, node: &NodeHandle) -> bool { todo!() } diff --git a/src/assignments/assignment11/tv_room.rs b/src/assignments/assignment11/tv_room.rs index 1e9dbd0..d1ae8b6 100644 --- a/src/assignments/assignment11/tv_room.rs +++ b/src/assignments/assignment11/tv_room.rs @@ -1,6 +1,7 @@ //! TV Room Simulator. //! -//! People can come to the TV room and watch TV. There are two types of TV watchers, manager and guest. +//! People can come to the TV room and watch TV. There are two types of TV watchers, manager and +//! guest. //! //! The rule of the TV room is as follows: //! @@ -9,8 +10,9 @@ //! - Manager can leave the TV room earlier than guests. //! - The TV room closes when the last person left the TV room. //! -//! Both `Manager` and `Guest` have `Rc` as a field, and its reference count indicates the number of people in -//! the TV room. When the 'Manager' and 'Guest' object is dropped, it means that the person leaves the TV room. +//! Both `Manager` and `Guest` have `Rc` as a field, and its reference count indicates the +//! number of people in the TV room. When the 'Manager' and 'Guest' object is dropped, it means that +//! the person leaves the TV room. //! //! Consult the following documentations: //! - @@ -18,7 +20,8 @@ //! //! Refer `tv_room_grade.rs` for test cases. -use std::{cell::RefCell, rc::Rc}; +use std::cell::RefCell; +use std::rc::Rc; #[derive(Debug, Clone, Copy)] enum TVRoomState { diff --git a/src/assignments/assignment12/card.rs b/src/assignments/assignment12/card.rs index c7f6e51..331c33f 100644 --- a/src/assignments/assignment12/card.rs +++ b/src/assignments/assignment12/card.rs @@ -8,10 +8,8 @@ //! //! Have fun! -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; /// Color represents the color of the card. /// The color of a card can be either Blue or White. diff --git a/src/assignments/assignment12/card_grade.rs b/src/assignments/assignment12/card_grade.rs index 8828a31..8bd801c 100644 --- a/src/assignments/assignment12/card_grade.rs +++ b/src/assignments/assignment12/card_grade.rs @@ -2,13 +2,13 @@ #[cfg(test)] mod test_card { - use crate::assignments::assignment12::card::*; - use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Barrier, Mutex}; use std::thread; use std::time::Duration; + use crate::assignments::assignment12::card::*; + const NUM_CARDS: usize = 10000; const DURATION: u64 = 20; const NUM_ENEMIES: usize = 25; @@ -60,7 +60,7 @@ mod test_card { fn play() { let ground = Ground::new(); let barrier = Arc::new(Barrier::new( - NUM_ENEMIES + 1 /*Player*/ + 1, /*Referee*/ + NUM_ENEMIES + 1 /*Player*/ + 1, /* Referee */ )); let playing = Arc::new(AtomicBool::new(true)); diff --git a/src/assignments/assignment12/demux.rs b/src/assignments/assignment12/demux.rs index 2d98008..86b5d11 100644 --- a/src/assignments/assignment12/demux.rs +++ b/src/assignments/assignment12/demux.rs @@ -1,6 +1,7 @@ //! Demultiplexing sender //! -//! Implement demultiplexing sender +//! Implement a demultiplexing sender. +//! //! Demultiplexer, `Demux` in short, is a device that has one input and many outputs. //! It distributes the input to the outputs according to the control signal. //! It is used when a circuit wishes to send a signal to one of many devices. diff --git a/src/assignments/assignment12/demux_grade.rs b/src/assignments/assignment12/demux_grade.rs index 145ff0e..0229414 100644 --- a/src/assignments/assignment12/demux_grade.rs +++ b/src/assignments/assignment12/demux_grade.rs @@ -2,12 +2,13 @@ #[cfg(test)] mod test_demux { - use crate::assignments::assignment12::demux::*; - use ntest::timeout; - use std::sync::mpsc::channel; use std::thread; + use ntest::timeout; + + use crate::assignments::assignment12::demux::*; + #[test] #[timeout(5000)] fn test_demux() { diff --git a/src/assignments/assignment12/funnel.rs b/src/assignments/assignment12/funnel.rs index 8b050e8..8cf6dcf 100644 --- a/src/assignments/assignment12/funnel.rs +++ b/src/assignments/assignment12/funnel.rs @@ -1,17 +1,19 @@ //! Funnel //! //! Spawn a thread that executes a funnel. -//! Funnel will receive data from multiple receivers and send it to a single sender. -//! Also, the funnel will filter out data that does not pass the filter function. //! -//! Refer `funnel_grade.rs` for test cases +//! Funnel will receive data from multiple receivers and send it to a single sender. Also, the +//! funnel will filter out data that does not pass the filter function. +//! +//! Refer to `funnel_grade.rs` for test cases. use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::Arc; use std::thread; use std::thread::JoinHandle; -/// Spawn a thread that concurrently receive datas from `rxs`, send it to `tx` if it makes `f` true. Returns its handle. +/// Spawn a thread that concurrently receive datas from `rxs`, send it to `tx` if it makes `f` true. +/// Returns its handle. pub fn spawn_funnel(rxs: Vec>, tx: Sender, f: F) -> JoinHandle<()> where T: Send + 'static, diff --git a/src/assignments/assignment12/funnel_grade.rs b/src/assignments/assignment12/funnel_grade.rs index 6672419..b327832 100644 --- a/src/assignments/assignment12/funnel_grade.rs +++ b/src/assignments/assignment12/funnel_grade.rs @@ -2,12 +2,13 @@ #[cfg(test)] mod test_funnel { - use crate::assignments::assignment12::funnel::*; - use ntest::timeout; - use std::sync::mpsc::channel; use std::thread; + use ntest::timeout; + + use crate::assignments::assignment12::funnel::*; + #[test] #[timeout(5000)] fn test_funnel_concurrent() { diff --git a/src/assignments/assignment12/mod.rs b/src/assignments/assignment12/mod.rs index 0c623e0..d06ce46 100644 --- a/src/assignments/assignment12/mod.rs +++ b/src/assignments/assignment12/mod.rs @@ -2,8 +2,8 @@ //! //! The primary goal of this assignment is to get used to concurrency. //! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 12` works fine. -//! See `assignment12/*_grade.rs` and `/scripts/grade.sh 12` for the test script. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 12` works +//! fine. See `assignment12/*_grade.rs` and `/scripts/grade.sh 12` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment12/small_exercises.rs b/src/assignments/assignment12/small_exercises.rs index 121b670..035ac36 100644 --- a/src/assignments/assignment12/small_exercises.rs +++ b/src/assignments/assignment12/small_exercises.rs @@ -1,5 +1,3 @@ -#![allow(single_use_lifetimes)] - //! Small exercises //! //! Refer `small_exercises_grade.rs` for test cases @@ -12,16 +10,18 @@ use etrace::*; /// The "pong" function /// /// Data will be sent and received through `rx` and `tx`. -/// Read the `test_ping_pong` function in `small_exercises_grade.rs` to figure out what it should do. +/// Read the `test_ping_pong` function in `small_exercises_grade.rs` to figure out what it should +/// do. pub fn pong(rx1: &mut Receiver, tx2: &mut Sender) -> bool { todo!() } /// Executes the given functions (f1, f2) in concurrent and returns the results. /// -/// Read the `test_scoped_thread` function in `small_exercises_grade.rs` to figure out what it should do. -pub fn use_scoped_thread<'scope, 'env, T1, T2, F1, F2>( - s: &'scope thread::Scope<'scope, 'env>, +/// Read the `test_scoped_thread` function in `small_exercises_grade.rs` to figure out what it +/// should do. +pub fn use_scoped_thread<'scope, T1, T2, F1, F2>( + s: &'scope thread::Scope<'scope, '_>, f1: F1, f2: F2, ) -> (T1, T2) diff --git a/src/assignments/assignment12/small_exercises_grade.rs b/src/assignments/assignment12/small_exercises_grade.rs index b9f59e8..c7b1653 100644 --- a/src/assignments/assignment12/small_exercises_grade.rs +++ b/src/assignments/assignment12/small_exercises_grade.rs @@ -2,12 +2,13 @@ #[cfg(test)] mod test_pingpong { - use crate::assignments::assignment12::small_exercises::*; - use ntest::timeout; - use std::sync::mpsc::channel; use std::thread; + use ntest::timeout; + + use crate::assignments::assignment12::small_exercises::*; + #[test] fn test_ping_pong() { let (tx1, mut rx1) = channel(); diff --git a/src/assignments/assignment13/mod.rs b/src/assignments/assignment13/mod.rs index e0eac42..087c02e 100644 --- a/src/assignments/assignment13/mod.rs +++ b/src/assignments/assignment13/mod.rs @@ -2,9 +2,10 @@ //! //! The primary goal of this assignment is to get used to data parallelism. //! -//! Refer to your solution for assignment 09. You will implement the parallelized version of assignment 09. -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 13` works fine. -//! See `assignment13/small_exercises_grade.rs` and `/scripts/grade.sh 13` for the test script. +//! Refer to your solution for assignment 09. You will implement the parallelized version of +//! assignment 09. You should fill out the `todo!()` placeholders in such a way that +//! `/scripts/grade.sh 13` works fine. See `assignment13/small_exercises_grade.rs` and +//! `/scripts/grade.sh 13` for the test script. //! //! To submit, run //! ```bash diff --git a/src/assignments/assignment13/small_exercises.rs b/src/assignments/assignment13/small_exercises.rs index f37e52a..9c282a5 100644 --- a/src/assignments/assignment13/small_exercises.rs +++ b/src/assignments/assignment13/small_exercises.rs @@ -1,19 +1,15 @@ //! Assignment 13: Parallelism. //! -//! If you did well on assignment 09, you will do well on this assignment. -//! Take it easy! +//! If you did well on assignment 09, you will do well on this assignment. Take it easy! use rayon::prelude::*; -// Use this function if you want. -use crate::assignments::assignment09::matmul::dot_product; - /// Returns the sum of `f(v)` for all element `v` the given array. /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment13::sigma; +/// use cs220::assignments::assignment13::small_exercises::*; /// use rayon::iter::IntoParallelIterator; /// /// assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x + 2), 7); @@ -31,7 +27,7 @@ pub fn sigma_par i64 + Sync + Send>( /// # Example /// /// ``` -/// use cs220::assignments::assignment13::interleave3; +/// use cs220::assignments::assignment13::small_exercises::*; /// use rayon::iter::IntoParallelIterator; /// /// assert_eq!( @@ -49,10 +45,10 @@ pub fn interleave3_par( /// Parallel vector addition /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment13::vec_add_par; +/// use cs220::assignments::assignment13::small_exercises::*; /// /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; @@ -68,10 +64,10 @@ pub fn vec_add_par(lhs: &[f64], rhs: &[f64]) -> Vec { /// You don't know how to calculate dot product? /// See /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment13::dot_product_par; +/// use cs220::assignments::assignment13::small_exercises::*; /// /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; @@ -93,10 +89,10 @@ pub fn dot_product_par(lhs: &[f64], rhs: &[f64]) -> f64 { /// - rhs: (p, n) /// - output: (m, p) /// -/// # Exmaple +/// # Example /// /// ``` -/// use cs220::assignments::assignment13::matmul_par; +/// use cs220::assignments::assignment13::small_exercises::*; /// /// let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; /// let mat2 = vec![ diff --git a/src/assignments/assignment13/small_exercises_grade.rs b/src/assignments/assignment13/small_exercises_grade.rs index 72318d5..22dbef0 100644 --- a/src/assignments/assignment13/small_exercises_grade.rs +++ b/src/assignments/assignment13/small_exercises_grade.rs @@ -1,13 +1,17 @@ #[cfg(test)] mod test { - use crate::assignments::assignment09::matmul::*; - use crate::assignments::assignment13::small_exercises::*; + use std::hint; + use std::time::Instant; + use approx::*; use itertools::Itertools; use ndarray::prelude::*; - use ndarray_rand::{rand_distr::Uniform, RandomExt}; + use ndarray_rand::rand_distr::Uniform; + use ndarray_rand::RandomExt; use rayon::prelude::IntoParallelIterator; - use std::time::Instant; + + use crate::assignments::assignment09::matmul::*; + use crate::assignments::assignment13::small_exercises::*; #[test] fn test_sigma_par() { @@ -72,72 +76,66 @@ mod test { } #[test] - fn vec_add_correctness() { - // small test + fn vec_add_test() { let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; - let res = vec_add_par(&vec1, &vec2); + let res = vec_add(&vec1, &vec2); assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]); - // random test - let vec1 = Array::random(1000, Uniform::new(0., 10.)); - let vec2 = Array::random(1000, Uniform::new(0., 10.)); - - let res_par = vec_add_par(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); - - let ans = vec1 + vec2; - assert_eq!(Array::from_vec(res_par), ans); - } - - #[test] - fn vec_add_test_performance() { - for _ in 0..2 { - let vec1 = Array::random(500000, Uniform::new(0., 10.)); - let vec2 = Array::random(500000, Uniform::new(0., 10.)); + for _ in 0..5 { + let vec1 = hint::black_box(Array::random(5_000_000, Uniform::new(0., 10.))); + let vec2 = hint::black_box(Array::random(5_000_000, Uniform::new(0., 10.))); let now_seq = Instant::now(); - let res_seq = vec_add(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); + let res_seq = hint::black_box(vec_add( + hint::black_box(vec1.as_slice().unwrap()), + hint::black_box(vec2.as_slice().unwrap()), + )); let elapsed_seq = now_seq.elapsed(); let now_par = Instant::now(); - let res_par = vec_add_par(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); + let res_par = hint::black_box(vec_add_par( + hint::black_box(vec1.as_slice().unwrap()), + hint::black_box(vec2.as_slice().unwrap()), + )); let elapsed_par = now_par.elapsed(); + let ans = vec1 + vec2; + assert_eq!(Array::from_vec(res_seq), ans); + assert_eq!(Array::from_vec(res_par), ans); assert!(elapsed_par < elapsed_seq); } } #[test] - fn dot_product_correctness() { - // small test + fn dot_product_test() { let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; + let res_seq = dot_product(&vec1, &vec2); let res_par = dot_product_par(&vec1, &vec2); + assert_eq!(res_seq, 55.0); assert_eq!(res_par, 55.0); - // random test - let vec1 = Array::random(1000, Uniform::new(0., 10.)); - let vec2 = Array::random(1000, Uniform::new(0., 10.)); - - let res_par = dot_product_par(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); - - let _res = relative_eq!(res_par, vec1.dot(&vec2), epsilon = f64::EPSILON); - } - - #[test] - fn dot_product_performance() { - for _ in 0..2 { - let vec1 = Array::random(1000000, Uniform::new(0., 10.)); - let vec2 = Array::random(1000000, Uniform::new(0., 10.)); + for _ in 0..5 { + let vec1 = Array::random(500_000, Uniform::new(0., 10.)); + let vec2 = Array::random(500_000, Uniform::new(0., 10.)); let now_seq = Instant::now(); - let res_seq = dot_product(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); + let res_seq = hint::black_box(dot_product( + hint::black_box(vec1.as_slice().unwrap()), + hint::black_box(vec2.as_slice().unwrap()), + )); let elapsed_seq = now_seq.elapsed(); let now_par = Instant::now(); - let res_par = dot_product_par(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); + let res_par = hint::black_box(dot_product_par( + hint::black_box(vec1.as_slice().unwrap()), + hint::black_box(vec2.as_slice().unwrap()), + )); let elapsed_par = now_par.elapsed(); + let _res = relative_eq!(res_seq, vec1.dot(&vec2), epsilon = f64::EPSILON); + let _res = relative_eq!(res_par, vec1.dot(&vec2), epsilon = f64::EPSILON); assert!(elapsed_par < elapsed_seq); } } @@ -163,8 +161,7 @@ mod test { } #[test] - fn matmul_correctness() { - // small case + fn matmul_test() { let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; let mat2 = vec![ vec![7.0, 8.0, 9.0], @@ -176,72 +173,68 @@ mod test { vec![50.0, 68.0, 86.0, 104.0], vec![122.0, 167.0, 212.0, 257.0], ]; + let res_seq = matmul(&mat1, &mat2); let res_par = matmul_par(&mat1, &mat2); + assert_eq!(ans, res_seq); assert_eq!(ans, res_par); - let mat1 = Array::random((10, 10), Uniform::new(0., 10.)); - let mat2 = Array::random((10, 10), Uniform::new(0., 10.)); - let ans = mat1.dot(&mat2); - let mat2_transposed = mat2.t(); - - // Run parallel matrix multiplication - let now_par = Instant::now(); - let res_par = matmul_par( - mat1.axis_iter(Axis(0)) - .map(|row| row.to_vec()) - .collect::>() - .as_slice(), - mat2_transposed - .axis_iter(Axis(0)) - .map(|row| row.to_vec()) - .collect::>() - .as_slice(), - ); - let elapsed_par = now_par.elapsed(); - - for it in ans.iter().zip(vec_to_array(res_par).iter()) { - let (ans, par) = it; - let _res = relative_eq!(ans, par); - } - } - - #[test] - fn matmul_performance() { - for _ in 0..2 { + for _ in 0..5 { let mat1 = Array::random((500, 500), Uniform::new(0., 10.)); let mat2 = Array::random((500, 500), Uniform::new(0., 10.)); + let ans = mat1.dot(&mat2); let mat2_transposed = mat2.t(); // Run sequential matrix multiplication let now_seq = Instant::now(); - let res_seq = matmul( - mat1.axis_iter(Axis(0)) - .map(|row| row.to_vec()) - .collect::>() - .as_slice(), - mat2_transposed - .axis_iter(Axis(0)) - .map(|row| row.to_vec()) - .collect::>() - .as_slice(), - ); + let res_seq = hint::black_box(matmul( + hint::black_box( + mat1.axis_iter(Axis(0)) + .map(|row| row.to_vec()) + .collect::>() + .as_slice(), + ), + hint::black_box( + mat2_transposed + .axis_iter(Axis(0)) + .map(|row| row.to_vec()) + .collect::>() + .as_slice(), + ), + )); let elapsed_seq = now_seq.elapsed(); // Run parallel matrix multiplication let now_par = Instant::now(); - let res_par = matmul_par( - mat1.axis_iter(Axis(0)) - .map(|row| row.to_vec()) - .collect::>() - .as_slice(), - mat2_transposed - .axis_iter(Axis(0)) - .map(|row| row.to_vec()) - .collect::>() - .as_slice(), - ); + let res_par = hint::black_box(matmul_par( + hint::black_box( + mat1.axis_iter(Axis(0)) + .map(|row| row.to_vec()) + .collect::>() + .as_slice(), + ), + hint::black_box( + mat2_transposed + .axis_iter(Axis(0)) + .map(|row| row.to_vec()) + .collect::>() + .as_slice(), + ), + )); let elapsed_par = now_par.elapsed(); + // Check answer + for it in ans.iter().zip(vec_to_array(res_seq).iter()) { + let (ans, seq) = it; + let _res = relative_eq!(ans, seq); + } + for it in ans.iter().zip(vec_to_array(res_par).iter()) { + let (ans, par) = it; + let _res = relative_eq!(ans, par); + } + + // Check time + // println!("Sequential: {:?}", elapsed_seq); + // println!("Parallel: {:?}", elapsed_par); assert!(elapsed_par < elapsed_seq); } } diff --git a/src/bin/calc.rs b/src/bin/calc.rs index 55c2602..42f8a67 100644 --- a/src/bin/calc.rs +++ b/src/bin/calc.rs @@ -3,7 +3,6 @@ use std::io::{self, BufRead, Read}; use anyhow::Result; use clap::Parser; - use cs220::assignments::assignment04::*; struct Input<'a> { diff --git a/src/lib.rs b/src/lib.rs index 951d5ac..45e7169 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,31 +1,57 @@ //! KAIST CS220: Programming Principles -// # Tries to deny all lints (`rustc -W help`). -#![deny(absolute_paths_not_starting_with_crate)] -#![deny(anonymous_parameters)] -// #![deny(box_pointers)] -#![deny(deprecated_in_future)] -#![deny(explicit_outlives_requirements)] -#![deny(keyword_idents)] -#![deny(macro_use_extern_crate)] -#![deny(missing_debug_implementations)] -#![deny(non_ascii_idents)] -#![deny(rust_2018_idioms)] -#![deny(trivial_numeric_casts)] -// #![deny(unused_crate_dependencies)] // TODO: uncomment -#![deny(unused_extern_crates)] -#![deny(unused_import_braces)] -#![deny(unused_qualifications)] -#![deny(unused_results)] -#![deny(variant_size_differences)] #![deny(warnings)] -#![deny(rustdoc::invalid_html_tags)] -// #![deny(rustdoc::missing_doc_code_examples)] -#![deny(missing_docs)] #![deny(rustdoc::all)] -#![deny(unreachable_pub)] -#![deny(single_use_lifetimes)] -#![deny(unused_lifetimes)] -#![deny(unstable_features)] +// # Tries to deny all lints (`rustc -W help`). +#![deny( + absolute_paths_not_starting_with_crate, + // box_pointers, + deprecated_safe, + elided_lifetimes_in_paths, + explicit_outlives_requirements, + ffi_unwind_calls, + // fuzzy_provenance_casts, + // impl_trait_overcaptures, + keyword_idents, + keyword_idents_2018, + keyword_idents_2024, + let_underscore_drop, + // lossy_provenance_casts, + macro_use_extern_crate, + meta_variable_misuse, + missing_abi, + // missing_copy_implementations, + missing_debug_implementations, + missing_docs, + missing_unsafe_on_extern, + // multiple_supertrait_upcastable, + // must_not_suspend, + non_ascii_idents, + // non_exhaustive_omitted_patterns, + non_local_definitions, + redundant_lifetimes, + rust_2021_incompatible_closure_captures, + rust_2021_incompatible_or_patterns, + rust_2021_prefixes_incompatible_syntax, + rust_2021_prelude_collisions, + // rust_2024_incompatible_pat, + single_use_lifetimes, + trivial_casts, + trivial_numeric_casts, + unit_bindings, + unnameable_types, + unreachable_pub, + unsafe_code, + unsafe_op_in_unsafe_fn, + unstable_features, + // unused_crate_dependencies, + unused_extern_crates, + unused_import_braces, + unused_lifetimes, + unused_macro_rules, + unused_qualifications, + unused_results, + variant_size_differences +)] pub mod assignments; diff --git a/suppress_tsan.txt b/suppress_tsan.txt deleted file mode 100644 index e69de29..0000000