This commit is contained in:
Janggun Lee
2024-07-30 15:26:33 +09:00
parent d34f586e4d
commit af889722bc
64 changed files with 452 additions and 384 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
/target /target
rustfmt.toml
/.vscode

10
Cargo.lock generated
View File

@@ -190,12 +190,10 @@ dependencies = [
"ndarray", "ndarray",
"ndarray-rand", "ndarray-rand",
"ntest", "ntest",
"num-traits",
"pest", "pest",
"pest_derive", "pest_derive",
"rand", "rand",
"rayon", "rayon",
"thiserror",
] ]
[[package]] [[package]]
@@ -210,9 +208,9 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.12.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
@@ -298,9 +296,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]] [[package]]
name = "libm" name = "libm"
version = "0.2.7" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]] [[package]]
name = "matrixmultiply" name = "matrixmultiply"

View File

@@ -5,19 +5,33 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # 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] [dependencies]
anyhow = "1.0.86" anyhow = "1.0.86"
clap = { version = "4.5.11", features = ["derive"] } clap = { version = "4.5.11", features = ["derive"], optional = true }
etrace = "1.1.1" etrace = "1.1.1"
itertools = "0.13.0" itertools = "0.13.0"
lazy_static = "1.5.0" lazy_static = "1.5.0"
pest = "2.7.11" pest = "2.7.11"
pest_derive = "2.7.11" pest_derive = "2.7.11"
rayon = "1.10.0" rayon = "1.10.0"
thiserror = "1.0.63"
ntest = "0.9.3" ntest = "0.9.3"
approx = "0.5.1" approx = "0.5.1"
num-traits = "0.2.19"
ndarray = "0.15.6" ndarray = "0.15.6"
ndarray-rand = "0.14.0" ndarray-rand = "0.14.0"
rand = "0.8.5" rand = "0.8.5"

View File

