├── .gitignore ├── rust-toolchain.toml ├── src ├── assignments │ ├── mod.rs │ ├── assignment01 │ │ ├── small_exercises_grade.rs │ │ ├── small_exercises.rs │ │ └── mod.rs │ ├── assignment04 │ │ ├── syntax.pest │ │ ├── syntax.rs │ │ ├── parser.rs │ │ ├── mod.rs │ │ └── context.rs │ ├── assignment10 │ │ ├── mod.rs │ │ ├── labyrinth.rs │ │ ├── labyrinth_grade.rs │ │ └── small_exercises.rs │ ├── assignment08 │ │ ├── mod.rs │ │ ├── small_exercises_grade.rs │ │ ├── small_exercises.rs │ │ ├── church_grade.rs │ │ └── church.rs │ ├── assignment03 │ │ ├── mod.rs │ │ ├── parse_shell.rs │ │ ├── parse_shell_grade.rs │ │ ├── custom_operators_grade.rs │ │ ├── custom_operators.rs │ │ ├── small_exercises.rs │ │ └── small_exercises_grade.rs │ ├── assignment09 │ │ ├── mod.rs │ │ ├── matmul.rs │ │ ├── bigint.rs │ │ ├── bigint_grade.rs │ │ ├── matmul_grade.rs │ │ ├── small_exercises.rs │ │ └── small_exercises_grade.rs │ ├── assignment06 │ │ ├── mod.rs │ │ ├── semiring_grade.rs │ │ ├── semiring.rs │ │ └── symbolic_differentiation_grade.rs │ ├── assignment12 │ │ ├── mod.rs │ │ ├── funnel.rs │ │ ├── small_exercises.rs │ │ ├── demux_grade.rs │ │ ├── funnel_grade.rs │ │ ├── demux.rs │ │ ├── card.rs │ │ ├── small_exercises_grade.rs │ │ └── card_grade.rs │ ├── assignment13 │ │ ├── mod.rs │ │ ├── small_exercises.rs │ │ └── small_exercises_grade.rs │ ├── assignment11 │ │ ├── mod.rs │ │ ├── tv_room_grade.rs │ │ ├── mock_storage_grade.rs │ │ ├── graph_grade.rs │ │ ├── linked_list_grade.rs │ │ ├── mock_storage.rs │ │ ├── linked_list.rs │ │ ├── tv_room.rs │ │ └── graph.rs │ ├── assignment07 │ │ ├── mod.rs │ │ ├── generator.rs │ │ ├── generator_grade.rs │ │ ├── my_itertools_grade.rs │ │ ├── transform_grade.rs │ │ ├── transform.rs │ │ ├── small_exercises.rs │ │ ├── my_itertools.rs │ │ └── small_exercises_grade.rs │ └── assignment02 │ │ ├── mod.rs │ │ ├── vec_and_mat_grade.rs │ │ ├── small_exercises.rs │ │ ├── vec_and_mat.rs │ │ └── small_exercises_grade.rs ├── bin │ ├── par_iter.rs │ └── calc.rs └── lib.rs ├── .github ├── ISSUE_TEMPLATE │ ├── ASSIGNMENT.md │ └── assignment_question.yml └── workflows │ └── rustdoc.yaml ├── assets └── why3 │ ├── exercises │ ├── ex1_eucl_div.mlw │ ├── solutions │ │ ├── ex2_fact_sol.mlw │ │ ├── ex1_eucl_div_sol.mlw │ │ └── ex3_two_way_sol.mlw │ ├── ex2_fact.mlw │ └── ex3_two_way.mlw │ └── assignment05 │ ├── binary_search.mlw │ ├── README.md │ ├── max.mlw │ └── pascal.mlw ├── Cargo.toml └── scripts ├── submit.sh ├── grade-utils.sh └── grade.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | rustfmt.toml 3 | /.vscode 4 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.81.0" 3 | components = ["rustfmt", "clippy"] 4 | -------------------------------------------------------------------------------- /src/assignments/mod.rs: -------------------------------------------------------------------------------- 1 | //! KAIST CS220 Assignments. 2 | 3 | #![allow(dead_code)] 4 | #![allow(unused_mut)] 5 | #![allow(unused_imports)] 6 | #![allow(unused_variables)] 7 | #![allow(unreachable_code)] 8 | 9 | pub mod assignment01; 10 | pub mod assignment02; 11 | pub mod assignment03; 12 | pub mod assignment04; 13 | pub mod assignment06; 14 | pub mod assignment07; 15 | pub mod assignment08; 16 | pub mod assignment09; 17 | pub mod assignment10; 18 | pub mod assignment11; 19 | pub mod assignment12; 20 | pub mod assignment13; 21 | -------------------------------------------------------------------------------- /src/assignments/assignment01/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::assignments::assignment01::small_exercises::*; 4 | 5 | #[test] 6 | fn test_add_7_3() { 7 | assert_eq!(add(7, 3), 10); 8 | } 9 | 10 | #[test] 11 | fn test_add_overflow() { 12 | assert_eq!(add(usize::MAX, 1), usize::MIN); 13 | } 14 | 15 | #[test] 16 | fn test_sub_7_3() { 17 | assert_eq!(sub(7, 3), 4); 18 | } 19 | 20 | #[test] 21 | fn test_sub_overflow() { 22 | assert_eq!(sub(usize::MIN, 1), usize::MAX); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/assignments/assignment04/syntax.pest: -------------------------------------------------------------------------------- 1 | num = @{ int ~ ("." ~ ASCII_DIGIT*)? ~ (^"e" ~ int)? } 2 | int = { ("+" | "-")? ~ ASCII_DIGIT+ } 3 | var = { ("$" | ASCII_ALPHA) ~ (ASCII_ALPHA | ASCII_DIGIT)* } 4 | 5 | operation = _{ add | subtract | multiply | divide | power } 6 | add = { "+" } 7 | subtract = { "-" } 8 | multiply = { "*" } 9 | divide = { "/" } 10 | power = { "^" } 11 | 12 | expr = { term ~ (operation ~ term)* } 13 | term = _{ num | var | "(" ~ expr ~ ")" } 14 | 15 | command = _{ SOI ~ (var ~ "=")? ~ expr ~ EOI } 16 | 17 | WHITESPACE = _{ " " | "\t" } 18 | -------------------------------------------------------------------------------- /src/assignments/assignment10/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 10: Iterators (2/2). 2 | //! The primary goal of this assignment is to get used to iterators. 3 | //! 4 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 10` works 5 | //! fine. See `assignment10/*_grade.rs` and `/scripts/grade.sh 10` for the test script. 6 | //! 7 | //! To submit, run 8 | //! ```bash 9 | //! # At the cs220 home directory, 10 | //! ./scripts/submit.sh 11 | //! ``` 12 | //! and submit the generated `assignment10.zip` file in `target` directory. 13 | 14 | pub mod labyrinth; 15 | pub mod small_exercises; 16 | 17 | mod labyrinth_grade; 18 | mod small_exercises_grade; 19 | -------------------------------------------------------------------------------- /src/assignments/assignment08/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 8: First-class functions. 2 | //! 3 | //! The primary goal of this assignment is to get used to first-class functions. 4 | //! 5 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 8` works 6 | //! fine. See `assignment08/*_grade.rs` and `/scripts/grade.sh 8` for the test script. 7 | //! 8 | //! To submit, run 9 | //! ```bash 10 | //! # At the cs220 home directory, 11 | //! ./scripts/submit.sh 12 | //! ``` 13 | //! and submit the generated `assignment08.zip` file in `target` directory. 14 | 15 | pub mod church; 16 | pub mod small_exercises; 17 | 18 | mod church_grade; 19 | mod small_exercises_grade; 20 | -------------------------------------------------------------------------------- /src/assignments/assignment03/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 3: Mastering common programming concepts (2/2) 2 | //! 3 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 3` works 4 | //! fine. See `assignment03/*_grade.rs` and `/scripts/grade.sh 3` for the test script. 5 | //! 6 | //! To submit, run 7 | //! ```bash 8 | //! # At the cs220 home directory, 9 | //! ./scripts/submit.sh 10 | //! ``` 11 | //! and submit the generated `assignment03.zip` file in `target` directory. 12 | 13 | pub mod small_exercises; 14 | mod small_exercises_grade; 15 | 16 | pub mod parse_shell; 17 | mod parse_shell_grade; 18 | 19 | pub mod custom_operators; 20 | mod custom_operators_grade; 21 | -------------------------------------------------------------------------------- /src/assignments/assignment09/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 9: Iterators (1/2). 2 | //! 3 | //! The primary goal of this assignment is to get used to iterators. 4 | //! 5 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 9` works 6 | //! fine. See `assignment09/*_grade.rs` and `/scripts/grade.sh 9` for the test script. 7 | //! 8 | //! To submit, run 9 | //! ```bash 10 | //! # At the cs220 home directory, 11 | //! ./scripts/submit.sh 12 | //! ``` 13 | //! and submit the generated `assignment09.zip` file in `target` directory. 14 | 15 | pub mod bigint; 16 | pub mod matmul; 17 | pub mod small_exercises; 18 | 19 | mod bigint_grade; 20 | mod matmul_grade; 21 | mod small_exercises_grade; 22 | -------------------------------------------------------------------------------- /src/assignments/assignment01/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 1: Preparing Rust Development Environment. 2 | //! Welcome to CS220! 3 | //! 4 | //! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade.sh 1` 5 | //! works fine. See `small_problems_grade.rs` and `/scripts/grade.sh 1` for the test script. 6 | //! 7 | //! Hint: 8 | 9 | /// Adds two unsigned words. If overflow happens, just wrap around. 10 | pub fn add(lhs: usize, rhs: usize) -> usize { 11 | todo!() 12 | } 13 | 14 | /// Subtracts two unsigned words. If overflow happens, just wrap around. 15 | pub fn sub(lhs: usize, rhs: usize) -> usize { 16 | todo!() 17 | } 18 | -------------------------------------------------------------------------------- /src/assignments/assignment06/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 6: Mastering advanced types (1/2). 2 | //! 3 | //! The primary goal of this assignment is to understand generics, traits, and lifetimes. 4 | //! 5 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 6` works 6 | //! fine. See `assignment06/*_grade.rs` and `/scripts/grade.sh 6` for the test script. 7 | //! 8 | //! To submit, run 9 | //! ```bash 10 | //! # At the cs220 home directory, 11 | //! ./scripts/submit.sh 12 | //! ``` 13 | //! and submit the generated `assignment06.zip` file in `target` directory. 14 | 15 | pub mod semiring; 16 | pub mod symbolic_differentiation; 17 | 18 | mod semiring_grade; 19 | mod symbolic_differentiation_grade; 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ASSIGNMENT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Homework 3 | about: Create a homework 4 | title: "[Assignment TODO] TODO (due: TODO, 23:59:59 (KST))" 5 | labels: assignment, announcement 6 | assignees: '' 7 | 8 | --- 9 | 10 | DESCRIPTION. 11 | 12 | - Read the description [here](https://github.com/kaist-cp/cs220/blob/main/src/assignments/assignmentX/mod.rs). You're going to fill out the `todo!()`s. 13 | 14 | - You can grade your solution yourself by running `./scripts/grade.sh X`. 15 | 16 | - Submit your code [here](https://gg.kaist.ac.kr/assignment/GGX/). 17 | 18 | - **IMPORTANT**: only the last submission counts. Please make sure the last submission succeeds. 19 | 20 | - **IMPORTANT**: don't fork this repository. It'll be public! 21 | -------------------------------------------------------------------------------- /src/assignments/assignment12/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 12: Concurrency. 2 | //! 3 | //! The primary goal of this assignment is to get used to concurrency. 4 | //! 5 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 12` works 6 | //! fine. See `assignment12/*_grade.rs` and `/scripts/grade.sh 12` for the test script. 7 | //! 8 | //! To submit, run 9 | //! ```bash 10 | //! # At the cs220 home directory, 11 | //! ./scripts/submit.sh 12 | //! ``` 13 | //! and submit the generated `assignment12.zip` file in `target` directory. 14 | 15 | pub mod card; 16 | pub mod demux; 17 | pub mod funnel; 18 | pub mod small_exercises; 19 | 20 | mod card_grade; 21 | mod demux_grade; 22 | mod funnel_grade; 23 | mod small_exercises_grade; 24 | -------------------------------------------------------------------------------- /src/assignments/assignment13/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 13: Parallelism. 2 | //! 3 | //! The primary goal of this assignment is to get used to data parallelism. 4 | //! 5 | //! Refer to your solution for assignment 09. You will implement the parallelized version of 6 | //! assignment 09. You should fill out the `todo!()` placeholders in such a way that 7 | //! `/scripts/grade.sh 13` works fine. See `assignment13/small_exercises_grade.rs` and 8 | //! `/scripts/grade.sh 13` for the test script. 9 | //! 10 | //! To submit, run 11 | //! ```bash 12 | //! # At the cs220 home directory, 13 | //! ./scripts/submit.sh 14 | //! ``` 15 | //! and submit the generated `assignment13.zip` file in `target` directory. 16 | 17 | pub mod small_exercises; 18 | mod small_exercises_grade; 19 | -------------------------------------------------------------------------------- /assets/why3/exercises/ex1_eucl_div.mlw: -------------------------------------------------------------------------------- 1 | (* Euclidean division 2 | 3 | 1. Prove correctness of euclideian divison: 4 | `division a b` returns an integer `q` such that 5 | `a = bq+r` and `0 <= r < b` for some `r`. 6 | 7 | - You have to strengthen the loop invariant. 8 | *) 9 | 10 | module Division 11 | 12 | use int.Int 13 | 14 | let division (a b: int) : int 15 | requires { a >= 0 } 16 | requires { b > 0 } 17 | ensures { exists r: int. a = b * result + r /\ 0 <= r < b } 18 | = 19 | let ref q = 0 in 20 | let ref r = a in 21 | while r >= b do 22 | invariant { true (* TODO: Replace `true` with your solution *) } 23 | variant { r } 24 | q <- q + 1; 25 | r <- r - b 26 | done; 27 | q 28 | 29 | end 30 | -------------------------------------------------------------------------------- /assets/why3/assignment05/binary_search.mlw: -------------------------------------------------------------------------------- 1 | (* Binary search 2 | 3 | A classical example. Searches a sorted array for a given value v. 4 | Consult . 5 | *) 6 | 7 | module BinarySearch 8 | 9 | use int.Int 10 | use int.ComputerDivision 11 | use ref.Ref 12 | use array.Array 13 | 14 | let binary_search (a : array int) (v : int) : int 15 | requires { forall i1 i2 : int. 0 <= i1 < i2 < length a -> a[i1] <= a[i2] } 16 | ensures { 0 <= result <= length a } 17 | ensures { forall i: int. 0 <= i < result -> a[i] < v } 18 | ensures { forall i: int. result <= i < length a -> v <= a[i] } 19 | = 20 | (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) 21 | 0 (* TODO *) 22 | 23 | end 24 | -------------------------------------------------------------------------------- /assets/why3/exercises/solutions/ex2_fact_sol.mlw: -------------------------------------------------------------------------------- 1 | (* Two programs to compute the factorial 2 | 3 | *) 4 | 5 | module FactRecursive 6 | 7 | use int.Int 8 | use int.Fact 9 | 10 | let rec fact_rec (n: int) : int 11 | requires { n >= 0 } 12 | ensures { result = fact n } 13 | variant { n } 14 | = 15 | if n = 0 then 1 else n * fact_rec (n - 1) 16 | 17 | end 18 | 19 | module FactLoop 20 | 21 | use int.Int 22 | use int.Fact 23 | 24 | let fact_loop (n: int) : int 25 | requires { 0 < n } 26 | ensures { result = fact n } 27 | = let ref m = 0 in 28 | let ref r = 1 in 29 | while m < n do 30 | invariant { 0 <= m <= n /\ r = fact m } 31 | variant { n - m } 32 | m <- m + 1; 33 | r <- r * m 34 | done; 35 | r 36 | 37 | end 38 | -------------------------------------------------------------------------------- /src/assignments/assignment11/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 11: Familiarizing with smart pointers. 2 | //! 3 | //! You should fill out `todo!()` placeholders in such a way that `/scripts/grade.sh 11` works fine. 4 | //! See `assignment11/*_grade.rs` and `/scripts/grade.sh 11` for the test script. 5 | //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to . 6 | //! 7 | //! To submit, run 8 | //! ```bash 9 | //! # At the cs220 home directory, 10 | //! ./scripts/submit.sh 11 | //! ``` 12 | //! and submit the generated `assignment11.zip` file in `target` directory. 13 | 14 | pub mod graph; 15 | pub mod linked_list; 16 | pub mod mock_storage; 17 | pub mod tv_room; 18 | 19 | mod graph_grade; 20 | mod linked_list_grade; 21 | mod mock_storage_grade; 22 | mod tv_room_grade; 23 | -------------------------------------------------------------------------------- /src/bin/par_iter.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | use rayon::prelude::*; 4 | 5 | const SIZE: usize = 100_000_000; 6 | 7 | fn sequential() { 8 | let _v = (0..SIZE) 9 | .filter_map(|x| if x % 2 == 0 { Some(x * 3) } else { None }) 10 | .collect::>(); 11 | } 12 | 13 | fn parallel() { 14 | let _v = (0..SIZE) 15 | .into_par_iter() 16 | .filter_map(|x| if x % 2 == 0 { Some(x * 3) } else { None }) 17 | .collect::>(); 18 | } 19 | 20 | fn bench(name: &str, f: F) 21 | where 22 | F: FnOnce(), 23 | { 24 | let begin = Instant::now(); 25 | f(); 26 | let elapsed = begin.elapsed(); 27 | println!("{}: {:.2?}", name, elapsed); 28 | } 29 | 30 | fn main() { 31 | bench("sequential", sequential); 32 | bench("parallel", parallel); 33 | } 34 | -------------------------------------------------------------------------------- /assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw: -------------------------------------------------------------------------------- 1 | (* Euclidean division 2 | 3 | 1. Prove correctness of euclideian divison: 4 | `division a b` returns an integer `q` such that 5 | `a = bq+r` and `0 <= r < b` for some `r`. 6 | 7 | - You have to strengthen the precondition. 8 | - You have to strengthen the loop invariant. 9 | *) 10 | 11 | module Division 12 | 13 | use int.Int 14 | 15 | let division (a b: int) : int 16 | requires { a >= 0 } 17 | requires { b > 0 } 18 | ensures { exists r: int. a = b * result + r /\ 0 <= r < b } 19 | = 20 | let ref q = 0 in 21 | let ref r = a in 22 | while r >= b do 23 | invariant { a = b * q + r /\ 0 <= r } 24 | variant { r } 25 | q <- q + 1; 26 | r <- r - b 27 | done; 28 | q 29 | 30 | end 31 | -------------------------------------------------------------------------------- /src/assignments/assignment07/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 7: Mastering advanced types (2/2). 2 | //! 3 | //! The primary goal of this assignment is to understand generics, traits, and lifetimes. 4 | //! 5 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 7` works 6 | //! fine. See `assignment07/*_grade.rs` and `/scripts/grade.sh 7` for the test script. 7 | //! 8 | //! To submit, run 9 | //! ```bash 10 | //! # At the cs220 home directory, 11 | //! ./scripts/submit.sh 12 | //! ``` 13 | //! and submit the generated `assignment07.zip` file in `target` directory. 14 | 15 | pub mod generator; 16 | pub mod my_itertools; 17 | pub mod small_exercises; 18 | pub mod transform; 19 | 20 | mod generator_grade; 21 | mod my_itertools_grade; 22 | mod small_exercises_grade; 23 | mod transform_grade; 24 | -------------------------------------------------------------------------------- /src/assignments/assignment12/funnel.rs: -------------------------------------------------------------------------------- 1 | //! Funnel 2 | //! 3 | //! Spawn a thread that executes a funnel. 4 | //! 5 | //! Funnel will receive data from multiple receivers and send it to a single sender. Also, the 6 | //! funnel will filter out data that does not pass the filter function. 7 | //! 8 | //! Refer to `funnel_grade.rs` for test cases. 9 | 10 | use std::sync::mpsc::{channel, Receiver, Sender}; 11 | use std::sync::Arc; 12 | use std::thread; 13 | use std::thread::JoinHandle; 14 | 15 | /// Spawn a thread that concurrently receive datas from `rxs`, send it to `tx` if it makes `f` true. 16 | /// Returns its handle. 17 | pub fn spawn_funnel(rxs: Vec>, tx: Sender, f: F) -> JoinHandle<()> 18 | where 19 | T: Send + 'static, 20 | F: Send + Sync + Fn(&T) -> bool + 'static, 21 | { 22 | todo!() 23 | } 24 | -------------------------------------------------------------------------------- /src/assignments/assignment01/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 1: Preparing Rust Development Environment. 2 | //! 3 | //! The primary goal of this assignment is bringing up SSH, VSCode, and all the other necessary 4 | //! tools to develop Rust programs. Please make sure you're comfortable with developing Rust 5 | //! programs before moving on to the next assignments. 6 | //! 7 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 1` works 8 | //! fine. See `assigment01/small_exercises_grade.rs` and `/scripts/grade.sh 1` for the test script. 9 | //! 10 | //! To submit, run 11 | //! ```bash 12 | //! # At the cs220 home directory, 13 | //! ./scripts/submit.sh 14 | //! ``` 15 | //! and submit the generated `assignment01.zip` file in `target` directory. 16 | 17 | pub mod small_exercises; 18 | mod small_exercises_grade; 19 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cs220" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [lib] 9 | name = "cs220" 10 | path = "src/lib.rs" 11 | 12 | [[bin]] 13 | name = "calc" 14 | path = "src/bin/calc.rs" 15 | required-features = ["build-calc"] 16 | 17 | [[bin]] 18 | name = "par_iter" 19 | path = "src/bin/par_iter.rs" 20 | 21 | [features] 22 | build-calc = ["clap"] 23 | 24 | [dependencies] 25 | anyhow = "1.0.86" 26 | clap = { version = "4.5.11", features = ["derive"], optional = true } 27 | etrace = "1.1.1" 28 | itertools = "0.13.0" 29 | lazy_static = "1.5.0" 30 | pest = "2.7.11" 31 | pest_derive = "2.7.11" 32 | rayon = "1.10.0" 33 | ntest = "0.9.3" 34 | approx = "0.5.1" 35 | ndarray = "0.15.6" 36 | ndarray-rand = "0.14.0" 37 | rand = "0.8.5" 38 | -------------------------------------------------------------------------------- /src/assignments/assignment02/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 2: Mastering common programming concepts (1/2). 2 | //! 3 | //! The primary goal of this assignment is to re-learn the common programming concepts in Rust, 4 | //! especially those in the Rust Book chapters 3 and 5. Please make sure you're comfortable with the 5 | //! concepts to proceed on to the next assignments. 6 | //! 7 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 2` works 8 | //! fine. See `assigment02/*_grade.rs` and `/scripts/grade.sh 2` for the test script. 9 | //! 10 | //! To submit, run 11 | //! ```bash 12 | //! # At the cs220 home directory, 13 | //! ./scripts/submit.sh 14 | //! ``` 15 | //! and submit the generated `assignment02.zip` file in `target` directory. 16 | 17 | pub mod small_exercises; 18 | mod small_exercises_grade; 19 | 20 | pub mod vec_and_mat; 21 | mod vec_and_mat_grade; 22 | -------------------------------------------------------------------------------- /scripts/submit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | BASEDIR=$(dirname "$0")/.. 6 | 7 | mkdir -p $BASEDIR/target 8 | 9 | for i in {01..13} ; do 10 | if [ $i -eq 5 ] 11 | then 12 | if [ -f $BASEDIR/target/assignment05.zip ]; then 13 | rm $BASEDIR/target/assignment05.zip 14 | fi 15 | zip -rj $BASEDIR/target/assignment05.zip $BASEDIR/assets/why3/assignment05 16 | continue 17 | fi 18 | 19 | if [ $i -eq 13 ] 20 | then 21 | if [ -f $BASEDIR/target/assignment13.zip ]; then 22 | rm $BASEDIR/target/assignment13.zip 23 | fi 24 | zip -rj $BASEDIR/target/assignment13.zip $BASEDIR/src/assignments/assignment13 $BASEDIR/src/assignments/assignment09/matmul.rs 25 | continue 26 | fi 27 | 28 | if [ -f $BASEDIR/target/assignment$i.zip ]; then 29 | rm $BASEDIR/target/assignment$i.zip 30 | fi 31 | zip -rj $BASEDIR/target/assignment$i.zip $BASEDIR/src/assignments/assignment$i 32 | done 33 | -------------------------------------------------------------------------------- /src/assignments/assignment04/syntax.rs: -------------------------------------------------------------------------------- 1 | //! Syntax. 2 | 3 | /// Command of the form "{expression}" or "{var} = {expression}". 4 | #[derive(Debug, Clone, PartialEq)] 5 | pub struct Command { 6 | /// Variable (lhs). 7 | pub variable: Option, 8 | /// Expression (rhs). 9 | pub expression: Expression, 10 | } 11 | 12 | /// Binary operators. 13 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 14 | pub enum BinOp { 15 | /// Add. 16 | Add, 17 | /// Subtract. 18 | Subtract, 19 | /// Multiply. 20 | Multiply, 21 | /// Divide. 22 | Divide, 23 | /// Power. 24 | Power, 25 | } 26 | 27 | /// Expression. 28 | #[derive(Debug, Clone, PartialEq)] 29 | pub enum Expression { 30 | /// Number. 31 | Num(f64), 32 | /// Variable. 33 | Variable(String), 34 | /// Binary operation. 35 | BinOp { 36 | /// Operator. 37 | op: BinOp, 38 | /// Lhs. 39 | lhs: Box, 40 | /// Rhs. 41 | rhs: Box, 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /src/assignments/assignment04/parser.rs: -------------------------------------------------------------------------------- 1 | #![allow(deprecated)] 2 | 3 | //! Parser. 4 | 5 | use anyhow::{bail, Result}; 6 | use etrace::*; 7 | use lazy_static::*; 8 | use pest::iterators::{Pair, Pairs}; 9 | use pest::prec_climber::*; 10 | use pest::Parser; 11 | 12 | use super::syntax::*; 13 | 14 | #[allow(missing_docs)] 15 | #[allow(missing_debug_implementations)] 16 | mod inner { 17 | use pest_derive::*; 18 | 19 | #[derive(Parser)] 20 | #[grammar = "assignments/assignment04/syntax.pest"] 21 | pub(crate) struct SyntaxParser; 22 | } 23 | 24 | use inner::*; 25 | 26 | /// Parses command. 27 | /// 28 | /// ## Operator Associativty 29 | /// 30 | /// For associativity of each operator, please follow [here](https://docs.rs/pest/latest/pest/prec_climber/struct.PrecClimber.html#examples). 31 | /// 32 | /// e.g. `1+2+3` should be parsed into `(1+2)+3`, not `1+(2+3)` because the associativity of 33 | /// plus("add" in our hw) operator is `Left`. 34 | pub fn parse_command(line: &str) -> Result { 35 | todo!("fill here") 36 | } 37 | -------------------------------------------------------------------------------- /src/assignments/assignment11/tv_room_grade.rs: -------------------------------------------------------------------------------- 1 | //! Test cases for assignment11/tv_room.rs 2 | 3 | #[cfg(test)] 4 | mod test_tv_room { 5 | use crate::assignments::assignment11::tv_room::*; 6 | 7 | #[test] 8 | fn test_tv_room() { 9 | let tv_room = TVRoom::new(); 10 | assert!(!tv_room.is_opened()); 11 | 12 | // Turn on and add new guests. 13 | let manager = tv_room.open().unwrap(); 14 | assert!(tv_room.is_opened()); 15 | let guest1 = manager.new_guest(); 16 | let guest2 = manager.new_guest(); 17 | drop(manager); 18 | drop(guest1); 19 | assert!(tv_room.open().is_none()); 20 | drop(guest2); 21 | assert!(!tv_room.is_opened()); 22 | 23 | // Turn on and add new guests. 24 | let manager = tv_room.open().unwrap(); 25 | assert!(tv_room.is_opened()); 26 | let guest3 = manager.new_guest(); 27 | drop(guest3); 28 | assert!(tv_room.is_opened()); 29 | drop(manager); 30 | assert!(!tv_room.is_opened()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/assignments/assignment12/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Small exercises 2 | //! 3 | //! Refer `small_exercises_grade.rs` for test cases 4 | 5 | use std::sync::mpsc::{Receiver, RecvError, Sender}; 6 | use std::thread; 7 | 8 | use etrace::*; 9 | 10 | /// The "pong" function 11 | /// 12 | /// Data will be sent and received through `rx` and `tx`. 13 | /// Read the `test_ping_pong` function in `small_exercises_grade.rs` to figure out what it should 14 | /// do. 15 | pub fn pong(rx1: &mut Receiver, tx2: &mut Sender) -> bool { 16 | todo!() 17 | } 18 | 19 | /// Executes the given functions (f1, f2) in concurrent and returns the results. 20 | /// 21 | /// Read the `test_scoped_thread` function in `small_exercises_grade.rs` to figure out what it 22 | /// should do. 23 | pub fn use_scoped_thread<'scope, T1, T2, F1, F2>( 24 | s: &'scope thread::Scope<'scope, '_>, 25 | f1: F1, 26 | f2: F2, 27 | ) -> (T1, T2) 28 | where 29 | T1: Send + 'scope, 30 | T2: Send + 'scope, 31 | F1: Send + FnOnce() -> T1 + 'scope, 32 | F2: Send + FnOnce() -> T2 + 'scope, 33 | { 34 | todo!() 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/rustdoc.yaml: -------------------------------------------------------------------------------- 1 | name: rustdoc 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | env: 8 | CARGO_INCREMENTAL: 0 9 | CARGO_NET_RETRY: 10 10 | RUSTFLAGS: "-D warnings -W unreachable-pub" 11 | RUSTUP_MAX_RETRIES: 10 12 | 13 | jobs: 14 | rustdoc: 15 | if: github.repository == 'kaist-cp/cs220' 16 | runs-on: [self-hosted, ubuntu-22.04] 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v4.1.1 21 | 22 | - name: Install Rustup 23 | run: if ! command -v rustup &>/dev/null; then (curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y); fi 24 | 25 | - name: Install Rust toolchain 26 | run: source "$HOME/.cargo/env"; rustup update --no-self-update stable 27 | 28 | - name: Build Documentation 29 | run: source "$HOME/.cargo/env"; cargo doc --all 30 | 31 | - name: Deploy Docs 32 | uses: peaceiris/actions-gh-pages@v4.0.0 33 | with: 34 | github_token: ${{ secrets.GITHUB_TOKEN }} 35 | publish_branch: gh-pages 36 | publish_dir: ./target/doc 37 | force_orphan: true 38 | -------------------------------------------------------------------------------- /src/assignments/assignment12/demux_grade.rs: -------------------------------------------------------------------------------- 1 | //! Test cases for assignment12/demux.rs 2 | 3 | #[cfg(test)] 4 | mod test_demux { 5 | use std::sync::mpsc::channel; 6 | use std::thread; 7 | 8 | use ntest::timeout; 9 | 10 | use crate::assignments::assignment12::demux::*; 11 | 12 | #[test] 13 | #[timeout(5000)] 14 | fn test_demux() { 15 | let (tx, rx1, rx2) = demux::(|x| x % 2 == 0); 16 | 17 | let thread_tx = thread::spawn(move || { 18 | for i in 0..100 { 19 | tx.send(i).unwrap(); 20 | } 21 | }); 22 | 23 | let thread_rx1 = thread::spawn(move || { 24 | let sum: u32 = rx1.iter().sum(); 25 | assert_eq!(sum, (0..100).filter(|x| x % 2 == 0).sum()); 26 | }); 27 | 28 | let thread_rx2 = thread::spawn(move || { 29 | let sum: u32 = rx2.iter().sum(); 30 | assert_eq!(sum, (0..100).filter(|x| x % 2 != 0).sum()); 31 | }); 32 | 33 | thread_tx.join().unwrap(); 34 | thread_rx1.join().unwrap(); 35 | thread_rx2.join().unwrap(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/assignments/assignment12/funnel_grade.rs: -------------------------------------------------------------------------------- 1 | //! Test cases for assignment12/funnel.rs 2 | 3 | #[cfg(test)] 4 | mod test_funnel { 5 | use std::sync::mpsc::channel; 6 | use std::thread; 7 | 8 | use ntest::timeout; 9 | 10 | use crate::assignments::assignment12::funnel::*; 11 | 12 | #[test] 13 | #[timeout(5000)] 14 | fn test_funnel_concurrent() { 15 | let (txs, rxs): (Vec<_>, Vec<_>) = (0..10).map(|_| channel::()).unzip(); 16 | let (tx, rx) = channel::(); 17 | let filter = |x: &u32| x % 2 == 0; 18 | 19 | let thread_txs_rx = thread::spawn(move || { 20 | for i in 0..100 { 21 | let idx = (i * 7) % 13 * 17 % 10; 22 | txs[idx].send(i as u32).unwrap(); 23 | if i % 2 == 0 { 24 | let x = rx.recv().unwrap(); 25 | assert_eq!(x, i as u32); 26 | } 27 | } 28 | }); 29 | let thread_funnel = spawn_funnel(rxs, tx, filter); 30 | 31 | thread_txs_rx.join().unwrap(); 32 | thread_funnel.join().unwrap(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/assignments/assignment11/mock_storage_grade.rs: -------------------------------------------------------------------------------- 1 | //! Test cases for assignment11/mock_storage.rs 2 | 3 | #[cfg(test)] 4 | mod test_mock_storage { 5 | use crate::assignments::assignment11::mock_storage::*; 6 | 7 | #[test] 8 | fn test_mock_storage() { 9 | let mock_storage = MockStorage::new(100); 10 | 11 | let uploader1 = FileUploader::new(&mock_storage); 12 | let uploader2 = FileUploader::new(&mock_storage); 13 | 14 | let usage_analyzer = UsageAnalyzer::new(&mock_storage, 0.75); 15 | 16 | assert!(uploader1.upload("file1.txt", 20).is_ok()); 17 | assert!(usage_analyzer.is_usage_under_bound()); 18 | 19 | assert!(uploader2.upload("file2.txt", 30).is_ok()); 20 | assert!(usage_analyzer.is_usage_under_bound()); 21 | 22 | assert!(uploader1.upload("file3.txt", 40).is_ok()); 23 | assert!(!usage_analyzer.is_usage_under_bound()); 24 | 25 | assert_eq!(uploader2.upload("file4.txt", 50), Err(40)); 26 | assert!(!usage_analyzer.is_usage_under_bound()); 27 | 28 | assert!(uploader1.upload("file3.txt", 10).is_ok()); 29 | assert!(usage_analyzer.is_usage_under_bound()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /assets/why3/exercises/ex2_fact.mlw: -------------------------------------------------------------------------------- 1 | (* Two programs to compute the factorial 2 | 3 | Questions: 4 | 5 | 1. In module FactRecursive: 6 | 7 | a. Implement the program that satisfies specification. 8 | 9 | 2. In module FactLoop: 10 | 11 | a. Strengthen the invariant to prove correctness of the given implementation. 12 | 13 | b. Select a correct variant to prove the termination. 14 | 15 | *) 16 | 17 | module FactRecursive 18 | 19 | use int.Int 20 | use int.Fact 21 | 22 | let rec fact_rec (n: int) : int 23 | requires { n >= 0 } 24 | ensures { result = fact n } 25 | variant { n } 26 | = (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) 27 | 0 (*TODO*) 28 | 29 | end 30 | 31 | module FactLoop 32 | 33 | use int.Int 34 | use int.Fact 35 | 36 | let fact_loop (n: int) : int 37 | requires { 0 < n } 38 | ensures { result = fact n } 39 | = let ref m = 0 in 40 | let ref r = 1 in 41 | while m < n do 42 | invariant { true (* TODO: Replace `true` with your solution *) } 43 | variant { n (* TODO: Replace `n` with your solution *) } 44 | m <- m + 1; 45 | r <- r * m 46 | done; 47 | r 48 | 49 | end 50 | -------------------------------------------------------------------------------- /src/assignments/assignment03/parse_shell.rs: -------------------------------------------------------------------------------- 1 | //! Parsing a shell command. 2 | //! 3 | //! Shell commands are text-based instructions that you can enter in a command-line interface (CLI) 4 | //! to interact with operating systems (e.g. Linux) and others. For example, you can use the `ls` 5 | //! command to list files in a directory. 6 | //! 7 | //! You will parse a given string consists of a small number of shell commands. 8 | 9 | /// Parse the string as a shell command. 10 | /// 11 | /// Usually, a shell command is whitespace-separated array of strings. 12 | /// 13 | /// ```text 14 | /// cat file --> ["cat", "file"] 15 | /// ``` 16 | /// 17 | /// But sometimes, you may want to include whitespaces in each argument. In that case, you can use 18 | /// quotes. 19 | /// 20 | /// ```text 21 | /// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs'] 22 | /// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs'] 23 | /// ``` 24 | /// 25 | /// For simplicity, you may assume that the string only contains alphanumeric characters, spaces 26 | /// (" "), and single quotes ("'"). 27 | /// 28 | /// See `test_shell` for more examples. 29 | pub fn parse_shell_command(command: &str) -> Vec { 30 | todo!() 31 | } 32 | -------------------------------------------------------------------------------- /assets/why3/assignment05/README.md: -------------------------------------------------------------------------------- 1 | # Assignment 5: Program correctness and logic 2 | 3 | * The primary goal of this assignment is to grasp basic concepts about proving a program's correctness with deductive reasoning. 4 | 5 | * You should fill in `TODO`s in three files: `max.mlw`, `binary_search.mlw`, `pascal.mlw`. 6 | * You will get PARTIAL SCOREs for each of those three files. 7 | * E.g. If `max.mlw` and `binary_search.mlw` get passed, 2 out of 3 points will be given. 8 | 9 | * You may use [Why3 in your browser](https://www.why3.org/try/). 10 | * Clicking `Verify` button at the top will open a panel on the right side. 11 | * For each task in the panel (e.g. `loop invariant preservation`), you can right-click it and run the prover. 12 | * Important: The prover might not be able to verify the correct solution if the number of steps is too small. Make sure to test with 1000~5000 steps. 13 | * Fill in `TODO`s until the prover can verify all tasks, notified with green check-marks. 14 | 15 | * To submit your solution, run `./scripts/submit.sh` and submit `assignment05.zip` in the `target` directory to gg. 16 | 17 | * [More on Why3](https://www.why3.org/doc/). 18 | * [Why3 standard library](https://www.why3.org/stdlib/). 19 | -------------------------------------------------------------------------------- /src/assignments/assignment04/mod.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 4: Designing a calculator. 2 | //! 3 | //! The primary goal of this assignment is twofold: 4 | //! - (1) understanding the `pest` third-party library from documentations; and 5 | //! - (2) using programming concepts you've learned so far to implement a simple arithmetic 6 | //! calculator. 7 | //! 8 | //! For `pest`, read the following documentations (that contain 90% of the solution): 9 | //! - 10 | //! - 11 | //! - 12 | //! 13 | //! For calculator, just reading `syntax.rs` would suffice for you to understand what to do. 14 | //! 15 | //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade.sh 4` works 16 | //! fine. See `assignment04/grade.rs` and `/scripts/grade.sh 4` for the test script. 17 | //! 18 | //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment04.zip` to . 19 | //! 20 | //! To submit, run 21 | //! ```bash 22 | //! # At the cs220 home directory, 23 | //! ./scripts/submit.sh 24 | //! ``` 25 | //! and submit the generated `assignment04.zip` file in `target` directory. 26 | 27 | pub mod context; 28 | mod grade; 29 | pub mod parser; 30 | pub mod syntax; 31 | -------------------------------------------------------------------------------- /assets/why3/assignment05/max.mlw: -------------------------------------------------------------------------------- 1 | (* Max 2 | 3 | Given an array `a` of integers with length `n` greater than `0`, 4 | return `max_idx`, the index of the maximum element of that array. 5 | 6 | E.g. `max_idx [5, 12, 34, 10] 4` will return `2` 7 | E.g. `max_idx [4, 3, 2] 3` will return `0` 8 | E.g. `max_idx [1, 2, 3, 4] 4` will return `3` 9 | 10 | Prove the below program indeed follows the given specification, 11 | by giving an appropriate invariant. 12 | *) 13 | 14 | module Max 15 | 16 | use int.Int 17 | use ref.Ref 18 | use array.Array 19 | 20 | let max_idx (a: array int) (n: int) : (max_idx: int) 21 | requires { length a > 0 } 22 | requires { n = length a } 23 | ensures { 0 <= max_idx <= n-1 } 24 | ensures { forall i. 0 <= i <= n-1 -> a[i] <= a[max_idx] } 25 | = 26 | let ref max_idx = 0 in 27 | for i = 0 to n-1 do 28 | invariant { 0 <= max_idx <= n-1 } 29 | (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) 30 | (* TODO: Replace `true` with your solution. Your solution MUST be a single line, at line 31. DON'T add more code above or below. *) 31 | invariant { true } 32 | (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) 33 | if a[max_idx] < a[i] then max_idx <- i; 34 | done; 35 | max_idx 36 | 37 | end 38 | 39 | -------------------------------------------------------------------------------- /src/assignments/assignment03/parse_shell_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::assignments::assignment03::parse_shell::*; 4 | 5 | #[test] 6 | fn test_shell() { 7 | assert_eq!( 8 | parse_shell_command("cat file"), 9 | vec!["cat".to_string(), "file".to_string()] 10 | ); 11 | assert_eq!( 12 | parse_shell_command("ls 'VirtualBox VMs'"), 13 | vec!["ls".to_string(), "VirtualBox VMs".to_string()] 14 | ); 15 | assert_eq!( 16 | parse_shell_command("ls VirtualBox' 'VMs"), 17 | vec!["ls".to_string(), "VirtualBox VMs".to_string()] 18 | ); 19 | assert_eq!( 20 | parse_shell_command("echo once upon a midnight dreary"), 21 | vec![ 22 | "echo".to_string(), 23 | "once".to_string(), 24 | "upon".to_string(), 25 | "a".to_string(), 26 | "midnight".to_string(), 27 | "dreary".to_string(), 28 | ] 29 | ); 30 | assert_eq!( 31 | parse_shell_command("echo 'once upon a midnight dreary'"), 32 | vec![ 33 | "echo".to_string(), 34 | "once upon a midnight dreary".to_string(), 35 | ] 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/assignments/assignment07/generator.rs: -------------------------------------------------------------------------------- 1 | //! Generators 2 | //! 3 | //! HINT: Look at the `generator_grade.rs` file to see how the generator is used. 4 | 5 | /// Yielded value. It can be either a value or a stop signal. 6 | enum Yielded { 7 | Value(T), 8 | Stop, 9 | } 10 | 11 | /// Generator 12 | /// - You can call `next()` method to get the next value. 13 | /// - The generator should stop when it yields `Yielded::Stop`. 14 | /// 15 | /// Reference: 16 | /// - [Python generator](https://python-reference.readthedocs.io/en/latest/docs/generator/) 17 | #[derive(Debug)] 18 | pub struct Generator { 19 | state: S, 20 | f: fn(&mut S) -> Yielded, 21 | } 22 | 23 | impl Iterator for Generator { 24 | type Item = T; 25 | 26 | fn next(&mut self) -> Option { 27 | todo!() 28 | } 29 | } 30 | 31 | /// Returns a generator that yields fibonacci numbers. 32 | /// 33 | /// HINT: Consult 34 | pub fn fib_generator(first: usize, second: usize) -> Generator { 35 | todo!() 36 | } 37 | 38 | /// Returns a generator that yields collatz numbers. 39 | /// 40 | /// HINT: Consult 41 | pub fn collatz_conjecture(start: usize) -> Generator { 42 | todo!() 43 | } 44 | -------------------------------------------------------------------------------- /assets/why3/exercises/solutions/ex3_two_way_sol.mlw: -------------------------------------------------------------------------------- 1 | (* Two Way Sort 2 | 3 | The following program sorts an array of Boolean values, with False a[i1] << a[i2] 25 | 26 | let two_way_sort (a: array bool) : unit 27 | ensures { sorted a } 28 | ensures { permut_all (old a) a } 29 | = 30 | let ref i = 0 in 31 | let ref j = length a - 1 in 32 | while i < j do 33 | invariant { 0 <= i /\ j < length a } 34 | invariant { forall i1: int. 0 <= i1 < i -> a[i1] = False } 35 | invariant { forall i2: int. j < i2 < length a -> a[i2] = True } 36 | invariant { permut_all (old a) a } 37 | variant { j - i } 38 | if not a[i] then 39 | incr i 40 | else if a[j] then 41 | decr j 42 | else begin 43 | swap a i j; 44 | incr i; 45 | decr j 46 | end 47 | done 48 | 49 | end 50 | -------------------------------------------------------------------------------- /src/assignments/assignment12/demux.rs: -------------------------------------------------------------------------------- 1 | //! Demultiplexing sender 2 | //! 3 | //! Implement a demultiplexing sender. 4 | //! 5 | //! Demultiplexer, `Demux` in short, is a device that has one input and many outputs. 6 | //! It distributes the input to the outputs according to the control signal. 7 | //! It is used when a circuit wishes to send a signal to one of many devices. 8 | //! For more information, refer 9 | //! 10 | //! In this assignment, closure `f` will be given as an argument to `demux` function. 11 | //! This closure will be used to determine which destination to send the input data. 12 | //! 13 | //! Refer `demux_grade.rs` for test cases 14 | 15 | use std::sync::mpsc::{channel, Receiver, SendError, Sender}; 16 | use std::thread; 17 | 18 | /// Sender for demux. 19 | #[derive(Debug)] 20 | pub struct DemuxSender bool> { 21 | tx_true: Sender, 22 | tx_false: Sender, 23 | f: F, 24 | } 25 | 26 | impl bool> DemuxSender { 27 | /// send 28 | /// 29 | /// If `f(&value)` is true, send `value` to `tx_true`. Otherwise, send `value` to `tx_false`. 30 | pub fn send(&self, value: T) -> Result<(), SendError> { 31 | todo!() 32 | } 33 | } 34 | 35 | /// Demux. 36 | pub fn demux bool>(f: F) -> (DemuxSender, Receiver, Receiver) { 37 | todo!() 38 | } 39 | -------------------------------------------------------------------------------- /src/assignments/assignment02/vec_and_mat_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::assignments::assignment02::vec_and_mat::*; 4 | 5 | #[test] 6 | fn test_fibonacci() { 7 | assert_eq!(fibonacci(0), 1); 8 | assert_eq!(fibonacci(1), 1); 9 | assert_eq!(fibonacci(2), 2); 10 | assert_eq!(fibonacci(3), 3); 11 | assert_eq!(fibonacci(4), 5); 12 | assert_eq!(fibonacci(5), 8); 13 | assert_eq!(fibonacci(6), 13); 14 | assert_eq!(fibonacci(7), 21); 15 | assert_eq!(fibonacci(50), 20365011074); 16 | assert_eq!(fibonacci(92), 12200160415121876738); 17 | } 18 | 19 | #[test] 20 | fn test_inverse() { 21 | assert_eq!( 22 | FMat2 { 23 | a: 1.0, 24 | b: 1.0, 25 | c: 2.0, 26 | d: 3.0 27 | } 28 | .inverse(), 29 | FMat2 { 30 | a: 3.0, 31 | b: -1.0, 32 | c: -2.0, 33 | d: 1.0 34 | } 35 | ); 36 | assert_eq!( 37 | FMat2 { 38 | a: 2.0, 39 | b: 3.0, 40 | c: 5.0, 41 | d: 7.0 42 | } 43 | .inverse(), 44 | FMat2 { 45 | a: -7.0, 46 | b: 3.0, 47 | c: 5.0, 48 | d: -2.0 49 | } 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/assignments/assignment10/labyrinth.rs: -------------------------------------------------------------------------------- 1 | //! Labyrinth 2 | //! 3 | //! Look at `labyrinth_grade.rs` below before you start. 4 | //! HINT: 5 | //! 6 | //! NOTE: You will have to implement a probabilistic algorithm, which means, the algorithm can fail 7 | //! even if you have implemented the solution. We recommend running multiple times (at least 5 8 | //! times) to check your solution works well. 9 | 10 | use std::cell::RefCell; 11 | 12 | /// Husband 13 | #[derive(Debug)] 14 | pub struct Husband { 15 | brain: RefCell<[usize; 100]>, 16 | } 17 | 18 | impl Husband { 19 | /// What might a husband, who is looking for his wife's ID my_wife, be thinking? 20 | pub fn seeking(my_wife: usize) -> Self { 21 | todo!() 22 | } 23 | 24 | #[allow(missing_docs)] 25 | pub fn has_devised_a_strategy(&self) -> Strategy<'_> { 26 | Strategy { husband: self } 27 | } 28 | 29 | /// Based on the information about currently visited room number and someone's wife ID trapped 30 | /// inside, what the husband should do next? 31 | pub fn carefully_checks_whos_inside(&self, room: usize, wife: usize) { 32 | todo!() 33 | } 34 | } 35 | 36 | /// Strategy of husband 37 | #[derive(Debug)] 38 | pub struct Strategy<'a> { 39 | husband: &'a Husband, 40 | } 41 | 42 | impl Iterator for Strategy<'_> { 43 | type Item = usize; 44 | 45 | fn next(&mut self) -> Option { 46 | todo!() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /assets/why3/exercises/ex3_two_way.mlw: -------------------------------------------------------------------------------- 1 | (* Two Way Sort 2 | 3 | The following program sorts an array of Boolean values, with False a[i1] << a[i2] 25 | 26 | let two_way_sort (a: array bool) : unit 27 | ensures { sorted a } 28 | ensures { permut_all (old a) a } 29 | = 30 | let ref i = 0 in 31 | let ref j = length a - 1 in 32 | while i < j do 33 | invariant { 0 <= i /\ j < length a } 34 | invariant { forall i1: int. 0 <= i1 < i 35 | -> true (* TODO: Replace `true` with your solution *) } 36 | invariant { forall i2: int. j < i2 < length a 37 | -> true (* TODO: Replace `true` with your solution *) } 38 | invariant { true (* TODO: Replace `true` with your solution *) } 39 | variant { j - i } 40 | if not a[i] then 41 | incr i 42 | else if a[j] then 43 | decr j 44 | else begin 45 | swap a i j; 46 | incr i; 47 | decr j 48 | end 49 | done 50 | 51 | end 52 | -------------------------------------------------------------------------------- /src/assignments/assignment04/context.rs: -------------------------------------------------------------------------------- 1 | //! Calculator. 2 | 3 | use std::collections::HashMap; 4 | 5 | use anyhow::*; 6 | use etrace::*; 7 | 8 | use super::syntax::{BinOp, Command, Expression}; 9 | 10 | /// Calculator's context. 11 | #[derive(Debug, Default, Clone)] 12 | pub struct Context { 13 | anonymous_counter: usize, 14 | variables: HashMap, 15 | } 16 | 17 | impl Context { 18 | /// Creates a new context. 19 | pub fn new() -> Self { 20 | Self::default() 21 | } 22 | 23 | /// Returns the current anonymous variable counter. 24 | pub fn current_counter(&self) -> usize { 25 | self.anonymous_counter 26 | } 27 | 28 | /// Calculates the given expression. (We assume the absence of overflow.) 29 | pub fn calc_expression(&self, expression: &Expression) -> Result { 30 | todo!("fill here") 31 | } 32 | 33 | /// Calculates the given command. (We assume the absence of overflow.) 34 | /// 35 | /// If there is no variable lhs in the command (i.e. `command.variable = None`), its value 36 | /// should be stored at `$0`, `$1`, `$2`, ... respectively. 37 | /// 38 | /// # Example 39 | /// 40 | /// After calculating commad `3 + 5` => Context's variables = `{($0,8)}` 41 | /// 42 | /// After calculating commad `v = 3 - 2` => Context's variables = `{($0,8),(v,1))}` 43 | /// 44 | /// After calculating commad `3 ^ 2` => Context's variables = `{($0,8),(v,1),($1,9)}` 45 | pub fn calc_command(&mut self, command: &Command) -> Result<(String, f64)> { 46 | todo!("fill here") 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/assignments/assignment12/card.rs: -------------------------------------------------------------------------------- 1 | //! Flipping card game. 2 | //! 3 | //! HINT: For this assignment, you have to see `play` function in `card_grade.rs` file. 4 | //! Multiple threads will be created and they will run as enemy bots(`bot_threads`). 5 | //! Strategy of the enemy bots is implemented in the closure of the `thread::spawn` function. 6 | //! Your goal is to beat them so that there are more white cards than blue cards in the ground. 7 | //! Write your strategy in the `flip_card_strategy` function of the `Player` struct. 8 | //! 9 | //! Have fun! 10 | 11 | use std::collections::HashMap; 12 | use std::sync::{Arc, Mutex}; 13 | 14 | /// Color represents the color of the card. 15 | /// The color of a card can be either Blue or White. 16 | #[derive(Clone, Copy, Debug, PartialEq)] 17 | pub enum Color { 18 | /// blue 19 | Blue, 20 | 21 | /// white 22 | White, 23 | } 24 | 25 | /// Player struct represents a player in the card game. 26 | /// Each player has a memory which is represented as a HashMap. 27 | #[derive(Debug)] 28 | pub struct Player { 29 | memory: HashMap, 30 | } 31 | 32 | impl Default for Player { 33 | fn default() -> Self { 34 | Self::new() 35 | } 36 | } 37 | 38 | impl Player { 39 | /// Creates a new player with an empty memory. 40 | pub fn new() -> Self { 41 | Self { 42 | memory: HashMap::new(), 43 | } 44 | } 45 | 46 | /// This function should return the index of the card to flip and the color to change to. 47 | pub fn flip_card_strategy(&mut self) -> (usize, Color) { 48 | todo!() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /assets/why3/assignment05/pascal.mlw: -------------------------------------------------------------------------------- 1 | (* Pascal 2 | 3 | Prove that the Pascal's triangle indeed computes combinations. 4 | HINT: https://en.wikipedia.org/wiki/Pascal%27s_triangle 5 | *) 6 | 7 | module Pascal 8 | 9 | use int.Int 10 | use ref.Ref 11 | use array.Array 12 | 13 | (* The mathematical combination, defined recursively. *) 14 | let rec function comb (n k: int) : int 15 | requires { 0 <= k <= n } 16 | variant { n } 17 | ensures { result >= 1 } 18 | = if k = 0 || k = n then 1 else comb (n-1) k + comb (n-1) (k-1) 19 | 20 | (* Computes Pascal's triangle and returns the `n`th row of it. *) 21 | (* Insert an appropriate invariant so that Why3 can verify this function. *) 22 | (* You should understand Pascal's triangle first to find good invariants. *) 23 | let chooses (n : int) : array int 24 | requires { n > 0 } 25 | ensures { forall i: int. 26 | 0 <= i < length result -> result[i] = comb n i } 27 | = 28 | let ref row = Array.make 1 1 in 29 | for r = 1 to n do 30 | invariant { length row = r } 31 | invariant { forall c: int. 0 <= c < r -> row[c] = comb (r-1) c } 32 | let new_row = Array.make (r+1) 1 in 33 | for c = 1 to r-1 do 34 | (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) 35 | (* TODO: Replace `true` with your solution. Your solution MUST be a single line, at line 36. DON'T add more code above or below. *) 36 | invariant { true } 37 | (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) 38 | new_row[c] <- row[c-1] + row[c] 39 | done; 40 | row <- new_row 41 | done; 42 | row 43 | 44 | end 45 | -------------------------------------------------------------------------------- /src/assignments/assignment07/generator_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use itertools::Itertools; 4 | use ntest::assert_about_eq; 5 | 6 | use crate::assignments::assignment07::generator::*; 7 | 8 | #[test] 9 | fn test_generator() { 10 | assert_eq!( 11 | fib_generator(0, 1).take(10).collect::>(), 12 | vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 13 | ); 14 | 15 | assert_eq!( 16 | collatz_conjecture(12).collect::>(), 17 | vec![12, 6, 3, 10, 5, 16, 8, 4, 2, 1] 18 | ); 19 | 20 | assert_eq!( 21 | collatz_conjecture(19).collect::>(), 22 | vec![19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1] 23 | ); 24 | 25 | assert_eq!( 26 | collatz_conjecture(27).collect::>(), 27 | vec![ 28 | 27, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364, 29 | 182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790, 30 | 395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566, 31 | 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 32 | 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 33 | 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 34 | 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1 35 | ] 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/assignments/assignment08/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::assignments::assignment08::small_exercises::*; 4 | 5 | #[test] 6 | fn test_repeat() { 7 | for i in 0..10 { 8 | assert_eq!(42 + 2 * i, repeat(i, |x| x + 2)(42)); 9 | } 10 | } 11 | 12 | #[test] 13 | fn test_funny_map() { 14 | assert_eq!( 15 | vec![0, 3, 6, 9, 12], 16 | funny_map(|x| x + 2, vec![0, 1, 2, 3, 4]) 17 | ); 18 | } 19 | 20 | #[test] 21 | fn test_either2_map() { 22 | let v1 = Either2::::Case1 { inner: 42 }; 23 | let u1 = Either2::::Case1 { inner: 43 }; 24 | assert_eq!(u1, v1.map(|i| i + 1, |f| f + 1.0)); 25 | 26 | let v2 = Either2::::Case2 { inner: 42.0 }; 27 | let u2 = Either2::::Case2 { inner: 43.0 }; 28 | assert_eq!(u2, v2.map(|i| i + 1, |f| f + 1.0)); 29 | } 30 | 31 | #[test] 32 | fn test_count_repeat() { 33 | let inc_mod_100 = |x| (x + 1) % 100; 34 | assert_eq!(count_repeat(inc_mod_100, 10), 100); 35 | assert_eq!(count_repeat(inc_mod_100, 12345), 101); 36 | 37 | let p_lookup = |n| vec![1, 0, 2, 4, 5, 6, 7, 3][n]; 38 | assert_eq!(count_repeat(p_lookup, 0), 2); 39 | assert_eq!(count_repeat(p_lookup, 1), 2); 40 | assert_eq!(count_repeat(p_lookup, 2), 1); 41 | assert_eq!(count_repeat(p_lookup, 3), 5); 42 | assert_eq!(count_repeat(p_lookup, 4), 5); 43 | assert_eq!(count_repeat(p_lookup, 5), 5); 44 | assert_eq!(count_repeat(p_lookup, 6), 5); 45 | assert_eq!(count_repeat(p_lookup, 7), 5); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! KAIST CS220: Programming Principles 2 | 3 | #![deny(warnings)] 4 | #![deny(rustdoc::all)] 5 | // # Tries to deny all lints (`rustc -W help`). 6 | #![deny( 7 | absolute_paths_not_starting_with_crate, 8 | // box_pointers, 9 | deprecated_safe, 10 | elided_lifetimes_in_paths, 11 | explicit_outlives_requirements, 12 | ffi_unwind_calls, 13 | // fuzzy_provenance_casts, 14 | // impl_trait_overcaptures, 15 | keyword_idents, 16 | keyword_idents_2018, 17 | keyword_idents_2024, 18 | let_underscore_drop, 19 | // lossy_provenance_casts, 20 | macro_use_extern_crate, 21 | meta_variable_misuse, 22 | missing_abi, 23 | // missing_copy_implementations, 24 | missing_debug_implementations, 25 | missing_docs, 26 | missing_unsafe_on_extern, 27 | // multiple_supertrait_upcastable, 28 | // must_not_suspend, 29 | non_ascii_idents, 30 | // non_exhaustive_omitted_patterns, 31 | non_local_definitions, 32 | redundant_lifetimes, 33 | rust_2021_incompatible_closure_captures, 34 | rust_2021_incompatible_or_patterns, 35 | rust_2021_prefixes_incompatible_syntax, 36 | rust_2021_prelude_collisions, 37 | // rust_2024_incompatible_pat, 38 | single_use_lifetimes, 39 | trivial_casts, 40 | trivial_numeric_casts, 41 | unit_bindings, 42 | unnameable_types, 43 | unreachable_pub, 44 | unsafe_code, 45 | unsafe_op_in_unsafe_fn, 46 | unstable_features, 47 | // unused_crate_dependencies, 48 | unused_extern_crates, 49 | unused_import_braces, 50 | unused_lifetimes, 51 | unused_macro_rules, 52 | unused_qualifications, 53 | unused_results, 54 | variant_size_differences 55 | )] 56 | 57 | pub mod assignments; 58 | -------------------------------------------------------------------------------- /src/assignments/assignment02/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Small problems. 2 | 3 | use std::iter; 4 | 5 | const FAHRENHEIT_OFFSET: f64 = 32.0; 6 | const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0; 7 | 8 | /// Converts Fahrenheit to Celsius temperature degree. 9 | pub fn fahrenheit_to_celsius(degree: f64) -> f64 { 10 | todo!() 11 | } 12 | 13 | /// Capitalizes English alphabets (leaving the other characters intact). 14 | pub fn capitalize(input: String) -> String { 15 | todo!() 16 | } 17 | 18 | /// Returns the sum of the given array. (We assume the absence of integer overflow.) 19 | pub fn sum_array(input: &[u64]) -> u64 { 20 | todo!() 21 | } 22 | 23 | /// Given a non-negative integer, say `n`, return the smallest integer of the form `3^m` that's 24 | /// greater than or equal to `n`. 25 | /// 26 | /// For instance, up3(6) = 9, up3(9) = 9, up3(10) = 27. (We assume the absence of integer overflow.) 27 | pub fn up3(n: u64) -> u64 { 28 | todo!() 29 | } 30 | 31 | /// Returns the greatest common divisor (GCD) of two non-negative integers. (We assume the absence 32 | /// of integer overflow.) 33 | pub fn gcd(lhs: u64, rhs: u64) -> u64 { 34 | todo!() 35 | } 36 | 37 | /// Returns the array of nC0, nC1, nC2, ..., nCn, where nCk = n! / (k! * (n-k)!). (We assume the 38 | /// absence of integer overflow.) 39 | /// 40 | /// Consult for computation of binomial 41 | /// coefficients without integer overflow. 42 | pub fn chooses(n: u64) -> Vec { 43 | todo!() 44 | } 45 | 46 | /// Returns the "zip" of two vectors. 47 | /// 48 | /// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`. Here, `3` is 49 | /// ignored because it doesn't have a partner. 50 | pub fn zip(lhs: Vec, rhs: Vec) -> Vec<(u64, u64)> { 51 | todo!() 52 | } 53 | -------------------------------------------------------------------------------- /src/bin/calc.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::{self, BufRead, Read}; 3 | 4 | use anyhow::Result; 5 | use clap::Parser; 6 | use cs220::assignments::assignment04::*; 7 | 8 | struct Input<'a> { 9 | source: Box, 10 | } 11 | 12 | impl<'a> Input<'a> { 13 | fn console(stdin: &'a io::Stdin) -> Input<'a> { 14 | Input { 15 | source: Box::new(stdin.lock()), 16 | } 17 | } 18 | 19 | fn file(path: &str) -> io::Result> { 20 | File::open(path).map(|file| Input { 21 | source: Box::new(io::BufReader::new(file)), 22 | }) 23 | } 24 | } 25 | 26 | impl<'a> Read for Input<'a> { 27 | fn read(&mut self, buf: &mut [u8]) -> io::Result { 28 | self.source.read(buf) 29 | } 30 | } 31 | 32 | impl<'a> BufRead for Input<'a> { 33 | fn fill_buf(&mut self) -> io::Result<&[u8]> { 34 | self.source.fill_buf() 35 | } 36 | 37 | fn consume(&mut self, amt: usize) { 38 | self.source.consume(amt); 39 | } 40 | } 41 | 42 | #[derive(Parser, Debug)] 43 | #[clap(author, version, about, long_about = None)] 44 | struct Args { 45 | /// Expression filepath. 46 | #[clap(value_parser)] 47 | filepath: Option, 48 | } 49 | 50 | fn main() -> Result<()> { 51 | // Parses arguments. 52 | let args = Args::parse(); 53 | 54 | let stdin = io::stdin(); 55 | let input = if let Some(filepath) = args.filepath { 56 | Input::file(&filepath)? 57 | } else { 58 | Input::console(&stdin) 59 | }; 60 | 61 | let mut context = context::Context::new(); 62 | for line in input.lines() { 63 | let command = parser::parse_command(&line?)?; 64 | let (variable, value) = context.calc_command(&command)?; 65 | println!("{} = {}", variable, value); 66 | } 67 | 68 | Ok(()) 69 | } 70 | -------------------------------------------------------------------------------- /src/assignments/assignment07/my_itertools_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use itertools::Itertools; 4 | use ntest::assert_about_eq; 5 | 6 | use crate::assignments::assignment07::my_itertools::*; 7 | 8 | #[test] 9 | fn test_itertools() { 10 | assert_eq!( 11 | [10, 1, 1, 1, 2, 3, 4, 1, 3, 2] 12 | .into_iter() 13 | .my_chain(std::iter::repeat(100)) 14 | .my_unique() 15 | .take(4) 16 | .collect::>(), 17 | vec![10, 1, 2, 3] 18 | ); 19 | 20 | assert_eq!( 21 | std::iter::repeat(5) 22 | .my_enumerate() 23 | .map(|(i, e)| { i * e }) 24 | .take(5) 25 | .collect::>(), 26 | vec![0, 5, 10, 15, 20] 27 | ); 28 | 29 | assert_eq!( 30 | vec![0, 1, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,], 31 | [0, 1, 10].into_iter().my_chain(0..10).collect::>(), 32 | ); 33 | 34 | let it = || (1..=5).cycle().my_zip((1..=3).cycle()).map(|(x, y)| x * y); 35 | let take15 = vec![ 36 | 1, // 1 * 1, 37 | 4, // 2 * 2, 38 | 9, // 3 * 3, 39 | 4, // 4 * 1, 40 | 10, // 5 * 2, 41 | 3, // 1 * 3, 42 | 2, // 2 * 1, 43 | 6, // 3 * 2, 44 | 12, // 4 * 3, 45 | 5, // 5 * 1, 46 | 2, // 1 * 2, 47 | 6, // 2 * 3, 48 | 3, // 3 * 1, 49 | 8, // 4 * 2, 50 | 15, // 5 * 3, 51 | ]; 52 | 53 | assert_eq!( 54 | // 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 55 | // 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 56 | it().take(15).collect::>(), 57 | take15 58 | ); 59 | 60 | assert_eq!( 61 | it().take(15).my_fold(0, |elt, acc| elt + acc), 62 | take15.iter().sum() 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/assignments/assignment11/graph_grade.rs: -------------------------------------------------------------------------------- 1 | //! Test cases for assignment11/graph.rs 2 | 3 | #[cfg(test)] 4 | mod test_graph { 5 | use crate::assignments::assignment11::graph::*; 6 | 7 | #[test] 8 | fn test_graph() { 9 | let mut nodes = (0..6).map(NodeHandle::new).collect::>(); 10 | let edges = [ 11 | (0, 1), 12 | (0, 3), 13 | (1, 4), 14 | (2, 4), 15 | (2, 5), 16 | (3, 1), 17 | (4, 3), 18 | (5, 5), 19 | ]; 20 | 21 | for (from, to) in edges { 22 | assert!(nodes[from].add_edge(nodes[to].clone()).unwrap()); 23 | } 24 | 25 | let mut graph1 = SubGraph::new(); 26 | (0..6).for_each(|n| { 27 | assert!(graph1.add_node(nodes[n].clone())); 28 | }); 29 | assert!(graph1.detect_cycle()); 30 | assert!(!graph1.add_node(nodes[0].clone())); 31 | 32 | let mut graph2 = SubGraph::new(); 33 | for n in [0, 1, 3] { 34 | assert!(graph2.add_node(nodes[n].clone())); 35 | } 36 | assert!(!graph2.detect_cycle()); 37 | 38 | assert!(graph2.add_node(nodes[4].clone())); 39 | assert!(graph2.detect_cycle()); 40 | 41 | assert!(nodes[4].remove_edge(&nodes[3]).unwrap()); 42 | assert!(!graph2.detect_cycle()); 43 | 44 | let mut graph3 = SubGraph::new(); 45 | for n in [0, 1, 2, 3] { 46 | assert!(graph3.add_node(nodes[n].clone())); 47 | } 48 | assert!(!graph3.detect_cycle()); 49 | 50 | let more_edges = [(1, 2), (2, 3)]; 51 | for (from, to) in more_edges { 52 | assert!(nodes[from].add_edge(nodes[to].clone()).unwrap()); 53 | } 54 | assert!(graph3.detect_cycle()); 55 | 56 | assert!(graph3.remove_node(&nodes[2])); 57 | assert!(!graph3.detect_cycle()); 58 | 59 | for n in nodes { 60 | n.clear_edges().unwrap(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/assignments/assignment03/custom_operators_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::assignments::assignment03::custom_operators::MyOption::*; 4 | use crate::assignments::assignment03::custom_operators::*; 5 | 6 | #[test] 7 | fn test_my_map() { 8 | fn len(s: &str) -> usize { 9 | s.len() 10 | } 11 | 12 | fn plus_one(x: isize) -> isize { 13 | x + 1 14 | } 15 | 16 | fn is_positive(x: f64) -> bool { 17 | x > 0.0f64 18 | } 19 | 20 | assert_eq!(my_map(MySome("Hello, World!"), len), MySome(13)); 21 | assert_eq!(my_map(MyNone, len), MyNone); 22 | 23 | assert_eq!(my_map(MySome(1), plus_one), MySome(2)); 24 | assert_eq!(my_map(MyNone, plus_one), MyNone); 25 | 26 | assert_eq!(my_map(MySome(5.0f64), is_positive), MySome(true)); 27 | assert_eq!(my_map(MySome(-3.0f64), is_positive), MySome(false)); 28 | assert_eq!(my_map(MyNone::, is_positive), MyNone); 29 | } 30 | 31 | #[test] 32 | fn test_my_and_then() { 33 | fn plus_one(x: isize) -> MyOption { 34 | MySome(x + 1) 35 | } 36 | 37 | fn none(_: isize) -> MyOption { 38 | MyNone 39 | } 40 | 41 | assert_eq!(my_and_then(MySome(1), plus_one), MySome(2)); 42 | assert_eq!(my_and_then(MySome(1), none), MyNone); 43 | 44 | assert_eq!(my_and_then(MyNone, plus_one), MyNone); 45 | assert_eq!(my_and_then(MyNone, none), MyNone); 46 | } 47 | 48 | fn product(a: i32, b: i32) -> i32 { 49 | a * b 50 | } 51 | 52 | #[test] 53 | fn test_my_option_op_or() { 54 | assert_eq!(my_option_op_or(MyNone, MyNone, product), MyNone); 55 | assert_eq!(my_option_op_or(MySome(3), MyNone, product), MySome(3)); 56 | assert_eq!(my_option_op_or(MyNone, MySome(5), product), MySome(5)); 57 | assert_eq!(my_option_op_or(MySome(3), MySome(5), product), MySome(15)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/assignments/assignment09/matmul.rs: -------------------------------------------------------------------------------- 1 | //! Simple matrix multiplication 2 | 3 | use itertools::*; 4 | 5 | /// elementwise vector addition 6 | /// 7 | /// # Example 8 | /// 9 | /// ``` 10 | /// use cs220::assignments::assignment09::matmul::*; 11 | /// 12 | /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 13 | /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 14 | /// let res = vec_add(&vec1, &vec2); 15 | /// assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]); 16 | /// ``` 17 | pub fn vec_add(lhs: &[f64], rhs: &[f64]) -> Vec { 18 | todo!() 19 | } 20 | 21 | /// dot product of two arrays 22 | /// 23 | /// You don't know how to calculate dot product? 24 | /// See 25 | /// 26 | /// # Example 27 | /// 28 | /// ``` 29 | /// use cs220::assignments::assignment09::matmul::*; 30 | /// 31 | /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 32 | /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 33 | /// let res = dot_product(&vec1, &vec2); 34 | /// 35 | /// assert_eq!(res, 55.0); 36 | /// ``` 37 | pub fn dot_product(lhs: &[f64], rhs: &[f64]) -> f64 { 38 | todo!() 39 | } 40 | 41 | /// Matrix multiplication 42 | /// 43 | /// You don't know how to multiply matrix? 44 | /// Quite simple! See 45 | /// 46 | /// Assume rhs is transposed 47 | /// - lhs: (m, n) 48 | /// - rhs: (p, n) 49 | /// - output: (m, p) 50 | /// 51 | /// # Example 52 | /// 53 | /// ``` 54 | /// use cs220::assignments::assignment09::matmul::*; 55 | /// 56 | /// let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; 57 | /// let mat2 = vec![ 58 | /// vec![7.0, 8.0, 9.0], 59 | /// vec![10.0, 11.0, 12.0], 60 | /// vec![13.0, 14.0, 15.0], 61 | /// vec![16.0, 17.0, 18.0], 62 | /// ]; 63 | /// let ans = vec![ 64 | /// vec![50.0, 68.0, 86.0, 104.0], 65 | /// vec![122.0, 167.0, 212.0, 257.0], 66 | /// ]; 67 | /// let res = matmul(&mat1, &mat2); 68 | /// assert_eq!(ans, res); 69 | /// ``` 70 | pub fn matmul(lhs: &[Vec], rhs: &[Vec]) -> Vec> { 71 | todo!() 72 | } 73 | -------------------------------------------------------------------------------- /src/assignments/assignment07/transform_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use itertools::Itertools; 4 | use ntest::assert_about_eq; 5 | 6 | use crate::assignments::assignment07::transform::*; 7 | 8 | #[test] 9 | fn test_transform_identity() { 10 | let tr = Identity; 11 | 12 | assert_eq!(tr.transform(3), 3); 13 | assert_eq!(tr.transform(3.0), 3.0); 14 | assert_eq!(tr.transform("abc"), "abc"); 15 | } 16 | 17 | #[test] 18 | fn test_transform_tuple() { 19 | let f1 = |x: u32| x + 1; 20 | let f2 = |x: String| x.clone() + &x; 21 | 22 | let tr1: Custom<_, _> = f1.into(); 23 | let tr2: Custom<_, _> = f2.into(); 24 | 25 | let list1 = 0u32..10u32; 26 | let list2 = ["a".to_string(), "bb".to_string(), "ccc".to_string()]; 27 | 28 | for v1 in list1 { 29 | for v2 in list2.clone() { 30 | let tr = (tr1, tr2.clone()); 31 | let input = (v1, v2.clone()); 32 | let expected = (f1(v1), f2(v2)); 33 | assert_eq!(tr.transform(input), expected); 34 | } 35 | } 36 | } 37 | 38 | #[test] 39 | fn test_transform_repeat() { 40 | let inc = Custom::from(|x: i32| x + 1); 41 | let dec = Custom::from(|x: i32| x - 1); 42 | 43 | for i in 0..10 { 44 | for j in -10..10 { 45 | assert_eq!(Repeat::new(inc, i as u32).transform(j), j + i); 46 | assert_eq!(Repeat::new(dec, i as u32).transform(j), j - i); 47 | } 48 | } 49 | } 50 | 51 | #[test] 52 | fn test_transform_repeat_until_converge() { 53 | let inc = Custom::from(|x: i32| if x < 50 { x + 1 } else { x }); 54 | let dec = Custom::from(|x: i32| if x > 50 { x - 1 } else { x }); 55 | 56 | assert_eq!(RepeatUntilConverge::new(inc).transform(40), 50); 57 | assert_eq!(RepeatUntilConverge::new(inc).transform(60), 60); 58 | 59 | assert_eq!(RepeatUntilConverge::new(dec).transform(40), 40); 60 | assert_eq!(RepeatUntilConverge::new(dec).transform(60), 50); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/assignments/assignment08/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 08: First-class functions. 2 | 3 | /// Repeat 4 | /// 5 | /// Returns an anonymous function that applies the given function `f` for `n` times. 6 | /// For instance, `repeat(3, f)(x)` roughly translates to `f(f(f(x)))`. 7 | /// 8 | /// Refer `test_repeat` in `assignment08_grade.rs` for detailed examples. 9 | pub fn repeat T>(n: usize, mut f: F) -> impl FnMut(T) -> T { 10 | todo!(); 11 | f // This line has been added to prevent compile error. You can erase this line. 12 | } 13 | 14 | /// Funny Map 15 | /// 16 | /// Applies the given function `f` for `i` times for the `i`-th element of the given vector. 17 | /// 18 | /// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), 19 | /// f(f(f(v3)))]`. 20 | /// 21 | /// Refer `test_funny_map` in `assignment08_grade.rs` for detailed examples. 22 | pub fn funny_map T>(f: F, vs: Vec) -> Vec { 23 | todo!() 24 | } 25 | 26 | /// Count Repeat 27 | /// 28 | /// Returns the number of the elements in the set {`x`, `f(x)`, `f(f(x))`, `f(f(f(x)))`, ...}. You 29 | /// may assume that the answer is finite and small enough. 30 | /// 31 | /// Refer `test_count_repeat` in `assignment08_grade.rs` for detailed examples. 32 | pub fn count_repeat T>(f: F, x: T) -> usize 33 | where 34 | T: PartialEq + Copy, 35 | { 36 | todo!() 37 | } 38 | 39 | /// Either `T1`, or `T2`. 40 | /// 41 | /// Fill out `map` method for this type. 42 | #[derive(Debug, PartialEq, Eq)] 43 | pub enum Either2 { 44 | /// Case 1. 45 | Case1 { 46 | /// The inner value. 47 | inner: T1, 48 | }, 49 | /// Case 2. 50 | Case2 { 51 | /// The inner value. 52 | inner: T2, 53 | }, 54 | } 55 | 56 | impl Either2 { 57 | /// Maps the inner value. 58 | /// 59 | /// If the inner value is case 1, apply `f1`, and if it is case 2, apply `f2`. 60 | /// 61 | /// Refer `test_either2_map` in `assignment08_grade.rs` for detailed examples. 62 | pub fn map(self, f1: F1, f2: F2) -> Either2 63 | where 64 | F1: FnOnce(T1) -> U1, 65 | F2: FnOnce(T2) -> U2, 66 | { 67 | todo!() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/assignments/assignment08/church_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use rand::Rng; 4 | 5 | use crate::assignments::assignment08::church::*; 6 | 7 | #[test] 8 | fn you_must_pass_these_examples() { 9 | let c_zero = zero::(); 10 | assert_eq!(to_usize(c_zero.clone()), 0); 11 | 12 | let c_one = succ(c_zero.clone()); 13 | assert_eq!(to_usize(c_one.clone()), to_usize(one::<()>())); 14 | 15 | let c_two = add(c_one.clone(), c_one.clone()); 16 | let c_three = add(c_one.clone(), c_two.clone()); 17 | assert_eq!(to_usize(c_three.clone()), 3); 18 | 19 | let c_product = mult(c_three.clone(), c_two.clone()); 20 | assert_eq!(to_usize(c_product.clone()), 6); 21 | 22 | let c_exponent = exp::<()>(6, 3); 23 | assert_eq!(to_usize(c_exponent), 216); 24 | 25 | let c_exponent2 = exp::<()>(3, 0); 26 | assert_eq!(to_usize(c_exponent2), 1); 27 | } 28 | 29 | fn id(n: usize) -> usize { 30 | to_usize(from_usize::<()>(n)) 31 | } 32 | 33 | fn c_id(n: Church) -> Church { 34 | from_usize(to_usize(n)) 35 | } 36 | 37 | #[test] 38 | fn engineering_isnt_just_mathematics() { 39 | const N: usize = 77777; 40 | assert_eq!(N, id(N)); 41 | } 42 | 43 | /// This test case is an optional challenge. 44 | /// While it's not necessary to pass this test, 45 | /// successfully doing so could provide a sense of satisfaction and achievement. 46 | // #[test] 47 | // fn i_said_engineering_isnt_just_mathematics() { 48 | // const N: usize = 777777777777777; 49 | // assert_eq!(N, id(N)); 50 | // } 51 | 52 | #[test] 53 | fn be_honest() { 54 | let mut rng = rand::thread_rng(); 55 | 56 | for _ in 0..77 { 57 | let x = rng.gen_range(0..=7); 58 | let y = rng.gen_range(0..=7); 59 | 60 | let c_x = from_usize(x); 61 | let c_y = from_usize(y); 62 | 63 | let c_sum = add(c_x.clone(), c_y.clone()); 64 | assert_eq!(to_usize(c_id(c_sum)), x + y); 65 | 66 | let c_prod = mult(c_x.clone(), c_y.clone()); 67 | assert_eq!(to_usize(c_id(c_prod)), x * y); 68 | 69 | let c_exp = exp(x, y); 70 | assert_eq!(to_usize(c_id(c_exp)), x.pow(y as u32)); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/assignments/assignment07/transform.rs: -------------------------------------------------------------------------------- 1 | //! Tranformer 2 | use std::marker::PhantomData; 3 | use std::ops::Add; 4 | 5 | /// Represents transformation of type `T`. 6 | pub trait Transform { 7 | /// Transforms value. 8 | fn transform(&self, value: T) -> T; 9 | } 10 | 11 | impl, Tr2: Transform> Transform<(T1, T2)> for (Tr1, Tr2) { 12 | fn transform(&self, value: (T1, T2)) -> (T1, T2) { 13 | todo!() 14 | } 15 | } 16 | 17 | /// Identity transformation. 18 | #[derive(Debug, Clone, Copy)] 19 | pub struct Identity; 20 | 21 | impl Transform for Identity { 22 | fn transform(&self, value: T) -> T { 23 | todo!() 24 | } 25 | } 26 | 27 | /// Custom transformation. 28 | #[derive(Debug, Clone, Copy)] 29 | pub struct Custom T> { 30 | f: F, 31 | _marker: PhantomData, 32 | } 33 | 34 | impl T> From for Custom { 35 | fn from(f: F) -> Self { 36 | Self { 37 | f, 38 | _marker: PhantomData, 39 | } 40 | } 41 | } 42 | 43 | impl T> Transform for Custom { 44 | fn transform(&self, value: T) -> T { 45 | todo!() 46 | } 47 | } 48 | 49 | /// Repeats transformation for `n` times. 50 | #[derive(Debug, Clone, Copy)] 51 | pub struct Repeat> { 52 | inner: Tr, 53 | n: u32, 54 | _marker: PhantomData, 55 | } 56 | 57 | impl> Repeat { 58 | /// Creates a new repeat transformation. 59 | pub fn new(inner: Tr, n: u32) -> Self { 60 | Repeat { 61 | inner, 62 | n, 63 | _marker: PhantomData, 64 | } 65 | } 66 | } 67 | 68 | impl> Transform for Repeat { 69 | fn transform(&self, mut value: T) -> T { 70 | todo!() 71 | } 72 | } 73 | 74 | /// Repeats transformation until converges. 75 | #[derive(Debug, Clone, Copy)] 76 | pub struct RepeatUntilConverge> { 77 | inner: Tr, 78 | _marker: PhantomData, 79 | } 80 | 81 | impl> RepeatUntilConverge { 82 | /// Creates a new repeat transformation. 83 | pub fn new(inner: Tr) -> Self { 84 | RepeatUntilConverge { 85 | inner, 86 | _marker: PhantomData, 87 | } 88 | } 89 | } 90 | 91 | impl> Transform for RepeatUntilConverge { 92 | fn transform(&self, mut value: T) -> T { 93 | todo!() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/assignments/assignment10/labyrinth_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | 4 | use rand::seq::SliceRandom; 5 | use rand::thread_rng; 6 | 7 | use crate::assignments::assignment10::labyrinth::*; 8 | 9 | type Wife = usize; 10 | type Rooms = Vec; 11 | 12 | struct Labyrinth { 13 | rooms: Rooms, 14 | } 15 | 16 | impl From for Labyrinth { 17 | fn from(rooms: Rooms) -> Self { 18 | Self { rooms } 19 | } 20 | } 21 | 22 | impl Labyrinth { 23 | fn open_the_door(&self, index: usize) -> Wife { 24 | self.rooms[index] 25 | } 26 | } 27 | 28 | fn can_every_husband_rescue_his_wife() -> bool { 29 | // HINT: https://en.wikipedia.org/wiki/100_prisoners_problem 30 | const WIVES: usize = 100; 31 | 32 | // One day, wives of 100 husbands were kidnapped by the Minotaur 33 | // and imprisoned in a labyrinth.... 🏰 34 | let labyrinth = Labyrinth::from({ 35 | let mut rooms: Vec<_> = (0..WIVES).collect(); 36 | rooms.shuffle(&mut thread_rng()); 37 | rooms 38 | }); 39 | 40 | (0..WIVES).all(|his_wife| { 41 | // A new husband steps into the labyrinth to rescue his wife...! 42 | let husband = Box::new(Husband::seeking(his_wife /* 👩 */)); 43 | let strategy = Box::new(husband.has_devised_a_strategy()); 44 | 45 | // (Allow for better storytelling.) 46 | #[allow(clippy::search_is_some)] 47 | // The Minotaur🐂 will arrive in 48 | (0..50) // steps... 49 | .zip(strategy) 50 | .find(|(_, room)| { 51 | // The husband contemplates his next move... 🤔 52 | // and finally, 53 | let someone/*👤*/ = labyrinth.open_the_door(*room); // 🚪 54 | husband.carefully_checks_whos_inside(*room, someone); 55 | 56 | // Has the husband found his wife...? 57 | someone/*👤*/ == his_wife /*👩*/ 58 | }) 59 | .is_some(/* The husband has successfully rescued his wife! 👫*/) 60 | // or is_none(/* The unfortunate husband has encountered the Minotaur and... 🪓*/) 61 | }) 62 | } 63 | 64 | #[test] 65 | fn main() { 66 | let mut num_success = 0; 67 | for _ in 0..10000 { 68 | if can_every_husband_rescue_his_wife() { 69 | num_success += 1 70 | } 71 | } 72 | 73 | assert!(num_success > 3000) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/assignments/assignment12/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | //! Test cases for assignment12/small_exercises_grade.rs 2 | 3 | #[cfg(test)] 4 | mod test_pingpong { 5 | use std::sync::mpsc::channel; 6 | use std::thread; 7 | 8 | use ntest::timeout; 9 | 10 | use crate::assignments::assignment12::small_exercises::*; 11 | 12 | #[test] 13 | fn test_ping_pong() { 14 | let (tx1, mut rx1) = channel(); 15 | let (mut tx2, rx2) = channel(); 16 | 17 | let thread_ping = thread::spawn(move || { 18 | for i in 0..100 { 19 | tx1.send(i).unwrap(); 20 | let x = rx2.recv().unwrap(); 21 | assert_eq!(x, i + 1); 22 | } 23 | }); 24 | 25 | let thread_pong = thread::spawn(move || while pong(&mut rx1, &mut tx2) {}); 26 | 27 | thread_ping.join().unwrap(); 28 | thread_pong.join().unwrap(); 29 | } 30 | 31 | #[test] 32 | fn test_scoped_thread() { 33 | for i in 0..100 { 34 | let v = (0..i).collect::>(); 35 | 36 | thread::scope(|s| { 37 | let (r1, r2) = use_scoped_thread( 38 | s, 39 | || v.iter().sum::(), 40 | || v.windows(2).map(|x| x[0] * x[1]).sum::(), 41 | ); 42 | 43 | assert_eq!(r1, v.iter().sum()); 44 | assert_eq!(r2, v.windows(2).map(|x| x[0] * x[1]).sum()); 45 | }); 46 | } 47 | } 48 | 49 | #[test] 50 | #[timeout(5000)] 51 | fn test_scoped_thread_concurrent() { 52 | use std::sync::Mutex; 53 | 54 | let m = Mutex::new(0); 55 | let (r1, r2) = thread::scope(|s| { 56 | use_scoped_thread( 57 | s, 58 | || { 59 | for i in 0..100 { 60 | loop { 61 | let mut a = m.lock().unwrap(); 62 | if *a == 2 * i { 63 | *a += 1; 64 | break; 65 | } 66 | } 67 | } 68 | thread::current().id() 69 | }, 70 | || { 71 | for i in 0..100 { 72 | loop { 73 | let mut a = m.lock().unwrap(); 74 | if *a == 2 * i + 1 { 75 | *a += 1; 76 | break; 77 | } 78 | } 79 | } 80 | thread::current().id() 81 | }, 82 | ) 83 | }); 84 | 85 | assert!(r1 != r2); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /scripts/grade-utils.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Global variables 4 | # * TEMPLATE_REV: git revision of the latest homework template 5 | # * TESTS: array of "[TARGET] [TEST_NAME] [-- ...]" 6 | # e.g. "--test linked_list", "--lib cache", "--test list_set -- --test-thread 1" 7 | # * RUNNERS: array of "cargo[_asan | _tsan] [--release]" 8 | # * TIMEOUT: default 10s 9 | 10 | 11 | echo_err() { 12 | echo "$@" 1>&2 13 | } 14 | export -f echo_err 15 | 16 | # check_diff FILE TEST_LINES_FROM_TAIL 17 | # Abort if "--lib" tests are modified. 18 | # Uses global variable TEMPLATE_REV. 19 | check_diff() { 20 | local FILE=$1 21 | local TAIL_N=$2 22 | diff <(tail -n $TAIL_N <(git show $TEMPLATE_REV:$FILE)) <(tail -n $TAIL_N $FILE) \ 23 | || (echo_err "You modified tests for ${FILE}!"; exit 1) 24 | } 25 | export -f check_diff 26 | 27 | # Returns non-zero exit code if any of the linters have failed. 28 | run_linters() { 29 | cargo fmt -- --check 30 | local FMT_ERR=$? 31 | cargo clippy -- -D warnings 32 | local CLIPPY_ERR=$? 33 | [ "$FMT_ERR" -ne 0 ] && echo_err 'Please format your code with `cargo fmt` first.' 34 | [ "$CLIPPY_ERR" -ne 0 ] && echo_err 'Please fix the issues from `cargo clippy` first.' 35 | return $(( FMT_ERR || CLIPPY_ERR )) 36 | } 37 | export -f run_linters 38 | 39 | # usage: _run_tests_with CARGO [OPTIONS] 40 | # example: _run_tests_with cargo_tsan --release 41 | # Echos number of failed tests to stdout. 42 | # Echos error message to stderr. 43 | # Uses global variables TESTS, TIMEOUT. 44 | # [OPTIONS] must not contain " -- " (cargo options only). 45 | _run_tests_with() { 46 | local CARGO=$1; shift 47 | local MSGS # https://mywiki.wooledge.org/BashPitfalls#local_var.3D.24.28cmd.29 48 | MSGS=$($CARGO test --no-run "$@" 2>&1) 49 | if [ $? -ne 0 ]; then 50 | echo_err "Build failed! Error message:" 51 | echo_err "${MSGS}" 52 | echo_err "--------------------------------------------------------------------------------" 53 | echo ${#TESTS[@]} # failed all tests 54 | exit 1 55 | fi 56 | 57 | local PASSED=0 58 | # local NUM_TESTS=$(echo $TESTS | wc -w) 59 | for TEST in ${TESTS[@]}; do 60 | local TEST_CMD="$CARGO test $* --lib -- $TEST" 61 | # card_game in Assignment12 takes 20 seconds. 62 | timeout ${TIMEOUT:-22s} bash -c "$TEST_CMD 2> /dev/null" 1>&2 63 | case $? in 64 | 0) PASSED=$((PASSED + 1));; 65 | 124) echo_err "Test timed out: $TEST_CMD";; 66 | *) echo_err "Test failed: $TEST_CMD";; 67 | esac 68 | done 69 | 70 | echo $PASSED 71 | } 72 | 73 | # example: run_tests 74 | # Uses global variable RUNNER and TESTS 75 | run_tests() { 76 | # "cargo --release" should be split into "cargo" and "--release" 77 | local IFS=' ' 78 | _run_tests_with $RUNNER 79 | } 80 | export -f run_tests 81 | -------------------------------------------------------------------------------- /src/assignments/assignment03/custom_operators.rs: -------------------------------------------------------------------------------- 1 | //! You will implement a number of custom operators. 2 | 3 | /// Custom option type. 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 5 | pub enum MyOption { 6 | /// Some value of type `T`. 7 | MySome(T), 8 | /// No value. 9 | MyNone, 10 | } 11 | 12 | /// Maps an `MyOption` to `MyOption` by applying a function to a contained value. 13 | /// 14 | /// # Examples 15 | /// 16 | /// Converts an `MyOption` into an `MyOption`, consuming the original: 17 | /// 18 | /// ``` 19 | /// use cs220::assignments::assignment03::custom_operators::*; 20 | /// 21 | /// fn len(s: String) -> usize { 22 | /// s.len() 23 | /// } 24 | /// 25 | /// assert_eq!(my_map(MyOption::MySome(String::from("Hello, World!")), len), MyOption::MySome(13)); 26 | /// assert_eq!(my_map(MyOption::MyNone, len), MyOption::MyNone); 27 | /// ``` 28 | pub fn my_map U>(v: MyOption, f: F) -> MyOption { 29 | todo!() 30 | } 31 | 32 | /// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and 33 | /// returns the result. 34 | /// 35 | /// Some languages call this operation flatmap. 36 | /// 37 | /// # Examples 38 | /// 39 | /// ``` 40 | /// use cs220::assignments::assignment03::custom_operators::*; 41 | /// 42 | /// fn pos_then_to_string(x: isize) -> MyOption { 43 | /// if x > 0 { 44 | /// MyOption::MySome(x.to_string()) 45 | /// } else { 46 | /// MyOption::MyNone 47 | /// } 48 | /// } 49 | /// 50 | /// assert_eq!(my_and_then(MyOption::MySome(2), pos_then_to_string), MyOption::MySome(2.to_string())); 51 | /// assert_eq!(my_and_then(MyOption::MySome(-3), pos_then_to_string), MyOption::MyNone); 52 | /// assert_eq!(my_and_then(MyOption::MyNone, pos_then_to_string), MyOption::MyNone); 53 | /// ``` 54 | pub fn my_and_then MyOption>(v: MyOption, f: F) -> MyOption { 55 | todo!() 56 | } 57 | 58 | /// Custom operator: `option_op_or(v1, v2, f)`. If neither `v1` nor `v2` is `Some`, returns `None`. 59 | /// If exactly one is `Some`, returns the same `Some` value. If both are `Some`, apply the values 60 | /// inside `Some` to `f` and wrap the resulting value inside `Some`. 61 | /// 62 | /// # Examples 63 | /// 64 | /// ``` 65 | /// use cs220::assignments::assignment03::custom_operators::*; 66 | /// fn product(a: i32, b: i32) -> i32 { 67 | /// a * b 68 | /// } 69 | /// 70 | /// assert_eq!(my_option_op_or(MyOption::MyNone, MyOption::MyNone, product), MyOption::MyNone); 71 | /// assert_eq!(my_option_op_or(MyOption::MySome(3), MyOption::MyNone, product), MyOption::MySome(3)); 72 | /// assert_eq!(my_option_op_or(MyOption::MySome(3), MyOption::MySome(5), product), MyOption::MySome(15)); 73 | /// ``` 74 | pub fn my_option_op_or T>( 75 | v1: MyOption, 76 | v2: MyOption, 77 | f: F, 78 | ) -> MyOption { 79 | todo!() 80 | } 81 | -------------------------------------------------------------------------------- /src/assignments/assignment11/linked_list_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test_linked_list { 3 | use crate::assignments::assignment11::linked_list::*; 4 | 5 | #[derive(Debug, PartialEq, Eq)] 6 | struct V(usize); 7 | 8 | #[test] 9 | fn test_push_pop() { 10 | let mut list = SinglyLinkedList::new(); 11 | list.push_back(V(3)); 12 | list.push_front(V(2)); 13 | list.push_back(V(4)); 14 | list.push_front(V(1)); 15 | list.push_back(V(5)); 16 | 17 | assert_eq!(list.pop_front(), Some(V(1))); 18 | assert_eq!(list.pop_back(), Some(V(5))); 19 | assert_eq!(list.pop_front(), Some(V(2))); 20 | assert_eq!(list.pop_back(), Some(V(4))); 21 | assert_eq!(list.pop_front(), Some(V(3))); 22 | assert_eq!(list.pop_back(), None); 23 | assert_eq!(list.pop_front(), None); 24 | } 25 | 26 | #[test] 27 | fn test_from_into_vec() { 28 | assert_eq!(SinglyLinkedList::::new().into_vec(), vec![]); 29 | assert_eq!( 30 | SinglyLinkedList::from_vec(vec![1, 2, 3]).into_vec(), 31 | vec![1, 2, 3] 32 | ); 33 | } 34 | 35 | #[test] 36 | fn test_length() { 37 | let list = SinglyLinkedList::from_vec(vec![1, 2, 3]); 38 | assert_eq!(list.length(), 3); 39 | } 40 | 41 | #[test] 42 | fn test_map() { 43 | let list = SinglyLinkedList::from_vec(vec![1, 2, 3]); 44 | let list_ = list.map(|x: i32| x + 1); 45 | assert_eq!(list_.into_vec(), vec![2, 3, 4]); 46 | } 47 | 48 | #[test] 49 | fn test_pair_map() { 50 | let add = |x: i32, y: i32| x + y; 51 | 52 | let list1 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).pair_map(add); 53 | let vec1 = list1.into_vec(); 54 | assert_eq!(vec1.clone(), vec![3, 5, 7, 9, 11, 13, 15, 17]); 55 | 56 | let list2 = SinglyLinkedList::from_vec(vec1).pair_map(add); 57 | let vec2 = list2.into_vec(); 58 | assert_eq!(vec2.clone(), vec![8, 12, 16, 20, 24, 28, 32]); 59 | 60 | let list3 = SinglyLinkedList::from_vec(vec2).pair_map(add); 61 | let vec3 = list3.into_vec(); 62 | assert_eq!(vec3.clone(), vec![20, 28, 36, 44, 52, 60]); 63 | 64 | let list4 = SinglyLinkedList::from_vec(vec3).pair_map(add); 65 | assert_eq!(list4.into_vec(), vec![48, 64, 80, 96, 112]); 66 | } 67 | 68 | #[test] 69 | fn test_flatten() { 70 | let list1 = SinglyLinkedList::from_vec(vec![1, 2]); 71 | let list2 = SinglyLinkedList::from_vec(vec![3]); 72 | let list3 = SinglyLinkedList::from_vec(vec![4, 5, 6, 7]); 73 | let list4 = SinglyLinkedList::::new(); 74 | let list5 = SinglyLinkedList::from_vec(vec![8, 9, 10]); 75 | 76 | let list_list = SinglyLinkedList::from_vec(vec![list1, list2, list3, list4, list5]); 77 | 78 | assert_eq!( 79 | list_list.flatten().into_vec(), 80 | vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/assignments/assignment11/mock_storage.rs: -------------------------------------------------------------------------------- 1 | //! Mock storage. 2 | //! 3 | //! Hint: Consult . 4 | //! 5 | //! Refer `mock_storage_grade.rs` for test cases. 6 | 7 | use std::cell::RefCell; 8 | use std::collections::HashMap; 9 | 10 | /// Mock storage. 11 | #[derive(Debug)] 12 | pub struct MockStorage { 13 | /// Files stored in the storage. 14 | /// 15 | /// Each entry of the hashmap represents the `(name, size)` of the file. 16 | files: RefCell>, 17 | 18 | /// Capacity of the storage. 19 | /// 20 | /// The total size of files stored on the storage cannot exceed the capacity. 21 | capacity: usize, 22 | } 23 | 24 | impl MockStorage { 25 | /// Creates a new mock storage. 26 | pub fn new(capacity: usize) -> Self { 27 | Self { 28 | files: RefCell::new(HashMap::new()), 29 | capacity, 30 | } 31 | } 32 | } 33 | 34 | /// Trait for storage object. 35 | pub trait Storage { 36 | /// Uploads a file. If a file with the same name already exists in the storage, overwrite it. 37 | /// 38 | /// Returns `Err` with insufficient memory size if there is no free space to upload a file. 39 | fn upload(&self, name: &str, size: usize) -> Result<(), usize>; 40 | 41 | /// Returns the used memory size of the storage. 42 | fn used(&self) -> usize; 43 | 44 | /// Returns the capacity of the storage. 45 | fn capacity(&self) -> usize; 46 | } 47 | 48 | impl Storage for MockStorage { 49 | fn upload(&self, name: &str, size: usize) -> Result<(), usize> { 50 | todo!() 51 | } 52 | 53 | fn used(&self) -> usize { 54 | todo!() 55 | } 56 | 57 | fn capacity(&self) -> usize { 58 | todo!() 59 | } 60 | } 61 | 62 | /// File uploader. 63 | /// 64 | /// It uploads files to the internal storage. 65 | #[derive(Debug)] 66 | pub struct FileUploader<'a, T: Storage> { 67 | storage: &'a T, 68 | } 69 | 70 | impl<'a, T: Storage> FileUploader<'a, T> { 71 | /// Creates a new file uploader with given internal storage. 72 | pub fn new(storage: &'a T) -> Self { 73 | Self { storage } 74 | } 75 | 76 | /// Uploads a file to the internal storage. 77 | pub fn upload(&self, name: &str, size: usize) -> Result<(), usize> { 78 | todo!() 79 | } 80 | } 81 | 82 | /// Storage usage analyzer. 83 | #[derive(Debug)] 84 | pub struct UsageAnalyzer<'a, T: Storage> { 85 | storage: &'a T, 86 | bound: f64, 87 | } 88 | 89 | impl<'a, T: Storage> UsageAnalyzer<'a, T> { 90 | /// Creates a new usage analyzer. 91 | pub fn new(storage: &'a T, bound: f64) -> Self { 92 | Self { storage, bound } 93 | } 94 | 95 | /// Returns `true` if the usage of the internal storage is under the bound. 96 | pub fn is_usage_under_bound(&self) -> bool { 97 | todo!() 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/assignments/assignment08/church.rs: -------------------------------------------------------------------------------- 1 | //! Church Numerals 2 | //! 3 | //! This exercise involves the use of "Church numerals", a 4 | //! representation of natural numbers using lambda calculus, named after 5 | //! Alonzo Church. Each Church numeral corresponds to a natural number `n` 6 | //! and is represented as a higher-order function that applies a given function `f` `n` times. 7 | //! 8 | //! For more information, see: 9 | //! - 10 | //! - 11 | 12 | use std::cell::RefCell; 13 | use std::rc::Rc; 14 | 15 | /// Church numerals are represented as higher-order functions that take a function `f` 16 | pub type Church = Rc T>) -> Rc T>>; 17 | 18 | /// This function returns a Church numeral equivalent of the natural number 1. 19 | /// It takes a function `f` and applies it exactly once. 20 | pub fn one() -> Church { 21 | Rc::new(move |f| Rc::new(move |x| f(x))) 22 | } 23 | 24 | /// This function returns a Church numeral equivalent of the natural number 2. 25 | /// It takes a function `f` and applies it twice. 26 | pub fn two() -> Church { 27 | Rc::new(move |f| Rc::new(move |x| f(f(x)))) 28 | } 29 | 30 | /// This function represents the Church numeral for zero. As zero applications 31 | /// of `f` should leave the argument unchanged, the function simply returns the input. 32 | pub fn zero() -> Church { 33 | Rc::new(|_| Rc::new(|x| x)) 34 | } 35 | 36 | /// Implement a function to add 1 to a given Church numeral. 37 | pub fn succ(n: Church) -> Church { 38 | todo!() 39 | } 40 | 41 | /// Implement a function to add two Church numerals. 42 | pub fn add(n: Church, m: Church) -> Church { 43 | todo!() 44 | } 45 | 46 | /// Implement a function to multiply (mult) two Church numerals. 47 | pub fn mult(n: Church, m: Church) -> Church { 48 | todo!() 49 | } 50 | 51 | /// Implement a function to raise one Church numeral to the power of another. 52 | /// This is the Church numeral equivalent of the natural number operation of exponentiation. 53 | /// Given two natural numbers `n` and `m`, the function should return a Church numeral 54 | /// that represents `n` to the power of `m`. The key is to convert `n` and `m` to Church numerals, 55 | /// and then apply the Church numeral for `m` (the exponent) to the Church numeral for `n` (the 56 | /// base). Note: This function should be implemented *WITHOUT* using the `to_usize` or any 57 | /// `pow`-like method. 58 | pub fn exp(n: usize, m: usize) -> Church { 59 | // ACTION ITEM: Uncomment the following lines and replace `todo!()` with your code. 60 | // let n = from_usize(n); 61 | // let m = from_usize(m); 62 | todo!() 63 | } 64 | 65 | /// Implement a function to convert a Church numeral to a usize type. 66 | pub fn to_usize(n: Church) -> usize { 67 | todo!() 68 | } 69 | 70 | /// Implement a function to convert a usize type to a Church numeral. 71 | pub fn from_usize(n: usize) -> Church { 72 | todo!() 73 | } 74 | -------------------------------------------------------------------------------- /src/assignments/assignment09/bigint.rs: -------------------------------------------------------------------------------- 1 | //! Big integer with infinite precision. 2 | 3 | use std::fmt; 4 | use std::iter::zip; 5 | use std::ops::*; 6 | 7 | /// An signed integer with infinite precision implemented with an "carrier" vector of `u32`s. 8 | /// 9 | /// The vector is interpreted as a base 2^(32 * (len(carrier) - 1)) integer, where negative 10 | /// integers are represented in their [2's complement form](https://en.wikipedia.org/wiki/Two%27s_complement). 11 | /// 12 | /// For example, the vector `vec![44,345,3]` represents the integer 13 | /// `44 * (2^32)^2 + 345 * (2^32) + 3`, 14 | /// and the vector `vec![u32::MAX - 5, u32::MAX - 7]` represents the integer 15 | /// `- (5 * 2^32 + 8)` 16 | /// 17 | /// You will implement the `Add` and `Sub` trait for this type. 18 | /// 19 | /// Unlike standard fix-sized intergers in Rust where overflow will panic, the carrier is extended 20 | /// to save the overflowed bit. On the contrary, if the precision is too much (e.g, vec![0,0] is 21 | /// used to represent 0, where `vec![0]` is sufficent), the carrier is truncated. 22 | /// 23 | /// See [this section](https://en.wikipedia.org/wiki/Two%27s_complement#Arithmetic_operations) for a rouge guide on implementation, 24 | /// while keeping in mind that the carrier should be extended to deal with overflow. 25 | /// 26 | /// The `sign_extension()`, `two_complement()`, and `truncate()` are non-mandatory helper methods. 27 | /// 28 | /// For testing and debugging purposes, the `Display` trait is implemented for you, which shows the 29 | /// integer in hexadecimal form. 30 | #[derive(Debug, Clone)] 31 | pub struct BigInt { 32 | /// The carrier for `BigInt`. 33 | /// 34 | /// Note that the carrier should always be non-empty. 35 | pub carrier: Vec, 36 | } 37 | 38 | impl BigInt { 39 | /// Create a new `BigInt` from a `usize`. 40 | pub fn new(n: u32) -> Self { 41 | todo!() 42 | } 43 | 44 | /// Creates a new `BigInt` from a `Vec`. 45 | /// 46 | /// # Panic 47 | /// 48 | /// Panics if `carrier` is empty. 49 | pub fn new_large(carrier: Vec) -> Self { 50 | assert!(!carrier.is_empty()); 51 | todo!() 52 | } 53 | } 54 | 55 | const SIGN_MASK: u32 = 1 << 31; 56 | 57 | impl BigInt { 58 | /// Extend `self` to `len` bits. 59 | fn sign_extension(&self, len: usize) -> Self { 60 | todo!() 61 | } 62 | 63 | /// Compute the two's complement of `self`. 64 | fn two_complement(&self) -> Self { 65 | todo!() 66 | } 67 | 68 | /// Truncate a `BigInt` to the minimum length. 69 | fn truncate(&self) -> Self { 70 | todo!() 71 | } 72 | } 73 | 74 | impl Add for BigInt { 75 | type Output = Self; 76 | 77 | fn add(self, rhs: Self) -> Self::Output { 78 | todo!() 79 | } 80 | } 81 | 82 | impl Sub for BigInt { 83 | type Output = Self; 84 | 85 | fn sub(self, rhs: Self) -> Self::Output { 86 | todo!() 87 | } 88 | } 89 | 90 | impl fmt::Display for BigInt { 91 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 92 | // Hex formatting so that each u32 can be formatted independently. 93 | for i in self.carrier.iter() { 94 | write!(f, "{:08x}", i)?; 95 | } 96 | Ok(()) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/assignments/assignment11/linked_list.rs: -------------------------------------------------------------------------------- 1 | //! Singly linked list. 2 | //! 3 | //! Consult . 4 | 5 | use std::fmt::Debug; 6 | 7 | /// Node of the list. 8 | #[derive(Debug)] 9 | pub struct Node { 10 | /// Value of current node. 11 | pub value: T, 12 | 13 | /// Pointer to the next node. If it is `None`, there is no next node. 14 | pub next: Option>>, 15 | } 16 | 17 | impl Node { 18 | /// Creates a new node. 19 | pub fn new(value: T) -> Self { 20 | Self { value, next: None } 21 | } 22 | } 23 | 24 | /// A singly-linked list. 25 | #[derive(Debug)] 26 | pub struct SinglyLinkedList { 27 | /// Head node of the list. If it is `None`, the list is empty. 28 | head: Option>, 29 | } 30 | 31 | impl Default for SinglyLinkedList { 32 | fn default() -> Self { 33 | Self::new() 34 | } 35 | } 36 | 37 | impl SinglyLinkedList { 38 | /// Creates a new list. 39 | pub fn new() -> Self { 40 | Self { head: None } 41 | } 42 | 43 | /// Adds the given node to the front of the list. 44 | pub fn push_front(&mut self, value: T) { 45 | todo!() 46 | } 47 | 48 | /// Adds the given node to the back of the list. 49 | pub fn push_back(&mut self, value: T) { 50 | todo!() 51 | } 52 | 53 | /// Removes and returns the node at the front of the list. 54 | pub fn pop_front(&mut self) -> Option { 55 | todo!() 56 | } 57 | 58 | /// Removes and returns the node at the back of the list. 59 | pub fn pop_back(&mut self) -> Option { 60 | todo!() 61 | } 62 | 63 | /// Create a new list from the given vector `vec`. 64 | pub fn from_vec(vec: Vec) -> Self { 65 | todo!() 66 | } 67 | 68 | /// Convert the current list into a vector. 69 | pub fn into_vec(self) -> Vec { 70 | todo!() 71 | } 72 | 73 | /// Return the length (i.e., number of nodes) of the list. 74 | pub fn length(&self) -> usize { 75 | todo!() 76 | } 77 | 78 | /// Apply function `f` on every element of the list. 79 | /// 80 | /// # Examples 81 | /// 82 | /// `self`: `[1, 2]`, `f`: `|x| x + 1` ==> `[2, 3]` 83 | pub fn map T>(self, f: F) -> Self { 84 | todo!() 85 | } 86 | 87 | /// Apply given function `f` for each adjacent pair of elements in the list. 88 | /// If `self.length() < 2`, do nothing. 89 | /// 90 | /// # Examples 91 | /// 92 | /// `self`: `[1, 2, 3, 4]`, `f`: `|x, y| x + y` 93 | /// // each adjacent pair of elements: `(1, 2)`, `(2, 3)`, `(3, 4)` 94 | /// // apply `f` to each pair: `f(1, 2) == 3`, `f(2, 3) == 5`, `f(3, 4) == 7` 95 | /// ==> `[3, 5, 7]` 96 | pub fn pair_map T>(self, f: F) -> Self 97 | where 98 | T: Clone, 99 | { 100 | todo!() 101 | } 102 | } 103 | 104 | // A list of lists. 105 | impl SinglyLinkedList> { 106 | /// Flatten the list of lists into a single list. 107 | /// 108 | /// # Examples 109 | /// `self`: `[[1, 2, 3], [4, 5, 6], [7, 8]]` 110 | /// ==> `[1, 2, 3, 4, 5, 6, 7, 8]` 111 | pub fn flatten(self) -> SinglyLinkedList { 112 | todo!() 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/assignments/assignment09/bigint_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | 4 | use ntest::{assert_false, assert_true}; 5 | 6 | use crate::assignments::assignment09::bigint::*; 7 | 8 | #[test] 9 | fn test_inf_prec_simple() { 10 | // Basic 11 | assert_eq!("00000000", format!("{}", BigInt::new(0))); 12 | assert_eq!("ffffffff", format!("{}", BigInt::new(u32::MAX))); 13 | assert_eq!("00bc4fdc", format!("{}", BigInt::new(12_341_212))); 14 | assert_eq!("fffffed8", format!("{}", BigInt::new(4_294_967_000u32))); 15 | 16 | // Add Basic 17 | assert_eq!("00000001", format!("{}", BigInt::new(0) + BigInt::new(1))); 18 | 19 | assert_eq!( 20 | "0df655df", 21 | format!("{}", BigInt::new(13_413) + BigInt::new(234_234_234)) 22 | ); 23 | 24 | assert_eq!( 25 | "ffffff03", 26 | format!("{}", BigInt::new(4_294_967_000u32) + BigInt::new(43)) 27 | ); 28 | 29 | // Sub Basic 30 | assert_eq!("ffffffff", format!("{}", BigInt::new(0) - BigInt::new(1))); 31 | 32 | assert_eq!( 33 | "f20a12eb", 34 | format!("{}", BigInt::new(13_413) - BigInt::new(234_234_234)) 35 | ); 36 | 37 | assert_eq!( 38 | "fffffead", 39 | format!("{}", BigInt::new(4_294_967_000u32) - BigInt::new(43)) 40 | ); 41 | } 42 | 43 | #[test] 44 | #[should_panic] 45 | fn test_inf_prec_panic() { 46 | let _unused = BigInt::new_large(vec![]); 47 | } 48 | 49 | #[test] 50 | fn test_inf_prec_complex() { 51 | // Positive overflow 52 | assert_eq!( 53 | "0000000080000000", 54 | format!("{}", BigInt::new(i32::MAX as u32) + BigInt::new(1)) 55 | ); 56 | 57 | // Negative overflow 58 | assert_eq!( 59 | "ffffffff7fffffff", 60 | format!("{}", BigInt::new(i32::MIN as u32) - BigInt::new(1)) 61 | ); 62 | 63 | // Larger positive overflow 64 | assert_eq!( 65 | "00000000fffffffe00000000", 66 | format!( 67 | "{}", 68 | BigInt::new_large(vec![i32::MAX as u32, 0]) 69 | + BigInt::new_large(vec![i32::MAX as u32, 0]) 70 | ) 71 | ); 72 | 73 | // Smaller negative overflow 74 | assert_eq!( 75 | "ffffffff000000000119464a", 76 | format!( 77 | "{}", 78 | BigInt::new_large(vec![i32::MIN as u32, 2_871_572]) 79 | + BigInt::new_large(vec![i32::MIN as u32, 15_562_038]) 80 | ) 81 | ); 82 | 83 | // Truncate 84 | assert_eq!( 85 | "00000000", 86 | format!( 87 | "{}", 88 | BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456]) 89 | - BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456]) 90 | ) 91 | ); 92 | 93 | assert_eq!( 94 | "ffffffff", 95 | format!( 96 | "{}", 97 | BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456]) 98 | - BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_457]) 99 | ) 100 | ); 101 | 102 | // TODO: add a test case testing sign extension. 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/assignments/assignment11/tv_room.rs: -------------------------------------------------------------------------------- 1 | //! TV Room Simulator. 2 | //! 3 | //! People can come to the TV room and watch TV. There are two types of TV watchers, manager and 4 | //! guest. 5 | //! 6 | //! The rule of the TV room is as follows: 7 | //! 8 | //! - Closed TV room can be opened by the manager. 9 | //! - Guests can enter the TV room by the manager. 10 | //! - Manager can leave the TV room earlier than guests. 11 | //! - The TV room closes when the last person left the TV room. 12 | //! 13 | //! Both `Manager` and `Guest` have `Rc` as a field, and its reference count indicates the 14 | //! number of people in the TV room. When the 'Manager' and 'Guest' object is dropped, it means that 15 | //! the person leaves the TV room. 16 | //! 17 | //! Consult the following documentations: 18 | //! - 19 | //! - 20 | //! 21 | //! Refer `tv_room_grade.rs` for test cases. 22 | 23 | use std::cell::RefCell; 24 | use std::rc::Rc; 25 | 26 | #[derive(Debug, Clone, Copy)] 27 | enum TVRoomState { 28 | Opened, 29 | Closed, 30 | } 31 | 32 | /// TV Room 33 | #[derive(Debug)] 34 | pub struct TVRoom { 35 | /// Indicates whether the TV room is state. 36 | state: RefCell, 37 | } 38 | 39 | impl Default for TVRoom { 40 | fn default() -> Self { 41 | Self::new() 42 | } 43 | } 44 | 45 | impl TVRoom { 46 | /// Creates a new TV room. 47 | /// 48 | /// Initial state of the TV room is closed. 49 | pub fn new() -> Self { 50 | Self { 51 | state: RefCell::new(TVRoomState::Closed), 52 | } 53 | } 54 | 55 | /// Opens the TV room and returns the manager. 56 | /// 57 | /// Returns `None` if the TV room is already opened. 58 | pub fn open(&self) -> Option> { 59 | todo!() 60 | } 61 | 62 | /// Returns whether the TV room is opened or not. 63 | pub fn is_opened(&self) -> bool { 64 | todo!() 65 | } 66 | } 67 | 68 | /// TV Room Manager. 69 | /// 70 | /// - The manager is special TV's watcher that has privileges to add other guests. 71 | /// - If all watchers including the manager drop (~= leave the TV room), the TV must be turned off. 72 | /// - Note that the manager can be dropped while other watchers are watching TV. 73 | #[derive(Debug)] 74 | pub struct Manager<'a> { 75 | inner: Rc>, 76 | } 77 | 78 | impl<'a> Manager<'a> { 79 | fn new(tvstate: &'a RefCell) -> Self { 80 | Self { 81 | inner: Rc::new(Watcher::new(tvstate)), 82 | } 83 | } 84 | 85 | /// Adds new guest to the TV room. 86 | pub fn new_guest(&self) -> Guest<'a> { 87 | todo!() 88 | } 89 | } 90 | 91 | /// TV Room Guest. 92 | #[derive(Debug)] 93 | pub struct Guest<'a> { 94 | inner: Rc>, 95 | } 96 | 97 | #[derive(Debug)] 98 | struct Watcher<'a> { 99 | tvstate: &'a RefCell, 100 | } 101 | 102 | impl<'a> Watcher<'a> { 103 | fn new(tvstate: &'a RefCell) -> Self { 104 | Self { tvstate } 105 | } 106 | } 107 | 108 | impl Drop for Watcher<'_> { 109 | fn drop(&mut self) { 110 | // When the last person leaves the TV room, the TV room should be closed. 111 | todo!() 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/assignments/assignment13/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Assignment 13: Parallelism. 2 | //! 3 | //! If you did well on assignment 09, you will do well on this assignment. Take it easy! 4 | 5 | use rayon::prelude::*; 6 | 7 | /// Returns the sum of `f(v)` for all element `v` the given array. 8 | /// 9 | /// # Example 10 | /// 11 | /// ``` 12 | /// use cs220::assignments::assignment13::small_exercises::*; 13 | /// use rayon::iter::IntoParallelIterator; 14 | /// 15 | /// assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x + 2), 7); 16 | /// assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x * 4), 12); 17 | /// ``` 18 | pub fn sigma_par i64 + Sync + Send>( 19 | inner: impl ParallelIterator, 20 | f: F, 21 | ) -> i64 { 22 | todo!() 23 | } 24 | 25 | /// Alternate elements from three iterators until they have run out. 26 | /// 27 | /// # Example 28 | /// 29 | /// ``` 30 | /// use cs220::assignments::assignment13::small_exercises::*; 31 | /// use rayon::iter::IntoParallelIterator; 32 | /// 33 | /// assert_eq!( 34 | /// interleave3_par([1, 2].into_par_iter(), [3, 4].into_par_iter(), [5, 6].into_par_iter()), 35 | /// vec![1, 3, 5, 2, 4, 6] 36 | /// ); 37 | /// ``` 38 | pub fn interleave3_par( 39 | list1: impl IndexedParallelIterator, 40 | list2: impl IndexedParallelIterator, 41 | list3: impl IndexedParallelIterator, 42 | ) -> Vec { 43 | todo!() 44 | } 45 | 46 | /// Parallel vector addition 47 | /// 48 | /// # Example 49 | /// 50 | /// ``` 51 | /// use cs220::assignments::assignment13::small_exercises::*; 52 | /// 53 | /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 54 | /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 55 | /// let res = vec_add_par(&vec1, &vec2); 56 | /// assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]); 57 | /// ``` 58 | pub fn vec_add_par(lhs: &[f64], rhs: &[f64]) -> Vec { 59 | todo!() 60 | } 61 | 62 | /// Parallel dot product of two arrays 63 | /// 64 | /// You don't know how to calculate dot product? 65 | /// See 66 | /// 67 | /// # Example 68 | /// 69 | /// ``` 70 | /// use cs220::assignments::assignment13::small_exercises::*; 71 | /// 72 | /// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 73 | /// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 74 | /// let res = dot_product_par(&vec1, &vec2); 75 | /// 76 | /// assert_eq!(res, 55.0); 77 | /// ``` 78 | pub fn dot_product_par(lhs: &[f64], rhs: &[f64]) -> f64 { 79 | todo!() 80 | } 81 | 82 | /// Parallel Matrix multiplication 83 | /// 84 | /// You don't know how to multiply matrix? 85 | /// Quite simple! See 86 | /// 87 | /// Assume rhs is transposed 88 | /// - lhs: (m, n) 89 | /// - rhs: (p, n) 90 | /// - output: (m, p) 91 | /// 92 | /// # Example 93 | /// 94 | /// ``` 95 | /// use cs220::assignments::assignment13::small_exercises::*; 96 | /// 97 | /// let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; 98 | /// let mat2 = vec![ 99 | /// vec![7.0, 8.0, 9.0], 100 | /// vec![10.0, 11.0, 12.0], 101 | /// vec![13.0, 14.0, 15.0], 102 | /// vec![16.0, 17.0, 18.0], 103 | /// ]; 104 | /// let ans = vec![ 105 | /// vec![50.0, 68.0, 86.0, 104.0], 106 | /// vec![122.0, 167.0, 212.0, 257.0], 107 | /// ]; 108 | /// let res = matmul_par(&mat1, &mat2); 109 | /// assert_eq!(ans, res); 110 | /// ``` 111 | pub fn matmul_par(lhs: &[Vec], rhs: &[Vec]) -> Vec> { 112 | todo!() 113 | } 114 | -------------------------------------------------------------------------------- /src/assignments/assignment07/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Implement functions using `Iterator` trait 2 | 3 | struct FindIter<'s, T: Eq> { 4 | query: &'s [T], 5 | base: &'s [T], 6 | curr: usize, 7 | } 8 | 9 | impl Iterator for FindIter<'_, T> { 10 | type Item = usize; 11 | 12 | fn next(&mut self) -> Option { 13 | todo!() 14 | } 15 | } 16 | 17 | /// Returns an iterator over substring query indexes in the base. 18 | pub fn find<'s, T: Eq>(query: &'s [T], base: &'s [T]) -> impl 's + Iterator { 19 | FindIter { 20 | query, 21 | base, 22 | curr: 0, 23 | } 24 | } 25 | 26 | /// Implement generic fibonacci iterator 27 | struct FibIter { 28 | // TODO: remove `_marker` and add necessary fields as you want 29 | _marker: std::marker::PhantomData, 30 | } 31 | 32 | impl + Copy> FibIter { 33 | fn new(first: T, second: T) -> Self { 34 | todo!() 35 | } 36 | } 37 | 38 | impl Iterator for FibIter 39 | where 40 | T: std::ops::Add + Copy, 41 | { 42 | type Item = T; 43 | 44 | fn next(&mut self) -> Option { 45 | todo!() 46 | } 47 | } 48 | 49 | /// Returns and iterator over the generic fibonacci sequence starting from `first` and `second`. 50 | /// This is a generic version of `fibonacci` function, which works for any types that implements 51 | /// `std::ops::Add` trait. 52 | pub fn fib(first: T, second: T) -> impl Iterator 53 | where 54 | T: std::ops::Add + Copy, 55 | { 56 | todo!("replace `std::iter::empty() with your own implementation`"); 57 | std::iter::empty() 58 | } 59 | 60 | /// Endpoint of range, inclusive or exclusive. 61 | #[derive(Debug)] 62 | pub enum Endpoint { 63 | /// Inclusive endpoint 64 | Inclusive(isize), 65 | 66 | /// Exclusive endpoint 67 | Exclusive(isize), 68 | } 69 | 70 | struct RangeIter { 71 | // TODO: add necessary fields as you want 72 | } 73 | 74 | impl RangeIter { 75 | fn new(endpoints: (Endpoint, Endpoint), step: isize) -> Self { 76 | todo!() 77 | } 78 | } 79 | 80 | impl Iterator for RangeIter { 81 | type Item = isize; 82 | 83 | fn next(&mut self) -> Option { 84 | todo!() 85 | } 86 | } 87 | 88 | /// Returns an iterator over the range [left, right) with the given step. 89 | pub fn range(left: Endpoint, right: Endpoint, step: isize) -> impl Iterator { 90 | todo!("replace `std::iter::empty() with your own implementation`"); 91 | std::iter::empty() 92 | } 93 | 94 | /// Write an iterator that returns all divisors of n in increasing order. 95 | /// Assume n > 0. 96 | /// 97 | /// Hint: trying all candidates from 1 to n will most likely time out! 98 | /// To optimize it, make use of the following fact: 99 | /// if x is a divisor of n that is greater than sqrt(n), 100 | /// then n/x is a divisor of n that is smaller than sqrt(n). 101 | struct Divisors { 102 | n: u64, 103 | // TODO: you may define additional fields here 104 | } 105 | 106 | impl Iterator for Divisors { 107 | type Item = u64; 108 | 109 | fn next(&mut self) -> Option { 110 | todo!() 111 | } 112 | } 113 | 114 | /// Returns an iterator over the divisors of n. 115 | pub fn divisors(n: u64) -> impl Iterator { 116 | Divisors { 117 | n, 118 | // TODO: you may define additional fields here 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/assignments/assignment07/my_itertools.rs: -------------------------------------------------------------------------------- 1 | //! Implement your own minimal `itertools` crate. 2 | 3 | use std::collections::HashSet; 4 | use std::hash::Hash; 5 | 6 | /// Iterator that iterates over the given iterator and returns only unique elements. 7 | #[derive(Debug)] 8 | pub struct Unique { 9 | // TODO: remove `_marker` and add necessary fields as you want 10 | _marker: std::marker::PhantomData, 11 | } 12 | 13 | impl Iterator for Unique 14 | where 15 | I::Item: Eq + Hash + Clone, 16 | { 17 | type Item = I::Item; 18 | 19 | fn next(&mut self) -> Option { 20 | todo!() 21 | } 22 | } 23 | 24 | /// Iterator that chains two iterators together. 25 | #[derive(Debug)] 26 | pub struct Chain { 27 | // TODO: remove `_marker` and add necessary fields as you want 28 | _marker: std::marker::PhantomData<(I1, I2)>, 29 | } 30 | 31 | impl, I2: Iterator> Iterator 32 | for Chain 33 | { 34 | type Item = T; 35 | 36 | fn next(&mut self) -> Option { 37 | todo!() 38 | } 39 | } 40 | 41 | /// Iterator that iterates over given iterator and enumerates each element. 42 | #[derive(Debug)] 43 | pub struct Enumerate { 44 | // TODO: remove `_marker` and add necessary fields as you want 45 | _marker: std::marker::PhantomData, 46 | } 47 | 48 | impl Iterator for Enumerate { 49 | type Item = (usize, I::Item); 50 | 51 | fn next(&mut self) -> Option { 52 | todo!() 53 | } 54 | } 55 | 56 | /// Iterator that zips two iterators together. 57 | /// 58 | /// If one iterator is longer than the other one, the remaining elements for the longer element 59 | /// should be ignored. 60 | #[derive(Debug)] 61 | pub struct Zip { 62 | // TODO: remove `_marker` and add necessary fields as you want 63 | _marker: std::marker::PhantomData<(I1, I2)>, 64 | } 65 | 66 | impl Iterator for Zip { 67 | type Item = (I1::Item, I2::Item); 68 | 69 | fn next(&mut self) -> Option { 70 | todo!() 71 | } 72 | } 73 | 74 | /// My Itertools trait. 75 | pub trait MyIterTools: Iterator { 76 | /// Returns an iterator that iterates over the `self` and returns only unique elements. 77 | fn my_unique(self) -> Unique 78 | where 79 | Self: Sized, 80 | { 81 | todo!() 82 | } 83 | 84 | /// Returns an iterator that chains `self` and `other` together. 85 | fn my_chain(self, other: I) -> Chain 86 | where 87 | Self: Sized, 88 | { 89 | todo!() 90 | } 91 | 92 | /// Returns an iterator that iterates over `self` and enumerates each element. 93 | fn my_enumerate(self) -> Enumerate 94 | where 95 | Self: Sized, 96 | { 97 | todo!() 98 | } 99 | 100 | /// Returns an iterator that zips `self` and `other` together. 101 | fn my_zip(self, other: I) -> Zip 102 | where 103 | Self: Sized, 104 | { 105 | todo!() 106 | } 107 | 108 | /// Foldleft for `MyIterTools` 109 | fn my_fold(mut self, init: T, mut f: F) -> T 110 | where 111 | Self: Sized, 112 | F: FnMut(Self::Item, T) -> T, 113 | { 114 | todo!() 115 | } 116 | } 117 | 118 | impl MyIterTools for T where T: Iterator {} 119 | -------------------------------------------------------------------------------- /src/assignments/assignment02/vec_and_mat.rs: -------------------------------------------------------------------------------- 1 | //! Vector and matrices. 2 | //! 3 | //! You will implement simple operations on vectors and matrices. 4 | 5 | use std::cmp::PartialEq; 6 | use std::ops::Mul; 7 | 8 | /// 2x2 matrix of the following configuration: 9 | /// 10 | /// a, b 11 | /// c, d 12 | #[derive(Debug, Clone, Copy)] 13 | struct Mat2 { 14 | a: u64, 15 | b: u64, 16 | c: u64, 17 | d: u64, 18 | } 19 | 20 | /// 2x1 matrix of the following configuration: 21 | /// 22 | /// a 23 | /// b 24 | #[derive(Debug, Clone, Copy)] 25 | struct Vec2 { 26 | a: u64, 27 | b: u64, 28 | } 29 | 30 | impl Mat2 { 31 | /// Creates an identity matrix. 32 | fn new() -> Self { 33 | Self { 34 | a: 1, 35 | b: 0, 36 | c: 0, 37 | d: 1, 38 | } 39 | } 40 | } 41 | 42 | impl Mul for Mat2 { 43 | type Output = Mat2; 44 | 45 | /// Consult 46 | fn mul(self, rhs: Mat2) -> Self::Output { 47 | todo!() 48 | } 49 | } 50 | 51 | impl Mul for Mat2 { 52 | type Output = Vec2; 53 | 54 | /// Multiplies the matrix by the vector. 55 | /// 56 | /// Consult 57 | fn mul(self, rhs: Vec2) -> Self::Output { 58 | todo!() 59 | } 60 | } 61 | 62 | impl Mat2 { 63 | /// Calculates the power of matrix. 64 | fn power(self, power: u64) -> Mat2 { 65 | todo!() 66 | } 67 | } 68 | 69 | impl Vec2 { 70 | /// Gets the upper value of vector. 71 | fn get_upper(self) -> u64 { 72 | todo!() 73 | } 74 | } 75 | 76 | /// The matrix used for calculating Fibonacci numbers. 77 | const FIBONACCI_MAT: Mat2 = Mat2 { 78 | a: 1, 79 | b: 1, 80 | c: 1, 81 | d: 0, 82 | }; 83 | 84 | /// The vector used for calculating Fibonacci numbers. 85 | const FIBONACCI_VEC: Vec2 = Vec2 { a: 1, b: 0 }; 86 | 87 | /// Calculates the Fibonacci number. (We assume the absence of integer overflow.) 88 | /// 89 | /// Consult for matrix computation of Fibonacci numbers. 90 | pub fn fibonacci(n: u64) -> u64 { 91 | (FIBONACCI_MAT.power(n) * FIBONACCI_VEC).get_upper() 92 | } 93 | 94 | /// 2x2 floating-point matrix of the following configuration: 95 | /// 96 | /// a, b 97 | /// c, d 98 | #[derive(Debug, Clone, Copy)] 99 | pub struct FMat2 { 100 | /// row 1, column 1 101 | pub a: f64, 102 | /// row 1, column 2 103 | pub b: f64, 104 | /// row 2, column 1 105 | pub c: f64, 106 | /// row 2, column 2 107 | pub d: f64, 108 | } 109 | 110 | impl FMat2 { 111 | /// Returns the inverse of the given matrix. (We assume the given matrix is always invertible.) 112 | /// HINT: 113 | /// 114 | /// # Example 115 | /// 116 | /// ```ignore 117 | /// assert_eq!( 118 | /// FMat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(), 119 | /// FMat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0 } 120 | /// ); 121 | /// ``` 122 | pub fn inverse(self) -> Self { 123 | todo!() 124 | } 125 | } 126 | 127 | // Equivalence between two floating-point matrices, as element-wise equivalence 128 | impl PartialEq for FMat2 { 129 | fn eq(&self, other: &FMat2) -> bool { 130 | self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/assignment_question.yml: -------------------------------------------------------------------------------- 1 | name: Question about Assignment 2 | description: Ask questions about assignment in this format. 3 | title: '[Assignment #] (SUMMARIZE YOUR QUESTION AS CLEARLY AS POSSIBLE)' 4 | labels: 5 | - question 6 | assignees: 7 | - Lee-Janggun 8 | - kingdoctor123 9 | - Jaewookim08 10 | body: 11 | - type: markdown 12 | attributes: 13 | value: | 14 | # Please read the followings before asking a question: 15 | - When you're asking a question, please make sure, 16 | - You clarify your questions as clear as possible. 17 | - If possible, please make it a yes/no question. 18 | - If possible, please summarize your question in one sentence at the beginning of an issue. 19 | - If you're asking a question on concepts, 20 | - You read the corresponding sections of the slide. 21 | - You searched for the concepts using search engines and Wikipedia. 22 | - If you're asking a question on Rust programming, 23 | - You searched for error messages or any relevant logs using search engines. 24 | - Your problem is reproducible in the provided server. Please describe how others can reproduce your problem. 25 | - You paste code, if any, in text with [syntax hightlight](https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks). No images. 26 | - You paste code, if any, that is minimized as much as possible. Your code should be immediately relevant to your question. 27 | - type: markdown 28 | attributes: 29 | value: | 30 | # 1. Related Issue 31 | - type: input 32 | attributes: 33 | label: Related Issue 34 | description: >- 35 | Please search to see if a related issue already exists. If so, give me 36 | the links. If there are multiple issues, please write them all. 37 | placeholder: 'https://github.com/kaist-cp/cs220/issues/' 38 | validations: 39 | required: false 40 | - type: markdown 41 | attributes: 42 | value: | 43 | # 2. Googling Result 44 | - type: textarea 45 | attributes: 46 | label: Googling Result 47 | description: >- 48 | Share the link that looks relavant to your situation. Multiple links are 49 | welcomed. 50 | placeholder: >- 51 | https://stackoverflow.blog/2020/01/20/what-is-rust-and-why-is-it-so-popular/ 52 | validations: 53 | required: true 54 | - type: markdown 55 | attributes: 56 | value: | 57 | # 3. ChatGPT Result 58 | - type: input 59 | attributes: 60 | label: ChatGPT Result 61 | description: >- 62 | Before writing this issue, you should have asked ChatGPT. We want to see 63 | how you used ChatGPT for troubleshooting your problem. You can upload 64 | link like 65 | [this](https://help.openai.com/en/articles/7925741-chatgpt-shared-links-faq). 66 | It should contain the history of, including but not limited to, your 67 | problem statement, the answer from ChatGPT, and your follow-up 68 | questions. There should be at least 3 turns of conversation. 69 | placeholder: 'https://chat.openai.com/share/' 70 | validations: 71 | required: true 72 | - type: markdown 73 | attributes: 74 | value: | 75 | # 4. Your question 76 | - type: textarea 77 | attributes: 78 | label: Your question here 79 | description: 'Also tell us, what did you expect to happen?' 80 | placeholder: YOUR QUESTION HERE 81 | validations: 82 | required: true 83 | -------------------------------------------------------------------------------- /scripts/grade.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -uo pipefail 5 | IFS=$'\n\t' 6 | 7 | # Imports library. 8 | BASEDIR=$(dirname "$0") 9 | source $BASEDIR/grade-utils.sh 10 | 11 | RUNNER="cargo" 12 | 13 | # Lints. 14 | run_linters || exit 1 15 | 16 | # Executes test for each runner. 17 | echo "Running with $RUNNER..." 18 | 19 | if [ $# != 1 ] 20 | then 21 | echo "===============================" 22 | echo "Invalid argument." 23 | echo "Usage: './grade.sh '" 24 | echo "Example: './grade.sh 1' to grade assignment01" 25 | exit 1 26 | fi 27 | TEST_NAME=$(printf "TEST%02d" $1) 28 | case $TEST_NAME in 29 | TEST01) 30 | TESTS=( 31 | "assignments::assignment01::small_exercises_grade::test" 32 | ) 33 | ;; 34 | TEST02) 35 | TESTS=( 36 | "assignments::assignment02::small_exercises_grade::test" 37 | "assignments::assignment02::vec_and_mat_grade::test" 38 | ) 39 | ;; 40 | TEST03) 41 | TESTS=( 42 | "assignments::assignment03::custom_operators_grade::test" 43 | "assignments::assignment03::parse_shell_grade::test" 44 | "assignments::assignment03::small_exercises_grade::test" 45 | ) 46 | ;; 47 | TEST04) 48 | TESTS=( 49 | "assignments::assignment04::grade::test" 50 | ) 51 | ;; 52 | TEST06) 53 | TESTS=( 54 | "assignments::assignment06::semiring_grade::test" 55 | "assignments::assignment06::symbolic_differentiation_grade::test" 56 | ) 57 | ;; 58 | TEST07) 59 | TESTS=( 60 | "assignments::assignment07::generator_grade::test" 61 | "assignments::assignment07::my_itertools_grade::test" 62 | "assignments::assignment07::small_exercises_grade::test" 63 | "assignments::assignment07::transform_grade::test" 64 | ) 65 | ;; 66 | TEST08) 67 | TESTS=( 68 | "assignments::assignment08::church_grade::test" 69 | "assignments::assignment08::small_exercises_grade::test" 70 | ) 71 | ;; 72 | TEST09) 73 | TESTS=( 74 | "assignments::assignment09::bigint_grade::test" 75 | "assignments::assignment09::small_exercises_grade::test" 76 | "assignments::assignment09::matmul_grade::test" 77 | ) 78 | ;; 79 | TEST10) 80 | TESTS=( 81 | "assignments::assignment10::labyrinth_grade::test" 82 | "assignments::assignment10::small_exercises_grade::test" 83 | ) 84 | ;; 85 | TEST11) 86 | TESTS=( 87 | "assignments::assignment11::graph_grade::test_graph" 88 | "assignments::assignment11::linked_list_grade::test_linked_list" 89 | "assignments::assignment11::mock_storage_grade::test_mock_storage" 90 | "assignments::assignment11::tv_room_grade::test_tv_room" 91 | ) 92 | ;; 93 | TEST12) 94 | TESTS=( 95 | "assignments::assignment12::card_grade" 96 | "assignments::assignment12::demux_grade::test_demux" 97 | "assignments::assignment12::funnel_grade::test_funnel" 98 | "assignments::assignment12::small_exercises_grade::test_pingpong" 99 | ) 100 | ;; 101 | TEST13) 102 | TESTS=( 103 | "assignments::assignment13::small_exercises_grade::test" 104 | ) 105 | ;; 106 | *) 107 | echo_err "Invalid assignment number: $1" 108 | echo_err "The assignment number should be between 1 and 12, excluding 5." 109 | exit 1 110 | ;; 111 | esac 112 | 113 | # Runs tests. 114 | SCORE=$(run_tests) 115 | NUM_TESTS=${#TESTS[@]} 116 | echo Your score: ${SCORE}/${NUM_TESTS} 117 | -------------------------------------------------------------------------------- /src/assignments/assignment11/graph.rs: -------------------------------------------------------------------------------- 1 | //! A small graph library. 2 | //! 3 | //! A node has a i32 value and (directed) edges to other nodes. A node does not have multiple edges 4 | //! to the same node. Nodes are not associated with a particular domain, and users can freely 5 | //! create nodes however they like. However, after a node is created, it can be added to a 6 | //! `SubGraph`, which form a subgraph of the graph of all nodes. A node can be added to multiple 7 | //! subgraphs. `SubGraph` has a method to check if the it has a cycle. 8 | //! 9 | //! The goal of this assignment is to learn how to deal with inherently shared mutable data in 10 | //! Rust. Design the types and fill in the `todo!()`s in methods. There are several possible 11 | //! approaches to this problem and you may import anything from the std library accordingly. 12 | //! 13 | //! Refer `graph_grade.rs` for test cases. 14 | 15 | use std::cell::RefCell; 16 | use std::collections::HashSet; 17 | use std::rc::Rc; 18 | 19 | #[derive(PartialEq, Eq, Debug)] 20 | enum VisitStatus { 21 | Unvisited, 22 | Visiting, 23 | Visited, 24 | } 25 | 26 | /// Handle to a graph node. 27 | /// 28 | /// `NodeHandle` should implement `Clone`, which clones the handle without cloning the underlying 29 | /// node. That is, there can be multiple handles to the same node. 30 | /// The user can access the node through a handle if it does not violate Rust's aliasing rules. 31 | /// 32 | /// You can freely add fields to this struct. 33 | #[derive(Debug, Clone)] 34 | pub struct NodeHandle; 35 | 36 | /// Error type for graph operations. 37 | #[derive(Debug)] 38 | pub struct GraphError; 39 | 40 | /// Subgraph 41 | /// 42 | /// You can freely add fields to this struct. 43 | #[derive(Debug)] 44 | pub struct SubGraph; 45 | 46 | impl NodeHandle { 47 | /// Creates a node and returns the handle to it. 48 | pub fn new(value: i32) -> Self { 49 | todo!() 50 | } 51 | 52 | /// Adds an edge to `to`. 53 | /// If the modification cannot be done, e.g. because of aliasing issues, returns 54 | /// `Err(GraphError)`. Returns `Ok(true)` if the edge is successfully added. 55 | /// Returns `Ok(false)` if an edge to `to` already exits. 56 | pub fn add_edge(&self, to: NodeHandle) -> Result { 57 | todo!() 58 | } 59 | 60 | /// Removes the edge to `to`. 61 | /// If the modification cannot be done, e.g. because of aliasing issues, returns 62 | /// `Err(GraphError)`. Returns `Ok(true)` if the edge is successfully removed. 63 | /// Returns `Ok(false)` if an edge to `to` does not exist. 64 | pub fn remove_edge(&self, to: &NodeHandle) -> Result { 65 | todo!() 66 | } 67 | 68 | /// Removes all edges. 69 | /// If the modification cannot be done, e.g. because of aliasing issues, returns 70 | /// `Err(GraphError)`. 71 | pub fn clear_edges(&self) -> Result<(), GraphError> { 72 | todo!() 73 | } 74 | } 75 | 76 | impl Default for SubGraph { 77 | fn default() -> Self { 78 | Self::new() 79 | } 80 | } 81 | 82 | impl SubGraph { 83 | /// Creates a new subgraph. 84 | pub fn new() -> Self { 85 | todo!() 86 | } 87 | 88 | /// Adds a node to the subgraph. Returns true iff the node is newly added. 89 | pub fn add_node(&mut self, node: NodeHandle) -> bool { 90 | todo!() 91 | } 92 | 93 | /// Removes a node from the subgraph. Returns true iff the node is successfully removed. 94 | pub fn remove_node(&mut self, node: &NodeHandle) -> bool { 95 | todo!() 96 | } 97 | 98 | /// Returns true iff the subgraph contains a cycle. Nodes that do not belong to this subgraph 99 | /// are ignored. See for an algorithm. 100 | pub fn detect_cycle(&self) -> bool { 101 | todo!() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/assignments/assignment09/matmul_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use approx::*; 4 | use itertools::Itertools; 5 | use ndarray::prelude::*; 6 | use ndarray_rand::rand_distr::Uniform; 7 | use ndarray_rand::RandomExt; 8 | 9 | use crate::assignments::assignment09::matmul::*; 10 | 11 | #[test] 12 | fn vec_add_test() { 13 | let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 14 | let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 15 | let res = vec_add(&vec1, &vec2); 16 | assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]); 17 | 18 | for _ in 0..5 { 19 | let vec1 = Array::random(500000, Uniform::new(0., 10.)); 20 | let vec2 = Array::random(500000, Uniform::new(0., 10.)); 21 | 22 | let res = vec_add(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); 23 | 24 | let ans = vec1 + vec2; 25 | assert_eq!(Array::from_vec(res), ans); 26 | } 27 | } 28 | 29 | #[test] 30 | fn dot_product_test() { 31 | let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 32 | let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 33 | let res = dot_product(&vec1, &vec2); 34 | assert_eq!(res, 55.0); 35 | 36 | for _ in 0..5 { 37 | let vec1 = Array::random(1000000, Uniform::new(0., 10.)); 38 | let vec2 = Array::random(1000000, Uniform::new(0., 10.)); 39 | 40 | let res = dot_product(vec1.as_slice().unwrap(), vec2.as_slice().unwrap()); 41 | let _res = relative_eq!(res, vec1.dot(&vec2), epsilon = f64::EPSILON); 42 | } 43 | } 44 | 45 | /// Reference: 46 | /// Converts nested `Vec`s to a 2-D array by cloning the elements. 47 | /// 48 | /// **Panics** if the length of any axis overflows `isize`, if the 49 | /// size in bytes of all the data overflows `isize`, or if not all the 50 | /// rows have the same length. 51 | fn vec_to_array(v: Vec>) -> Array2 { 52 | if v.is_empty() { 53 | return Array2::from_shape_vec((0, 0), Vec::new()).unwrap(); 54 | } 55 | let nrows = v.len(); 56 | let ncols = v[0].len(); 57 | let mut data = Vec::with_capacity(nrows * ncols); 58 | for row in &v { 59 | assert_eq!(row.len(), ncols); 60 | data.extend_from_slice(row); 61 | } 62 | Array2::from_shape_vec((nrows, ncols), data).unwrap() 63 | } 64 | 65 | #[test] 66 | fn matmul_test() { 67 | let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; 68 | let mat2 = vec![ 69 | vec![7.0, 8.0, 9.0], 70 | vec![10.0, 11.0, 12.0], 71 | vec![13.0, 14.0, 15.0], 72 | vec![16.0, 17.0, 18.0], 73 | ]; 74 | let ans = vec![ 75 | vec![50.0, 68.0, 86.0, 104.0], 76 | vec![122.0, 167.0, 212.0, 257.0], 77 | ]; 78 | let res = matmul(&mat1, &mat2); 79 | assert_eq!(ans, res); 80 | 81 | for _ in 0..5 { 82 | let mat1 = Array::random((500, 500), Uniform::new(0., 10.)); 83 | let mat2 = Array::random((500, 500), Uniform::new(0., 10.)); 84 | let ans = mat1.dot(&mat2); 85 | let mat2_transposed = mat2.t(); 86 | 87 | // Run sequential matrix multiplication 88 | let res = matmul( 89 | mat1.axis_iter(Axis(0)) 90 | .map(|row| row.to_vec()) 91 | .collect::>() 92 | .as_slice(), 93 | mat2_transposed 94 | .axis_iter(Axis(0)) 95 | .map(|row| row.to_vec()) 96 | .collect::>() 97 | .as_slice(), 98 | ); 99 | 100 | // Check answer 101 | for it in ans.iter().zip(vec_to_array(res).iter()) { 102 | let (ans, res) = it; 103 | let _res = relative_eq!(ans, res); 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/assignments/assignment06/semiring_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use ntest::assert_about_eq; 4 | 5 | use crate::assignments::assignment06::semiring::*; 6 | 7 | fn test_from_str(s: &str, f: impl Fn(i64) -> i64) { 8 | let poly = s.parse::>().unwrap(); 9 | for i in 0..10 { 10 | assert_eq!(poly.eval(i), f(i)); 11 | } 12 | } 13 | 14 | fn test_polynomial() { 15 | // x^2 + 5x + 6 16 | let poly = Polynomial::add( 17 | &Polynomial::add( 18 | &Polynomial::mul( 19 | &Polynomial::from(from_usize::(1)), 20 | &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), 21 | ), 22 | &Polynomial::mul(&Polynomial::from(from_usize::(5)), &Polynomial::x()), 23 | ), 24 | &Polynomial::from(from_usize::(6)), 25 | ); 26 | 27 | // 13^2 + 5*13 + 6 28 | let value = poly.eval(from_usize(13)); 29 | 30 | assert_eq!(value, from_usize(13 * 13 + 5 * 13 + 6)); 31 | } 32 | 33 | #[test] 34 | fn test_123() { 35 | test_from_str("123", |x| 123); 36 | } 37 | 38 | #[test] 39 | fn test_x() { 40 | test_from_str("x", |x| x); 41 | } 42 | 43 | #[test] 44 | fn test_24x() { 45 | test_from_str("24x", |x| 24 * x); 46 | } 47 | 48 | #[test] 49 | fn test_2x_3() { 50 | test_from_str("2x + 3", |x| 2 * x + 3); 51 | } 52 | 53 | #[test] 54 | fn test_x3() { 55 | test_from_str("x^3", |x| x * x * x); 56 | } 57 | 58 | #[test] 59 | fn test_2x3_3x2_5x_12() { 60 | test_from_str("2x^3 + 3x^2 + 5x + 12", |x| { 61 | 2 * x * x * x + 3 * x * x + 5 * x + 12 62 | }); 63 | } 64 | 65 | #[test] 66 | fn test_x5_1() { 67 | test_from_str("x^5 + 1", |x| x * x * x * x * x + 1); 68 | } 69 | 70 | #[test] 71 | fn test_polynomial_u64() { 72 | test_polynomial::(); 73 | } 74 | 75 | #[test] 76 | fn test_polynomial_f64() { 77 | test_polynomial::(); 78 | } 79 | 80 | #[test] 81 | fn test_polynomial_p_u64() { 82 | test_polynomial::>(); 83 | } 84 | 85 | #[test] 86 | fn test_polynomial_xy() { 87 | // (x+1)(y+2) 88 | let poly: Polynomial> = Polynomial::mul( 89 | &Polynomial::from(Polynomial::add( 90 | &Polynomial::x(), 91 | &Polynomial::from(from_usize::(1)), 92 | )), 93 | &(Polynomial::add( 94 | &Polynomial::x(), 95 | &Polynomial::from(Polynomial::from(from_usize::(2))), 96 | )), 97 | ); 98 | 99 | // poly with y = x+3 100 | let value = poly.eval(Polynomial::add( 101 | &Polynomial::x(), 102 | &Polynomial::from(from_usize::(3)), 103 | )); 104 | 105 | // x^2 + 6x + 5 106 | let expected = Polynomial::add( 107 | &Polynomial::add( 108 | &Polynomial::mul( 109 | &Polynomial::from(from_usize::(1)), 110 | &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), 111 | ), 112 | &Polynomial::mul(&Polynomial::from(from_usize::(6)), &Polynomial::x()), 113 | ), 114 | &Polynomial::from(from_usize::(5)), 115 | ); 116 | 117 | assert_eq!(value, expected); 118 | } 119 | 120 | #[test] 121 | fn test_zero_remove() { 122 | // (x-1)(x+1) 123 | let poly: Polynomial = Polynomial::mul( 124 | &Polynomial::add(&Polynomial::x(), &Polynomial::from(-1)), 125 | &Polynomial::add(&Polynomial::x(), &Polynomial::from(1)), 126 | ); 127 | 128 | // (x-1)(x+1) == x^2 - 1 129 | assert_eq!( 130 | poly, 131 | Polynomial::add( 132 | &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), 133 | &Polynomial::from(-1) 134 | ) 135 | ); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/assignments/assignment06/semiring.rs: -------------------------------------------------------------------------------- 1 | //! Semiring 2 | 3 | use std::collections::HashMap; 4 | use std::fmt::Debug; 5 | 6 | use itertools::Itertools; 7 | 8 | /// Semiring. 9 | /// 10 | /// Consult . 11 | pub trait Semiring: Debug + Clone + PartialEq { 12 | /// Additive identity. 13 | fn zero() -> Self; 14 | /// Multiplicative identity. 15 | fn one() -> Self; 16 | /// Addition operation. 17 | fn add(&self, rhs: &Self) -> Self; 18 | /// Multiplication operation. 19 | fn mul(&self, rhs: &Self) -> Self; 20 | } 21 | 22 | /// Converts integer to semiring value. 23 | pub fn from_usize(value: usize) -> T { 24 | let mut result = T::zero(); 25 | let one = T::one(); 26 | 27 | for _ in 0..value { 28 | result = T::add(&result, &one); 29 | } 30 | 31 | result 32 | } 33 | 34 | impl Semiring for u64 { 35 | fn zero() -> Self { 36 | todo!() 37 | } 38 | 39 | fn one() -> Self { 40 | todo!() 41 | } 42 | 43 | fn add(&self, rhs: &Self) -> Self { 44 | todo!() 45 | } 46 | 47 | fn mul(&self, rhs: &Self) -> Self { 48 | todo!() 49 | } 50 | } 51 | 52 | impl Semiring for i64 { 53 | fn zero() -> Self { 54 | todo!() 55 | } 56 | 57 | fn one() -> Self { 58 | todo!() 59 | } 60 | 61 | fn add(&self, rhs: &Self) -> Self { 62 | todo!() 63 | } 64 | 65 | fn mul(&self, rhs: &Self) -> Self { 66 | todo!() 67 | } 68 | } 69 | 70 | impl Semiring for f64 { 71 | fn zero() -> Self { 72 | todo!() 73 | } 74 | 75 | fn one() -> Self { 76 | todo!() 77 | } 78 | 79 | fn add(&self, rhs: &Self) -> Self { 80 | todo!() 81 | } 82 | 83 | fn mul(&self, rhs: &Self) -> Self { 84 | todo!() 85 | } 86 | } 87 | 88 | /// Polynomials with coefficient in `C`. 89 | /// 90 | /// For example, polynomial `x^2 + 5x + 6` is represented in `Polynomial` as follows: 91 | /// 92 | /// ```ignore 93 | /// Polynomial { 94 | /// coefficients: { 95 | /// 2: 1, 96 | /// 1: 5, 97 | /// 0: 6, 98 | /// }, 99 | /// } 100 | /// ``` 101 | #[derive(Debug, Clone, PartialEq, Eq)] 102 | pub struct Polynomial { 103 | coefficients: HashMap, 104 | } 105 | 106 | impl Semiring for Polynomial { 107 | fn zero() -> Self { 108 | todo!() 109 | } 110 | 111 | fn one() -> Self { 112 | todo!() 113 | } 114 | 115 | fn add(&self, rhs: &Self) -> Self { 116 | todo!() 117 | } 118 | 119 | fn mul(&self, rhs: &Self) -> Self { 120 | todo!() 121 | } 122 | } 123 | 124 | impl Polynomial { 125 | /// Constructs polynomial `x`. 126 | pub fn x() -> Self { 127 | todo!() 128 | } 129 | 130 | /// Evaluates the polynomial with the given value. 131 | pub fn eval(&self, value: C) -> C { 132 | todo!() 133 | } 134 | 135 | /// Constructs polynomial `ax^n`. 136 | pub fn term(a: C, n: u64) -> Self { 137 | todo!() 138 | } 139 | } 140 | 141 | impl From for Polynomial { 142 | fn from(value: C) -> Self { 143 | todo!() 144 | } 145 | } 146 | 147 | /// Given a string `s`, parse it into a `Polynomial`. 148 | /// You may assume that `s` follows the criteria below. 149 | /// Therefore, you do not have to return `Err`. 150 | /// 151 | /// Assumptions: 152 | /// - Each term is separated by ` + `. 153 | /// - Each term is one of the following form: `a`, `x`, `ax`, `x^n`, and `ax^n`, where `a` is a 154 | /// `usize` number and `n` is a `u64` number. This `a` should then be converted to a `C` type. 155 | /// - In `a`, it is guaranteed that `a >= 1`. 156 | /// - In `ax` and `ax^n`, it is guaranteed that `a >= 2`. 157 | /// - In `x^n` and `ax^n`, it is guaranteed that `n >= 2`. 158 | /// - All terms have unique degrees. 159 | /// 160 | /// Consult `assignment06/grade.rs` for example valid strings. 161 | /// 162 | /// Hint: `.split`, `.parse`, and `Polynomial::term` 163 | impl std::str::FromStr for Polynomial { 164 | type Err = (); // Ignore this for now... 165 | 166 | fn from_str(s: &str) -> Result { 167 | todo!() 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/assignments/assignment03/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Small problems. 2 | 3 | use std::collections::{HashMap, HashSet}; 4 | use std::fmt; 5 | 6 | /// Day of week. 7 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 8 | pub enum DayOfWeek { 9 | /// Sunday. 10 | Sun, 11 | /// Monday. 12 | Mon, 13 | /// Tuesday. 14 | Tue, 15 | /// Wednesday. 16 | Wed, 17 | /// Thursday. 18 | Thu, 19 | /// Friday. 20 | Fri, 21 | /// Saturday. 22 | Sat, 23 | } 24 | 25 | /// The next day of week. 26 | /// 27 | /// `next_weekday(Thu)` is `Fri`; and `next_weekday(Fri)` is `Mon`. 28 | pub fn next_weekday(day: DayOfWeek) -> DayOfWeek { 29 | todo!() 30 | } 31 | 32 | /// Given a list of integers, returns its median (when sorted, the value in the middle position). 33 | /// 34 | /// For a data set `x` of `n` elements, the median can be defined as follows: 35 | /// 36 | /// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`. 37 | /// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`. 38 | /// 39 | /// For example, the following list of seven numbers, 40 | /// 41 | /// ```ignore 42 | /// vec![1, 3, 3, 6, 7, 8, 9] 43 | /// ``` 44 | /// 45 | /// has the median of 6, which is the fourth value. And for this data set of eight numbers, 46 | /// 47 | /// ```ignore 48 | /// vec![1, 2, 3, 4, 5, 6, 8, 9] 49 | /// ``` 50 | /// 51 | /// it has the median of 5, which is the fifth value. 52 | /// 53 | /// Returns `None` if the list is empty. 54 | pub fn median(values: Vec) -> Option { 55 | todo!() 56 | } 57 | 58 | /// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash 59 | /// map will be helpful here). 60 | /// 61 | /// Returns `None` if the list is empty. 62 | pub fn mode(values: Vec) -> Option { 63 | todo!() 64 | } 65 | 66 | /// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig 67 | /// Latin. 68 | /// 69 | /// 1. If a word starts with a consonant and a vowel, move the first letter of the word at the end 70 | /// of the word and add "ay". 71 | /// 72 | /// Example: "happy" -> "appyh" + "ay" -> "appyhay" 73 | /// 74 | /// 2. If a word starts with multiple consonants, move them to the end of the word and add "ay". 75 | /// 76 | /// Example: "string" -> "ingstr" + "ay" -> "ingstray" 77 | /// 78 | /// 3. If a word starts with a vowel, add the word "hay" at the end of the word. 79 | /// 80 | /// Example: "explain" -> "explain" + "hay" -> "explainhay" 81 | /// 82 | /// Keep in mind the details about UTF-8 encoding! 83 | /// 84 | /// You may assume the string only contains lowercase alphabets, and it contains at least one vowel. 85 | pub fn piglatin(input: String) -> String { 86 | todo!() 87 | } 88 | 89 | /// Converts HR commands to the organization table. 90 | /// 91 | /// If the commands are as follows: 92 | /// 93 | /// ```ignore 94 | /// vec!["Add Amir to Engineering", "Add Sally to Sales", "Remove Jeehoon from Sales", "Move Amir from Engineering to Sales"] 95 | /// ``` 96 | /// 97 | /// The return value should be: 98 | /// 99 | /// ```ignore 100 | /// ["Sales" -> ["Amir", "Sally"]] 101 | /// ``` 102 | /// 103 | /// - The result is a map from department to the list of its employees. 104 | /// - An empty department should not appear in the result. 105 | /// - There are three commands: "Add {person} to {department}", "Remove {person} from {department}", 106 | /// and "Move {person} from {department} to {department}". 107 | /// - If a command is not executable, then it's ignored. 108 | /// - There is no space in the name of the person and department. 109 | /// 110 | /// See the test function for more details. 111 | pub fn organize(commands: Vec) -> HashMap> { 112 | todo!() 113 | } 114 | 115 | /// Events in a text editor. 116 | #[derive(Debug)] 117 | pub enum TypeEvent { 118 | /// A character is typed. 119 | Type(char), 120 | /// The last character is removed. 121 | Backspace, 122 | /// The whole string is copied to the clipboard. 123 | Copy, 124 | /// The string in the clipboard is appended. 125 | Paste, 126 | } 127 | 128 | /// Starting from an empty string and an empty clipboard, 129 | /// processes the given `events` in order and returns the resulting string. 130 | /// 131 | /// See the test function `test_editor` for examples. 132 | pub fn use_editor(events: Vec) -> String { 133 | todo!() 134 | } 135 | -------------------------------------------------------------------------------- /src/assignments/assignment02/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::assignments::assignment02::small_exercises::*; 4 | 5 | #[test] 6 | fn test_fahrenheit() { 7 | assert_eq!(fahrenheit_to_celsius(32.0), 0.0); 8 | assert_eq!(fahrenheit_to_celsius(212.0), 100.0); 9 | } 10 | 11 | #[test] 12 | fn test_capitalize() { 13 | assert_eq!( 14 | capitalize(String::from("aAbbBcccCddddD❤한글과✓")), 15 | String::from("AABBBCCCCDDDDD❤한글과✓"), 16 | ); 17 | assert_eq!(capitalize(String::from("Tschüß")), String::from("TSCHüß")); 18 | } 19 | 20 | #[test] 21 | fn test_up3() { 22 | assert_eq!(up3(0), 1); 23 | assert_eq!(up3(1), 1); 24 | assert_eq!(up3(6), 9); 25 | assert_eq!(up3(9), 9); 26 | assert_eq!(up3(10), 27); 27 | assert_eq!(up3(1_000_000), 1_594_323); 28 | assert_eq!(up3(3u64.pow(39).wrapping_add(1)), 3u64.pow(40)); 29 | assert_eq!(up3(3u64.pow(40)), 3u64.pow(40)); 30 | } 31 | 32 | #[test] 33 | fn test_gcd() { 34 | assert_eq!(gcd(5, 1), 1); 35 | assert_eq!(gcd(3, 3), 3); 36 | assert_eq!(gcd(2, 6), 2); 37 | assert_eq!(gcd(24, 18), 6); 38 | assert_eq!(gcd(20, 63), 1); 39 | assert_eq!(gcd(0, 33), 33); 40 | } 41 | 42 | #[test] 43 | fn test_sum_array() { 44 | assert_eq!(sum_array(&[]), 0); 45 | assert_eq!(sum_array(&[1]), 1); 46 | assert_eq!(sum_array(&[1, 2, 3, 4, 5, 100]), 115); 47 | } 48 | 49 | #[test] 50 | fn test_chooses() { 51 | assert_eq!(chooses(0), vec![1]); 52 | assert_eq!(chooses(1), vec![1, 1]); 53 | assert_eq!(chooses(5), vec![1, 5, 10, 10, 5, 1]); 54 | assert_eq!(chooses(6), vec![1, 6, 15, 20, 15, 6, 1]); 55 | assert_eq!( 56 | chooses(67), 57 | vec![ 58 | 1, 59 | 67, 60 | 2211, 61 | 47905, 62 | 766480, 63 | 9657648, 64 | 99795696, 65 | 869648208, 66 | 6522361560, 67 | 42757703560, 68 | 247994680648, 69 | 1285063345176, 70 | 5996962277488, 71 | 25371763481680, 72 | 97862516286480, 73 | 345780890878896, 74 | 1123787895356412, 75 | 3371363686069236, 76 | 9364899127970100, 77 | 24151581961607100, 78 | 57963796707857040, 79 | 129728497393775280, 80 | 271250494550621040, 81 | 530707489338171600, 82 | 972963730453314600, 83 | 1673497616379701112, 84 | 2703342303382594104, 85 | 4105075349580976232, 86 | 5864393356544251760, 87 | 7886597962249166160, 88 | 9989690752182277136, 89 | 11923179284862717872, 90 | 13413576695470557606, 91 | 14226520737620288370, 92 | 14226520737620288370, 93 | 13413576695470557606, 94 | 11923179284862717872, 95 | 9989690752182277136, 96 | 7886597962249166160, 97 | 5864393356544251760, 98 | 4105075349580976232, 99 | 2703342303382594104, 100 | 1673497616379701112, 101 | 972963730453314600, 102 | 530707489338171600, 103 | 271250494550621040, 104 | 129728497393775280, 105 | 57963796707857040, 106 | 24151581961607100, 107 | 9364899127970100, 108 | 3371363686069236, 109 | 1123787895356412, 110 | 345780890878896, 111 | 97862516286480, 112 | 25371763481680, 113 | 5996962277488, 114 | 1285063345176, 115 | 247994680648, 116 | 42757703560, 117 | 6522361560, 118 | 869648208, 119 | 99795696, 120 | 9657648, 121 | 766480, 122 | 47905, 123 | 2211, 124 | 67, 125 | 1 126 | ] 127 | ); 128 | } 129 | 130 | #[test] 131 | fn test_zip() { 132 | assert_eq!(zip(vec![1, 2], vec![4, 5]), vec![(1, 4), (2, 5)]); 133 | assert_eq!(zip(vec![1, 2, 3], vec![4, 5]), vec![(1, 4), (2, 5)]); 134 | assert_eq!(zip(vec![1, 2], vec![4, 5, 6]), vec![(1, 4), (2, 5)]); 135 | assert_eq!(zip(vec![], vec![4, 5]), vec![]); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/assignments/assignment12/card_grade.rs: -------------------------------------------------------------------------------- 1 | //! Test cases for assignment12/card.rs 2 | 3 | #[cfg(test)] 4 | mod test_card { 5 | use std::sync::atomic::{AtomicBool, Ordering}; 6 | use std::sync::{Arc, Barrier, Mutex}; 7 | use std::thread; 8 | use std::time::Duration; 9 | 10 | use crate::assignments::assignment12::card::*; 11 | 12 | const NUM_CARDS: usize = 10000; 13 | const DURATION: u64 = 20; 14 | const NUM_ENEMIES: usize = 25; 15 | 16 | #[derive(Clone, Debug)] 17 | struct Card { 18 | color: Arc>, 19 | } 20 | 21 | impl Card { 22 | fn new() -> Self { 23 | Card { 24 | color: Arc::new(Mutex::new(Color::Blue)), 25 | } 26 | } 27 | 28 | fn flip(&self, new_color: Color) { 29 | let mut color = self.color.lock().unwrap(); 30 | *color = new_color; 31 | } 32 | 33 | fn get_color(&self) -> Color { 34 | let color = self.color.lock().unwrap(); 35 | *color 36 | } 37 | } 38 | 39 | #[derive(Clone, Debug)] 40 | struct Ground { 41 | cards: Vec, 42 | } 43 | 44 | impl Ground { 45 | fn new() -> Self { 46 | let cards: Vec<_> = (0..NUM_CARDS).map(|_| Card::new()).collect(); 47 | Ground { cards } 48 | } 49 | 50 | fn flip_card(&self, idx: usize, color: Color) { 51 | self.cards[idx % NUM_CARDS].flip(color); 52 | } 53 | 54 | fn get_card_color(&self, idx: usize) -> Color { 55 | self.cards[idx % NUM_CARDS].get_color() 56 | } 57 | } 58 | 59 | #[test] 60 | fn play() { 61 | let ground = Ground::new(); 62 | let barrier = Arc::new(Barrier::new( 63 | NUM_ENEMIES + 1 /*Player*/ + 1, /* Referee */ 64 | )); 65 | let playing = Arc::new(AtomicBool::new(true)); 66 | 67 | // Create a thread for the student's strategy 68 | let mut player = Player::new(); 69 | let player_thread = { 70 | let ground = ground.clone(); 71 | let barrier = barrier.clone(); 72 | let playing = playing.clone(); 73 | 74 | // The player's strategy thread 75 | thread::spawn(move || { 76 | // Get, Set, Ready, Go! 77 | let _ = barrier.wait(); 78 | 79 | // As long as the game is still playing... 80 | while playing.load(Ordering::SeqCst) { 81 | let (idx, color) = player.flip_card_strategy(); 82 | ground.flip_card(idx, color); 83 | } 84 | }) 85 | }; 86 | 87 | // Create multiple threads for the computer's strategy 88 | let dist = NUM_CARDS / NUM_ENEMIES; 89 | let bot_threads: Vec<_> = (0..NUM_ENEMIES) 90 | .map(|i| { 91 | let ground = ground.clone(); 92 | let barrier = barrier.clone(); 93 | let playing = playing.clone(); 94 | 95 | let init = i * dist; 96 | let mut cnt = 0; 97 | 98 | thread::spawn(move || { 99 | // Get, Set, Ready, Go! 100 | let _ = barrier.wait(); 101 | 102 | // As long as the game is still playing... 103 | while playing.load(Ordering::SeqCst) { 104 | let idx = init + (cnt % dist); 105 | match ground.get_card_color(idx) { 106 | Color::White => ground.flip_card(idx, Color::Blue), 107 | Color::Blue => thread::sleep(Duration::from_micros(10)), 108 | }; 109 | cnt += 1; 110 | } 111 | }) 112 | }) 113 | .collect(); 114 | 115 | // Get, Set, Ready, Go! 116 | let _ = barrier.wait(); 117 | 118 | // Wait for a while and stop the game 119 | thread::sleep(Duration::from_secs(DURATION)); 120 | playing.store(false, Ordering::SeqCst); 121 | 122 | // Wait for all threads to finish 123 | player_thread.join().unwrap(); 124 | for bot_thread in bot_threads { 125 | bot_thread.join().unwrap(); 126 | } 127 | 128 | // Count the number of white and blue cards 129 | let mut white_cnt = 0; 130 | let mut blue_cnt = 0; 131 | for card in ground.cards { 132 | match card.get_color() { 133 | Color::White => white_cnt += 1, 134 | Color::Blue => blue_cnt += 1, 135 | } 136 | } 137 | 138 | // Print the winner 139 | println!("[White: {white_cnt}, Blue: {blue_cnt}]"); 140 | assert!(white_cnt > blue_cnt, "You lose...",); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/assignments/assignment10/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Small exercises. 2 | 3 | use std::collections::HashSet; 4 | 5 | use itertools::*; 6 | 7 | /// Returns the pairs of `(i, j)` where `i < j` and `inner[i] > inner[j]` in increasing order. 8 | /// 9 | /// For example, the inversions of `[3, 5, 1, 2, 4]` is `[(0, 2), (0, 3), (1, 2), (1, 3), (1, 4)]` 10 | /// because as follows: 11 | /// 12 | /// - `0 < 2`, `inner[0] = 3 > 1 = inner[2]` 13 | /// - `0 < 3`, `inner[0] = 3 > 2 = inner[3]` 14 | /// - `1 < 2`, `inner[1] = 5 > 1 = inner[2]` 15 | /// - `1 < 3`, `inner[1] = 5 > 2 = inner[3]` 16 | /// - `1 < 4`, `inner[1] = 5 > 4 = inner[4]` 17 | /// 18 | /// Consult for more details of inversion. 19 | pub fn inversion(inner: Vec) -> Vec<(usize, usize)> { 20 | todo!() 21 | } 22 | 23 | /// Represents a node of tree data structure. 24 | /// 25 | /// Consult for more details on tree data structure. 26 | #[derive(Debug)] 27 | pub enum Node { 28 | /// Non-leaf node 29 | /// 30 | /// It contains `(the name of node, list of child nodes)`. 31 | NonLeaf((T, Vec>)), 32 | /// Leaf node 33 | /// 34 | /// It contains the name of node. 35 | Leaf(T), 36 | } 37 | 38 | /// Traverses the tree in preorder. 39 | /// 40 | /// The algorithm for preorder traversal is as follows: 41 | /// 42 | /// 1. Visit the root. 43 | /// 2. If the root is a leaf node, end the traverse. 44 | /// 3. If the root is a non-leaf node, traverse each subtree from the child nodes. 45 | /// 46 | /// For example, the result of preorder traversal for the following tree 47 | /// 48 | /// ```text 49 | /// 1 50 | /// /|\ 51 | /// 2 3 4 52 | /// /| /|\ 53 | /// 5 6 7 8 9 54 | /// ``` 55 | /// 56 | /// which can be represented as 57 | /// 58 | /// ```ignore 59 | /// Node::NonLeaf(( 60 | /// 1, 61 | /// vec![ 62 | /// Node::NonLeaf((2, vec![Node::Leaf(5), Node::Leaf(6)])), 63 | /// Node::Leaf(3), 64 | /// Node::NonLeaf((4, vec![Node::Leaf(7), Node::Leaf(8), Node::Leaf(9)])), 65 | /// ] 66 | /// )) 67 | /// ``` 68 | /// 69 | /// is `1 -> 2 -> 5 -> 6 -> 3 -> 4 -> 7 -> 8 -> 9`. 70 | pub fn traverse_preorder(root: Node) -> Vec { 71 | todo!() 72 | } 73 | 74 | /// File 75 | #[derive(Debug)] 76 | pub enum File { 77 | /// Directory 78 | /// 79 | /// It contains `(name of directory, list of files under the directory)` 80 | /// 81 | /// The size of a directory is the sum of the sizes of its sub-files. 82 | Directory(String, Vec), 83 | 84 | /// Data 85 | /// 86 | /// It contains `(name of data, size of data)` 87 | Data(String, usize), 88 | } 89 | 90 | /// Given a file, summarize all subfiles and sizes in ascending order of size. 91 | /// 92 | /// - Its behaviour is the same as the `du | sort -h` command on Linux. 93 | /// - If the file size is the same, sort it by name. 94 | /// - Assume that there are no duplicate file names. 95 | /// 96 | /// # Example 97 | /// 98 | /// Input: 99 | /// 100 | /// ```txt 101 | /// root (Directory) 102 | /// | 103 | /// |__a (Directory) 104 | /// | |__a1 (Data, size: 1) 105 | /// | |__a2 (Data, size: 3) 106 | /// | 107 | /// |__b (Directory) 108 | /// | |__b1 (Data, size: 3) 109 | /// | |__b2 (Data, size: 15) 110 | /// | 111 | /// |__c (Data, size: 8) 112 | /// ``` 113 | /// 114 | /// Output: `[("a1", 1), ("a2", 3), ("b1", 3), ("a", 4), ("c", 8), ("b2", 15), ("b", 18), ("root", 115 | /// 30)]` 116 | pub fn du_sort(root: &File) -> Vec<(&str, usize)> { 117 | todo!() 118 | } 119 | 120 | /// Remove all even numbers inside a vector using the given mutable reference. 121 | /// That is, you must modify the vector using the given mutable reference instead 122 | /// of returning a new vector. 123 | /// 124 | /// # Example 125 | /// ```ignore 126 | /// let mut vec = vec![1, 2, 3, 4, 5]; 127 | /// remove_even(&mut vec); 128 | /// assert_eq!(*vec, vec![1, 3, 5]); 129 | /// ``` 130 | #[allow(clippy::ptr_arg)] 131 | pub fn remove_even(inner: &mut Vec) { 132 | todo!() 133 | } 134 | 135 | /// Remove all duplicate occurences of a number inside the array. 136 | /// That is, if an integer appears more than once, remove some occurences 137 | /// of it so that it only appears once. Note that you must modify the vector 138 | /// using the given mutable reference instead of returning a new vector. 139 | /// Also, note that the order does not matter. 140 | /// 141 | /// # Example 142 | /// ```ignore 143 | /// let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7]; 144 | /// remove_duplicate(&mut vec); 145 | /// assert_eq!(*vec, vec![1, 2, 3, 7, 5]); 146 | /// ``` 147 | #[allow(clippy::ptr_arg)] 148 | pub fn remove_duplicate(inner: &mut Vec) { 149 | todo!() 150 | } 151 | 152 | /// Returns the natural join of two tables using the first column as the join argument. 153 | /// That is, for each pair of a row(`Vec`) from table1 and a row(`Vec`) from table2, 154 | /// if the first element of them are equal, then add all elements of the row from table2 155 | /// except its first element to the row from table1 and add it to the results. 156 | /// Note that the order of results does not matter. 157 | /// 158 | /// # Example 159 | /// 160 | /// ```text 161 | /// table1 table2 162 | /// ---------------------- ---------------------- 163 | /// 20230001 | Jack 20230001 | CS 164 | /// 20231234 | Mike 20230001 | EE 165 | /// 20231234 | ME 166 | /// 167 | /// 168 | /// result 169 | /// ----------------------------------- 170 | /// 20230001 | Jack | CS 171 | /// 20230001 | Jack | EE 172 | /// 20231234 | Mike | ME 173 | /// ``` 174 | pub fn natural_join(table1: Vec>, table2: Vec>) -> Vec> { 175 | todo!() 176 | } 177 | 178 | /// You can freely add more fields. 179 | struct Pythagorean; 180 | 181 | impl Pythagorean { 182 | fn new() -> Self { 183 | todo!() 184 | } 185 | } 186 | 187 | impl Iterator for Pythagorean { 188 | type Item = (u64, u64, u64); 189 | 190 | fn next(&mut self) -> Option { 191 | todo!() 192 | } 193 | } 194 | 195 | /// Generates sequence of unique [primitive Pythagorean triples](https://en.wikipedia.org/wiki/Pythagorean_triple), 196 | /// i.e. (a,b,c) such that a² + b² = c², a and b are coprimes, and a < b. Generate in the increasing 197 | /// order of c. 198 | pub fn pythagorean() -> impl Iterator { 199 | Pythagorean::new() 200 | } 201 | -------------------------------------------------------------------------------- /src/assignments/assignment07/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use itertools::Itertools; 4 | use ntest::assert_about_eq; 5 | 6 | use crate::assignments::assignment07::small_exercises::*; 7 | 8 | #[test] 9 | fn test_find() { 10 | assert_eq!( 11 | find("abc".as_bytes(), "abcdabcd".as_bytes()).collect::>(), 12 | vec![0, 4] 13 | ); 14 | 15 | assert_eq!( 16 | find("aaba".as_bytes(), "aabaacaadaabaaba".as_bytes()).collect::>(), 17 | vec![0, 9, 12] 18 | ); 19 | 20 | assert_eq!( 21 | find("ababac".as_bytes(), "abababcabababcabababc".as_bytes()).collect::>(), 22 | vec![] 23 | ); 24 | 25 | assert_eq!( 26 | find("ababc".as_bytes(), "abc".as_bytes()).collect::>(), 27 | vec![] 28 | ); 29 | } 30 | 31 | #[test] 32 | fn test_find_usize() { 33 | assert_eq!( 34 | find(&[1, 2, 3], &[1, 2, 3, 4, 1, 2, 3, 4]).collect::>(), 35 | vec![0, 4] 36 | ); 37 | 38 | assert_eq!( 39 | find( 40 | &[5, 5, 7, 5], 41 | &[5, 5, 7, 5, 5, 8, 5, 5, 9, 5, 5, 7, 5, 5, 7, 5] 42 | ) 43 | .collect::>(), 44 | vec![0, 9, 12] 45 | ); 46 | } 47 | 48 | #[test] 49 | fn test_fib_iter() { 50 | assert_eq!( 51 | fib(0, 1).take(10).collect::>(), 52 | vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 53 | ); 54 | 55 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 56 | struct Rgb(u8, u8, u8); 57 | 58 | impl std::ops::Add for Rgb { 59 | type Output = Self; 60 | 61 | fn add(self, rhs: Self) -> Self::Output { 62 | Self( 63 | ((self.0 as u16 + rhs.0 as u16) / 2) as u8, 64 | ((self.1 as u16 + rhs.1 as u16) / 2) as u8, 65 | ((self.2 as u16 + rhs.2 as u16) / 2) as u8, 66 | ) 67 | } 68 | } 69 | 70 | assert_eq!( 71 | fib(Rgb(255, 0, 100), Rgb(1, 128, 0)) 72 | .take(20) 73 | .collect::>(), 74 | vec![ 75 | Rgb(255, 0, 100), 76 | Rgb(1, 128, 0), 77 | Rgb(128, 64, 50), 78 | Rgb(64, 96, 25), 79 | Rgb(96, 80, 37), 80 | Rgb(80, 88, 31), 81 | Rgb(88, 84, 34), 82 | Rgb(84, 86, 32), 83 | Rgb(86, 85, 33), 84 | Rgb(85, 85, 32), 85 | Rgb(85, 85, 32), 86 | Rgb(85, 85, 32), 87 | Rgb(85, 85, 32), 88 | Rgb(85, 85, 32), 89 | Rgb(85, 85, 32), 90 | Rgb(85, 85, 32), 91 | Rgb(85, 85, 32), 92 | Rgb(85, 85, 32), 93 | Rgb(85, 85, 32), 94 | Rgb(85, 85, 32) 95 | ] 96 | ); 97 | } 98 | 99 | #[test] 100 | fn test_range_iter() { 101 | let one_to_tens = [ 102 | vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 103 | range(Endpoint::Inclusive(1), Endpoint::Inclusive(10), 1).collect(), 104 | range(Endpoint::Exclusive(0), Endpoint::Inclusive(10), 1).collect(), 105 | range(Endpoint::Inclusive(1), Endpoint::Exclusive(11), 1).collect(), 106 | range(Endpoint::Exclusive(0), Endpoint::Exclusive(11), 1).collect(), 107 | ]; 108 | assert!(one_to_tens.iter().all_equal()); 109 | 110 | let ten_to_ones = [ 111 | vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1], 112 | range(Endpoint::Inclusive(10), Endpoint::Inclusive(1), -1).collect(), 113 | range(Endpoint::Exclusive(11), Endpoint::Inclusive(1), -1).collect(), 114 | range(Endpoint::Inclusive(10), Endpoint::Exclusive(0), -1).collect(), 115 | range(Endpoint::Exclusive(11), Endpoint::Exclusive(0), -1).collect(), 116 | ]; 117 | assert!(ten_to_ones.iter().all_equal()); 118 | 119 | let five_evens = vec![ 120 | vec![2, 4, 6, 8, 10], 121 | range(Endpoint::Inclusive(2), Endpoint::Inclusive(10), 2).collect(), 122 | range(Endpoint::Inclusive(2), Endpoint::Inclusive(11), 2).collect(), 123 | range(Endpoint::Exclusive(1), Endpoint::Inclusive(10), 2).collect(), 124 | range(Endpoint::Exclusive(1), Endpoint::Inclusive(11), 2).collect(), 125 | range(Endpoint::Inclusive(2), Endpoint::Exclusive(11), 2).collect(), 126 | range(Endpoint::Inclusive(2), Endpoint::Exclusive(12), 2).collect(), 127 | range(Endpoint::Exclusive(1), Endpoint::Exclusive(11), 2).collect(), 128 | range(Endpoint::Exclusive(1), Endpoint::Exclusive(12), 2).collect(), 129 | ]; 130 | assert!(five_evens.iter().all_equal()); 131 | 132 | let emptys = [ 133 | vec![], 134 | range(Endpoint::Inclusive(2), Endpoint::Inclusive(10), -1).collect(), 135 | range(Endpoint::Inclusive(10), Endpoint::Inclusive(-100), 1).collect(), 136 | range(Endpoint::Inclusive(1), Endpoint::Exclusive(1), 1).collect(), 137 | ]; 138 | assert!(emptys.iter().all_equal()); 139 | } 140 | 141 | #[test] 142 | fn test_small() { 143 | assert_eq!(divisors(10).collect::>(), vec![1, 2, 5, 10]); 144 | 145 | assert_eq!(divisors(17).collect::>(), vec![1, 17]); 146 | 147 | assert_eq!(divisors(49).collect::>(), vec![1, 7, 49]); 148 | 149 | assert_eq!( 150 | divisors(120).collect::>(), 151 | vec![1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60, 120] 152 | ); 153 | 154 | assert_eq!(divisors(1).collect::>(), vec![1]); 155 | 156 | assert_eq!(divisors(2).collect::>(), vec![1, 2]); 157 | 158 | assert_eq!(divisors(3).collect::>(), vec![1, 3]); 159 | } 160 | 161 | #[test] 162 | fn test_large() { 163 | assert_eq!( 164 | divisors(1_000_000_000_000_037).collect::>(), 165 | vec![1, 1_000_000_000_000_037] 166 | ); 167 | 168 | assert_eq!( 169 | divisors(99_999_820_000_081).collect::>(), 170 | vec![1, 9_999_991, 99_999_820_000_081] 171 | ); 172 | 173 | assert_eq!( 174 | divisors(1_234_567_890_123).collect::>(), 175 | vec![ 176 | 1, 177 | 3, 178 | 3_541, 179 | 10_623, 180 | 116_216_501, 181 | 348_649_503, 182 | 411_522_630_041, 183 | 1_234_567_890_123 184 | ] 185 | ); 186 | 187 | assert_eq!(divisors(97_821_761_637_600).count(), 17280); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/assignments/assignment09/small_exercises.rs: -------------------------------------------------------------------------------- 1 | //! Small exercises. 2 | 3 | use std::collections::HashMap; 4 | 5 | use itertools::Itertools; 6 | 7 | /// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's 8 | /// first two terms. 9 | /// 10 | /// Returns `true` if the length of sequence is less or equal than 2. 11 | /// 12 | /// # Example 13 | /// 14 | /// ``` 15 | /// use cs220::assignments::assignment09::small_exercises::*; 16 | /// 17 | /// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 13].into_iter()), true); 18 | /// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter()), false); 19 | /// ``` 20 | pub fn is_fibonacci(inner: impl Iterator) -> bool { 21 | todo!() 22 | } 23 | 24 | /// Returns the sum of `f(v)` for all element `v` the given array. 25 | /// 26 | /// # Example 27 | /// 28 | /// ``` 29 | /// use cs220::assignments::assignment09::small_exercises::*; 30 | /// 31 | /// assert_eq!(sigma([1, 2].into_iter(), |x| x + 2), 7); 32 | /// assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); 33 | /// ``` 34 | pub fn sigma i64>(inner: impl Iterator, f: F) -> i64 { 35 | todo!() 36 | } 37 | 38 | /// Alternate elements from three iterators until they have run out. 39 | /// 40 | /// You can assume that the number of elements of three iterators are same. 41 | /// 42 | /// # Example 43 | /// 44 | /// ``` 45 | /// use cs220::assignments::assignment09::small_exercises::*; 46 | /// 47 | /// assert_eq!( 48 | /// interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), 49 | /// vec![1, 3, 5, 2, 4, 6] 50 | /// ); 51 | /// ``` 52 | pub fn interleave3( 53 | list1: impl Iterator, 54 | list2: impl Iterator, 55 | list3: impl Iterator, 56 | ) -> Vec { 57 | todo!() 58 | } 59 | 60 | /// Alternate elements from array of n iterators until they have run out. 61 | /// 62 | /// You can assume that the number of elements of iterators are same. 63 | /// 64 | /// # Example 65 | /// 66 | /// ``` 67 | /// use cs220::assignments::assignment09::small_exercises::*; 68 | /// 69 | /// assert_eq!( 70 | /// interleave_n(&mut [[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]), 71 | /// vec![1, 3, 5, 2, 4, 6] 72 | /// ); 73 | /// ``` 74 | pub fn interleave_n( 75 | mut iters: [impl Iterator; N], 76 | ) -> impl Iterator { 77 | todo!(); 78 | std::iter::empty() 79 | } 80 | 81 | /// Returns mean of k smallest value's mean. 82 | /// 83 | /// # Example 84 | /// 85 | /// ``` 86 | /// use cs220::assignments::assignment09::small_exercises::*; 87 | /// 88 | /// assert_eq!( 89 | /// k_smallest_mean(vec![1, 3, 2].into_iter(), 2), 90 | /// ((1 + 2) as f64 / 2.0) 91 | /// ); 92 | /// assert_eq!( 93 | /// k_smallest_mean(vec![7, 5, 3, 6].into_iter(), 3), 94 | /// ((3 + 5 + 6) as f64 / 3.0) 95 | /// ); 96 | /// ``` 97 | pub fn k_smallest_mean(inner: impl Iterator, k: usize) -> f64 { 98 | todo!() 99 | } 100 | 101 | /// Returns mean for each class. 102 | /// 103 | /// # Example 104 | /// 105 | /// ``` 106 | /// use cs220::assignments::assignment09::small_exercises::*; 107 | /// 108 | /// assert_eq!( 109 | /// calculate_mean( 110 | /// [ 111 | /// ("CS100".to_string(), 60), 112 | /// ("CS200".to_string(), 60), 113 | /// ("CS200".to_string(), 80), 114 | /// ("CS300".to_string(), 100), 115 | /// ] 116 | /// .into_iter() 117 | /// ), 118 | /// [ 119 | /// ("CS100".to_string(), 60.0), 120 | /// ("CS200".to_string(), 70.0), 121 | /// ("CS300".to_string(), 100.0) 122 | /// ] 123 | /// .into_iter() 124 | /// .collect() 125 | /// ); 126 | /// ``` 127 | pub fn calculate_mean(inner: impl Iterator) -> HashMap { 128 | todo!() 129 | } 130 | 131 | /// Among the cartesian product of input vectors, return the number of sets whose sum equals `n`. 132 | /// 133 | /// # Example 134 | /// 135 | /// The cartesian product of [1, 2, 3] and [2, 3] are: 136 | /// [1, 2], [1, 3], [2, 2], [2, 3], [3, 2], [3, 3]. 137 | /// 138 | /// Among these sets, the number of sets whose sum is 4 is 2, which is [1, 3] and [2, 2]. 139 | /// 140 | /// ``` 141 | /// use cs220::assignments::assignment09::small_exercises::*; 142 | /// 143 | /// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1); 144 | /// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2); 145 | /// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 5), 2); 146 | /// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 6), 1); 147 | /// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 2), 0); 148 | /// ``` 149 | pub fn sum_is_n(inner: Vec>, n: i64) -> usize { 150 | todo!() 151 | } 152 | 153 | /// Returns a new vector that contains the item that appears `n` times in the input vector in 154 | /// increasing order. 155 | /// 156 | /// # Example 157 | /// 158 | /// ``` 159 | /// use cs220::assignments::assignment09::small_exercises::*; 160 | /// 161 | /// assert_eq!(find_count_n(vec![1, 2], 1), vec![1, 2]); 162 | /// assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); 163 | /// assert_eq!(find_count_n(vec![1, 3, 3], 2), vec![3]); 164 | /// assert_eq!(find_count_n(vec![1, 2, 3, 4, 4], 1), vec![1, 2, 3]); 165 | /// ``` 166 | pub fn find_count_n(inner: Vec, n: usize) -> Vec { 167 | todo!() 168 | } 169 | 170 | /// Return the position of the median element in the vector. 171 | /// 172 | /// For a data set `x` of `n` elements, the median can be defined as follows: 173 | /// 174 | /// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`. 175 | /// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`. 176 | /// 177 | /// Please following these rules: 178 | /// 179 | /// - If the list is empty, returns `None`. 180 | /// - If several elements are equally median, the position of the first of them is returned. 181 | /// 182 | /// # Example 183 | /// 184 | /// ``` 185 | /// use cs220::assignments::assignment09::small_exercises::*; 186 | /// 187 | /// assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); 188 | /// assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); 189 | /// ``` 190 | pub fn position_median(inner: Vec) -> Option { 191 | todo!() 192 | } 193 | 194 | /// Returns the sum of all elements in a two-dimensional array. 195 | /// 196 | /// # Example 197 | /// ``` 198 | /// use cs220::assignments::assignment09::small_exercises::*; 199 | /// 200 | /// assert_eq!( 201 | /// two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()), 202 | /// 21 203 | /// ); 204 | /// ``` 205 | pub fn two_dimensional_sum(inner: impl Iterator>) -> i64 { 206 | todo!() 207 | } 208 | 209 | /// Returns whether the given string is palindrome or not. 210 | /// 211 | /// A palindrome is a word, number, phrase, or other sequence of characters which reads the same 212 | /// backward as forward. 213 | /// 214 | /// We consider the empty string as a palindrome. 215 | /// 216 | /// Consult . 217 | pub fn is_palindrome(s: String) -> bool { 218 | todo!() 219 | } 220 | -------------------------------------------------------------------------------- /src/assignments/assignment03/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use crate::assignments::assignment03::small_exercises::*; 4 | 5 | #[test] 6 | fn test_next_weekday() { 7 | assert_eq!(next_weekday(DayOfWeek::Sun), DayOfWeek::Mon); 8 | assert_eq!(next_weekday(DayOfWeek::Mon), DayOfWeek::Tue); 9 | assert_eq!(next_weekday(DayOfWeek::Tue), DayOfWeek::Wed); 10 | assert_eq!(next_weekday(DayOfWeek::Wed), DayOfWeek::Thu); 11 | assert_eq!(next_weekday(DayOfWeek::Thu), DayOfWeek::Fri); 12 | assert_eq!(next_weekday(DayOfWeek::Fri), DayOfWeek::Mon); 13 | assert_eq!(next_weekday(DayOfWeek::Sat), DayOfWeek::Mon); 14 | } 15 | 16 | #[test] 17 | fn test_median() { 18 | assert_eq!(median(vec![]), None); 19 | assert_eq!(median(vec![1]), Some(1)); 20 | assert_eq!(median(vec![1, 2]), Some(2)); 21 | assert_eq!(median(vec![2, 4, 5, 1, 3]), Some(3)); 22 | assert_eq!(median(vec![2, 3, 5, 7, 11, 13]), Some(7)); 23 | assert_eq!(median(vec![1, 3, 3, 6, 7, 8, 9]), Some(6)); 24 | assert_eq!(median(vec![6, 7, 3, 1, 9, 3, 8]), Some(6)); 25 | assert_eq!(median(vec![1, 2, 3, 4, 5, 6, 8, 9]), Some(5)); 26 | assert_eq!(median(vec![3, 4, 8, 9, 1, 6, 5, 2]), Some(5)); 27 | } 28 | 29 | #[test] 30 | fn test_mode() { 31 | assert_eq!(mode(vec![]), None); 32 | assert_eq!(mode(vec![3]), Some(3)); 33 | assert_eq!(mode(vec![2, 1, 2, 3]), Some(2)); 34 | assert_eq!(mode(vec![2, 3, 1, 2, 2, 3, 3]), Some(2)); 35 | assert_eq!(mode(vec![1, 1, 2, 2, 3, 3]), Some(1)); 36 | } 37 | 38 | #[test] 39 | fn test_piglatin() { 40 | assert_eq!(piglatin("pig".to_string()), "igpay".to_string()); 41 | assert_eq!(piglatin("latin".to_string()), "atinlay".to_string()); 42 | assert_eq!(piglatin("banana".to_string()), "ananabay".to_string()); 43 | assert_eq!(piglatin("will".to_string()), "illway".to_string()); 44 | assert_eq!(piglatin("butler".to_string()), "utlerbay".to_string()); 45 | assert_eq!(piglatin("happy".to_string()), "appyhay".to_string()); 46 | assert_eq!(piglatin("duck".to_string()), "uckday".to_string()); 47 | assert_eq!(piglatin("me".to_string()), "emay".to_string()); 48 | assert_eq!(piglatin("bagel".to_string()), "agelbay".to_string()); 49 | assert_eq!(piglatin("history".to_string()), "istoryhay".to_string()); 50 | 51 | assert_eq!(piglatin("smile".to_string()), "ilesmay".to_string()); 52 | assert_eq!(piglatin("string".to_string()), "ingstray".to_string()); 53 | assert_eq!(piglatin("stupid".to_string()), "upidstay".to_string()); 54 | assert_eq!(piglatin("glove".to_string()), "oveglay".to_string()); 55 | assert_eq!(piglatin("trash".to_string()), "ashtray".to_string()); 56 | assert_eq!(piglatin("floor".to_string()), "oorflay".to_string()); 57 | assert_eq!(piglatin("store".to_string()), "orestay".to_string()); 58 | 59 | assert_eq!(piglatin("eat".to_string()), "eathay".to_string()); 60 | assert_eq!(piglatin("omelet".to_string()), "omelethay".to_string()); 61 | assert_eq!(piglatin("are".to_string()), "arehay".to_string()); 62 | assert_eq!(piglatin("egg".to_string()), "egghay".to_string()); 63 | assert_eq!(piglatin("explain".to_string()), "explainhay".to_string()); 64 | assert_eq!(piglatin("ends".to_string()), "endshay".to_string()); 65 | assert_eq!(piglatin("amulet".to_string()), "amulethay".to_string()); 66 | } 67 | 68 | #[test] 69 | fn test_organize() { 70 | assert_eq!( 71 | organize(vec![ 72 | "Add Amir to Engineering".to_string(), 73 | "Add Sally to Sales".to_string(), 74 | "Remove Jeehoon from Sales".to_string(), 75 | "Move Amir from Engineering to Sales".to_string(), 76 | ]), 77 | [( 78 | "Sales".to_string(), 79 | ["Amir".to_string(), "Sally".to_string()].into() 80 | )] 81 | .into() 82 | ); 83 | 84 | assert_eq!( 85 | organize(vec![ 86 | "Add Jeehoon to Mathematics".to_string(), 87 | "Add Minseong to Mathematics".to_string(), 88 | "Add Seungmin to Computer-Science".to_string(), 89 | "Move Jeehoon from Mathematics to Computer-Science".to_string(), 90 | "Remove Minseong from Mathematics".to_string(), 91 | "Add Minseong to Computer-Science".to_string(), 92 | ]), 93 | [( 94 | "Computer-Science".to_string(), 95 | [ 96 | "Seungmin".to_string(), 97 | "Jeehoon".to_string(), 98 | "Minseong".to_string() 99 | ] 100 | .into() 101 | )] 102 | .into() 103 | ); 104 | 105 | assert_eq!( 106 | organize(vec![ 107 | "Move P1 from D1 to D2".to_string(), 108 | "Remove P2 from D2".to_string(), 109 | "Add P3 to D3".to_string(), 110 | "Add P4 to D1".to_string(), 111 | "Add P3 to D4".to_string(), 112 | "Move P3 from D4 to D2".to_string(), 113 | ]), 114 | [ 115 | ("D1".to_string(), ["P4".to_string()].into()), 116 | ("D2".to_string(), ["P3".to_string()].into()), 117 | ("D3".to_string(), ["P3".to_string()].into()) 118 | ] 119 | .into() 120 | ); 121 | } 122 | 123 | #[test] 124 | fn test_editor() { 125 | assert_eq!( 126 | use_editor(vec![ 127 | TypeEvent::Type('a'), 128 | TypeEvent::Backspace, 129 | TypeEvent::Backspace, 130 | TypeEvent::Type('b'), 131 | TypeEvent::Type('c') 132 | ]), 133 | "bc" 134 | ); 135 | 136 | assert_eq!( 137 | use_editor(vec![ 138 | TypeEvent::Type('a'), 139 | TypeEvent::Copy, 140 | TypeEvent::Paste, 141 | TypeEvent::Paste, 142 | TypeEvent::Type('b'), 143 | TypeEvent::Copy, 144 | TypeEvent::Paste 145 | ]), 146 | "aaabaaab" 147 | ); 148 | 149 | assert_eq!( 150 | use_editor(vec![ 151 | TypeEvent::Paste, // clipboard starts empty 152 | TypeEvent::Type('a'), 153 | TypeEvent::Type('n'), 154 | TypeEvent::Copy, 155 | TypeEvent::Backspace, 156 | TypeEvent::Backspace, 157 | TypeEvent::Type('b'), 158 | TypeEvent::Paste, 159 | TypeEvent::Paste, 160 | TypeEvent::Paste, 161 | TypeEvent::Backspace 162 | ]), 163 | "banana" 164 | ); 165 | 166 | assert_eq!( 167 | use_editor(vec![ 168 | TypeEvent::Copy, 169 | TypeEvent::Backspace, 170 | TypeEvent::Backspace, 171 | TypeEvent::Paste, 172 | TypeEvent::Paste, 173 | TypeEvent::Copy, 174 | TypeEvent::Backspace 175 | ]), 176 | "" 177 | ); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/assignments/assignment06/symbolic_differentiation_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use ntest::assert_about_eq; 4 | 5 | use crate::assignments::assignment06::symbolic_differentiation::*; 6 | 7 | // Constant rationals to use 8 | const TWO: Rational = Rational::new(2, 1); 9 | const FOUR: Rational = Rational::new(4, 1); 10 | const THIRD: Rational = Rational::new(1, 3); 11 | const FIVE_THIRD: Rational = Rational::new(5, 3); 12 | const TWO_SEVENTH: Rational = Rational::new(2, 7); 13 | 14 | #[test] 15 | fn test_rational_simpl() { 16 | assert_eq!(format!("{}", Rational::new(1, 2)), "1/2".to_string()); 17 | 18 | assert_eq!(format!("{}", Rational::new(0, 0)), "0".to_string()); 19 | 20 | assert_eq!(format!("{}", Rational::new(1, 1)), "1".to_string()); 21 | 22 | assert_eq!(format!("{}", Rational::new(-3, 7)), "-3/7".to_string()); 23 | } 24 | 25 | #[test] 26 | fn test_rational_arithmetic() { 27 | assert_eq!( 28 | format!("{}", Rational::new(1, 4) + Rational::new(3, 4)), 29 | "1".to_string() 30 | ); 31 | 32 | assert_eq!( 33 | format!("{}", Rational::new(1, 3) + Rational::new(1, 6)), 34 | "1/2".to_string() 35 | ); 36 | 37 | assert_eq!( 38 | format!("{}", Rational::new(1, 5) - Rational::new(1, 2)), 39 | "-3/10".to_string() 40 | ); 41 | 42 | assert_eq!( 43 | format!("{}", Rational::new(-5, 12) * Rational::new(6, 125)), 44 | "-1/50".to_string() 45 | ); 46 | 47 | assert_eq!( 48 | format!("{}", Rational::new(-3, 4) / Rational::new(-7, 13)), 49 | "39/28".to_string() 50 | ); 51 | } 52 | 53 | #[test] 54 | fn test_rational_arithmetic_long() { 55 | assert_eq!( 56 | format!( 57 | "{}", 58 | Rational::new(1, 2) + Rational::new(1, 2) + Rational::new(1, 2) 59 | ), 60 | "3/2".to_string() 61 | ); 62 | 63 | assert_eq!( 64 | format!( 65 | "{}", 66 | Rational::new(1, 2) - Rational::new(1, 4) + Rational::new(1, 5) 67 | ), 68 | "9/20".to_string() 69 | ); 70 | 71 | assert_eq!( 72 | format!( 73 | "{}", 74 | Rational::new(1, 2) 75 | * Rational::new(1, 4) 76 | * Rational::new(1, 8) 77 | * Rational::new(1, 16) 78 | / Rational::new(1, 1024) 79 | ), 80 | "1".to_string() 81 | ); 82 | 83 | assert_eq!( 84 | format!( 85 | "{}", 86 | Rational::new(123, 798) 87 | + Rational::new(684, 32) / (Rational::new(13, 44) - Rational::new(123, 4472)) 88 | * Rational::new(1237, 2) 89 | ), 90 | "12356494070/250439".to_string() 91 | ); 92 | } 93 | 94 | #[test] 95 | fn test_differentiate_simple() { 96 | // Constant 97 | assert_eq!(format!("{}", Rational::new(3, 2).diff()), "0".to_string()); 98 | 99 | // Polynomials 100 | assert_eq!( 101 | format!("{}", SingletonPolynomial::new_c(Rational::new(3, 1)).diff()), 102 | "0".to_string() 103 | ); 104 | assert_eq!( 105 | format!("{}", SingletonPolynomial::new_poly(TWO, FOUR).diff()), 106 | "(8)x^(3)".to_string() 107 | ); 108 | assert_eq!( 109 | format!( 110 | "{}", 111 | SingletonPolynomial::new_poly(FIVE_THIRD, THIRD).diff() 112 | ), 113 | "(5/9)x^(-2/3)".to_string() 114 | ); 115 | 116 | // Exponential 117 | assert_eq!(format!("{}", Exp::new().diff()), "exp(x)".to_string()); 118 | 119 | // Trigonometric 120 | assert_eq!( 121 | format!("{}", Trignometric::new_sine(ONE).diff()), 122 | "cos(x)".to_string() 123 | ); 124 | assert_eq!( 125 | format!("{}", Trignometric::new_cosine(ONE).diff()), 126 | "-sin(x)".to_string() 127 | ); 128 | assert_eq!( 129 | format!("{}", Trignometric::new_sine(FIVE_THIRD).diff()), 130 | "(5/3)cos(x)".to_string() 131 | ); 132 | assert_eq!( 133 | format!("{}", Trignometric::new_cosine(TWO_SEVENTH).diff()), 134 | "(-2/7)sin(x)".to_string() 135 | ); 136 | } 137 | 138 | #[test] 139 | fn test_differentiate_complex() { 140 | type BF = BaseFuncs; 141 | type CF = ComplexFuncs; 142 | 143 | // Unlike the above simple test, it is hard to state a canonical 144 | // form for derivative of more complex functions. Thus, we only test that the 145 | // derivative is correct at certain points. 146 | 147 | // Add 148 | // 149 | // d/dx (2x^4 + exp(x)) = 8x^3 + exp(x) 150 | let f1 = SingletonPolynomial::new_poly(TWO, FOUR); 151 | let f2 = Exp::new(); 152 | let deriv = CF::Add( 153 | Box::new(CF::Func(BF::Poly(f1))), 154 | Box::new(CF::Func(BF::Exp(f2))), 155 | ) 156 | .diff(); 157 | assert_about_eq!(deriv.evaluate(2.2), 94.2090134994f64); 158 | assert_about_eq!(deriv.evaluate(4.5), 819.017131301); 159 | 160 | // Sub 161 | // 162 | // d/dx ((5/3)cos(x) - sin(x)) = (-5/3)sin(x) - cos(x) 163 | let f1 = Trignometric::new_cosine(FIVE_THIRD); 164 | let f2 = Trignometric::new_sine(ONE); 165 | let deriv = CF::Sub( 166 | Box::new(CF::Func(BF::Trig(f1))), 167 | Box::new(CF::Func(BF::Trig(f2))), 168 | ) 169 | .diff(); 170 | assert_about_eq!(deriv.evaluate(2.7), 0.191772341627); 171 | assert_about_eq!(deriv.evaluate(0.01), -1.01661638931); 172 | 173 | // Mult 174 | // 175 | // d/dx (2x^4 * cos(x) * exp(x)) = 176 | // 8x^2 * cos(x) * exp(x) - 2x^4 * sin(x) * exp(x) + 2x^4 * cos(x) * exp(x) 177 | let f1 = SingletonPolynomial::new_poly(TWO, FOUR); 178 | let f2 = Trignometric::new_cosine(ONE); 179 | let f3 = Exp::new(); 180 | let deriv = CF::Mul( 181 | Box::new(CF::Func(BF::Poly(f1))), 182 | Box::new(CF::Mul( 183 | Box::new(CF::Func(BF::Trig(f2))), 184 | Box::new(CF::Func(BF::Exp(f3))), 185 | )), 186 | ) 187 | .diff(); 188 | assert_about_eq!(deriv.evaluate(3.4), -14804.9016757); 189 | assert_about_eq!(deriv.evaluate(0.07), 0.00298352866); 190 | 191 | // Div 192 | // 193 | // (d/dx) (sin(x)/cos(x)) = (cos(x)*cos(x) + sin(x)*sin(x)) / cos(x)*cos(x) 194 | let f1 = Trignometric::new_sine(ONE); 195 | let f2 = Trignometric::new_cosine(ONE); 196 | let deriv = CF::Div( 197 | Box::new(CF::Func(BF::Trig(f1))), 198 | Box::new(CF::Func(BF::Trig(f2))), 199 | ) 200 | .diff(); 201 | assert_about_eq!(deriv.evaluate(core::f64::consts::PI), 1f64); 202 | assert_about_eq!(deriv.evaluate(0f64), 1f64); 203 | 204 | // Comp 205 | // 206 | // d/dx (cos(x^2)) = -2x * sin(x^2) 207 | let f1 = Trignometric::new_cosine(ONE); 208 | let f2 = SingletonPolynomial::new_poly(ONE, TWO); 209 | let deriv = CF::Comp( 210 | Box::new(CF::Func(BF::Trig(f1))), 211 | Box::new(CF::Func(BF::Poly(f2))), 212 | ) 213 | .diff(); 214 | assert_about_eq!(deriv.evaluate(2.714), -4.79392977); 215 | assert_about_eq!(deriv.evaluate(3.9), -3.72556973); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/assignments/assignment13/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | use std::hint; 4 | use std::time::Instant; 5 | 6 | use approx::*; 7 | use itertools::Itertools; 8 | use ndarray::prelude::*; 9 | use ndarray_rand::rand_distr::Uniform; 10 | use ndarray_rand::RandomExt; 11 | use ntest::assert_about_eq; 12 | use rayon::prelude::IntoParallelIterator; 13 | 14 | use crate::assignments::assignment09::matmul::*; 15 | use crate::assignments::assignment13::small_exercises::*; 16 | 17 | #[test] 18 | fn test_sigma_par() { 19 | assert_eq!(sigma_par([].into_par_iter(), |x: i64| x * 2), 0); 20 | assert_eq!(sigma_par([1].into_par_iter(), |x| x * 3), 3); 21 | assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x + 2), 7); 22 | assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x * 4), 12); 23 | assert_eq!(sigma_par([1, 2, 3].into_par_iter(), |x| x * 5), 30); 24 | 25 | assert_eq!( 26 | sigma_par([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.floor() 27 | as i64), 28 | 10 29 | ); 30 | assert_eq!( 31 | sigma_par([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.ceil() 32 | as i64), 33 | 13 34 | ); 35 | assert_eq!( 36 | sigma_par([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.round() 37 | as i64), 38 | 12 39 | ); 40 | 41 | assert_eq!( 42 | sigma_par(["Hello,", "World!"].into_par_iter(), |x| x.len() as i64), 43 | 12 44 | ); 45 | } 46 | 47 | #[test] 48 | fn test_interleave3_par() { 49 | assert_eq!( 50 | interleave3_par( 51 | [1, 2].into_par_iter(), 52 | [3, 4].into_par_iter(), 53 | [5, 6].into_par_iter() 54 | ), 55 | vec![1, 3, 5, 2, 4, 6] 56 | ); 57 | 58 | assert_eq!( 59 | interleave3_par( 60 | [1, 2, 3].into_par_iter(), 61 | [4, 5, 6].into_par_iter(), 62 | [7, 8, 9].into_par_iter() 63 | ), 64 | vec![1, 4, 7, 2, 5, 8, 3, 6, 9] 65 | ); 66 | 67 | assert_eq!( 68 | interleave3_par( 69 | ["a", "b", "c"].into_par_iter(), 70 | ["d", "e", "f"].into_par_iter(), 71 | ["g", "h", "i"].into_par_iter() 72 | ) 73 | .into_iter() 74 | .collect::(), 75 | "adgbehcfi" 76 | ); 77 | } 78 | 79 | #[test] 80 | fn vec_add_test() { 81 | let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 82 | let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 83 | let res = vec_add(&vec1, &vec2); 84 | assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]); 85 | 86 | for _ in 0..5 { 87 | let vec1 = hint::black_box(Array::random(5_000_000, Uniform::new(0., 10.))); 88 | let vec2 = hint::black_box(Array::random(5_000_000, Uniform::new(0., 10.))); 89 | 90 | let now_seq = Instant::now(); 91 | let res_seq = hint::black_box(vec_add( 92 | hint::black_box(vec1.as_slice().unwrap()), 93 | hint::black_box(vec2.as_slice().unwrap()), 94 | )); 95 | let elapsed_seq = now_seq.elapsed(); 96 | 97 | let now_par = Instant::now(); 98 | let res_par = hint::black_box(vec_add_par( 99 | hint::black_box(vec1.as_slice().unwrap()), 100 | hint::black_box(vec2.as_slice().unwrap()), 101 | )); 102 | let elapsed_par = now_par.elapsed(); 103 | 104 | let ans = vec1 + vec2; 105 | assert_eq!(Array::from_vec(res_seq), ans); 106 | assert_eq!(Array::from_vec(res_par), ans); 107 | assert!(elapsed_par < elapsed_seq); 108 | } 109 | } 110 | 111 | #[test] 112 | fn dot_product_test() { 113 | let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 114 | let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0]; 115 | let res_seq = dot_product(&vec1, &vec2); 116 | let res_par = dot_product_par(&vec1, &vec2); 117 | assert_eq!(res_seq, 55.0); 118 | assert_eq!(res_par, 55.0); 119 | 120 | for _ in 0..5 { 121 | let vec1 = Array::random(10_000_000, Uniform::new(0., 10.)); 122 | let vec2 = Array::random(10_000_000, Uniform::new(0., 10.)); 123 | 124 | let now_seq = Instant::now(); 125 | let res_seq = hint::black_box(dot_product( 126 | hint::black_box(vec1.as_slice().unwrap()), 127 | hint::black_box(vec2.as_slice().unwrap()), 128 | )); 129 | let elapsed_seq = now_seq.elapsed(); 130 | 131 | let now_par = Instant::now(); 132 | let res_par = hint::black_box(dot_product_par( 133 | hint::black_box(vec1.as_slice().unwrap()), 134 | hint::black_box(vec2.as_slice().unwrap()), 135 | )); 136 | let elapsed_par = now_par.elapsed(); 137 | 138 | let correct = vec1.dot(&vec2); 139 | assert_about_eq!(res_seq, correct, 1.0e-4); 140 | assert_about_eq!(res_par, correct, 1.0e-4); 141 | 142 | assert!( 143 | elapsed_par < elapsed_seq, 144 | "Sequential: {elapsed_seq:?}, Parallel: {elapsed_par:?}" 145 | ); 146 | } 147 | } 148 | 149 | /// Reference: 150 | /// Converts nested `Vec`s to a 2-D array by cloning the elements. 151 | /// 152 | /// **Panics** if the length of any axis overflows `isize`, if the 153 | /// size in bytes of all the data overflows `isize`, or if not all the 154 | /// rows have the same length. 155 | fn vec_to_array(v: Vec>) -> Array2 { 156 | if v.is_empty() { 157 | return Array2::from_shape_vec((0, 0), Vec::new()).unwrap(); 158 | } 159 | let nrows = v.len(); 160 | let ncols = v[0].len(); 161 | let mut data = Vec::with_capacity(nrows * ncols); 162 | for row in &v { 163 | assert_eq!(row.len(), ncols); 164 | data.extend_from_slice(row); 165 | } 166 | Array2::from_shape_vec((nrows, ncols), data).unwrap() 167 | } 168 | 169 | #[test] 170 | fn matmul_test() { 171 | let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]; 172 | let mat2 = vec![ 173 | vec![7.0, 8.0, 9.0], 174 | vec![10.0, 11.0, 12.0], 175 | vec![13.0, 14.0, 15.0], 176 | vec![16.0, 17.0, 18.0], 177 | ]; 178 | let ans = vec![ 179 | vec![50.0, 68.0, 86.0, 104.0], 180 | vec![122.0, 167.0, 212.0, 257.0], 181 | ]; 182 | let res_seq = matmul(&mat1, &mat2); 183 | let res_par = matmul_par(&mat1, &mat2); 184 | assert_eq!(ans, res_seq); 185 | assert_eq!(ans, res_par); 186 | 187 | for _ in 0..5 { 188 | let mat1 = Array::random((500, 500), Uniform::new(0., 10.)); 189 | let mat2 = Array::random((500, 500), Uniform::new(0., 10.)); 190 | let ans = mat1.dot(&mat2); 191 | let mat2_transposed = mat2.t(); 192 | 193 | // Run sequential matrix multiplication 194 | let now_seq = Instant::now(); 195 | let res_seq = hint::black_box(matmul( 196 | hint::black_box( 197 | mat1.axis_iter(Axis(0)) 198 | .map(|row| row.to_vec()) 199 | .collect::>() 200 | .as_slice(), 201 | ), 202 | hint::black_box( 203 | mat2_transposed 204 | .axis_iter(Axis(0)) 205 | .map(|row| row.to_vec()) 206 | .collect::>() 207 | .as_slice(), 208 | ), 209 | )); 210 | let elapsed_seq = now_seq.elapsed(); 211 | 212 | // Run parallel matrix multiplication 213 | let now_par = Instant::now(); 214 | let res_par = hint::black_box(matmul_par( 215 | hint::black_box( 216 | mat1.axis_iter(Axis(0)) 217 | .map(|row| row.to_vec()) 218 | .collect::>() 219 | .as_slice(), 220 | ), 221 | hint::black_box( 222 | mat2_transposed 223 | .axis_iter(Axis(0)) 224 | .map(|row| row.to_vec()) 225 | .collect::>() 226 | .as_slice(), 227 | ), 228 | )); 229 | let elapsed_par = now_par.elapsed(); 230 | 231 | // Check answer 232 | for it in ans.iter().zip(vec_to_array(res_seq).iter()) { 233 | let (ans, seq) = it; 234 | let _res = relative_eq!(ans, seq); 235 | } 236 | for it in ans.iter().zip(vec_to_array(res_par).iter()) { 237 | let (ans, par) = it; 238 | let _res = relative_eq!(ans, par); 239 | } 240 | 241 | // Check time 242 | // println!("Sequential: {:?}", elapsed_seq); 243 | // println!("Parallel: {:?}", elapsed_par); 244 | assert!(elapsed_par < elapsed_seq); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/assignments/assignment09/small_exercises_grade.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod test { 3 | 4 | use ntest::{assert_false, assert_true}; 5 | 6 | use crate::assignments::assignment09::small_exercises::*; 7 | 8 | #[test] 9 | fn test_is_fibonacci() { 10 | assert!(is_fibonacci([1, 1, 2, 3, 5, 8, 13].into_iter())); 11 | assert!(!is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter())); 12 | assert!(is_fibonacci([2, 4, 6, 10, 16, 26].into_iter())); 13 | assert!(is_fibonacci([4, 9, 13, 22, 35].into_iter())); 14 | assert!(is_fibonacci([0, 0, 0, 0, 0].into_iter())); 15 | assert!(is_fibonacci([1, 1].into_iter())); 16 | assert!(is_fibonacci([1].into_iter())); 17 | assert!(is_fibonacci([].into_iter())); 18 | 19 | assert!(!is_fibonacci([1, 1, 2, 2, 3, 3].into_iter())); 20 | assert!(!is_fibonacci([0, 0, 0, 0, 1].into_iter())); 21 | assert!(!is_fibonacci([1, 1, 1, 1].into_iter())); 22 | assert!(!is_fibonacci([4, 3, 2, 1].into_iter())); 23 | } 24 | 25 | #[test] 26 | fn test_sigma() { 27 | assert_eq!(sigma([].into_iter(), |x: i64| x * 2), 0); 28 | assert_eq!(sigma([1].into_iter(), |x| x * 3), 3); 29 | assert_eq!(sigma([1, 2].into_iter(), |x| x + 2), 7); 30 | assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); 31 | assert_eq!(sigma([1, 2, 3].into_iter(), |x| x * 5), 30); 32 | 33 | assert_eq!( 34 | sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.floor() as i64), 35 | 10 36 | ); 37 | assert_eq!( 38 | sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.ceil() as i64), 39 | 13 40 | ); 41 | assert_eq!( 42 | sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.round() as i64), 43 | 12 44 | ); 45 | 46 | assert_eq!( 47 | sigma(["Hello,", "World!"].into_iter(), |x| x.len() as i64), 48 | 12 49 | ); 50 | } 51 | 52 | #[test] 53 | fn test_interleave3() { 54 | assert_eq!( 55 | interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), 56 | vec![1, 3, 5, 2, 4, 6] 57 | ); 58 | 59 | assert_eq!( 60 | interleave3( 61 | [1, 2, 3].into_iter(), 62 | [4, 5, 6].into_iter(), 63 | [7, 8, 9].into_iter() 64 | ), 65 | vec![1, 4, 7, 2, 5, 8, 3, 6, 9] 66 | ); 67 | 68 | assert_eq!( 69 | interleave3( 70 | ["a", "b", "c"].into_iter(), 71 | ["d", "e", "f"].into_iter(), 72 | ["g", "h", "i"].into_iter() 73 | ) 74 | .into_iter() 75 | .collect::(), 76 | "adgbehcfi" 77 | ); 78 | } 79 | 80 | #[test] 81 | fn test_interleave_n() { 82 | assert_eq!( 83 | interleave_n([[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]) 84 | .collect::>(), 85 | vec![1, 3, 5, 2, 4, 6] 86 | ); 87 | 88 | assert_eq!( 89 | interleave_n([ 90 | [1, 2, 3].into_iter(), 91 | [4, 5, 6].into_iter(), 92 | [7, 8, 9].into_iter() 93 | ]) 94 | .collect::>(), 95 | vec![1, 4, 7, 2, 5, 8, 3, 6, 9] 96 | ); 97 | 98 | assert_eq!( 99 | interleave_n([ 100 | ["a", "b", "c"].into_iter(), 101 | ["d", "e", "f"].into_iter(), 102 | ["g", "h", "i"].into_iter() 103 | ]) 104 | .collect::(), 105 | "adgbehcfi" 106 | ); 107 | } 108 | 109 | #[test] 110 | fn test_k_smallest_man() { 111 | assert_eq!( 112 | k_smallest_mean(vec![1, 3, 2].into_iter(), 2), 113 | ((1 + 2) as f64 / 2.0) 114 | ); 115 | assert_eq!( 116 | k_smallest_mean(vec![5, 3, 7, 7].into_iter(), 2), 117 | ((3 + 5) as f64 / 2.0) 118 | ); 119 | assert_eq!( 120 | k_smallest_mean(vec![7, 5, 3, 6].into_iter(), 3), 121 | ((3 + 5 + 6) as f64 / 3.0) 122 | ); 123 | assert_eq!( 124 | k_smallest_mean(vec![1, 3, 2, 4, 4, 5, 6].into_iter(), 3), 125 | ((1 + 2 + 3) as f64 / 3.0) 126 | ); 127 | assert_eq!(k_smallest_mean(vec![].into_iter(), 3), (0 as f64 / 3.0)); 128 | assert_eq!( 129 | k_smallest_mean( 130 | vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5].into_iter(), 131 | 5 132 | ), 133 | ((1 + 2 + 3 + 4) as f64 / 5.0) 134 | ); 135 | } 136 | 137 | #[test] 138 | fn test_calculate_mean() { 139 | assert_eq!( 140 | calculate_mean( 141 | [ 142 | ("CS100".to_string(), 60), 143 | ("CS200".to_string(), 60), 144 | ("CS200".to_string(), 80), 145 | ("CS300".to_string(), 100), 146 | ] 147 | .into_iter() 148 | ), 149 | [ 150 | ("CS100".to_string(), 60.0), 151 | ("CS200".to_string(), 70.0), 152 | ("CS300".to_string(), 100.0) 153 | ] 154 | .into_iter() 155 | .collect() 156 | ); 157 | 158 | assert_eq!( 159 | calculate_mean( 160 | [ 161 | ("CS220".to_string(), 60), 162 | ("CS420".to_string(), 60), 163 | ("CS220".to_string(), 80), 164 | ("CS431".to_string(), 60), 165 | ("CS420".to_string(), 80), 166 | ("CS220".to_string(), 100) 167 | ] 168 | .into_iter() 169 | ), 170 | [ 171 | ("CS220".to_string(), 80.0), 172 | ("CS420".to_string(), 70.0), 173 | ("CS431".to_string(), 60.0) 174 | ] 175 | .into_iter() 176 | .collect() 177 | ) 178 | } 179 | 180 | #[test] 181 | fn test_sum_is_n() { 182 | assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1); 183 | assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2); 184 | assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 5), 2); 185 | assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 6), 1); 186 | assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 2), 0); 187 | 188 | assert_eq!(sum_is_n(vec![(1..100).collect()], 50), 1); 189 | 190 | assert_eq!( 191 | sum_is_n(vec![(1..10).collect(), (1..10).rev().collect()], 10), 192 | 9 193 | ); 194 | 195 | assert_eq!( 196 | sum_is_n( 197 | vec![ 198 | (0..10).map(|x| x * 2 + 1).collect(), 199 | (0..20).map(|x| x * 3).collect(), 200 | (0..30).map(|x| x * 5 + 2).collect() 201 | ], 202 | 53 203 | ), 204 | 30 205 | ); 206 | } 207 | 208 | // find_count_n 209 | #[test] 210 | fn test_find_count_n() { 211 | assert_eq!(find_count_n(vec![], 1), vec![]); 212 | assert_eq!(find_count_n(vec![1, 2], 1), vec![1, 2]); 213 | assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); 214 | assert_eq!(find_count_n(vec![1, 3, 3], 2), vec![3]); 215 | assert_eq!(find_count_n(vec![1, 2, 3, 4, 4], 1), vec![1, 2, 3]); 216 | assert_eq!(find_count_n(vec![1, 3, 2, 3, 2, 3], 3), vec![3]); 217 | assert_eq!(find_count_n(vec![1, 2, 2, 3, 3, 4], 2), vec![2, 3]); 218 | assert_eq!(find_count_n(vec![1, 3, 2, 2, 3], 2), vec![2, 3]); 219 | assert_eq!(find_count_n(vec![0, 2, 2, 4, 3], 0), vec![]); 220 | assert_eq!(find_count_n(vec![1, 1, 1, 2, 2], 1), vec![]); 221 | } 222 | 223 | #[test] 224 | fn test_position_median() { 225 | assert_eq!(position_median(Vec::::new()), None); 226 | assert_eq!(position_median(vec![3]), Some(0)); 227 | assert_eq!(position_median(vec![3, 3]), Some(0)); 228 | assert_eq!(position_median(vec![3, 3, 3]), Some(0)); 229 | assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); 230 | assert_eq!(position_median(vec![3, 1, 3, 3]), Some(0)); 231 | assert_eq!(position_median(vec![3, 1, 5, 3]), Some(0)); 232 | assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); 233 | assert_eq!(position_median(vec![1, 2, 3, 4, 5, 6, 8, 9]), Some(4)); 234 | } 235 | 236 | #[test] 237 | fn test_two_dimensional_sum() { 238 | assert_eq!( 239 | two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()), 240 | 21 241 | ); 242 | assert_eq!( 243 | two_dimensional_sum( 244 | [ 245 | [1, 2, 3, 4, 5].into_iter(), 246 | [10, 20, 30, 40, 50].into_iter() 247 | ] 248 | .into_iter() 249 | ), 250 | 165 251 | ); 252 | } 253 | 254 | #[test] 255 | fn test_is_palindrome() { 256 | assert_true!(is_palindrome("kayak".to_string())); 257 | assert_true!(is_palindrome("dammitimmad".to_string())); 258 | assert_true!(is_palindrome("deified".to_string())); 259 | assert_true!(is_palindrome("rotator".to_string())); 260 | assert_true!(is_palindrome("noon".to_string())); 261 | assert_true!(is_palindrome("".to_string())); 262 | assert_true!(is_palindrome("a".to_string())); 263 | 264 | assert_false!(is_palindrome("moon".to_string())); 265 | assert_false!(is_palindrome("hello".to_string())); 266 | assert_false!(is_palindrome("apple".to_string())); 267 | } 268 | } 269 | --------------------------------------------------------------------------------