@@ -12,7 +12,7 @@
- Announcements: in [issue tracker](https://github.com/kaist-cp/cs220/issues?q=is%3Aissue+is%3Aopen+label%3Aannouncement) - 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 assume you read each announcement within 24 hours.
+ We strongly recommend you to watch the repository. + 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. + Office Hours: Fri 9:00-10:00, Rm. 4441, Bldg. E3-1.
If you want to come, do so by 9:15. If you want to come, do so by 9:15.
See [below](https://github.com/kaist-cp/cs220#rules) for the office hour policy. See [below](https://github.com/kaist-cp/cs220#rules) for the office hour policy.

View File

@@ -27,7 +27,8 @@ module Max
for i = 0 to n-1 do for i = 0 to n-1 do
invariant { 0 <= max_idx <= n-1 } invariant { 0 <= max_idx <= n-1 }
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) (* 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 *) (* IMPORTANT: DON'T MODIFY THE BELOW LINES *)
if a[max_idx] < a[i] then max_idx <- i; if a[max_idx] < a[i] then max_idx <- i;
done; done;

View File

@@ -17,9 +17,9 @@ module Pascal
ensures { result >= 1 } ensures { result >= 1 }
= if k = 0 || k = n then 1 else comb (n-1) k + comb (n-1) (k-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. *) (* 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 let chooses (n : int) : array int
requires { n > 0 } requires { n > 0 }
ensures { forall i: int. ensures { forall i: int.
@@ -32,7 +32,8 @@ module Pascal
let new_row = Array.make (r+1) 1 in let new_row = Array.make (r+1) 1 in
for c = 1 to r-1 do for c = 1 to r-1 do
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) (* 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 *) (* IMPORTANT: DON'T MODIFY THE BELOW LINES *)
new_row[c] <- row[c-1] + row[c] new_row[c] <- row[c-1] + row[c]
done; done;

View File

@@ -7,7 +7,7 @@
# * RUNNERS: array of "cargo[_asan | _tsan] [--release]" # * RUNNERS: array of "cargo[_asan | _tsan] [--release]"
# * TIMEOUT: default 10s # * TIMEOUT: default 10s
rustup toolchain update stable nightly rustup toolchain update stable
echo_err() { echo_err() {
echo "$@" 1>&2 echo "$@" 1>&2
@@ -37,27 +37,6 @@ run_linters() {
} }
export -f run_linters export -f run_linters
# usage: cargo_asan [SUBCOMMAND] [OPTIONS] [-- <args>...]
# 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] # usage: _run_tests_with CARGO [OPTIONS]
# example: _run_tests_with cargo_tsan --release # example: _run_tests_with cargo_tsan --release
# Echos number of failed tests to stdout. # Echos number of failed tests to stdout.

View File

@@ -73,7 +73,6 @@ case $TEST_NAME in
TESTS=( TESTS=(
"assignments::assignment09::bigint_grade::test" "assignments::assignment09::bigint_grade::test"
"assignments::assignment09::small_exercises_grade::test" "assignments::assignment09::small_exercises_grade::test"
"assignments::assignment09::matmul_grade::test"
) )
;; ;;
TEST10) TEST10)

View File

@@ -15,16 +15,6 @@ for i in {01..13} ; do
zip -rj $BASEDIR/target/assignment05.zip $BASEDIR/assets/why3/assignment05 zip -rj $BASEDIR/target/assignment05.zip $BASEDIR/assets/why3/assignment05
continue continue
fi 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 if [ -f $BASEDIR/target/assignment$i.zip ]; then
rm $BASEDIR/target/assignment$i.zip rm $BASEDIR/target/assignment$i.zip
fi fi

View File

@@ -1,10 +1,11 @@
//! Assignment 1: Preparing Rust Development Environment. //! 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. //! The primary goal of this assignment is bringing up SSH, VSCode, and all the other necessary
//! Please make sure you're comfortable with developing Rust programs before moving on to the next assignments. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 1` works
//! See `assigment01/small_exercises_grade.rs` and `/scripts/grade.sh 1` for the test script. //! fine. See `assigment01/small_exercises_grade.rs` and `/scripts/grade.sh 1` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,8 +1,8 @@
//! Assignment 1: Preparing Rust Development Environment. //! 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. //! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade.sh 1`
//! See `small_problems_grade.rs` and `/scripts/grade.sh 1` for the test script. //! works fine. See `small_problems_grade.rs` and `/scripts/grade.sh 1` for the test script.
//! //!
//! Hint: <https://doc.rust-lang.org/std/primitive.usize.html> //! Hint: <https://doc.rust-lang.org/std/primitive.usize.html>

View File

@@ -1,10 +1,11 @@
//! Assignment 2: Mastering common programming concepts (1/2). //! 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. //! The primary goal of this assignment is to re-learn the common programming concepts in Rust,
//! Please make sure you're comfortable with the concepts to proceed on to the next assignments. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 2` works
//! See `assigment02/*_grade.rs` and `/scripts/grade.sh 2` for the test script. //! fine. See `assigment02/*_grade.rs` and `/scripts/grade.sh 2` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,5 +1,7 @@
//! Small problems. //! Small problems.
use std::iter;
const FAHRENHEIT_OFFSET: f64 = 32.0; const FAHRENHEIT_OFFSET: f64 = 32.0;
const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0; const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0;
@@ -18,29 +20,33 @@ pub fn sum_array(input: &[u64]) -> u64 {
todo!() 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.) /// For instance, up3(6) = 9, up3(9) = 9, up3(10) = 27. (We assume the absence of integer overflow.)
pub fn up3(n: u64) -> u64 { pub fn up3(n: u64) -> u64 {
todo!() 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 { pub fn gcd(lhs: u64, rhs: u64) -> u64 {
todo!() 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 <https://en.wikipedia.org/wiki/Pascal%27s_triangle> for computation of binomial coefficients without integer overflow. /// Consult <https://en.wikipedia.org/wiki/Pascal%27s_triangle> for computation of binomial
/// coefficients without integer overflow.
pub fn chooses(n: u64) -> Vec<u64> { pub fn chooses(n: u64) -> Vec<u64> {
todo!() todo!()
} }
/// Returns the "zip" of two vectors. /// Returns the "zip" of two vectors.
/// ///
/// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`. /// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`. Here, `3` is
/// Here, `3` is ignored because it doesn't have a partner. /// ignored because it doesn't have a partner.
pub fn zip(lhs: Vec<u64>, rhs: Vec<u64>) -> Vec<(u64, u64)> { pub fn zip(lhs: Vec<u64>, rhs: Vec<u64>) -> Vec<(u64, u64)> {
todo!() todo!()
} }

View File

@@ -2,6 +2,7 @@
//! //!
//! You will implement simple operations on vectors and matrices. //! You will implement simple operations on vectors and matrices.
use std::cmp::PartialEq;
use std::ops::Mul; use std::ops::Mul;
/// 2x2 matrix of the following configuration: /// 2x2 matrix of the following configuration:
@@ -112,13 +113,20 @@ impl FMat2 {
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```ignore
/// assert_eq!( /// assert_eq!(
/// Mat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(), /// FMat2 { 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: 3.0, b: -1.0, c: -2.0, d: 1.0 }
/// ); /// );
/// ``` /// ```
pub fn inverse(self) -> Self { pub fn inverse(self) -> Self {
todo!() 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
}
}

View File

@@ -16,14 +16,6 @@ mod test {
assert_eq!(fibonacci(92), 12200160415121876738); 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] #[test]
fn test_inverse() { fn test_inverse() {
assert_eq!( assert_eq!(

View File

@@ -16,7 +16,7 @@ pub enum MyOption<T> {
/// Converts an `MyOption<String>` into an `MyOption<usize>`, consuming the original: /// Converts an `MyOption<String>` into an `MyOption<usize>`, consuming the original:
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment03::{my_map, MyOption}; /// use cs220::assignments::assignment03::custom_operators::*;
/// ///
/// fn len(s: String) -> usize { /// fn len(s: String) -> usize {
/// s.len() /// s.len()
@@ -29,14 +29,15 @@ pub fn my_map<T, U, F: FnOnce(T) -> U>(v: MyOption<T>, f: F) -> MyOption<U> {
todo!() 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. /// Some languages call this operation flatmap.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment03::{MyOption, my_and_then}; /// use cs220::assignments::assignment03::custom_operators::*;
/// ///
/// fn pos_then_to_string(x: isize) -> MyOption<String> { /// fn pos_then_to_string(x: isize) -> MyOption<String> {
/// if x > 0 { /// if x > 0 {
@@ -54,21 +55,21 @@ pub fn my_and_then<T, U, F: FnOnce(T) -> MyOption<U>>(v: MyOption<T>, f: F) -> M
todo!() todo!()
} }
/// Custom operator: `option_op_or(v1, v2, f)` /// Custom operator: `option_op_or(v1, v2, f)`. If neither `v1` nor `v2` is `Some`, returns `None`.
/// 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
/// If exactly one is `Some`, returns the same `Some` value. /// inside `Some` to `f` and wrap the resulting value inside `Some`.
/// If both are `Some`, apply the values inside `Some` to `f` and wrap the resulting value inside `Some`.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment03::custom_operators::*;
/// fn product(a: i32, b: i32) -> i32 { /// fn product(a: i32, b: i32) -> i32 {
/// a * b /// a * b
/// } /// }
/// ///
/// assert_eq!(option_op_or(None, None, product), None); /// assert_eq!(my_option_op_or(MyOption::MyNone, MyOption::MyNone, product), MyOption::MyNone);
/// assert_eq!(option_op_or(Some(3), None, product), Some(3)); /// assert_eq!(my_option_op_or(MyOption::MySome(3), MyOption::MyNone, product), MyOption::MySome(3));
/// assert_eq!(option_op_or(Some(3), Some(5), product), Some(15)); /// assert_eq!(my_option_op_or(MyOption::MySome(3), MyOption::MySome(5), product), MyOption::MySome(15));
/// ``` /// ```
pub fn my_option_op_or<T, F: FnOnce(T, T) -> T>( pub fn my_option_op_or<T, F: FnOnce(T, T) -> T>(
v1: MyOption<T>, v1: MyOption<T>,

View File

@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::assignments::assignment03::custom_operators::{MyOption::*, *}; use crate::assignments::assignment03::custom_operators::MyOption::*;
use crate::assignments::assignment03::custom_operators::*;
#[test] #[test]
fn test_my_map() { fn test_my_map() {

View File

@@ -1,7 +1,7 @@
//! Assignment 3: Mastering common programming concepts (2/2) //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 3` works
//! See `assignment03/*_grade.rs` and `/scripts/grade.sh 3` for the test script. //! fine. See `assignment03/*_grade.rs` and `/scripts/grade.sh 3` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,19 +1,22 @@
//! Parsing a shell command. //! Parsing a shell command.
//! //!
//! Shell commands are text-based instructions that you can enter in a command-line interface (CLI) //! 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. //! to interact with operating systems (e.g. Linux) and others. For example, you can use the `ls`
//! For example, you can use the `ls` command to list files in a directory. //! command to list files in a directory.
//! //!
//! You will parse a given string consists of a small number of shell commands. //! You will parse a given string consists of a small number of shell commands.
/// Parse the string as a shell command. /// Parse the string as a shell command.
/// ///
/// Usually, a shell command is whitespace-separated array of strings. /// Usually, a shell command is whitespace-separated array of strings.
///
/// ```text /// ```text
/// cat file --> ["cat", "file"] /// 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 /// ```text
/// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs'] /// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs']
/// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs'] /// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs']

View File

@@ -55,16 +55,19 @@ pub fn median(values: Vec<isize>) -> Option<isize> {
todo!() 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. /// Returns `None` if the list is empty.
pub fn mode(values: Vec<isize>) -> Option<isize> { pub fn mode(values: Vec<isize>) -> Option<isize> {
todo!() 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" /// 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. /// - The result is a map from department to the list of its employees.
/// - An empty department should not appear in the result. /// - 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. /// - If a command is not executable, then it's ignored.
/// - There is no space in the name of the person and department. /// - There is no space in the name of the person and department.
/// ///

View File

@@ -3,8 +3,9 @@
use std::collections::HashMap; use std::collections::HashMap;
use anyhow::*; use anyhow::*;
use etrace::*;
use super::syntax::{Command, Expression}; use super::syntax::{BinOp, Command, Expression};
/// Calculator's context. /// Calculator's context.
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@@ -31,7 +32,8 @@ impl Context {
/// Calculates the given command. (We assume the absence of overflow.) /// 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 /// # Example
/// ///

View File

@@ -1,8 +1,9 @@
//! Assignment 4: Designing a calculator. //! Assignment 4: Designing a calculator.
//! //!
//! The primary goal of this assignment is twofold: //! The primary goal of this assignment is twofold:
//! (1) understanding the `pest` third-party library from documentations; and //! - (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. //! - (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): //! For `pest`, read the following documentations (that contain 90% of the solution):
//! - <https://pest.rs/> //! - <https://pest.rs/>
@@ -11,8 +12,9 @@
//! //!
//! For calculator, just reading `syntax.rs` would suffice for you to understand what to do. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 4` works
//! See `assignment04/grade.rs` and `/scripts/grade.sh 4` for the test script. //! 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 <https://gg.kaist.ac.kr>. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment04.zip` to <https://gg.kaist.ac.kr>.
//! //!
//! To submit, run //! To submit, run

View File

@@ -2,8 +2,14 @@
//! Parser. //! 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 super::syntax::*;
use anyhow::Result;
#[allow(missing_docs)] #[allow(missing_docs)]
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
@@ -15,13 +21,16 @@ mod inner {
pub(crate) struct SyntaxParser; pub(crate) struct SyntaxParser;
} }
use inner::*;
/// Parses command. /// Parses command.
/// ///
/// ## Operator Associativty /// ## Operator Associativty
/// ///
/// For associativity of each operator, please follow [here](https://docs.rs/pest/latest/pest/prec_climber/struct.PrecClimber.html#examples). /// 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<Command> { pub fn parse_command(line: &str) -> Result<Command> {
todo!("fill here") todo!("fill here")
} }

View File

@@ -2,8 +2,8 @@
//! //!
//! The primary goal of this assignment is to understand generics, traits, and lifetimes. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 6` works
//! See `assignment06/*_grade.rs` and `/scripts/grade.sh 6` for the test script. //! fine. See `assignment06/*_grade.rs` and `/scripts/grade.sh 6` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,6 +1,9 @@
//! Semiring //! Semiring
use std::{collections::HashMap, fmt::Debug}; use std::collections::HashMap;
use std::fmt::Debug;
use itertools::Itertools;
/// Semiring. /// Semiring.
/// ///
@@ -147,10 +150,8 @@ impl<C: Semiring> From<C> for Polynomial<C> {
/// ///
/// Assumptions: /// Assumptions:
/// - Each term is separated by ` + `. /// - Each term is separated by ` + `.
/// - Each term is one of the following form: /// - Each term is one of the following form: `a`, `x`, `ax`, `x^n`, and `ax^n`, where `a` is a
/// `a`, `x`, `ax`, `x^n`, and `ax^n`, /// `usize` number and `n` is a `u64` number. This `a` should then be converted to a `C` type.
/// 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 `a`, it is guaranteed that `a >= 1`.
/// - In `ax` and `ax^n`, it is guaranteed that `a >= 2`. /// - In `ax` and `ax^n`, it is guaranteed that `a >= 2`.
/// - In `x^n` and `ax^n`, it is guaranteed that `n >= 2`. /// - In `x^n` and `ax^n`, it is guaranteed that `n >= 2`.

View File

@@ -1,8 +1,9 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::assignments::assignment06::semiring::*;
use ntest::assert_about_eq; use ntest::assert_about_eq;
use crate::assignments::assignment06::semiring::*;
fn test_from_str(s: &str, f: impl Fn(i64) -> i64) { fn test_from_str(s: &str, f: impl Fn(i64) -> i64) {
let poly = s.parse::<Polynomial<i64>>().unwrap(); let poly = s.parse::<Polynomial<i64>>().unwrap();
for i in 0..10 { for i in 0..10 {

View File

@@ -5,10 +5,12 @@ use std::ops::*;
/// Rational number represented by two isize, numerator and denominator. /// 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. /// Each Rational number should be normalized so that `demoninator` is nonnegative and `numerator`
/// See `normalize` for examples. As a corner case, 0 is represented by Rational { numerator: 0, demoninator: 0 }. /// 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. /// See [here](https://doc.rust-lang.org/core/ops/index.html) for details.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -96,9 +98,9 @@ pub enum SingletonPolynomial {
Const(Rational), Const(Rational),
/// Non-const polynomial. /// Non-const polynomial.
Polynomial { Polynomial {
/// coefficent of polynomial. Must be non-zero. /// Coefficent of polynomial. Must be non-zero.
coeff: Rational, coeff: Rational,
/// power of polynomial. Must be non-zero. /// Power of polynomial. Must be non-zero.
power: Rational, power: Rational,
}, },
} }
@@ -156,7 +158,7 @@ pub enum Trignometric {
/// Coefficent /// Coefficent
coeff: Rational, coeff: Rational,
}, },
/// Sine function. /// Cosine function.
Cosine { Cosine {
/// Coefficent /// Coefficent
coeff: Rational, coeff: Rational,

View File

@@ -1,8 +1,9 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::assignments::assignment06::symbolic_differentiation::*;
use ntest::assert_about_eq; use ntest::assert_about_eq;
use crate::assignments::assignment06::symbolic_differentiation::*;
// Constant rationals to use // Constant rationals to use
const TWO: Rational = Rational::new(2, 1); const TWO: Rational = Rational::new(2, 1);
const FOUR: Rational = Rational::new(4, 1); const FOUR: Rational = Rational::new(4, 1);
@@ -172,7 +173,7 @@ mod test {
// Mult // Mult
// //
// d/dx (2x^4 * cos(x) * exp(x)) = // 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 f1 = SingletonPolynomial::new_poly(TWO, FOUR);
let f2 = Trignometric::new_cosine(ONE); let f2 = Trignometric::new_cosine(ONE);
let f3 = Exp::new(); let f3 = Exp::new();

View File

@@ -2,8 +2,8 @@
//! //!
//! The primary goal of this assignment is to understand generics, traits, and lifetimes. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 7` works
//! See `assignment07/*_grade.rs` and `/scripts/grade.sh 7` for the test script. //! fine. See `assignment07/*_grade.rs` and `/scripts/grade.sh 7` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,9 +1,10 @@
//! Implement your own minimal `itertools` crate. //! Implement your own minimal `itertools` crate.
use std::collections::HashSet;
use std::hash::Hash; use std::hash::Hash;
/// Iterator that iterates over the given iterator and returns only unique elements. /// Iterator that iterates over the given iterator and returns only unique elements.
#[allow(missing_debug_implementations)] #[derive(Debug)]
pub struct Unique<I: Iterator> { pub struct Unique<I: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want // TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<I>, _marker: std::marker::PhantomData<I>,
@@ -21,7 +22,7 @@ where
} }
/// Iterator that chains two iterators together. /// Iterator that chains two iterators together.
#[allow(missing_debug_implementations)] #[derive(Debug)]
pub struct Chain<I1: Iterator, I2: Iterator> { pub struct Chain<I1: Iterator, I2: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want // TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<(I1, I2)>, _marker: std::marker::PhantomData<(I1, I2)>,
@@ -38,7 +39,7 @@ impl<T: Eq + Hash + Clone, I1: Iterator<Item = T>, I2: Iterator<Item = T>> Itera
} }
/// Iterator that iterates over given iterator and enumerates each element. /// Iterator that iterates over given iterator and enumerates each element.
#[allow(missing_debug_implementations)] #[derive(Debug)]
pub struct Enumerate<I: Iterator> { pub struct Enumerate<I: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want // TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<I>, _marker: std::marker::PhantomData<I>,
@@ -56,7 +57,7 @@ impl<I: Iterator> Iterator for Enumerate<I> {
/// ///
/// If one iterator is longer than the other one, the remaining elements for the longer element /// If one iterator is longer than the other one, the remaining elements for the longer element
/// should be ignored. /// should be ignored.
#[allow(missing_debug_implementations)] #[derive(Debug)]
pub struct Zip<I1: Iterator, I2: Iterator> { pub struct Zip<I1: Iterator, I2: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want // TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<(I1, I2)>, _marker: std::marker::PhantomData<(I1, I2)>,

View File

@@ -47,7 +47,8 @@ where
} }
/// Returns and iterator over the generic fibonacci sequence starting from `first` and `second`. /// 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<T>(first: T, second: T) -> impl Iterator<Item = T> pub fn fib<T>(first: T, second: T) -> impl Iterator<Item = T>
where where
T: std::ops::Add<Output = T> + Copy, T: std::ops::Add<Output = T> + Copy,

View File

@@ -9,6 +9,7 @@
//! - <https://en.wikipedia.org/wiki/Church_encoding> //! - <https://en.wikipedia.org/wiki/Church_encoding>
//! - <https://opendsa-server.cs.vt.edu/OpenDSA/Books/PL/html/ChurchNumerals.html> //! - <https://opendsa-server.cs.vt.edu/OpenDSA/Books/PL/html/ChurchNumerals.html>
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
/// Church numerals are represented as higher-order functions that take a function `f` /// Church numerals are represented as higher-order functions that take a function `f`
@@ -51,8 +52,9 @@ pub fn mult<T: 'static>(n: Church<T>, m: Church<T>) -> Church<T> {
/// This is the Church numeral equivalent of the natural number operation of exponentiation. /// 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 /// 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, /// 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). /// and then apply the Church numeral for `m` (the exponent) to the Church numeral for `n` (the
/// Note: This function should be implemented *WITHOUT* using the `to_usize` or any `pow`-like method. /// base). Note: This function should be implemented *WITHOUT* using the `to_usize` or any
/// `pow`-like method.
pub fn exp<T: 'static>(n: usize, m: usize) -> Church<T> { pub fn exp<T: 'static>(n: usize, m: usize) -> Church<T> {
// ACTION ITEM: Uncomment the following lines and replace `todo!()` with your code. // ACTION ITEM: Uncomment the following lines and replace `todo!()` with your code.
// let n = from_usize(n); // let n = from_usize(n);

View File

@@ -2,8 +2,8 @@
//! //!
//! The primary goal of this assignment is to get used to first-class functions. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 8` works
//! See `assignment08/*_grade.rs` and `/scripts/grade.sh 8` for the test script. //! fine. See `assignment08/*_grade.rs` and `/scripts/grade.sh 8` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -15,7 +15,8 @@ pub fn repeat<T, F: FnMut(T) -> 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. /// 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. /// Refer `test_funny_map` in `assignment08_grade.rs` for detailed examples.
pub fn funny_map<T, F: Fn(T) -> T>(f: F, vs: Vec<T>) -> Vec<T> { pub fn funny_map<T, F: Fn(T) -> T>(f: F, vs: Vec<T>) -> Vec<T> {
@@ -24,9 +25,8 @@ pub fn funny_map<T, F: Fn(T) -> T>(f: F, vs: Vec<T>) -> Vec<T> {
/// Count Repeat /// Count Repeat
/// ///
/// Returns the number of the elements of the set /// Returns the number of the elements in the set {`x`, `f(x)`, `f(f(x))`, `f(f(f(x)))`, ...}. You
/// {x, f(x), f(f(x)), f(f(f(x))), ...}. /// may assume that the answer is finite and small enough.
/// You may assume that the answer is finite and small enough.
/// ///
/// Refer `test_count_repeat` in `assignment08_grade.rs` for detailed examples. /// Refer `test_count_repeat` in `assignment08_grade.rs` for detailed examples.
pub fn count_repeat<T, F: Fn(T) -> T>(f: F, x: T) -> usize pub fn count_repeat<T, F: Fn(T) -> T>(f: F, x: T) -> usize

View File

@@ -1,7 +1,8 @@
//! Big integer with infinite precision. //! Big integer with infinite precision.
use std::fmt; 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. /// 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. /// 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. /// Unlike standard fix-sized intergers in Rust where overflow will panic, the carrier is extended
/// 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. /// 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, /// 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. /// 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. /// 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)] #[derive(Debug, Clone)]
pub struct BigInt { pub struct BigInt {
/// The carrier for `BigInt`. /// The carrier for `BigInt`.
@@ -39,6 +42,10 @@ impl BigInt {
} }
/// Creates a new `BigInt` from a `Vec<u32>`. /// Creates a new `BigInt` from a `Vec<u32>`.
///
/// # Panic
///
/// Panics if `carrier` is empty.
pub fn new_large(carrier: Vec<u32>) -> Self { pub fn new_large(carrier: Vec<u32>) -> Self {
assert!(!carrier.is_empty()); assert!(!carrier.is_empty());
todo!() todo!()

View File

@@ -43,7 +43,7 @@ mod test {
#[test] #[test]
#[should_panic] #[should_panic]
fn test_inf_prec_panic() { fn test_inf_prec_panic() {
let _ = BigInt::new_large(vec![]); let _unused = BigInt::new_large(vec![]);
} }
#[test] #[test]

View File

@@ -7,7 +7,7 @@ use itertools::*;
/// # Example /// # 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 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 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<f64> {
/// You don't know how to calculate dot product? /// You don't know how to calculate dot product?
/// See <https://mathinsight.org/dot_product_examples> /// See <https://mathinsight.org/dot_product_examples>
/// ///
/// # 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 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 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) /// - rhs: (p, n)
/// - output: (m, p) /// - 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 mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]];
/// let mat2 = vec![ /// let mat2 = vec![

View File

@@ -1,11 +1,12 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::assignments::assignment09::matmul::*;
use approx::*; use approx::*;
use itertools::Itertools; use itertools::Itertools;
use ndarray::prelude::*; 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] #[test]
fn vec_add_test() { fn vec_add_test() {

View File

@@ -2,8 +2,8 @@
//! //!
//! The primary goal of this assignment is to get used to iterators. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 9` works
//! See `assignment09/*_grade.rs` and `/scripts/grade.sh 9` for the test script. //! fine. See `assignment09/*_grade.rs` and `/scripts/grade.sh 9` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -2,14 +2,17 @@
use std::collections::HashMap; 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. /// Returns `true` if the length of sequence is less or equal than 2.
/// ///
/// # Exmample /// # 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, 13].into_iter()), true);
/// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter()), false); /// 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<Item = i64>) -> bool {
/// Returns the sum of `f(v)` for all element `v` the given array. /// 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 + 2), 7);
/// assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); /// assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12);
@@ -39,7 +42,7 @@ pub fn sigma<T, F: Fn(T) -> i64>(inner: impl Iterator<Item = T>, f: F) -> i64 {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment09::interleave3; /// use cs220::assignments::assignment09::small_exercises::*;
/// ///
/// assert_eq!( /// assert_eq!(
/// interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), /// interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()),
@@ -61,7 +64,7 @@ pub fn interleave3<T>(
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment09::interleave_n; /// use cs220::assignments::assignment09::small_exercises::*;
/// ///
/// assert_eq!( /// assert_eq!(
/// interleave_n(&mut [[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]), /// interleave_n(&mut [[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]),
@@ -80,7 +83,7 @@ pub fn interleave_n<T, const N: usize>(
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment09::k_smallest_mean; /// use cs220::assignments::assignment09::small_exercises::*;
/// ///
/// assert_eq!( /// assert_eq!(
/// k_smallest_mean(vec![1, 3, 2].into_iter(), 2), /// k_smallest_mean(vec![1, 3, 2].into_iter(), 2),
@@ -97,10 +100,10 @@ pub fn k_smallest_mean(inner: impl Iterator<Item = i64>, k: usize) -> f64 {
/// Returns mean for each class. /// Returns mean for each class.
/// ///
/// # Exmaple /// # Example
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment09::calculate_mean; /// use cs220::assignments::assignment09::small_exercises::*;
/// ///
/// assert_eq!( /// assert_eq!(
/// calculate_mean( /// calculate_mean(
@@ -135,7 +138,7 @@ pub fn calculate_mean(inner: impl Iterator<Item = (String, i64)>) -> HashMap<Str
/// Among these sets, the number of sets whose sum is 4 is 2, which is [1, 3] and [2, 2]. /// Among these sets, the number of sets whose sum is 4 is 2, which is [1, 3] and [2, 2].
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment09::sum_is_n; /// use cs220::assignments::assignment09::small_exercises::*;
/// ///
/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1); /// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1);
/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2); /// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2);
@@ -147,12 +150,13 @@ pub fn sum_is_n(inner: Vec<Vec<i64>>, n: i64) -> usize {
todo!() 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 /// # 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, 2], 1), vec![1, 2]);
/// assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); /// assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]);
@@ -175,10 +179,10 @@ pub fn find_count_n(inner: Vec<usize>, n: usize) -> Vec<usize> {
/// - If the list is empty, returns `None`. /// - If the list is empty, returns `None`.
/// - If several elements are equally median, the position of the first of them is returned. /// - 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, 6, 7, 8, 9]), Some(3));
/// assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); /// assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1));
@@ -191,6 +195,8 @@ pub fn position_median<T: Ord>(inner: Vec<T>) -> Option<usize> {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// use cs220::assignments::assignment09::small_exercises::*;
///
/// assert_eq!( /// assert_eq!(
/// two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()), /// two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()),
/// 21 /// 21
@@ -202,8 +208,10 @@ pub fn two_dimensional_sum(inner: impl Iterator<Item = impl Iterator<Item = i64>
/// Returns whether the given string is palindrome or not. /// 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. /// A palindrome is a word, number, phrase, or other sequence of characters which reads the same
/// We consider the empty string is palindrome. /// backward as forward.
///
/// We consider the empty string as a palindrome.
/// ///
/// Consult <https://en.wikipedia.org/wiki/Palindrome>. /// Consult <https://en.wikipedia.org/wiki/Palindrome>.
pub fn is_palindrome(s: String) -> bool { pub fn is_palindrome(s: String) -> bool {

View File

@@ -1,11 +1,11 @@
//! Labyrinth //! Labyrinth
//! //!
//! Look at the `labyrinth_grade.rs` below before you start. //! Look at `labyrinth_grade.rs` below before you start.
//! HINT: <https://en.wikipedia.org/wiki/100_prisoners_problem> //! HINT: <https://en.wikipedia.org/wiki/100_prisoners_problem>
//! //!
//! NOTE: You will have to implement a probabilistic algorithm, which means, the algorithm can fail //! 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 //! even if you have implemented the solution. We recommend running multiple times (at least 5
//! solution works well. //! times) to check your solution works well.
use std::cell::RefCell; use std::cell::RefCell;
@@ -26,8 +26,8 @@ impl Husband {
Strategy { husband: self } Strategy { husband: self }
} }
/// Based on the information about currently visited room number and someone's wife ID trapped inside, /// Based on the information about currently visited room number and someone's wife ID trapped
/// what the husband should do next? /// inside, what the husband should do next?
pub fn carefully_checks_whos_inside(&self, room: usize, wife: usize) { pub fn carefully_checks_whos_inside(&self, room: usize, wife: usize) {
todo!() todo!()
} }

View File

@@ -1,5 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rand::thread_rng; use rand::thread_rng;
@@ -41,9 +42,10 @@ mod test {
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()); let strategy = Box::new(husband.has_devised_a_strategy());
#[allow(clippy::all)] // (Allow for better storytelling.)
/* The Minotaur🐂 will arrive in */ #[allow(clippy::search_is_some)]
(0..50) /* steps... */ // The Minotaur🐂 will arrive in
(0..50) // steps...
.zip(strategy) .zip(strategy)
.find(|(_, room)| { .find(|(_, room)| {
// The husband contemplates his next move... 🤔 // The husband contemplates his next move... 🤔

View File

@@ -1,8 +1,8 @@
//! Assignment 10: Iterators (2/2). //! Assignment 10: Iterators (2/2).
//! The primary goal of this assignment is to get used to iterators. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 10` works
//! See `assignment10/*_grade.rs` and `/scripts/grade.sh 10` for the test script. //! fine. See `assignment10/*_grade.rs` and `/scripts/grade.sh 10` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,10 +1,13 @@
//! Small exercises. //! Small exercises.
use std::collections::HashSet;
use itertools::*; use itertools::*;
/// Returns the pairs of `(i, j)` where `i < j` and `inner[i] > inner[j]` in increasing order. /// 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 < 2`, `inner[0] = 3 > 1 = inner[2]`
/// - `0 < 3`, `inner[0] = 3 > 2 = inner[3]` /// - `0 < 3`, `inner[0] = 3 > 2 = inner[3]`
@@ -108,7 +111,8 @@ pub enum File {
/// |__c (Data, size: 8) /// |__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)> { pub fn du_sort(root: &File) -> Vec<(&str, usize)> {
todo!() todo!()
} }
@@ -118,12 +122,11 @@ pub fn du_sort(root: &File) -> Vec<(&str, usize)> {
/// of returning a new vector. /// of returning a new vector.
/// ///
/// # Example /// # Example
/// ``` /// ```ignore
/// let mut vec = vec![1, 2, 3, 4, 5]; /// let mut vec = vec![1, 2, 3, 4, 5];
/// remove_even(&mut vec); /// remove_even(&mut vec);
/// assert_eq!(*vec, vec![1, 3, 5]); /// assert_eq!(*vec, vec![1, 3, 5]);
/// ``` /// ```
#[allow(clippy::ptr_arg)]
pub fn remove_even(inner: &mut Vec<i64>) { pub fn remove_even(inner: &mut Vec<i64>) {
todo!() todo!()
} }
@@ -135,12 +138,11 @@ pub fn remove_even(inner: &mut Vec<i64>) {
/// Also, note that the order does not matter. /// Also, note that the order does not matter.
/// ///
/// # Example /// # Example
/// ``` /// ```ignore
/// let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7]; /// let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7];
/// remove_duplicate(&mut vec); /// remove_duplicate(&mut vec);
/// assert_eq!(*vec, vec![1, 2, 3, 7, 5]); /// assert_eq!(*vec, vec![1, 2, 3, 7, 5]);
/// ``` /// ```
#[allow(clippy::ptr_arg)]
pub fn remove_duplicate(inner: &mut Vec<i64>) { pub fn remove_duplicate(inner: &mut Vec<i64>) {
todo!() todo!()
} }
@@ -153,6 +155,7 @@ pub fn remove_duplicate(inner: &mut Vec<i64>) {
/// ///
/// # Example /// # Example
/// ///
/// ```text
/// table1 table2 /// table1 table2
/// ---------------------- ---------------------- /// ---------------------- ----------------------
/// 20230001 | Jack 20230001 | CS /// 20230001 | Jack 20230001 | CS
@@ -165,11 +168,12 @@ pub fn remove_duplicate(inner: &mut Vec<i64>) {
/// 20230001 | Jack | CS /// 20230001 | Jack | CS
/// 20230001 | Jack | EE /// 20230001 | Jack | EE
/// 20231234 | Mike | ME /// 20231234 | Mike | ME
/// /// ```
pub fn natural_join(table1: Vec<Vec<String>>, table2: Vec<Vec<String>>) -> Vec<Vec<String>> { pub fn natural_join(table1: Vec<Vec<String>>, table2: Vec<Vec<String>>) -> Vec<Vec<String>> {
todo!() todo!()
} }
/// You can freely add more fields.
struct Pythagorean; struct Pythagorean;
impl 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), /// 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<Item = (u64, u64, u64)> { pub fn pythagorean() -> impl Iterator<Item = (u64, u64, u64)> {
Pythagorean::new() Pythagorean::new()
} }

View File

@@ -322,17 +322,11 @@ mod test {
(68, 285, 293), (68, 285, 293),
]; ];
let mut pythagorean_iter = pythagorean(); for (i, (a, b, c)) in pythagorean().enumerate().take(1000) {
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);
if i < pythagoreans.len() { if i < pythagoreans.len() {
assert_eq!(pythagoreans[i], (a, b, c)) assert_eq!(pythagoreans[i], (a, b, c))
} }
assert_eq!(a * a + b * b, c * c);
} }
} }
} }

View File

@@ -12,6 +12,10 @@
//! //!
//! Refer `graph_grade.rs` for test cases. //! Refer `graph_grade.rs` for test cases.
use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc;
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
enum VisitStatus { enum VisitStatus {
Unvisited, Unvisited,
@@ -20,11 +24,12 @@ enum VisitStatus {
} }
/// Handle to a graph node. /// Handle to a graph node.
///
/// `NodeHandle` should implement `Clone`, which clones the handle without cloning the underlying /// `NodeHandle` should implement `Clone`, which clones the handle without cloning the underlying
/// node. That is, there can be multiple handles to the same node. /// 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. /// 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)] #[derive(Debug, Clone)]
pub struct NodeHandle; pub struct NodeHandle;
@@ -34,7 +39,7 @@ pub struct GraphError;
/// Subgraph /// Subgraph
/// ///
/// TODO: You can freely add fields to this struct. /// You can freely add fields to this struct.
#[derive(Debug)] #[derive(Debug)]
pub struct SubGraph; pub struct SubGraph;
@@ -45,23 +50,24 @@ impl NodeHandle {
} }
/// Adds an edge to `to`. /// Adds an edge to `to`.
/// 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
/// Returns `Ok(true)` if the edge is successfully added. /// `Err(GraphError)`. Returns `Ok(true)` if the edge is successfully added.
/// Returns `Ok(false)` if an edge to `to` already exits. /// Returns `Ok(false)` if an edge to `to` already exits.
pub fn add_edge(&self, to: NodeHandle) -> Result<bool, GraphError> { pub fn add_edge(&self, to: NodeHandle) -> Result<bool, GraphError> {
todo!() todo!()
} }
/// Removes the edge to `to`. /// Removes the edge to `to`.
/// 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
/// Returns `Ok(true)` if the edge is successfully removed. /// `Err(GraphError)`. Returns `Ok(true)` if the edge is successfully removed.
/// Returns `Ok(false)` if an edge to `to` does not exist. /// Returns `Ok(false)` if an edge to `to` does not exist.
pub fn remove_edge(&self, to: &NodeHandle) -> Result<bool, GraphError> { pub fn remove_edge(&self, to: &NodeHandle) -> Result<bool, GraphError> {
todo!() todo!()
} }
/// Removes all edges. /// 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> { pub fn clear_edges(&self) -> Result<(), GraphError> {
todo!() todo!()
} }
@@ -84,7 +90,7 @@ impl SubGraph {
todo!() 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 { pub fn remove_node(&mut self, node: &NodeHandle) -> bool {
todo!() todo!()
} }

View File

@@ -1,6 +1,7 @@
//! TV Room Simulator. //! 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: //! The rule of the TV room is as follows:
//! //!
@@ -9,8 +10,9 @@
//! - Manager can leave the TV room earlier than guests. //! - Manager can leave the TV room earlier than guests.
//! - The TV room closes when the last person left the TV room. //! - The TV room closes when the last person left the TV room.
//! //!
//! Both `Manager` and `Guest` have `Rc<Watcher>` as a field, and its reference count indicates the number of people in //! Both `Manager` and `Guest` have `Rc<Watcher>` as a field, and its reference count indicates the
//! the TV room. When the 'Manager' and 'Guest' object is dropped, it means that the person leaves the TV room. //! 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: //! Consult the following documentations:
//! - <https://doc.rust-lang.org/book/ch15-04-rc.html#rct-the-reference-counted-smart-pointer> //! - <https://doc.rust-lang.org/book/ch15-04-rc.html#rct-the-reference-counted-smart-pointer>
@@ -18,7 +20,8 @@
//! //!
//! Refer `tv_room_grade.rs` for test cases. //! 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)] #[derive(Debug, Clone, Copy)]
enum TVRoomState { enum TVRoomState {

View File

@@ -8,10 +8,8 @@
//! //!
//! Have fun! //! Have fun!
use std::{ use std::collections::HashMap;
collections::HashMap, use std::sync::{Arc, Mutex};
sync::{Arc, Mutex},
};
/// Color represents the color of the card. /// Color represents the color of the card.
/// The color of a card can be either Blue or White. /// The color of a card can be either Blue or White.

View File

@@ -2,13 +2,13 @@
#[cfg(test)] #[cfg(test)]
mod test_card { mod test_card {
use crate::assignments::assignment12::card::*;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex}; use std::sync::{Arc, Barrier, Mutex};
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use crate::assignments::assignment12::card::*;
const NUM_CARDS: usize = 10000; const NUM_CARDS: usize = 10000;
const DURATION: u64 = 20; const DURATION: u64 = 20;
const NUM_ENEMIES: usize = 25; const NUM_ENEMIES: usize = 25;

View File

@@ -1,6 +1,7 @@
//! Demultiplexing sender //! Demultiplexing sender
//! //!
//! Implement demultiplexing sender //! Implement a demultiplexing sender.
//!
//! Demultiplexer, `Demux` in short, is a device that has one input and many outputs. //! 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 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. //! It is used when a circuit wishes to send a signal to one of many devices.

View File

@@ -2,12 +2,13 @@
#[cfg(test)] #[cfg(test)]
mod test_demux { mod test_demux {
use crate::assignments::assignment12::demux::*;
use ntest::timeout;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::thread; use std::thread;
use ntest::timeout;
use crate::assignments::assignment12::demux::*;
#[test] #[test]
#[timeout(5000)] #[timeout(5000)]
fn test_demux() { fn test_demux() {

View File

@@ -1,17 +1,19 @@
//! Funnel //! Funnel
//! //!
//! Spawn a thread that executes a 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::mpsc::{channel, Receiver, Sender};
use std::sync::Arc; use std::sync::Arc;
use std::thread; use std::thread;
use std::thread::JoinHandle; 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<T, F>(rxs: Vec<Receiver<T>>, tx: Sender<T>, f: F) -> JoinHandle<()> pub fn spawn_funnel<T, F>(rxs: Vec<Receiver<T>>, tx: Sender<T>, f: F) -> JoinHandle<()>
where where
T: Send + 'static, T: Send + 'static,

View File

@@ -2,12 +2,13 @@
#[cfg(test)] #[cfg(test)]
mod test_funnel { mod test_funnel {
use crate::assignments::assignment12::funnel::*;
use ntest::timeout;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::thread; use std::thread;
use ntest::timeout;
use crate::assignments::assignment12::funnel::*;
#[test] #[test]
#[timeout(5000)] #[timeout(5000)]
fn test_funnel_concurrent() { fn test_funnel_concurrent() {

View File

@@ -2,8 +2,8 @@
//! //!
//! The primary goal of this assignment is to get used to concurrency. //! 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. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 12` works
//! See `assignment12/*_grade.rs` and `/scripts/grade.sh 12` for the test script. //! fine. See `assignment12/*_grade.rs` and `/scripts/grade.sh 12` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,5 +1,3 @@
#![allow(single_use_lifetimes)]
//! Small exercises //! Small exercises
//! //!
//! Refer `small_exercises_grade.rs` for test cases //! Refer `small_exercises_grade.rs` for test cases
@@ -12,16 +10,18 @@ use etrace::*;
/// The "pong" function /// The "pong" function
/// ///
/// Data will be sent and received through `rx` and `tx`. /// 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<u32>, tx2: &mut Sender<u32>) -> bool { pub fn pong(rx1: &mut Receiver<u32>, tx2: &mut Sender<u32>) -> bool {
todo!() todo!()
} }
/// Executes the given functions (f1, f2) in concurrent and returns the results. /// 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. /// Read the `test_scoped_thread` function in `small_exercises_grade.rs` to figure out what it
pub fn use_scoped_thread<'scope, 'env, T1, T2, F1, F2>( /// should do.
s: &'scope thread::Scope<'scope, 'env>, pub fn use_scoped_thread<'scope, T1, T2, F1, F2>(
s: &'scope thread::Scope<'scope, '_>,
f1: F1, f1: F1,
f2: F2, f2: F2,
) -> (T1, T2) ) -> (T1, T2)

View File

@@ -2,12 +2,13 @@
#[cfg(test)] #[cfg(test)]
mod test_pingpong { mod test_pingpong {
use crate::assignments::assignment12::small_exercises::*;
use ntest::timeout;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::thread; use std::thread;
use ntest::timeout;
use crate::assignments::assignment12::small_exercises::*;
#[test] #[test]
fn test_ping_pong() { fn test_ping_pong() {
let (tx1, mut rx1) = channel(); let (tx1, mut rx1) = channel();

View File

@@ -2,9 +2,10 @@
//! //!
//! The primary goal of this assignment is to get used to data parallelism. //! 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. //! Refer to your solution for assignment 09. You will implement the parallelized version of
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 13` works fine. //! assignment 09. You should fill out the `todo!()` placeholders in such a way that
//! See `assignment13/small_exercises_grade.rs` and `/scripts/grade.sh 13` for the test script. //! `/scripts/grade.sh 13` works fine. See `assignment13/small_exercises_grade.rs` and
//! `/scripts/grade.sh 13` for the test script.
//! //!
//! To submit, run //! To submit, run
//! ```bash //! ```bash

View File

@@ -1,19 +1,15 @@
//! Assignment 13: Parallelism. //! Assignment 13: Parallelism.
//! //!
//! If you did well on assignment 09, you will do well on this assignment. //! If you did well on assignment 09, you will do well on this assignment. Take it easy!
//! Take it easy!
use rayon::prelude::*; 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. /// 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; /// use rayon::iter::IntoParallelIterator;
/// ///
/// assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x + 2), 7); /// assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x + 2), 7);
@@ -31,7 +27,7 @@ pub fn sigma_par<T, F: Fn(T) -> i64 + Sync + Send>(
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use cs220::assignments::assignment13::interleave3; /// use cs220::assignments::assignment13::small_exercises::*;
/// use rayon::iter::IntoParallelIterator; /// use rayon::iter::IntoParallelIterator;
/// ///
/// assert_eq!( /// assert_eq!(
@@ -49,10 +45,10 @@ pub fn interleave3_par<T: Send>(
/// Parallel vector addition /// 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 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 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<f64> {
/// You don't know how to calculate dot product? /// You don't know how to calculate dot product?
/// See <https://mathinsight.org/dot_product_examples> /// See <https://mathinsight.org/dot_product_examples>
/// ///
/// # 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 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 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) /// - rhs: (p, n)
/// - output: (m, p) /// - 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 mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]];
/// let mat2 = vec![ /// let mat2 = vec![

View File

@@ -1,13 +1,17 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::assignments::assignment09::matmul::*; use std::hint;
use crate::assignments::assignment13::small_exercises::*; use std::time::Instant;
use approx::*; use approx::*;
use itertools::Itertools; use itertools::Itertools;
use ndarray::prelude::*; 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 rayon::prelude::IntoParallelIterator;
use std::time::Instant;
use crate::assignments::assignment09::matmul::*;
use crate::assignments::assignment13::small_exercises::*;
#[test] #[test]
fn test_sigma_par() { fn test_sigma_par() {
@@ -72,72 +76,66 @@ mod test {
} }
#[test] #[test]
fn vec_add_correctness() { fn vec_add_test() {
// small test
let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 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 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]); assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]);
// random test for _ in 0..5 {
let vec1 = Array::random(1000, Uniform::new(0., 10.)); let vec1 = hint::black_box(Array::random(5_000_000, Uniform::new(0., 10.)));
let vec2 = Array::random(1000, Uniform::new(0., 10.)); let vec2 = hint::black_box(Array::random(5_000_000, 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.));
let now_seq = Instant::now(); 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 elapsed_seq = now_seq.elapsed();
let now_par = Instant::now(); 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 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); assert!(elapsed_par < elapsed_seq);
} }
} }
#[test] #[test]
fn dot_product_correctness() { fn dot_product_test() {
// small test
let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 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 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); let res_par = dot_product_par(&vec1, &vec2);
assert_eq!(res_seq, 55.0);
assert_eq!(res_par, 55.0); assert_eq!(res_par, 55.0);
// random test for _ in 0..5 {
let vec1 = Array::random(1000, Uniform::new(0., 10.)); let vec1 = Array::random(500_000, Uniform::new(0., 10.));
let vec2 = Array::random(1000, Uniform::new(0., 10.)); let vec2 = Array::random(500_000, 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.));
let now_seq = Instant::now(); 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 elapsed_seq = now_seq.elapsed();
let now_par = Instant::now(); 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 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); assert!(elapsed_par < elapsed_seq);
} }
} }
@@ -163,8 +161,7 @@ mod test {
} }
#[test] #[test]
fn matmul_correctness() { fn matmul_test() {
// small case
let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]];
let mat2 = vec![ let mat2 = vec![
vec![7.0, 8.0, 9.0], vec![7.0, 8.0, 9.0],
@@ -176,72 +173,68 @@ mod test {
vec![50.0, 68.0, 86.0, 104.0], vec![50.0, 68.0, 86.0, 104.0],
vec![122.0, 167.0, 212.0, 257.0], vec![122.0, 167.0, 212.0, 257.0],
]; ];
let res_seq = matmul(&mat1, &mat2);
let res_par = matmul_par(&mat1, &mat2); let res_par = matmul_par(&mat1, &mat2);
assert_eq!(ans, res_seq);
assert_eq!(ans, res_par); assert_eq!(ans, res_par);
let mat1 = Array::random((10, 10), Uniform::new(0., 10.)); for _ in 0..5 {
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::<Vec<_>>()
.as_slice(),
mat2_transposed
.axis_iter(Axis(0))
.map(|row| row.to_vec())
.collect::<Vec<_>>()
.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 {
let mat1 = Array::random((500, 500), Uniform::new(0., 10.)); let mat1 = Array::random((500, 500), Uniform::new(0., 10.));
let mat2 = 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(); let mat2_transposed = mat2.t();
// Run sequential matrix multiplication // Run sequential matrix multiplication
let now_seq = Instant::now(); let now_seq = Instant::now();
let res_seq = matmul( let res_seq = hint::black_box(matmul(
hint::black_box(
mat1.axis_iter(Axis(0)) mat1.axis_iter(Axis(0))
.map(|row| row.to_vec()) .map(|row| row.to_vec())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice(), .as_slice(),
),
hint::black_box(
mat2_transposed mat2_transposed
.axis_iter(Axis(0)) .axis_iter(Axis(0))
.map(|row| row.to_vec()) .map(|row| row.to_vec())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice(), .as_slice(),
); ),
));
let elapsed_seq = now_seq.elapsed(); let elapsed_seq = now_seq.elapsed();
// Run parallel matrix multiplication // Run parallel matrix multiplication
let now_par = Instant::now(); let now_par = Instant::now();
let res_par = matmul_par( let res_par = hint::black_box(matmul_par(
hint::black_box(
mat1.axis_iter(Axis(0)) mat1.axis_iter(Axis(0))
.map(|row| row.to_vec()) .map(|row| row.to_vec())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice(), .as_slice(),
),
hint::black_box(
mat2_transposed mat2_transposed
.axis_iter(Axis(0)) .axis_iter(Axis(0))
.map(|row| row.to_vec()) .map(|row| row.to_vec())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.as_slice(), .as_slice(),
); ),
));
let elapsed_par = now_par.elapsed(); 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); assert!(elapsed_par < elapsed_seq);
} }
} }

View File

@@ -3,7 +3,6 @@ use std::io::{self, BufRead, Read};
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use cs220::assignments::assignment04::*; use cs220::assignments::assignment04::*;
struct Input<'a> { struct Input<'a> {

View File

@@ -1,31 +1,57 @@
//! KAIST CS220: Programming Principles //! 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(warnings)]
#![deny(rustdoc::invalid_html_tags)]
// #![deny(rustdoc::missing_doc_code_examples)]
#![deny(missing_docs)]
#![deny(rustdoc::all)] #![deny(rustdoc::all)]
#![deny(unreachable_pub)] // # Tries to deny all lints (`rustc -W help`).
#![deny(single_use_lifetimes)] #![deny(
#![deny(unused_lifetimes)] absolute_paths_not_starting_with_crate,
#![deny(unstable_features)] // 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; pub mod assignments;

View File