From b0ee36a9ff9fd3a77492934ee1f59ec41bc57074 Mon Sep 17 00:00:00 2001 From: woojin Date: Fri, 18 Aug 2023 22:10:35 +0900 Subject: [PATCH 01/17] add 8, 11, 12 --- Cargo.lock | 267 +++++++++++---- Cargo.toml | 5 + scripts/grade-11.sh | 2 +- scripts/grade-12.sh | 2 +- src/assignments/assignment08.rs | 27 +- src/assignments/assignment08_grade.rs | 17 + src/assignments/assignment11/bst.rs | 202 ++++++++++++ src/assignments/assignment11/bst_grade.rs | 53 +++ .../assignment11/doubly_linked_list.rs | 101 ++++++ .../assignment11/doubly_linked_list_grade.rs | 43 +++ src/assignments/assignment11/graph.rs | 93 ++++++ src/assignments/assignment11/graph_grade.rs | 63 ++++ src/assignments/assignment11/linked_list.rs | 4 +- .../assignment11/linked_list_grade.rs | 27 ++ src/assignments/assignment11/mock_storage.rs | 4 +- .../assignment11/mock_storage_grade.rs | 31 ++ src/assignments/assignment11/mod.rs | 10 + .../assignment11/turing_machine.rs | 139 ++++++++ .../assignment11/turing_machine_grade.rs | 309 ++++++++++++++++++ src/assignments/assignment11/tv_room.rs | 2 + src/assignments/assignment11/tv_room_grade.rs | 32 ++ src/assignments/assignment12/card.rs | 52 +++ src/assignments/assignment12/card_grade.rs | 141 ++++++++ src/assignments/assignment12/demux.rs | 37 +++ src/assignments/assignment12/demux_grade.rs | 36 ++ src/assignments/assignment12/funnel.rs | 21 ++ src/assignments/assignment12/funnel_grade.rs | 33 ++ src/assignments/assignment12/mod.rs | 15 + .../small_exercises.rs} | 14 +- .../assignment12/small_exercises_grade.rs | 86 +++++ src/assignments/mod.rs | 2 - 31 files changed, 1797 insertions(+), 73 deletions(-) create mode 100644 src/assignments/assignment11/bst.rs create mode 100644 src/assignments/assignment11/bst_grade.rs create mode 100644 src/assignments/assignment11/doubly_linked_list.rs create mode 100644 src/assignments/assignment11/doubly_linked_list_grade.rs create mode 100644 src/assignments/assignment11/graph.rs create mode 100644 src/assignments/assignment11/graph_grade.rs create mode 100644 src/assignments/assignment11/linked_list_grade.rs create mode 100644 src/assignments/assignment11/mock_storage_grade.rs create mode 100644 src/assignments/assignment11/turing_machine.rs create mode 100644 src/assignments/assignment11/turing_machine_grade.rs create mode 100644 src/assignments/assignment11/tv_room_grade.rs create mode 100644 src/assignments/assignment12/card.rs create mode 100644 src/assignments/assignment12/card_grade.rs create mode 100644 src/assignments/assignment12/demux.rs create mode 100644 src/assignments/assignment12/demux_grade.rs create mode 100644 src/assignments/assignment12/funnel.rs create mode 100644 src/assignments/assignment12/funnel_grade.rs create mode 100644 src/assignments/assignment12/mod.rs rename src/assignments/{assignment12.rs => assignment12/small_exercises.rs} (60%) create mode 100644 src/assignments/assignment12/small_exercises_grade.rs diff --git a/Cargo.lock b/Cargo.lock index 7132052..e95c3d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,7 +6,16 @@ version = 3 name = "anyhow" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] [[package]] name = "autocfg" @@ -47,11 +56,21 @@ version = "4.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", "termcolor", ] @@ -145,14 +164,19 @@ name = "cs220" version = "0.1.0" dependencies = [ "anyhow", + "approx", "clap", "etrace", "itertools", "lazy_static", + "ndarray", + "ndarray-rand", "ntest", + "num-traits", "pest", "pest_derive", "rayon", + "thiserror", ] [[package]] @@ -209,10 +233,27 @@ dependencies = [ ] [[package]] -name = "heck" -version = "0.4.0" +name = "getrandom" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -225,11 +266,18 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "libc", + "autocfg", + "hashbrown", ] [[package]] @@ -273,13 +321,35 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" name = "libc" version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linux-raw-sys" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "matrixmultiply" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -290,6 +360,30 @@ dependencies = [ "autocfg", ] +[[package]] +name = "ndarray" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "rawpointer", +] + +[[package]] +name = "ndarray-rand" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65608f937acc725f5b164dcf40f4f0bc5d67dc268ab8a649d3002606718c4588" +dependencies = [ + "ndarray", + "rand", + "rand_distr", +] + [[package]] name = "ntest" version = "0.9.0" @@ -320,7 +414,36 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.109", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", + "libm", ] [[package]] @@ -335,15 +458,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "pest" @@ -389,6 +506,12 @@ dependencies = [ "sha1", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro-crate" version = "1.2.1" @@ -442,6 +565,52 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.6.0" @@ -486,16 +655,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "serde" -version = "1.0.149" +name = "sha2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" - -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", @@ -582,41 +745,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "winapi" -version = "0.3.9" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", diff --git a/Cargo.toml b/Cargo.toml index 280b42e..543cac1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,9 @@ lazy_static = "1.4.0" pest = "2.5.1" pest_derive = "2.5.1" rayon = "1.6.0" +thiserror = "1.0" ntest = "0.9.0" +approx = "0.5.1" +num-traits = "0.2" +ndarray = "0.15.0" +ndarray-rand = "0.14.0" diff --git a/scripts/grade-11.sh b/scripts/grade-11.sh index 8666182..34fb51a 100755 --- a/scripts/grade-11.sh +++ b/scripts/grade-11.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment11_grade") + TESTS=("--lib assignment11") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/scripts/grade-12.sh b/scripts/grade-12.sh index 6a87f98..34fb51a 100755 --- a/scripts/grade-12.sh +++ b/scripts/grade-12.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment12_grade") + TESTS=("--lib assignment11") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/src/assignments/assignment08.rs b/src/assignments/assignment08.rs index 972b1d3..d6ce58d 100644 --- a/src/assignments/assignment08.rs +++ b/src/assignments/assignment08.rs @@ -5,22 +5,45 @@ //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine. //! See `assignment08_grade.rs` and `/scripts/grade-08.sh` for the test script. -/// Returns an anonymous function that applies the given function `f` for `n` times. +/// Repeat /// +/// Returns an anonymous function that applies the given function `f` for `n` times. /// For instance, `repeat(3, f)(x)` roughly translates to `f(f(f(x)))`. +/// +/// Refer `test_repeat` in `assignment08_grade.rs` for detailed examples. pub fn repeat T>(n: usize, mut f: F) -> impl FnMut(T) -> T { todo!(); f // This line has been added to prevent compile error. You can erase this line. } +/// Funny Map +/// /// Applies the given function `f` for `i` times for the `i`-th element of the given vector. /// /// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), f(f(f(v3)))]`. +/// +/// Refer `test_funny_map` in `assignment08_grade.rs` for detailed examples. pub fn funny_map T>(f: F, vs: Vec) -> Vec { todo!() } +/// Count Repeat +/// +/// Returns the number of the elements of the set +/// {x, f(x), f(f(x)), f(f(f(x))), ...}. +/// You may assume that the answer is finite and small enough. +/// +/// Refer `test_count_repeat` in `assignment08_grade.rs` for detailed examples. +pub fn count_repeat T>(f: F, x: T) -> usize +where + T: PartialEq + Copy, +{ + todo!() +} + /// Either `T1`, or `T2`. +/// +/// Fill out `map` method for this type. #[derive(Debug, PartialEq, Eq)] pub enum Either2 { /// Case 1. @@ -39,6 +62,8 @@ impl Either2 { /// Maps the inner value. /// /// If the inner value is case 1, apply `f1`, and if it is case 2, apply `f2`. + /// + /// Refer `test_either2_map` in `assignment08_grade.rs` for detailed examples. pub fn map(self, f1: F1, f2: F2) -> Either2 where F1: FnOnce(T1) -> U1, diff --git a/src/assignments/assignment08_grade.rs b/src/assignments/assignment08_grade.rs index e6299ed..bce3398 100644 --- a/src/assignments/assignment08_grade.rs +++ b/src/assignments/assignment08_grade.rs @@ -27,4 +27,21 @@ mod test { let u2 = Either2::::Case2 { inner: 43.0 }; assert_eq!(u2, v2.map(|i| i + 1, |f| f + 1.0)); } + + #[test] + fn test_count_repeat() { + let inc_mod_100 = |x| (x + 1) % 100; + assert_eq!(count_repeat(inc_mod_100, 10), 100); + assert_eq!(count_repeat(inc_mod_100, 12345), 101); + + let p_lookup = |n| vec![1, 0, 2, 4, 5, 6, 7, 3][n]; + assert_eq!(count_repeat(p_lookup, 0), 2); + assert_eq!(count_repeat(p_lookup, 1), 2); + assert_eq!(count_repeat(p_lookup, 2), 1); + assert_eq!(count_repeat(p_lookup, 3), 5); + assert_eq!(count_repeat(p_lookup, 4), 5); + assert_eq!(count_repeat(p_lookup, 5), 5); + assert_eq!(count_repeat(p_lookup, 6), 5); + assert_eq!(count_repeat(p_lookup, 7), 5); + } } diff --git a/src/assignments/assignment11/bst.rs b/src/assignments/assignment11/bst.rs new file mode 100644 index 0000000..8d78a57 --- /dev/null +++ b/src/assignments/assignment11/bst.rs @@ -0,0 +1,202 @@ +//! Binary Search Tree +//! +//! Refer `bst_grade.rs` for test cases. + +use std::cell::RefCell; +use std::cmp::Ordering; +use std::fmt::Debug; +use std::ops::Deref; +use std::rc::{Rc, Weak}; + +/// Node struct of tree +#[derive(Debug, Clone)] +struct Node +where + T: Ord, +{ + value: T, + parent: Option>>>, + left: Option>>>, + right: Option>>>, +} + +impl Node +where + T: Ord, +{ + fn new(value: T) -> Rc>> { + Rc::new(RefCell::new(Node { + value, + parent: None, + left: None, + right: None, + })) + } + + fn with_parent(value: T, parent: Weak>>) -> Rc>> { + Rc::new(RefCell::new(Node { + value, + parent: Some(parent), + left: None, + right: None, + })) + } + + /// Minimum node starting from cursor + fn min_node(mut cursor: Rc>>) -> Rc>> { + todo!(); + } + + /// Upgraded parent node. + /// `None` if the node has no parent. + fn parent(&self) -> Option>>> { + self.parent.as_ref().and_then(|p| p.upgrade()) + } +} + +/// Binary Search Tree +#[derive(Debug)] +pub struct Tree +where + T: Ord, +{ + root: Option>>>, + len: usize, +} + +impl Default for Tree { + fn default() -> Self { + Self::new() + } +} + +impl Tree +where + T: Ord, +{ + /// New tree + pub fn new() -> Tree { + Tree { root: None, len: 0 } + } + + /// Length of the tree + pub fn len(&self) -> usize { + self.len + } + + /// Check if the tree is empty. + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Check if the tree contains the value. + pub fn contains(&self, value: &T) -> bool { + if let Some(mut cursor) = self.root.clone() { + todo!(); + } else { + false + } + } + + /// Insert the value into the tree. + /// If there was no equal value in the tree, it returns `true`. + /// Otherwise, it returns `false`. + pub fn insert(&mut self, value: T) -> bool { + self.len += 1; + if let Some(mut cursor) = self.root.clone() { + todo!(); + } else { + self.root = Some(Node::new(value)); + true + } + } + + /// Remove the node from the tree. + /// Returns the value of the removed node. + fn remove_node(&mut self, mut node: Rc>>) -> T { + todo!(); + } + + /// Remove the value from the tree. + /// If there is an equal value in the tree, it returns `true`. + /// Otherwise, it returns `false`. + pub fn remove(&mut self, value: &T) -> Option { + let res = if let Some(root) = self.root.clone() { + let mut cursor = root; + + loop { + let mut cursor_ref = cursor.deref().borrow_mut(); + let child = match value.cmp(&cursor_ref.value) { + Ordering::Less => cursor_ref.left.clone(), + Ordering::Greater => cursor_ref.right.clone(), + Ordering::Equal => { + drop(cursor_ref); + break Some(self.remove_node(cursor)); + } + }; + + if let Some(child) = child { + drop(cursor_ref); + cursor = child; + } else { + break None; + } + } + } else { + None + }; + + self.len -= res.is_some() as usize; + res + } +} + +impl Clone for Tree +where + T: Ord + Clone, +{ + fn clone(&self) -> Self { + Tree { + root: self.root.clone(), + len: self.len, + } + } +} + +/// IntoIterator for Tree +#[derive(Debug)] +pub struct IntoIter +where + T: Ord, +{ + tree: Tree, + len: usize, +} + +impl IntoIterator for Tree +where + T: Ord, +{ + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + let len = self.len; + IntoIter { tree: self, len } + } +} + +impl Iterator for IntoIter +where + T: Ord, +{ + type Item = T; + + fn next(&mut self) -> Option { + todo!(); + } + + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} diff --git a/src/assignments/assignment11/bst_grade.rs b/src/assignments/assignment11/bst_grade.rs new file mode 100644 index 0000000..40b82cb --- /dev/null +++ b/src/assignments/assignment11/bst_grade.rs @@ -0,0 +1,53 @@ +//! Test cases for assignment11/bst.rs + +#[cfg(test)] +mod test_bst { + use super::super::bst::*; + + #[test] + fn bst_insert_test() { + let mut tree = Tree::new(); + + let _ = tree.insert(1); + let _ = tree.insert(5); + let _ = tree.insert(3); + let _ = tree.insert(7); + + assert_eq!(tree.into_iter().collect::>(), vec![1, 3, 5, 7]); + } + + #[test] + fn bst_remove_test() { + let mut tree = Tree::new(); + + let _ = tree.insert(1); + let _ = tree.insert(5); + let _ = tree.insert(3); + let _ = tree.insert(7); + let _ = tree.remove(&7); + + assert_eq!(tree.into_iter().collect::>(), vec![1, 3, 5]); + } + + #[test] + fn bst_complex_test() { + let mut tree = Tree::new(); + + let _ = tree.insert(1); + let _ = tree.insert(5); + let _ = tree.insert(3); + let _ = tree.insert(7); + let _ = tree.remove(&7); + let _ = tree.insert(7); + let _ = tree.insert(6); + let _ = tree.insert(8); + let _ = tree.remove(&5); + let _ = tree.remove(&1); + let _ = tree.remove(&3); + let _ = tree.remove(&7); + let _ = tree.remove(&6); + let _ = tree.remove(&8); + + assert_eq!(tree.into_iter().collect::>(), vec![]); + } +} diff --git a/src/assignments/assignment11/doubly_linked_list.rs b/src/assignments/assignment11/doubly_linked_list.rs new file mode 100644 index 0000000..d3cc7bf --- /dev/null +++ b/src/assignments/assignment11/doubly_linked_list.rs @@ -0,0 +1,101 @@ +//! Doubly Linked List. +//! +//! Refer `doubly_linked_list_grade.rs` for test cases. + +use std::{cell::RefCell, fmt::Debug, rc::Rc}; + +type Link = Option>>>; + +/// Node of a doubly-linked list. +#[derive(Debug)] +pub struct Node { + /// Value of current node. + value: RefCell, + + /// Pointer to the next node. If it is `None`, there is no next node. + next: Link, + + /// Pointer to the previous node. If it is `None`, there is no previous node. + prev: Link, +} + +impl Node { + /// Creates a new node. + fn new(value: T) -> Self { + Self { + value: RefCell::new(value), + next: None, + prev: None, + } + } + + /// Fetch the value contained in node + pub fn get(&self) -> T { + self.value.borrow().clone() + } + + /// Replace the data contained in the node + pub fn replace(&self, new_value: T) -> T { + self.value.replace(new_value) + } + + /// Fetch previous node + pub fn prev(&self) -> Link { + self.prev.clone() + } + + /// Fetch next node + pub fn next(&self) -> Link { + self.next.clone() + } +} + +/// A doubly-linked list. +#[derive(Default, Debug)] +pub struct DoublyLinkedList { + /// Head node of the list. If it is `None`, the list is empty. + head: Link, + + /// Tail node of the list. If it is `None`, the list is empty. + tail: Link, +} + +impl DoublyLinkedList { + /// Creates a new list. + pub fn new() -> Self { + Self { + head: None, + tail: None, + } + } + + /// Adds the given node to the front of the list. + pub fn push_front(&mut self, value: T) { + todo!() + } + + /// Adds the given node to the back of the list. + pub fn push_back(&mut self, value: T) { + todo!() + } + + /// Removes and returns the node at the front of the list. + pub fn pop_front(&mut self) -> Option { + todo!() + } + + /// Removes and returns the node at the back of the list. + pub fn pop_back(&mut self) -> Option { + todo!() + } +} + +impl Drop for DoublyLinkedList { + fn drop(&mut self) { + while let Some(node) = self.head.take() { + let _ = node.borrow_mut().prev.take(); + self.head = node.borrow_mut().next.take(); + } + let _unused = self.tail.take(); + } +} diff --git a/src/assignments/assignment11/doubly_linked_list_grade.rs b/src/assignments/assignment11/doubly_linked_list_grade.rs new file mode 100644 index 0000000..0827f11 --- /dev/null +++ b/src/assignments/assignment11/doubly_linked_list_grade.rs @@ -0,0 +1,43 @@ +//! Test cases for assignment11/doubly_linked_list.rs + +#[cfg(test)] +mod test_doubly_linked_list { + use super::super::doubly_linked_list::*; + + #[test] + fn test_works() { + let mut list = DoublyLinkedList::new(); + + list.push_back(3); + list.push_back(4); + assert_eq!(list.pop_front(), Some(3)); + + list.push_front(5); + assert_eq!(list.pop_back(), Some(4)); + assert_eq!(list.pop_back(), Some(5)); + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_front(), None); + } + + #[test] + fn test_can_push_back() { + let mut list = DoublyLinkedList::new(); + assert_eq!(list.pop_back(), None); + + list.push_back(3); + list.push_back(4); + list.push_back(5); + assert_eq!(list.pop_back(), Some(5)); + + list.push_back(6); + list.push_back(7); + assert_eq!(list.pop_back(), Some(7)); + assert_eq!(list.pop_back(), Some(6)); + assert_eq!(list.pop_back(), Some(4)); + assert_eq!(list.pop_back(), Some(3)); + + list.push_back(2); + assert_eq!(list.pop_back(), Some(2)); + assert_eq!(list.pop_back(), None); + } +} diff --git a/src/assignments/assignment11/graph.rs b/src/assignments/assignment11/graph.rs new file mode 100644 index 0000000..65a92f3 --- /dev/null +++ b/src/assignments/assignment11/graph.rs @@ -0,0 +1,93 @@ +//! A small graph library. +//! +//! A node has a i32 value and (directed) edges to other nodes. A node does not have multiple edges +//! to the same node. Nodes are not associated with a particular domain, and users can freely +//! create nodes however they like. However, after a node is created, it can be added to a +//! `SubGraph`, which form a subgraph of the graph of all nodes. A node can be added to multiple +//! subgraphs. `SubGraph` has a method to check if the it has a cycle. +//! +//! The goal of this assignment is to learn how to deal with inherently shared mutable data in +//! Rust. Design the types and fill in the `todo!()`s in methods. There are several possible +//! approaches to this problem and you may import anything from the std library accordingly. +//! +//! Refer `graph_grade.rs` for test cases. + +#[derive(PartialEq, Eq, Debug)] +enum VisitStatus { + Unvisited, + Visiting, + Visited, +} + +/// Handle to a graph node. +/// `NodeHandle` should implement `Clone`, which clones the handle without cloning the underlying +/// node. That is, there can be multiple handles to the same node. +/// The user can access the node through a handle if it does not violate Rust's aliasing rules. +#[derive(Debug, Clone)] +pub struct NodeHandle; + +/// Error type for graph operations. +#[derive(Debug)] +pub struct GraphError; + +/// Subgraph +#[derive(Debug)] +pub struct SubGraph; + +impl NodeHandle { + /// Creates a node and returns the handle to it. + pub fn new(value: i32) -> Self { + todo!() + } + + /// Adds an edge to `to`. + /// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`. + /// Returns `Ok(true)` if the edge is successfully added. + /// Returns `Ok(false)` if an edge to `to` already exits. + pub fn add_edge(&self, to: NodeHandle) -> Result { + todo!() + } + + /// Removes the edge to `to`. + /// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`. + /// Returns `Ok(true)` if the edge is successfully removed. + /// Returns `Ok(false)` if an edge to `to` does not exist. + pub fn remove_edge(&self, to: &NodeHandle) -> Result { + todo!() + } + + /// Removes all edges. + /// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`. + pub fn clear_edges(&self) -> Result<(), GraphError> { + todo!() + } +} + +impl Default for SubGraph { + fn default() -> Self { + Self::new() + } +} + +impl SubGraph { + /// Creates a new subgraph. + pub fn new() -> Self { + todo!() + } + + /// Adds a node to the subgraph. Returns true iff the node is newly added. + pub fn add_node(&mut self, node: NodeHandle) -> bool { + todo!() + } + + /// Adds a node to the subgraph. Returns true iff the node is successfully removed. + pub fn remove_node(&mut self, node: &NodeHandle) -> bool { + todo!() + } + + /// Returns true iff the subgraph contains a cycle. Nodes that do not belong to this subgraph + /// are ignored. See https://en.wikipedia.org/wiki/Cycle_(graph_theory) for an algorithm. + pub fn detect_cycle(&self) -> bool { + todo!() + } +} diff --git a/src/assignments/assignment11/graph_grade.rs b/src/assignments/assignment11/graph_grade.rs new file mode 100644 index 0000000..fcdac3b --- /dev/null +++ b/src/assignments/assignment11/graph_grade.rs @@ -0,0 +1,63 @@ +//! Test cases for assignment11/graph.rs + +#[cfg(test)] +mod test_graph { + use super::super::graph::*; + + #[test] + fn test_graph() { + let mut nodes = (0..6).map(NodeHandle::new).collect::>(); + let edges = [ + (0, 1), + (0, 3), + (1, 4), + (2, 4), + (2, 5), + (3, 1), + (4, 3), + (5, 5), + ]; + + for (from, to) in edges { + assert!(nodes[from].add_edge(nodes[to].clone()).unwrap()); + } + + let mut graph1 = SubGraph::new(); + for n in 0..6 { + assert!(graph1.add_node(nodes[n].clone())); + } + assert!(graph1.detect_cycle()); + assert!(!graph1.add_node(nodes[0].clone())); + + let mut graph2 = SubGraph::new(); + for n in [0, 1, 3] { + assert!(graph2.add_node(nodes[n].clone())); + } + assert!(!graph2.detect_cycle()); + + assert!(graph2.add_node(nodes[4].clone())); + assert!(graph2.detect_cycle()); + + assert!(nodes[4].remove_edge(&nodes[3]).unwrap()); + assert!(!graph2.detect_cycle()); + + let mut graph3 = SubGraph::new(); + for n in [0, 1, 2, 3] { + assert!(graph3.add_node(nodes[n].clone())); + } + assert!(!graph3.detect_cycle()); + + let more_edges = [(1, 2), (2, 3)]; + for (from, to) in more_edges { + assert!(nodes[from].add_edge(nodes[to].clone()).unwrap()); + } + assert!(graph3.detect_cycle()); + + assert!(graph3.remove_node(&nodes[2])); + assert!(!graph3.detect_cycle()); + + for n in nodes { + n.clear_edges().unwrap(); + } + } +} diff --git a/src/assignments/assignment11/linked_list.rs b/src/assignments/assignment11/linked_list.rs index 5d772e3..704b6e9 100644 --- a/src/assignments/assignment11/linked_list.rs +++ b/src/assignments/assignment11/linked_list.rs @@ -1,6 +1,8 @@ //! Singly linked list. //! -//! Consult . +//! Hint: Consult . +//! +//! Refer `linked_list_grade.rs` for test cases. use std::fmt::Debug; diff --git a/src/assignments/assignment11/linked_list_grade.rs b/src/assignments/assignment11/linked_list_grade.rs new file mode 100644 index 0000000..2db6fe0 --- /dev/null +++ b/src/assignments/assignment11/linked_list_grade.rs @@ -0,0 +1,27 @@ +//! Test cases for assignment11/linked_list.rs + +#[cfg(test)] +mod test_linked_list { + use super::super::linked_list::*; + + #[derive(Debug, PartialEq, Eq)] + struct V(usize); + + #[test] + fn test_linked_list() { + let mut list = SinglyLinkedList::new(); + list.push_back(V(3)); + list.push_front(V(2)); + list.push_back(V(4)); + list.push_front(V(1)); + list.push_back(V(5)); + + assert_eq!(list.pop_front(), Some(V(1))); + assert_eq!(list.pop_back(), Some(V(5))); + assert_eq!(list.pop_front(), Some(V(2))); + assert_eq!(list.pop_back(), Some(V(4))); + assert_eq!(list.pop_front(), Some(V(3))); + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_front(), None); + } +} diff --git a/src/assignments/assignment11/mock_storage.rs b/src/assignments/assignment11/mock_storage.rs index a5d9604..4e0edc2 100644 --- a/src/assignments/assignment11/mock_storage.rs +++ b/src/assignments/assignment11/mock_storage.rs @@ -1,6 +1,8 @@ //! Mock storage. //! -//! Consult . +//! Hint: Consult . +//! +//! Refer `mock_storage_grade.rs` for test cases. use std::cell::RefCell; use std::collections::HashMap; diff --git a/src/assignments/assignment11/mock_storage_grade.rs b/src/assignments/assignment11/mock_storage_grade.rs new file mode 100644 index 0000000..b8e62d3 --- /dev/null +++ b/src/assignments/assignment11/mock_storage_grade.rs @@ -0,0 +1,31 @@ +//! Test cases for assignment11/mock_storage.rs + +#[cfg(test)] +mod test_mock_storage { + use super::super::mock_storage::*; + + #[test] + fn test_mock_storage() { + let mock_storage = MockStorage::new(100); + + let uploader1 = FileUploader::new(&mock_storage); + let uploader2 = FileUploader::new(&mock_storage); + + let usage_analyzer = UsageAnalyzer::new(&mock_storage, 0.75); + + assert!(uploader1.upload("file1.txt", 20).is_ok()); + assert!(usage_analyzer.is_usage_under_bound()); + + assert!(uploader2.upload("file2.txt", 30).is_ok()); + assert!(usage_analyzer.is_usage_under_bound()); + + assert!(uploader1.upload("file3.txt", 40).is_ok()); + assert!(!usage_analyzer.is_usage_under_bound()); + + assert_eq!(uploader2.upload("file4.txt", 50), Err(40)); + assert!(!usage_analyzer.is_usage_under_bound()); + + assert!(uploader1.upload("file3.txt", 10).is_ok()); + assert!(usage_analyzer.is_usage_under_bound()); + } +} diff --git a/src/assignments/assignment11/mod.rs b/src/assignments/assignment11/mod.rs index 64b4553..266f7d7 100644 --- a/src/assignments/assignment11/mod.rs +++ b/src/assignments/assignment11/mod.rs @@ -4,6 +4,16 @@ //! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to . +pub mod bst; +pub mod bst_grade; +pub mod doubly_linked_list; +pub mod doubly_linked_list_grade; +pub mod graph; +pub mod graph_grade; pub mod linked_list; pub mod mock_storage; +pub mod mock_storage_grade; +pub mod turing_machine; +pub mod turing_machine_grade; pub mod tv_room; +pub mod tv_room_grade; diff --git a/src/assignments/assignment11/turing_machine.rs b/src/assignments/assignment11/turing_machine.rs new file mode 100644 index 0000000..438f30a --- /dev/null +++ b/src/assignments/assignment11/turing_machine.rs @@ -0,0 +1,139 @@ +//! Simple Turing machien emulator +//! +//! Simple One-head, One-tape turing machine +//! See that describes what turing machine is. +//! See `test_turing_machine` module in `assignment11_grade.rs` for examples. +//! +//! Goal: To be accustomed with `RefCell`, `HashMap` +//! +//! Refer `turing_machine.rs` for test cases. + +use std::cell::RefCell; +use std::collections::HashMap; +use std::fmt::{self, Formatter}; +use thiserror::Error; + +/// Error type for Turing machine +/// +#[derive(Debug, Error, PartialEq, Eq)] +pub enum TuringMachineError { + /// Invalid movement + /// You can't move left from the leftmost location + /// or move right from the rightmost location. + #[error("Invalid movement")] + InvalidMovement, + + /// Exceeded maximum steps + #[error("Exceeded maximum steps")] + ExceedMaxSteps, + + /// Invalid state or value + /// Occurs when you cannot find instruction for the current state and value + #[error("Invalid state or value")] + InvalidStateOrValue, +} + +/// Turing Machine implementation +#[derive(Debug)] +pub struct TuringMachine +where + TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, + TMValue: Eq + PartialEq + std::hash::Hash + Clone, +{ + /// Number of steps taken by the Turing machine + pub steps: RefCell, + + /// Table of instructions for the Turing machine + pub table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>, + + /// Tape of the Turing machine. Finite length + pub tape: Vec>, +} + +/// Implementation of the movement instructions of the head of the tape. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Move { + /// Move Left + L, + /// Move Right + R, + /// Don't move + N, +} + +/// Cursor for Turing machine +#[derive(Debug)] +pub struct Cursor<'a, TMState, TMValue> +where + TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, + TMValue: Eq + PartialEq + std::hash::Hash + Clone, +{ + // Turing mahcine + tm: &'a TuringMachine, + // Index of the tape + index: usize, + // Current state of the Turing machine + state: TMState, +} + +impl<'a, TMState, TMValue> Cursor<'a, TMState, TMValue> +where + TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, + TMValue: Eq + PartialEq + std::hash::Hash + Clone, +{ + /// Generate new cursor + pub fn new(tm: &'a TuringMachine, state: TMState, index: usize) -> Self { + Cursor { tm, index, state } + } + + /// Run the Turing machine until it halts (if it halts). Print every step of that. + pub fn run(&mut self, max_step: usize) -> Result<(TMValue, usize), TuringMachineError> { + let mut steps = self.tm.steps.borrow_mut(); + while self.state != TMState::default() { + *steps += 1; + if *steps > max_step { + return Err(TuringMachineError::ExceedMaxSteps); + } + self.step()?; + // println!("{}", self); + } + Ok((self.get(), *steps)) + } + + /// Set tape value at the current index with `value` + /// You may need this function for `mov` function + fn set(&mut self, value: TMValue) -> TMValue { + todo!(); + } + + /// Step the Turing machine + /// Look at the `run` function to see how this function is used. + fn step(&mut self) -> Result<(), TuringMachineError> { + todo!(); + } + + /// Move the cursor while setting the value of the current index + fn mov(&mut self, new_value: TMValue, movement: &Move) -> Result<(), TuringMachineError> { + todo!(); + } + + /// Get the value of the current index + /// Look at the `run` function to see how this function is used. + fn get(&self) -> TMValue { + todo!(); + } +} + +impl TuringMachine +where + TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, + TMValue: Eq + PartialEq + std::hash::Hash + Clone, +{ + /// Generate new Turing machine + pub fn new( + table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>, + tape: Vec>, + ) -> Self { + todo!() + } +} diff --git a/src/assignments/assignment11/turing_machine_grade.rs b/src/assignments/assignment11/turing_machine_grade.rs new file mode 100644 index 0000000..89b617b --- /dev/null +++ b/src/assignments/assignment11/turing_machine_grade.rs @@ -0,0 +1,309 @@ +//! Test cases for assignment11/turing_machine.rs + +#[cfg(test)] +mod test_turing_machine { + use super::super::turing_machine::*; + use std::cell::RefCell; + use std::collections::HashMap; + + #[test] + fn test_invalid_movement() { + /// Cell value of the tape + #[derive(Debug, Clone, Hash, Eq, PartialEq)] + enum TMValue { + /// Zero + Zero, + + /// One + One, + } + + /// State for Turing machine + /// TODO: Modify this so that users can implement their own state + #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] + enum TMState { + /// Halt + #[default] + Halt, + + /// A + A, + + /// B + B, + } + + let tape: Vec> = vec![ + TMValue::One, + TMValue::Zero, + TMValue::One, + TMValue::One, + TMValue::One, + TMValue::Zero, + TMValue::One, + ] + .into_iter() + .map(|x| RefCell::new(x)) + .collect(); + + let instr = HashMap::from([ + ( + (TMState::A, TMValue::Zero), + (TMState::B, Move::R, TMValue::One), + ), + ( + (TMState::A, TMValue::One), + (TMState::B, Move::L, TMValue::Zero), + ), + ( + (TMState::B, TMValue::Zero), + (TMState::A, Move::L, TMValue::One), + ), + ( + (TMState::B, TMValue::One), + (TMState::A, Move::R, TMValue::Zero), + ), + ]); + + let mut tm = TuringMachine::new(instr, tape); + let mut cursor = Cursor::new(&tm, TMState::A, 0); + + let result = cursor.run(1000); + assert_eq!(result, Err(TuringMachineError::InvalidMovement)); + } + + #[test] + fn test_write_15_fail_move() { + /// Cell value of the tape + #[derive(Debug, Clone, Hash, Eq, PartialEq)] + enum TMValue { + /// Zero + Zero, + + /// One + One, + } + + /// State for Turing machine + /// TODO: Modify this so that users can implement their own state + #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] + enum TMState { + /// Halt + #[default] + Halt, + + /// A + A, + + /// B + B, + } + + let tape: Vec> = vec![TMValue::Zero; 10] + .into_iter() + .map(|x| RefCell::new(x)) + .collect(); + + let instr = HashMap::from([ + ( + (TMState::A, TMValue::Zero), + (TMState::B, Move::R, TMValue::One), + ), + ( + (TMState::A, TMValue::One), + (TMState::B, Move::L, TMValue::One), + ), + ( + (TMState::B, TMValue::Zero), + (TMState::A, Move::L, TMValue::One), + ), + ( + (TMState::B, TMValue::One), + (TMState::Halt, Move::R, TMValue::One), + ), + ]); + + let mut tm = TuringMachine::new(instr, tape); + let mut cursor = Cursor::new(&tm, TMState::A, 0); + + let result = cursor.run(1000); + assert_eq!(result, Err(TuringMachineError::InvalidMovement)); + } + + #[test] + fn test_write_15_pass() { + /// Cell value of the tape + #[derive(Debug, Clone, Hash, Eq, PartialEq)] + enum TMValue { + /// Zero + Zero, + + /// One + One, + } + + /// State for Turing machine + /// TODO: Modify this so that users can implement their own state + #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] + enum TMState { + /// Halt + #[default] + Halt, + + /// A + A, + + /// B + B, + } + + let tape: Vec> = vec![TMValue::Zero; 10] + .into_iter() + .map(|x| RefCell::new(x)) + .collect(); + + let instr = HashMap::from([ + ( + (TMState::A, TMValue::Zero), + (TMState::B, Move::R, TMValue::One), + ), + ( + (TMState::A, TMValue::One), + (TMState::B, Move::L, TMValue::One), + ), + ( + (TMState::B, TMValue::Zero), + (TMState::A, Move::L, TMValue::One), + ), + ( + (TMState::B, TMValue::One), + (TMState::Halt, Move::R, TMValue::One), + ), + ]); + + let mut tm = TuringMachine::new(instr, tape); + let mut cursor = Cursor::new(&tm, TMState::A, 2); + + let result = cursor.run(1000); + for (idx, val) in tm.tape.iter().enumerate() { + if idx < 4 { + assert_eq!(*val.borrow(), TMValue::One); + } else { + assert_eq!(*val.borrow(), TMValue::Zero); + } + } + } + + #[test] + fn test_write_zero_ones_fail_step() { + /// Cell value of the tape + #[derive(Debug, Clone, Hash, Eq, PartialEq)] + enum TMValue { + /// Empty + Empty, + + /// Zero + Zero, + + /// One + One, + } + + /// State for Turing machine + /// TODO: Modify this so that users can implement their own state + #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] + enum TMState { + /// Halt + #[default] + Halt, + + /// A + A, + + /// B + B, + } + + let tape: Vec> = vec![TMValue::Empty; 100] + .into_iter() + .map(|x| RefCell::new(x)) + .collect(); + + let instr = HashMap::from([ + ( + (TMState::A, TMValue::Empty), + (TMState::B, Move::R, TMValue::Zero), + ), + ( + (TMState::B, TMValue::Empty), + (TMState::A, Move::R, TMValue::One), + ), + ]); + + let mut tm = TuringMachine::new(instr, tape); + let mut cursor = Cursor::new(&tm, TMState::A, 0); + + let result = cursor.run(10); + assert_eq!(result, Err(TuringMachineError::ExceedMaxSteps)); + } + + #[test] + fn test_write_zero_ones() { + /// Cell value of the tape + #[derive(Debug, Clone, Hash, Eq, PartialEq)] + enum TMValue { + /// Empty + Empty, + + /// Zero + Zero, + + /// One + One, + } + + /// State for Turing machine + /// TODO: Modify this so that users can implement their own state + #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] + enum TMState { + /// Halt + #[default] + Halt, + + /// A + A, + + /// B + B, + } + + let tape: Vec> = vec![TMValue::Empty; 100] + .into_iter() + .map(|x| RefCell::new(x)) + .collect(); + + let instr = HashMap::from([ + ( + (TMState::A, TMValue::Empty), + (TMState::B, Move::R, TMValue::Zero), + ), + ( + (TMState::B, TMValue::Empty), + (TMState::A, Move::R, TMValue::One), + ), + ]); + + let mut tm = TuringMachine::new(instr, tape); + let mut cursor = Cursor::new(&tm, TMState::A, 0); + + let result = cursor.run(1000); + assert_eq!(result, Err(TuringMachineError::InvalidMovement)); + for (idx, val) in tm.tape.iter().enumerate() { + if idx % 2 == 0 { + assert_eq!(*val.borrow(), TMValue::Zero); + } else { + assert_eq!(*val.borrow(), TMValue::One); + } + } + } +} diff --git a/src/assignments/assignment11/tv_room.rs b/src/assignments/assignment11/tv_room.rs index a3cec53..1e9dbd0 100644 --- a/src/assignments/assignment11/tv_room.rs +++ b/src/assignments/assignment11/tv_room.rs @@ -15,6 +15,8 @@ //! Consult the following documentations: //! - //! - +//! +//! Refer `tv_room_grade.rs` for test cases. use std::{cell::RefCell, rc::Rc}; diff --git a/src/assignments/assignment11/tv_room_grade.rs b/src/assignments/assignment11/tv_room_grade.rs new file mode 100644 index 0000000..63495eb --- /dev/null +++ b/src/assignments/assignment11/tv_room_grade.rs @@ -0,0 +1,32 @@ +//! Test cases for assignment11/tv_room.rs + +#[cfg(test)] +mod test_tv_room { + use super::super::tv_room::*; + + #[test] + fn test_tv_room() { + let tv_room = TVRoom::new(); + assert!(!tv_room.is_opened()); + + // Turn on and add new guests. + let manager = tv_room.open().unwrap(); + assert!(tv_room.is_opened()); + let guest1 = manager.new_guest(); + let guest2 = manager.new_guest(); + drop(manager); + drop(guest1); + assert!(tv_room.open().is_none()); + drop(guest2); + assert!(!tv_room.is_opened()); + + // Turn on and add new guests. + let manager = tv_room.open().unwrap(); + assert!(tv_room.is_opened()); + let guest3 = manager.new_guest(); + drop(guest3); + assert!(tv_room.is_opened()); + drop(manager); + assert!(!tv_room.is_opened()); + } +} diff --git a/src/assignments/assignment12/card.rs b/src/assignments/assignment12/card.rs new file mode 100644 index 0000000..1a00da9 --- /dev/null +++ b/src/assignments/assignment12/card.rs @@ -0,0 +1,52 @@ +//! Flipping card game. +//! +//! For this assignment, you have to see `play` function in `card_grade.rs` file. +//! Multiple threads will be created and they will run as enemy bots(`bot_threads`). +//! Strategy of the enemy bots is implemented in the closure of the `thread::spawn` function. +//! Your goal is to beat them so that there are more white cards than blue cards in the ground. +//! Write your strategy in the `flip_card_strategy` function of the `Player` struct. +//! +//! Have fun! + +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; + +/// Color represents the color of the card. +/// The color of a card can be either Blue or White. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum Color { + /// blue + Blue, + + /// white + White, +} + +/// Player struct represents a player in the card game. +/// Each player has a memory which is represented as a HashMap. +#[derive(Debug)] +pub struct Player { + memory: HashMap, +} + +impl Default for Player { + fn default() -> Self { + Self::new() + } +} + +impl Player { + /// Creates a new player with an empty memory. + pub fn new() -> Self { + Self { + memory: HashMap::new(), + } + } + + /// This function should return the index of the card to flip and the color to change to. + pub fn flip_card_strategy(&mut self) -> (usize, Color) { + todo!() + } +} diff --git a/src/assignments/assignment12/card_grade.rs b/src/assignments/assignment12/card_grade.rs new file mode 100644 index 0000000..4f3ec84 --- /dev/null +++ b/src/assignments/assignment12/card_grade.rs @@ -0,0 +1,141 @@ +//! Test cases for assignment12/card.rs + +#[cfg(test)] +mod test_card { + use super::super::card::*; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::{Arc, Barrier, Mutex}; + use std::thread; + use std::time::Duration; + + const NUM_CARDS: usize = 10_000; + const DURATION: u64 = 1; + const NUM_ENEMIES: usize = 100; + + #[derive(Clone, Debug)] + struct Card { + color: Arc>, + } + + impl Card { + fn new() -> Self { + Card { + color: Arc::new(Mutex::new(Color::Blue)), + } + } + + fn flip(&self, new_color: Color) { + let mut color = self.color.lock().unwrap(); + *color = new_color; + } + + fn get_color(&self) -> Color { + let color = self.color.lock().unwrap(); + *color + } + } + + #[derive(Clone, Debug)] + struct Ground { + cards: Vec, + } + + impl Ground { + fn new() -> Self { + let cards: Vec<_> = (0..NUM_CARDS).map(|_| Card::new()).collect(); + Ground { cards } + } + + fn flip_card(&self, idx: usize, color: Color) { + self.cards[idx % NUM_CARDS].flip(color); + } + + fn get_card_color(&self, idx: usize) -> Color { + self.cards[idx % NUM_CARDS].get_color() + } + } + + #[test] + fn play() { + let ground = Ground::new(); + let barrier = Arc::new(Barrier::new( + NUM_ENEMIES + 1 /*Player*/ + 1, /*Referee*/ + )); + let playing = Arc::new(AtomicBool::new(true)); + + // Create a thread for the student's strategy + let mut player = Player::new(); + let player_thread = { + let ground = ground.clone(); + let barrier = barrier.clone(); + let playing = playing.clone(); + + // The player's strategy thread + thread::spawn(move || { + // Get, Set, Ready, Go! + let _ = barrier.wait(); + + // As long as the game is still playing... + while playing.load(Ordering::SeqCst) { + let (idx, color) = player.flip_card_strategy(); + ground.flip_card(idx, color); + } + }) + }; + + // Create multiple threads for the computer's strategy + let dist = NUM_CARDS / NUM_ENEMIES; + let bot_threads: Vec<_> = (0..NUM_ENEMIES) + .map(|i| { + let ground = ground.clone(); + let barrier = barrier.clone(); + let playing = playing.clone(); + + let init = i * dist; + let mut cnt = 0; + + thread::spawn(move || { + // Get, Set, Ready, Go! + let _ = barrier.wait(); + + // As long as the game is still playing... + while playing.load(Ordering::SeqCst) { + let idx = init + (cnt % dist); + match ground.get_card_color(idx) { + Color::White => ground.flip_card(idx, Color::Blue), + Color::Blue => thread::sleep(Duration::from_micros(1)), + }; + cnt += 1; + } + }) + }) + .collect(); + + // Get, Set, Ready, Go! + let _ = barrier.wait(); + + // Wait for a while and stop the game + thread::sleep(Duration::from_secs(DURATION)); + playing.store(false, Ordering::SeqCst); + + // Wait for all threads to finish + player_thread.join().unwrap(); + for bot_thread in bot_threads { + bot_thread.join().unwrap(); + } + + // Count the number of white and blue cards + let mut white_cnt = 0; + let mut blue_cnt = 0; + for card in ground.cards { + match card.get_color() { + Color::White => white_cnt += 1, + Color::Blue => blue_cnt += 1, + } + } + + // Print the winner + println!("[White: {white_cnt}, Blue: {blue_cnt}]"); + assert!(white_cnt > blue_cnt, "You lose...",); + } +} diff --git a/src/assignments/assignment12/demux.rs b/src/assignments/assignment12/demux.rs new file mode 100644 index 0000000..2d98008 --- /dev/null +++ b/src/assignments/assignment12/demux.rs @@ -0,0 +1,37 @@ +//! Demultiplexing sender +//! +//! Implement demultiplexing sender +//! Demultiplexer, `Demux` in short, is a device that has one input and many outputs. +//! It distributes the input to the outputs according to the control signal. +//! It is used when a circuit wishes to send a signal to one of many devices. +//! For more information, refer +//! +//! In this assignment, closure `f` will be given as an argument to `demux` function. +//! This closure will be used to determine which destination to send the input data. +//! +//! Refer `demux_grade.rs` for test cases + +use std::sync::mpsc::{channel, Receiver, SendError, Sender}; +use std::thread; + +/// Sender for demux. +#[derive(Debug)] +pub struct DemuxSender bool> { + tx_true: Sender, + tx_false: Sender, + f: F, +} + +impl bool> DemuxSender { + /// send + /// + /// If `f(&value)` is true, send `value` to `tx_true`. Otherwise, send `value` to `tx_false`. + pub fn send(&self, value: T) -> Result<(), SendError> { + todo!() + } +} + +/// Demux. +pub fn demux bool>(f: F) -> (DemuxSender, Receiver, Receiver) { + todo!() +} diff --git a/src/assignments/assignment12/demux_grade.rs b/src/assignments/assignment12/demux_grade.rs new file mode 100644 index 0000000..66e11f7 --- /dev/null +++ b/src/assignments/assignment12/demux_grade.rs @@ -0,0 +1,36 @@ +//! Test cases for assignment12/demux.rs + +#[cfg(test)] +mod test_demux { + use super::super::demux::*; + use ntest::timeout; + + use std::sync::mpsc::channel; + use std::thread; + + #[test] + #[timeout(5000)] + fn test_demux() { + let (tx, rx1, rx2) = demux::(|x| x % 2 == 0); + + let thread_tx = thread::spawn(move || { + for i in 0..100 { + tx.send(i).unwrap(); + } + }); + + let thread_rx1 = thread::spawn(move || { + let sum: u32 = rx1.iter().sum(); + assert_eq!(sum, (0..100).filter(|x| x % 2 == 0).sum()); + }); + + let thread_rx2 = thread::spawn(move || { + let sum: u32 = rx2.iter().sum(); + assert_eq!(sum, (0..100).filter(|x| x % 2 != 0).sum()); + }); + + thread_tx.join().unwrap(); + thread_rx1.join().unwrap(); + thread_rx2.join().unwrap(); + } +} diff --git a/src/assignments/assignment12/funnel.rs b/src/assignments/assignment12/funnel.rs new file mode 100644 index 0000000..8b050e8 --- /dev/null +++ b/src/assignments/assignment12/funnel.rs @@ -0,0 +1,21 @@ +//! Funnel +//! +//! Spawn a thread that executes a funnel. +//! Funnel will receive data from multiple receivers and send it to a single sender. +//! Also, the funnel will filter out data that does not pass the filter function. +//! +//! Refer `funnel_grade.rs` for test cases + +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::Arc; +use std::thread; +use std::thread::JoinHandle; + +/// Spawn a thread that concurrently receive datas from `rxs`, send it to `tx` if it makes `f` true. Returns its handle. +pub fn spawn_funnel(rxs: Vec>, tx: Sender, f: F) -> JoinHandle<()> +where + T: Send + 'static, + F: Send + Sync + Fn(&T) -> bool + 'static, +{ + todo!() +} diff --git a/src/assignments/assignment12/funnel_grade.rs b/src/assignments/assignment12/funnel_grade.rs new file mode 100644 index 0000000..8de4b99 --- /dev/null +++ b/src/assignments/assignment12/funnel_grade.rs @@ -0,0 +1,33 @@ +//! Test cases for assignment12/funnel.rs + +#[cfg(test)] +mod test_funnel { + use super::super::funnel::*; + use ntest::timeout; + + use std::sync::mpsc::channel; + use std::thread; + + #[test] + #[timeout(5000)] + fn test_funnel_concurrent() { + let (txs, rxs): (Vec<_>, Vec<_>) = (0..10).map(|_| channel::()).unzip(); + let (tx, rx) = channel::(); + let filter = |x: &u32| x % 2 == 0; + + let thread_txs_rx = thread::spawn(move || { + for i in 0..100 { + let idx = (i * 7) % 13 * 17 % 10; + txs[idx].send(i as u32).unwrap(); + if i % 2 == 0 { + let x = rx.recv().unwrap(); + assert_eq!(x, i as u32); + } + } + }); + let thread_funnel = spawn_funnel(rxs, tx, filter); + + thread_txs_rx.join().unwrap(); + thread_funnel.join().unwrap(); + } +} diff --git a/src/assignments/assignment12/mod.rs b/src/assignments/assignment12/mod.rs new file mode 100644 index 0000000..ae03552 --- /dev/null +++ b/src/assignments/assignment12/mod.rs @@ -0,0 +1,15 @@ +//! Assignment 12: Concurrency. +//! +//! The primary goal of this assignment is to get used to concurrency. +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-12.sh` works fine. +//! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script. + +pub mod card; +pub mod card_grade; +pub mod demux; +pub mod demux_grade; +pub mod funnel; +pub mod funnel_grade; +pub mod small_exercises; +pub mod small_exercises_grade; diff --git a/src/assignments/assignment12.rs b/src/assignments/assignment12/small_exercises.rs similarity index 60% rename from src/assignments/assignment12.rs rename to src/assignments/assignment12/small_exercises.rs index 73d4d84..121b670 100644 --- a/src/assignments/assignment12.rs +++ b/src/assignments/assignment12/small_exercises.rs @@ -1,23 +1,25 @@ #![allow(single_use_lifetimes)] -//! Assignment 12: Concurrency. +//! Small exercises //! -//! The primary goal of this assignment is to get used to concurrency. -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-12.sh` works fine. -//! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script. +//! Refer `small_exercises_grade.rs` for test cases use std::sync::mpsc::{Receiver, RecvError, Sender}; use std::thread; use etrace::*; -/// The "pong" function (read the test script to figure out what it should do). +/// The "pong" function +/// +/// Data will be sent and received through `rx` and `tx`. +/// Read the `test_ping_pong` function in `small_exercises_grade.rs` to figure out what it should do. pub fn pong(rx1: &mut Receiver, tx2: &mut Sender) -> bool { todo!() } /// Executes the given functions (f1, f2) in concurrent and returns the results. +/// +/// Read the `test_scoped_thread` function in `small_exercises_grade.rs` to figure out what it should do. pub fn use_scoped_thread<'scope, 'env, T1, T2, F1, F2>( s: &'scope thread::Scope<'scope, 'env>, f1: F1, diff --git a/src/assignments/assignment12/small_exercises_grade.rs b/src/assignments/assignment12/small_exercises_grade.rs new file mode 100644 index 0000000..e043ace --- /dev/null +++ b/src/assignments/assignment12/small_exercises_grade.rs @@ -0,0 +1,86 @@ +//! Test cases for assignment12/small_exercises_grade.rs + +#[cfg(test)] +mod test_pingpong { + use super::super::small_exercises::*; + use ntest::timeout; + + use std::sync::mpsc::channel; + use std::thread; + + #[test] + fn test_ping_pong() { + let (tx1, mut rx1) = channel(); + let (mut tx2, rx2) = channel(); + + let thread_ping = thread::spawn(move || { + for i in 0..100 { + tx1.send(i).unwrap(); + let x = rx2.recv().unwrap(); + assert_eq!(x, i + 1); + } + }); + + let thread_pong = thread::spawn(move || while pong(&mut rx1, &mut tx2) {}); + + thread_ping.join().unwrap(); + thread_pong.join().unwrap(); + } + + #[test] + fn test_scoped_thread() { + for i in 0..100 { + let v = (0..i).collect::>(); + + thread::scope(|s| { + let (r1, r2) = use_scoped_thread( + s, + || v.iter().sum::(), + || v.windows(2).map(|x| x[0] * x[1]).sum::(), + ); + + assert_eq!(r1, v.iter().sum()); + assert_eq!(r2, v.windows(2).map(|x| x[0] * x[1]).sum()); + }); + } + } + + #[test] + #[timeout(5000)] + fn test_scoped_thread_concurrent() { + use std::sync::Mutex; + + let m = Mutex::new(0); + let (r1, r2) = thread::scope(|s| { + use_scoped_thread( + s, + || { + for i in 0..100 { + loop { + let mut a = m.lock().unwrap(); + if *a == 2 * i { + *a += 1; + break; + } + } + } + thread::current().id() + }, + || { + for i in 0..100 { + loop { + let mut a = m.lock().unwrap(); + if *a == 2 * i + 1 { + *a += 1; + break; + } + } + } + thread::current().id() + }, + ) + }); + + assert!(r1 != r2); + } +} diff --git a/src/assignments/mod.rs b/src/assignments/mod.rs index 74e67fe..ff16701 100644 --- a/src/assignments/mod.rs +++ b/src/assignments/mod.rs @@ -25,8 +25,6 @@ mod assignment09_grade; pub mod assignment10; mod assignment10_grade; pub mod assignment11; -mod assignment11_grade; pub mod assignment12; -mod assignment12_grade; pub mod assignment13; mod assignment13_grade; From e7b8dc3899509a500a78946645c31091549acc2d Mon Sep 17 00:00:00 2001 From: woojin Date: Fri, 18 Aug 2023 22:10:46 +0900 Subject: [PATCH 02/17] cargo lock --- Cargo.lock | 388 +++++++++++++++++++++++++++++------------------------ 1 file changed, 212 insertions(+), 176 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e95c3d6..75ed63e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,10 +3,59 @@ version = 3 [[package]] -name = "anyhow" -version = "1.0.66" +name = "anstream" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "approx" @@ -25,24 +74,27 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" -version = "1.3.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "cc" -version = "1.0.77" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -52,9 +104,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.0.29" +version = "4.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" +checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2" dependencies = [ "clap_builder", "clap_derive", @@ -63,54 +115,54 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.4" +version = "4.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" +checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -118,9 +170,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -129,9 +181,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", @@ -142,9 +194,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -181,9 +233,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -191,19 +243,25 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.2.8" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys", ] [[package]] @@ -224,9 +282,9 @@ checksum = "f17311e68ea07046ee809b8513f6c259518bc10173681d98c21f8c3926f56f40" [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -245,9 +303,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "heck" @@ -257,47 +315,27 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "indexmap" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] -[[package]] -name = "io-lifetimes" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" -dependencies = [ - "libc", - "windows-sys", -] - [[package]] name = "is-terminal" -version = "0.4.1" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.2.6", - "io-lifetimes", + "hermit-abi", "rustix", "windows-sys", ] @@ -319,9 +357,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.138" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libm" @@ -331,9 +369,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linux-raw-sys" -version = "0.1.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "matrixmultiply" @@ -353,9 +391,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -402,7 +440,7 @@ checksum = "be7d33be719c6f4d09e64e27c1ef4e73485dc4cc1f4d22201f89860a7fe22e22" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -448,25 +486,25 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "pest" -version = "2.5.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ "thiserror", "ucd-trie", @@ -474,9 +512,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -484,26 +522,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] name = "pest_meta" -version = "2.5.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", - "sha1", + "sha2", ] [[package]] @@ -514,53 +552,28 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "thiserror", - "toml", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -613,20 +626,19 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -636,13 +648,12 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.4" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ "bitflags", "errno", - "io-lifetimes", "libc", "linux-raw-sys", "windows-sys", @@ -650,15 +661,15 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -673,9 +684,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.105" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -683,60 +694,76 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.1.3" +name = "syn" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ - "winapi-util", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.29", ] [[package]] -name = "toml" -version = "0.5.9" +name = "toml_datetime" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "serde", + "indexmap", + "toml_datetime", + "winnow", ] [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "version_check" @@ -761,9 +788,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "27f51fb4c64f8b770a823c043c7fad036323e1c48f55287b7bbb7987b2fcdf3b" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -776,42 +803,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "fde1bb55ae4ce76a597a8566d82c57432bc69c039449d61572a7a353da28f68c" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "1513e8d48365a78adad7322fd6b5e4c4e99d92a69db8df2d435b25b1f1f286d4" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "60587c0265d2b842298f5858e1a5d79d146f9ee0c37be5782e92a6eb5e1d7a83" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "224fe0e0ffff5d2ea6a29f82026c8f43870038a0ffc247aa95a52b47df381ac4" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "62fc52a0f50a088de499712cbc012df7ebd94e2d6eb948435449d76a6287e7ad" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "2093925509d91ea3d69bcd20238f4c2ecdb1a29d3c281d026a09705d0dd35f3d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.48.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "b6ade45bc8bf02ae2aa34a9d54ba660a1a58204da34ba793c00d83ca3730b5f1" + +[[package]] +name = "winnow" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97" +dependencies = [ + "memchr", +] From b1f1f1a5fcda6cee6041724d14e80bc8e3db9d5e Mon Sep 17 00:00:00 2001 From: "jungin.rhee" Date: Fri, 18 Aug 2023 16:07:30 +0000 Subject: [PATCH 03/17] copy-paste problems --- src/assignments/assignment06/mod.rs | 16 + src/assignments/assignment06/semiring.rs | 168 ++++++++ .../assignment06/semiring_grade.rs | 136 +++++++ src/assignments/assignment06/square_matrix.rs | 88 +++++ .../assignment06/square_matrix_grade.rs | 72 ++++ .../assignment06/symbolic_differentiation.rs | 360 ++++++++++++++++++ .../symbolic_differentiation_grade.rs | 216 +++++++++++ src/assignments/assignment07/generator.rs | 36 ++ .../assignment07/generator_grade.rs | 38 ++ src/assignments/assignment07/hubo.rs | 84 ++++ src/assignments/assignment07/hubo_grade.rs | 40 ++ src/assignments/assignment07/mod.rs | 18 + src/assignments/assignment07/my_itertools.rs | 117 ++++++ .../assignment07/my_itertools_grade.rs | 65 ++++ .../assignment07/small_exercises.rs | 119 ++++++ .../assignment07/small_exercises_grade.rs | 189 +++++++++ src/assignments/assignment07/transform.rs | 95 +++++ .../assignment07/transform_grade.rs | 62 +++ src/assignments/assignment09/bigint.rs | 94 +++++ src/assignments/assignment09/bigint_grade.rs | 104 +++++ src/assignments/assignment09/mod.rs | 12 + .../assignment09/small_exercises.rs | 211 ++++++++++ .../assignment09/small_exercises_grade.rs | 268 +++++++++++++ src/assignments/assignment10/labyrinth.rs | 50 +++ .../assignment10/labyrinth_grade.rs | 62 +++ src/assignments/assignment10/mod.rs | 12 + .../assignment10/small_exercises.rs | 193 ++++++++++ .../assignment10/small_exercises_grade.rs | 351 +++++++++++++++++ 28 files changed, 3276 insertions(+) create mode 100644 src/assignments/assignment06/mod.rs create mode 100644 src/assignments/assignment06/semiring.rs create mode 100644 src/assignments/assignment06/semiring_grade.rs create mode 100644 src/assignments/assignment06/square_matrix.rs create mode 100644 src/assignments/assignment06/square_matrix_grade.rs create mode 100644 src/assignments/assignment06/symbolic_differentiation.rs create mode 100644 src/assignments/assignment06/symbolic_differentiation_grade.rs create mode 100644 src/assignments/assignment07/generator.rs create mode 100644 src/assignments/assignment07/generator_grade.rs create mode 100644 src/assignments/assignment07/hubo.rs create mode 100644 src/assignments/assignment07/hubo_grade.rs create mode 100644 src/assignments/assignment07/mod.rs create mode 100644 src/assignments/assignment07/my_itertools.rs create mode 100644 src/assignments/assignment07/my_itertools_grade.rs create mode 100644 src/assignments/assignment07/small_exercises.rs create mode 100644 src/assignments/assignment07/small_exercises_grade.rs create mode 100644 src/assignments/assignment07/transform.rs create mode 100644 src/assignments/assignment07/transform_grade.rs create mode 100644 src/assignments/assignment09/bigint.rs create mode 100644 src/assignments/assignment09/bigint_grade.rs create mode 100644 src/assignments/assignment09/mod.rs create mode 100644 src/assignments/assignment09/small_exercises.rs create mode 100644 src/assignments/assignment09/small_exercises_grade.rs create mode 100644 src/assignments/assignment10/labyrinth.rs create mode 100644 src/assignments/assignment10/labyrinth_grade.rs create mode 100644 src/assignments/assignment10/mod.rs create mode 100644 src/assignments/assignment10/small_exercises.rs create mode 100644 src/assignments/assignment10/small_exercises_grade.rs diff --git a/src/assignments/assignment06/mod.rs b/src/assignments/assignment06/mod.rs new file mode 100644 index 0000000..da14417 --- /dev/null +++ b/src/assignments/assignment06/mod.rs @@ -0,0 +1,16 @@ +//! Assignment 6: Mastering advanced types (1/2). +//! +//! The primary goal of this assignment is to understand generics, traits, and lifetimes. +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-06.sh` works fine. +//! See `assignment06_grade.rs` and `/scripts/grade-06.sh` for the test script. + +use std::{collections::HashMap, fmt::Debug}; + +pub mod semiring; +pub mod square_matrix; +pub mod symbolic_differentiation; + +mod semiring_grade; +mod square_matrix_grade; +mod symbolic_differentiation_grade; diff --git a/src/assignments/assignment06/semiring.rs b/src/assignments/assignment06/semiring.rs new file mode 100644 index 0000000..1add902 --- /dev/null +++ b/src/assignments/assignment06/semiring.rs @@ -0,0 +1,168 @@ +//! Semiring + +use std::{collections::HashMap, fmt::Debug}; + +/// Semiring. +/// +/// Consult . +pub trait Semiring: Debug + Clone + PartialEq { + /// Additive identity. + fn zero() -> Self; + /// Multiplicative identity. + fn one() -> Self; + /// Addition operation. + fn add(&self, rhs: &Self) -> Self; + /// Multiplication operation. + fn mul(&self, rhs: &Self) -> Self; +} + +/// Converts integer to semiring value. +pub fn from_usize(value: usize) -> T { + let mut result = T::zero(); + let one = T::one(); + + for _ in 0..value { + result = T::add(&result, &one); + } + + result +} + +impl Semiring for u64 { + fn zero() -> Self { + todo!() + } + + fn one() -> Self { + todo!() + } + + fn add(&self, rhs: &Self) -> Self { + todo!() + } + + fn mul(&self, rhs: &Self) -> Self { + todo!() + } +} + +impl Semiring for i64 { + fn zero() -> Self { + todo!() + } + + fn one() -> Self { + todo!() + } + + fn add(&self, rhs: &Self) -> Self { + todo!() + } + + fn mul(&self, rhs: &Self) -> Self { + todo!() + } +} + +impl Semiring for f64 { + fn zero() -> Self { + todo!() + } + + fn one() -> Self { + todo!() + } + + fn add(&self, rhs: &Self) -> Self { + todo!() + } + + fn mul(&self, rhs: &Self) -> Self { + todo!() + } +} + +/// Polynomials with coefficient in `C`. +/// +/// For example, polynomial `x^2 + 5x + 6` is represented in `Polynomial` as follows: +/// +/// ```ignore +/// Polynomial { +/// coefficients: { +/// 2: 1, +/// 1: 5, +/// 0: 6, +/// }, +/// } +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Polynomial { + coefficients: HashMap, +} + +impl Semiring for Polynomial { + fn zero() -> Self { + todo!() + } + + fn one() -> Self { + todo!() + } + + fn add(&self, rhs: &Self) -> Self { + todo!() + } + + fn mul(&self, rhs: &Self) -> Self { + todo!() + } +} + +impl Polynomial { + /// Constructs polynomial `x`. + pub fn x() -> Self { + todo!() + } + + /// Evaluates the polynomial with the given value. + pub fn eval(&self, value: C) -> C { + todo!() + } + + /// Constructs polynomial `ax^n`. + pub fn term(a: C, n: u64) -> Self { + todo!() + } +} + +impl From for Polynomial { + fn from(value: C) -> Self { + todo!() + } +} + +/// Given a string `s`, parse it into a `Polynomial`. +/// You may assume that `s` follows the criteria below. +/// Therefore, you do not have to return `Err`. +/// +/// Assumptions: +/// - Each term is separated by ` + `. +/// - Each term is one of the following form: +/// `a`, `x`, `ax`, `x^n`, and `ax^n`, +/// where `a` is a `usize` number and `n` is a `u64` number. +/// This `a` should then be converted to a `C` type. +/// - In `a`, it is guaranteed that `a >= 1`. +/// - In `ax` and `ax^n`, it is guaranteed that `a >= 2`. +/// - In `x^n` and `ax^n`, it is guaranteed that `n >= 2`. +/// - All terms have unique degrees. +/// +/// Consult `assignment06_jaemin_choi_grade.rs` for example valid strings. +/// +/// Hint: `.split`, `.parse`, and `Polynomial::term` +impl std::str::FromStr for Polynomial { + type Err = (); // Ignore this for now... + + fn from_str(s: &str) -> Result { + todo!() + } +} diff --git a/src/assignments/assignment06/semiring_grade.rs b/src/assignments/assignment06/semiring_grade.rs new file mode 100644 index 0000000..bca3278 --- /dev/null +++ b/src/assignments/assignment06/semiring_grade.rs @@ -0,0 +1,136 @@ +#[cfg(test)] +mod test { + use super::super::semiring::*; + use ntest::assert_about_eq; + + fn test_from_str(s: &str, f: impl Fn(i64) -> i64) { + let poly = s.parse::>().unwrap(); + for i in 0..10 { + assert_eq!(poly.eval(i), f(i)); + } + } + + fn test_polynomial() { + // x^2 + 5x + 6 + let poly = Polynomial::add( + &Polynomial::add( + &Polynomial::mul( + &Polynomial::from(from_usize::(1)), + &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), + ), + &Polynomial::mul(&Polynomial::from(from_usize::(5)), &Polynomial::x()), + ), + &Polynomial::from(from_usize::(6)), + ); + + // 13^2 + 5*13 + 6 + let value = poly.eval(from_usize(13)); + + assert_eq!(value, from_usize(13 * 13 + 5 * 13 + 6)); + } + + #[test] + fn test_123() { + test_from_str("123", |x| 123); + } + + #[test] + fn test_x() { + test_from_str("x", |x| x); + } + + #[test] + fn test_24x() { + test_from_str("24x", |x| 24 * x); + } + + #[test] + fn test_2x_3() { + test_from_str("2x + 3", |x| 2 * x + 3); + } + + #[test] + fn test_x3() { + test_from_str("x^3", |x| x * x * x); + } + + #[test] + fn test_2x3_3x2_5x_12() { + test_from_str("2x^3 + 3x^2 + 5x + 12", |x| { + 2 * x * x * x + 3 * x * x + 5 * x + 12 + }); + } + + #[test] + fn test_x5_1() { + test_from_str("x^5 + 1", |x| x * x * x * x * x + 1); + } + + #[test] + fn test_polynomial_u64() { + test_polynomial::(); + } + + #[test] + fn test_polynomial_f64() { + test_polynomial::(); + } + + #[test] + fn test_polynomial_p_u64() { + test_polynomial::>(); + } + + #[test] + fn test_polynomial_xy() { + // (x+1)(y+2) + let poly: Polynomial> = Polynomial::mul( + &Polynomial::from(Polynomial::add( + &Polynomial::x(), + &Polynomial::from(from_usize::(1)), + )), + &(Polynomial::add( + &Polynomial::x(), + &Polynomial::from(Polynomial::from(from_usize::(2))), + )), + ); + + // poly with y = x+3 + let value = poly.eval(Polynomial::add( + &Polynomial::x(), + &Polynomial::from(from_usize::(3)), + )); + + // x^2 + 6x + 5 + let expected = Polynomial::add( + &Polynomial::add( + &Polynomial::mul( + &Polynomial::from(from_usize::(1)), + &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), + ), + &Polynomial::mul(&Polynomial::from(from_usize::(6)), &Polynomial::x()), + ), + &Polynomial::from(from_usize::(5)), + ); + + assert_eq!(value, expected); + } + + #[test] + fn test_zero_remove() { + // (x-1)(x+1) + let poly: Polynomial = Polynomial::mul( + &Polynomial::add(&Polynomial::x(), &Polynomial::from(-1)), + &Polynomial::add(&Polynomial::x(), &Polynomial::from(1)), + ); + + // (x-1)(x+1) == x^2 - 1 + assert_eq!( + poly, + Polynomial::add( + &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), + &Polynomial::from(-1) + ) + ); + } +} diff --git a/src/assignments/assignment06/square_matrix.rs b/src/assignments/assignment06/square_matrix.rs new file mode 100644 index 0000000..f81209e --- /dev/null +++ b/src/assignments/assignment06/square_matrix.rs @@ -0,0 +1,88 @@ +//! Square matrix + +/// Square matrix +pub trait SquareMatrix { + /// The type of the submatrix of this square matrix. + /// For example, the submatrix of a 3 x 3 matrix is a 2 x 2 matrix. + /// https://en.wikipedia.org/wiki/Matrix_(mathematics)#Submatrix + type Submatrix; + + /// Returns the submatrix obtained by removing the `row`th row and `col`th column + /// from the original matrix. + /// https://en.wikipedia.org/wiki/Matrix_(mathematics)#Submatrix + fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix; + + /// Returns the determinant of the matrix. + fn det(&self) -> i64; + + /// Returns the determinant of ab, where a is self, b is given, and ab is the matrix product of them. + /// Note that the size of a and b are the same. + /// Hint: Use the fact that det(ab) = det(a) * det(b) + /// https://en.wikipedia.org/wiki/Determinant#Multiplicativity_and_matrix_groups + fn det_ab(&self, b: &Self) -> i64 { + todo!() + } +} + +/// 2 x 2 matrix +#[derive(Debug, PartialEq)] +pub struct Mat2 { + /// inner is a 2 dimensional array (size: 2 x 2) + pub inner: [[i64; 2]; 2], +} + +impl SquareMatrix for Mat2 { + type Submatrix = i64; + + fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix { + // Hint: The submatrix of a 2 x 2 matrix is simply a single number. + todo!() + } + + // Hint: https://en.wikipedia.org/wiki/Determinant + fn det(&self) -> i64 { + todo!() + } +} + +/// 3 x 3 matrix +#[derive(Debug, PartialEq)] +pub struct Mat3 { + /// inner is a 2 dimensional array (size: 3 x 3) + pub inner: [[i64; 3]; 3], +} + +impl SquareMatrix for Mat3 { + type Submatrix = Mat2; + + fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix { + todo!() + } + + // Hint: Use the determinant of the sub-matrices. + // https://semath.info/src/determinant-three-by-three.html + fn det(&self) -> i64 { + todo!() + } +} + +/// 4 x 4 matrix +#[derive(Debug, PartialEq)] +pub struct Mat4 { + /// inner is a 2 dimensional array (size: 4 x 4) + pub inner: [[i64; 4]; 4], +} + +impl SquareMatrix for Mat4 { + type Submatrix = Mat3; + + fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix { + todo!() + } + + // Hint: Use the determinant of the sub-matrices. + // https://semath.info/src/determinant-four-by-four.html + fn det(&self) -> i64 { + todo!() + } +} diff --git a/src/assignments/assignment06/square_matrix_grade.rs b/src/assignments/assignment06/square_matrix_grade.rs new file mode 100644 index 0000000..7270c73 --- /dev/null +++ b/src/assignments/assignment06/square_matrix_grade.rs @@ -0,0 +1,72 @@ +#[cfg(test)] +mod test { + use super::super::square_matrix::*; + use ntest::assert_about_eq; + + #[test] + fn test_mat2() { + let mat = Mat2 { + inner: [[1, 2], [3, 4]], + }; + assert_eq!(mat.sub_matrix(1, 1), 4); + assert_eq!(mat.sub_matrix(1, 2), 3); + assert_eq!(mat.sub_matrix(2, 1), 2); + assert_eq!(mat.sub_matrix(2, 2), 1); + assert_eq!(mat.det(), -2); + + let mat2 = Mat2 { + inner: [[2, 3], [5, 7]], + }; + assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det()); + } + + #[test] + fn test_mat3() { + let mat = Mat3 { + inner: [[1, 2, 3], [5, 5, 6], [7, 8, 10]], + }; + assert_eq!( + mat.sub_matrix(1, 2), + Mat2 { + inner: [[5, 6], [7, 10]] + } + ); + assert_eq!(mat.det(), 1); + + let mat2 = Mat3 { + inner: [[2, 3, 5], [7, 10, 11], [12, 14, 20]], + }; + assert_eq!(mat2.det(), -42); + assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det()); + } + + #[test] + fn test_mat4() { + let mat = Mat4 { + inner: [ + [1, 11, 3, 4], + [5, 6, 7, 9], + [25, 10, 11, 20], + [36, 14, 15, 30], + ], + }; + assert_eq!( + mat.sub_matrix(2, 3), + Mat3 { + inner: [[1, 11, 4], [25, 10, 20], [36, 14, 30]] + } + ); + assert_eq!(mat.det(), 2089); + + let mat2 = Mat4 { + inner: [ + [2, 3, 5, 5], + [7, 10, 11, 20], + [12, 14, 20, 30], + [1, 2, 5, 10], + ], + }; + assert_eq!(mat2.det(), -340); + assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det()); + } +} diff --git a/src/assignments/assignment06/symbolic_differentiation.rs b/src/assignments/assignment06/symbolic_differentiation.rs new file mode 100644 index 0000000..28d3b4a --- /dev/null +++ b/src/assignments/assignment06/symbolic_differentiation.rs @@ -0,0 +1,360 @@ +//! Symbolic differentiation with rational coefficents. + +use std::fmt; +use std::ops::*; + +/// Rational number represented by two isize, numerator and denominator. +/// +/// Each Rational number should be normalized so that `demoninator` is nonnegative and `numerator` and `demoninator` are coprime. +/// See [`normalize`] for examples. As a corner case, 0 is represented by Rational { numerator: 0, demoninator: 0 }. +/// +/// For "natural use", Rational also overloads standard arithmetic operations, i.e, `+`, `-`, `*`, `/`. +/// +/// See [here](https://doc.rust-lang.org/core/ops/index.html) for details. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Rational { + numerator: isize, + denominator: isize, +} + +// Some useful constants. + +/// Zero +pub const ZERO: Rational = Rational::new(0, 0); +/// One +pub const ONE: Rational = Rational::new(1, 1); +/// Minus one +pub const MINUS_ONE: Rational = Rational::new(-1, 1); + +impl Rational { + /// Creates a new rational number. + pub const fn new(numerator: isize, denominator: isize) -> Self { + Self { + numerator, + denominator, + } + } +} + +impl Add for Rational { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl Mul for Rational { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl Sub for Rational { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl Div for Rational { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + todo!() + } +} + +/// Differentiable functions. +/// +/// For simplicity, we only consider infinitely differentiable functions. +pub trait Differentiable: Clone { + /// Differentiate. + /// + /// Since the return type is `Self`, this trait can only be implemented + /// for types that are closed under differentiation. + fn diff(&self) -> Self; +} + +impl Differentiable for Rational { + fn diff(&self) -> Self { + todo!() + } +} + +/// Singleton polynomial. +/// +/// Unlike regular polynomials, this type only represents a single term. +/// The `Const` variant is included to make `Polynomial` closed under differentiation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SingletonPolynomial { + /// Constant polynomial. + Const(Rational), + /// Non-const polynomial. + Polynomial { + /// coefficent of polynomial. Must be non-zero. + coeff: Rational, + /// power of polynomial. Must be non-zero. + power: Rational, + }, +} + +impl SingletonPolynomial { + /// Creates a new const polynomial. + pub fn new_c(r: Rational) -> Self { + todo!() + } + + /// Creates a new polynomial. + pub fn new_poly(coeff: Rational, power: Rational) -> Self { + todo!() + } +} + +impl Differentiable for SingletonPolynomial { + fn diff(&self) -> Self { + todo!() + } +} + +/// Expoential function. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Exp; + +impl Exp { + /// Creates a new exponential function. + pub fn new() -> Self { + todo!() + } +} + +impl Default for Exp { + fn default() -> Self { + Self::new() + } +} + +impl Differentiable for Exp { + fn diff(&self) -> Self { + todo!() + } +} + +/// Trigonometric functions. +/// +/// The trig fucntions carry their coefficents to be closed under differntiation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Trignometric { + /// Sine function. + Sine { + /// Coefficent + coeff: Rational, + }, + /// Sine function. + Cosine { + /// Coefficent + coeff: Rational, + }, +} + +impl Trignometric { + /// Creates a new sine function. + pub fn new_sine(coeff: Rational) -> Self { + todo!() + } + + /// Creates a new cosine function. + pub fn new_cosine(coeff: Rational) -> Self { + todo!() + } +} + +impl Differentiable for Trignometric { + fn diff(&self) -> Self { + todo!() + } +} + +/// Basic functions +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BaseFuncs { + /// Constant + Const(Rational), + /// Polynomial + Poly(SingletonPolynomial), + /// Exponential + Exp(Exp), + /// Trignometirc + Trig(Trignometric), +} + +impl Differentiable for BaseFuncs { + fn diff(&self) -> Self { + todo!() + } +} + +/// Complex functions. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ComplexFuncs { + /// Basic functions + Func(F), + /// Addition + Add(Box>, Box>), + /// Subtraction + Sub(Box>, Box>), + /// Multipliciation + Mul(Box>, Box>), + /// Division + Div(Box>, Box>), + /// Composition + Comp(Box>, Box>), +} + +impl Differentiable for Box { + fn diff(&self) -> Self { + todo!() + } +} + +impl Differentiable for ComplexFuncs { + fn diff(&self) -> Self { + todo!() + } +} + +/// Evaluate functions. +pub trait Evaluate { + /// Evaluate `self` at `x`. + fn evaluate(&self, x: f64) -> f64; +} + +impl Evaluate for Rational { + fn evaluate(&self, x: f64) -> f64 { + todo!() + } +} + +impl Evaluate for SingletonPolynomial { + fn evaluate(&self, x: f64) -> f64 { + todo!() + } +} + +impl Evaluate for Exp { + fn evaluate(&self, x: f64) -> f64 { + todo!() + } +} + +impl Evaluate for Trignometric { + fn evaluate(&self, x: f64) -> f64 { + todo!() + } +} + +impl Evaluate for BaseFuncs { + fn evaluate(&self, x: f64) -> f64 { + todo!() + } +} + +impl Evaluate for ComplexFuncs { + fn evaluate(&self, x: f64) -> f64 { + todo!() + } +} + +impl fmt::Display for Rational { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if *self == ZERO { + return write!(f, "0"); + } else if self.denominator == 1 { + return write!(f, "{}", self.numerator); + } + write!(f, "{}/{}", self.numerator, self.denominator) + } +} + +impl fmt::Display for SingletonPolynomial { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Const(r) => write!(f, "{r}"), + Self::Polynomial { coeff, power } => { + // coeff or power is zero + if *coeff == ZERO { + return write!(f, "0"); + } else if *power == ZERO { + return write!(f, "{coeff}"); + } + + // Standard form of px^q + let coeff = if *coeff == ONE { + "".to_string() + } else if *coeff == MINUS_ONE { + "-".to_string() + } else { + format!("({coeff})") + }; + let var = if *power == ONE { + "x".to_string() + } else { + format!("x^({power})") + }; + write!(f, "{coeff}{var}") + } + } + } +} + +impl fmt::Display for Exp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "exp(x)") + } +} + +impl fmt::Display for Trignometric { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (func, coeff) = match self { + Trignometric::Sine { coeff } => ("sin(x)", coeff), + Trignometric::Cosine { coeff } => ("cos(x)", coeff), + }; + + if *coeff == ZERO { + write!(f, "0") + } else if *coeff == ONE { + write!(f, "{func}") + } else if *coeff == MINUS_ONE { + write!(f, "-{func}") + } else { + write!(f, "({coeff}){func}") + } + } +} + +impl fmt::Display for BaseFuncs { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Const(r) => write!(f, "{r}"), + Self::Poly(p) => write!(f, "{p}"), + Self::Exp(e) => write!(f, "{e}"), + Self::Trig(t) => write!(f, "{t}"), + } + } +} + +impl fmt::Display for ComplexFuncs { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ComplexFuncs::Func(func) => write!(f, "{func}"), + ComplexFuncs::Add(l, r) => write!(f, "({l} + {r})"), + ComplexFuncs::Sub(l, r) => write!(f, "({l} - {r})"), + ComplexFuncs::Mul(l, r) => write!(f, "({l} * {r})"), + ComplexFuncs::Div(l, r) => write!(f, "({l} / {r})"), + ComplexFuncs::Comp(l, r) => write!(f, "({l} ∘ {r})"), + } + } +} diff --git a/src/assignments/assignment06/symbolic_differentiation_grade.rs b/src/assignments/assignment06/symbolic_differentiation_grade.rs new file mode 100644 index 0000000..0526219 --- /dev/null +++ b/src/assignments/assignment06/symbolic_differentiation_grade.rs @@ -0,0 +1,216 @@ +#[cfg(test)] +mod test { + use super::super::symbolic_differentiation::*; + use ntest::assert_about_eq; + + // Constant rationals to use + const TWO: Rational = Rational::new(2, 1); + const FOUR: Rational = Rational::new(4, 1); + const THIRD: Rational = Rational::new(1, 3); + const FIVE_THIRD: Rational = Rational::new(5, 3); + const TWO_SEVENTH: Rational = Rational::new(2, 7); + + #[test] + fn test_rational_simpl() { + assert_eq!(format!("{}", Rational::new(1, 2)), "1/2".to_string()); + + assert_eq!(format!("{}", Rational::new(0, 0)), "0".to_string()); + + assert_eq!(format!("{}", Rational::new(1, 1)), "1".to_string()); + + assert_eq!(format!("{}", Rational::new(-3, 7)), "-3/7".to_string()); + } + + #[test] + fn test_rational_arithmetic() { + assert_eq!( + format!("{}", Rational::new(1, 4) + Rational::new(3, 4)), + "1".to_string() + ); + + assert_eq!( + format!("{}", Rational::new(1, 3) + Rational::new(1, 6)), + "1/2".to_string() + ); + + assert_eq!( + format!("{}", Rational::new(1, 5) - Rational::new(1, 2)), + "-3/10".to_string() + ); + + assert_eq!( + format!("{}", Rational::new(-5, 12) * Rational::new(6, 125)), + "-1/50".to_string() + ); + + assert_eq!( + format!("{}", Rational::new(-3, 4) / Rational::new(-7, 13)), + "39/28".to_string() + ); + } + + #[test] + fn test_rational_arithmetic_long() { + assert_eq!( + format!( + "{}", + Rational::new(1, 2) + Rational::new(1, 2) + Rational::new(1, 2) + ), + "3/2".to_string() + ); + + assert_eq!( + format!( + "{}", + Rational::new(1, 2) - Rational::new(1, 4) + Rational::new(1, 5) + ), + "9/20".to_string() + ); + + assert_eq!( + format!( + "{}", + Rational::new(1, 2) + * Rational::new(1, 4) + * Rational::new(1, 8) + * Rational::new(1, 16) + / Rational::new(1, 1024) + ), + "1".to_string() + ); + + assert_eq!( + format!( + "{}", + Rational::new(123, 798) + + Rational::new(684, 32) / (Rational::new(13, 44) - Rational::new(123, 4472)) + * Rational::new(1237, 2) + ), + "12356494070/250439".to_string() + ); + } + + #[test] + fn test_differentiate_simple() { + // Constant + assert_eq!(format!("{}", Rational::new(3, 2).diff()), "0".to_string()); + + // Polynomials + assert_eq!( + format!("{}", SingletonPolynomial::new_c(Rational::new(3, 1)).diff()), + "0".to_string() + ); + assert_eq!( + format!("{}", SingletonPolynomial::new_poly(TWO, FOUR).diff()), + "(8)x^(3)".to_string() + ); + assert_eq!( + format!( + "{}", + SingletonPolynomial::new_poly(FIVE_THIRD, THIRD).diff() + ), + "(5/9)x^(-2/3)".to_string() + ); + + // Exponential + assert_eq!(format!("{}", Exp::new().diff()), "exp(x)".to_string()); + + // Trigonometric + assert_eq!( + format!("{}", Trignometric::new_sine(ONE).diff()), + "cos(x)".to_string() + ); + assert_eq!( + format!("{}", Trignometric::new_cosine(ONE).diff()), + "-sin(x)".to_string() + ); + assert_eq!( + format!("{}", Trignometric::new_sine(FIVE_THIRD).diff()), + "(5/3)cos(x)".to_string() + ); + assert_eq!( + format!("{}", Trignometric::new_cosine(TWO_SEVENTH).diff()), + "(-2/7)sin(x)".to_string() + ); + } + + #[test] + fn test_differentiate_complex() { + type BF = BaseFuncs; + type CF = ComplexFuncs; + + // Unlike the above simple test, it is hard to state a canonical + // form for derivative of more complex functions. Thus, we only test that the + // derivative is correct at certain points. + + // Add + // + // d/dx (2x^4 + exp(x)) = 8x^3 + exp(x) + let f1 = SingletonPolynomial::new_poly(TWO, FOUR); + let f2 = Exp::new(); + let deriv = CF::Add( + Box::new(CF::Func(BF::Poly(f1))), + Box::new(CF::Func(BF::Exp(f2))), + ) + .diff(); + assert_about_eq!(deriv.evaluate(2.2), 94.2090134994f64); + assert_about_eq!(deriv.evaluate(4.5), 819.017131301); + + // Sub + // + // d/dx ((5/3)cos(x) - sin(x)) = (-5/3)sin(x) - cos(x) + let f1 = Trignometric::new_cosine(FIVE_THIRD); + let f2 = Trignometric::new_sine(ONE); + let deriv = CF::Sub( + Box::new(CF::Func(BF::Trig(f1))), + Box::new(CF::Func(BF::Trig(f2))), + ) + .diff(); + assert_about_eq!(deriv.evaluate(2.7), 0.191772341627); + assert_about_eq!(deriv.evaluate(0.01), -1.01661638931); + + // Mult + // + // d/dx (2x^4 * cos(x) * exp(x)) = + // 8x^2 * cos(x) * exp(x) - 2x^4 * sin(x) * exp(x) + 2x^4 * cos(x) * exp(x) + let f1 = SingletonPolynomial::new_poly(TWO, FOUR); + let f2 = Trignometric::new_cosine(ONE); + let f3 = Exp::new(); + let deriv = CF::Mul( + Box::new(CF::Func(BF::Poly(f1))), + Box::new(CF::Mul( + Box::new(CF::Func(BF::Trig(f2))), + Box::new(CF::Func(BF::Exp(f3))), + )), + ) + .diff(); + assert_about_eq!(deriv.evaluate(3.4), -14804.9016757); + assert_about_eq!(deriv.evaluate(0.07), 0.00298352866); + + // Div + // + // (d/dx) (sin(x)/cos(x)) = (cos(x)*cos(x) + sin(x)*sin(x)) / cos(x)*cos(x) + let f1 = Trignometric::new_sine(ONE); + let f2 = Trignometric::new_cosine(ONE); + let deriv = CF::Div( + Box::new(CF::Func(BF::Trig(f1))), + Box::new(CF::Func(BF::Trig(f2))), + ) + .diff(); + assert_about_eq!(deriv.evaluate(core::f64::consts::PI), 1f64); + assert_about_eq!(deriv.evaluate(0f64), 1f64); + + // Comp + // + // d/dx (cos(x^2)) = -2x * sin(x^2) + let f1 = Trignometric::new_cosine(ONE); + let f2 = SingletonPolynomial::new_poly(ONE, TWO); + let deriv = CF::Comp( + Box::new(CF::Func(BF::Trig(f1))), + Box::new(CF::Func(BF::Poly(f2))), + ) + .diff(); + assert_about_eq!(deriv.evaluate(2.714), -4.79392977); + assert_about_eq!(deriv.evaluate(3.9), -3.72556973); + } +} diff --git a/src/assignments/assignment07/generator.rs b/src/assignments/assignment07/generator.rs new file mode 100644 index 0000000..fb0243b --- /dev/null +++ b/src/assignments/assignment07/generator.rs @@ -0,0 +1,36 @@ +//! Generators + +enum Yielded { + Value(T), + Stop, +} + +/// Generator +/// +/// Reference: +/// - [Python generator](https://python-reference.readthedocs.io/en/latest/docs/generator/) +#[allow(missing_debug_implementations)] +pub struct Generator { + state: S, + f: fn(&mut S) -> Yielded, +} + +impl Iterator for Generator { + type Item = T; + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Returns a generator that yields fibonacci numbers. +pub fn fib_generator(first: usize, second: usize) -> Generator { + todo!() +} + +/// Returns a generator that yields collatz numbers. +/// +/// The generator stops when it reaches to 1. +pub fn collatz_conjecture(start: usize) -> Generator { + todo!() +} diff --git a/src/assignments/assignment07/generator_grade.rs b/src/assignments/assignment07/generator_grade.rs new file mode 100644 index 0000000..5ff51d7 --- /dev/null +++ b/src/assignments/assignment07/generator_grade.rs @@ -0,0 +1,38 @@ +#[cfg(test)] +mod test { + use itertools::Itertools; + use ntest::assert_about_eq; + + use super::super::generator::*; + + #[test] + fn test_generator() { + assert_eq!( + fib_generator(0, 1).take(10).collect::>(), + vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34] + ); + + assert_eq!( + collatz_conjecture(12).collect::>(), + vec![12, 6, 3, 10, 5, 16, 8, 4, 2, 1] + ); + + assert_eq!( + collatz_conjecture(19).collect::>(), + vec![19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1] + ); + + assert_eq!( + collatz_conjecture(27).collect::>(), + vec![ + 27, 82, 41, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364, + 182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790, + 395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566, + 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, + 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, + 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, + 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1 + ] + ); + } +} diff --git a/src/assignments/assignment07/hubo.rs b/src/assignments/assignment07/hubo.rs new file mode 100644 index 0000000..581cea9 --- /dev/null +++ b/src/assignments/assignment07/hubo.rs @@ -0,0 +1,84 @@ +//! Hubo is back! + +/// Types that represent a direction. +pub trait Direction { + /// Get the direction in the form of a 2-dimensional vector. + /// The resulting value doesn't have to be normalized. + fn get_vector(&self) -> (f32, f32); +} + +/// 4-way enum to indicate directions. +#[derive(Debug)] +pub enum Dir4 { + /// +x direction + Right, + /// -x direction + Left, + /// +y direction + Up, + /// -y direction + Down, +} + +impl Direction for Dir4 { + fn get_vector(&self) -> (f32, f32) { + todo!() + } +} + +impl Direction for (f32, f32) { + fn get_vector(&self) -> (f32, f32) { + todo!() + } +} + +/// Hubo. +/// It's direction can be represented by an arbitrary type. +/// +/// It can be controlled by [HuboController] only if the direction type implements the [Direction] trait. +#[derive(Debug)] +pub struct Hubo { + direction: TDir, + x: f32, + y: f32, +} + +/// Controller of the Hubo +#[derive(Debug)] +pub struct HuboController<'s, TDir> { + hubo: &'s mut Hubo, +} + +impl Hubo { + /// Create a Hubo. + pub fn new(direction: TDir, x: f32, y: f32) -> Self { + Self { direction, x, y } + } + + /// Return the current position of Hubo. + pub fn get_position(&self) -> (f32, f32) { + (self.x, self.y) + } +} + +impl<'s, TDir: Direction> HuboController<'s, TDir> { + /// Return the controller of the given Hubo. + /// Note that the lifetime of hubo's mutable reference \['s\] is repeated in the return type. + /// + /// This represents that the controller cannot live longer than the mutable reference, + /// since the controller takes and stores the reference. + pub fn new(hubo: &'s mut Hubo) -> HuboController<'s, TDir> { + todo!() + } + + /// Make Hubo move forward by the given distance. You might need to normalize the vector + /// acquired from `Direction::get_move_vector`. + pub fn move_hubo_forward(&mut self, distance: f32) { + todo!() + } + + /// Make Hubo turn to the given direction. + pub fn set_hubo_direction(&mut self, dir: TDir) { + todo!() + } +} diff --git a/src/assignments/assignment07/hubo_grade.rs b/src/assignments/assignment07/hubo_grade.rs new file mode 100644 index 0000000..50a636a --- /dev/null +++ b/src/assignments/assignment07/hubo_grade.rs @@ -0,0 +1,40 @@ +#[cfg(test)] +mod test { + use itertools::Itertools; + use ntest::assert_about_eq; + + use super::super::hubo::*; + + #[test] + fn test_hubo_dir4_movement() { + let mut hubo = Hubo::new(Dir4::Right, 0.0, 0.0); + let mut controller = HuboController::new(&mut hubo); + + // Test moving forward + controller.move_hubo_forward(5.0); + + controller.set_hubo_direction(Dir4::Up); + controller.move_hubo_forward(3.0); + + controller.set_hubo_direction(Dir4::Left); + controller.move_hubo_forward(2.0); + + assert_eq!(hubo.get_position(), (3.0, 3.0)); + } + + #[test] + fn test_hubo_tuple_movement() { + let mut hubo = Hubo::new((1., 0.), 0.0, 0.0); + let mut controller = HuboController::new(&mut hubo); + + // Test moving forward + controller.move_hubo_forward(5.0); + + controller.set_hubo_direction((3., 4.)); + controller.move_hubo_forward(5.0); + + controller.set_hubo_direction((-8., -6.)); + controller.move_hubo_forward(15.0); + assert_eq!(hubo.get_position(), (-4., -5.)); + } +} diff --git a/src/assignments/assignment07/mod.rs b/src/assignments/assignment07/mod.rs new file mode 100644 index 0000000..87c48ed --- /dev/null +++ b/src/assignments/assignment07/mod.rs @@ -0,0 +1,18 @@ +//! Assignment 7: Mastering advanced types (2/2). +//! +//! The primary goal of this assignment is to understand generics, traits, and lifetimes. +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-07.sh` works fine. +//! See `assignment07_grade.rs` and `/scripts/grade-07.sh` for the test script. + +pub mod generator; +pub mod hubo; +pub mod my_itertools; +pub mod small_exercises; +pub mod transform; + +mod generator_grade; +mod hubo_grade; +mod my_itertools_grade; +mod small_exercises_grade; +mod transform_grade; diff --git a/src/assignments/assignment07/my_itertools.rs b/src/assignments/assignment07/my_itertools.rs new file mode 100644 index 0000000..9e2efcf --- /dev/null +++ b/src/assignments/assignment07/my_itertools.rs @@ -0,0 +1,117 @@ +//! Implement your own minimal `itertools` crate. + +use std::hash::Hash; + +/// Iterator that iterates over the given iterator and returns only unique elements. +#[allow(missing_debug_implementations)] +pub struct Unique { + // TODO: remove `_marker` and add necessary fields as you want + _marker: std::marker::PhantomData, +} + +impl Iterator for Unique +where + I::Item: Eq + Hash + Clone, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Iterator that chains two iterators together. +#[allow(missing_debug_implementations)] +pub struct Chain { + // TODO: remove `_marker` and add necessary fields as you want + _marker: std::marker::PhantomData<(I1, I2)>, +} + +impl, I2: Iterator> Iterator + for Chain +{ + type Item = T; + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Iterator that iterates over given iterator and enumerates each element. +#[allow(missing_debug_implementations)] +pub struct Enumerate { + // TODO: remove `_marker` and add necessary fields as you want + _marker: std::marker::PhantomData, +} + +impl Iterator for Enumerate { + type Item = (usize, I::Item); + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Iterator that zips two iterators together. +/// +/// If one iterator is longer than the other one, the remaining elements for the longer element +/// should be ignored. +#[allow(missing_debug_implementations)] +pub struct Zip { + // TODO: remove `_marker` and add necessary fields as you want + _marker: std::marker::PhantomData<(I1, I2)>, +} + +impl Iterator for Zip { + type Item = (I1::Item, I2::Item); + + fn next(&mut self) -> Option { + todo!() + } +} + +/// My Itertools trait. +pub trait MyIterTools: Iterator { + /// Returns an iterator that iterates over the `self` and returns only unique elements. + fn my_unique(self) -> Unique + where + Self: Sized, + { + todo!() + } + + /// Returns an iterator that chains `self` and `other` together. + fn my_chain(self, other: I) -> Chain + where + Self: Sized, + { + todo!() + } + + /// Returns an iterator that iterates over `self` and enumerates each element. + fn my_enumerate(self) -> Enumerate + where + Self: Sized, + { + todo!() + } + + /// Returns an iterator that zips `self` and `other` together. + fn my_zip(self, other: I) -> Zip + where + Self: Sized, + { + todo!() + } + + /// Foldleft for `MyIterTools` + fn my_fold(mut self, init: T, mut f: F) -> T + where + Self: Sized, + F: FnMut(Self::Item, T) -> T, + { + todo!() + } +} + +impl MyIterTools for T where T: Iterator {} diff --git a/src/assignments/assignment07/my_itertools_grade.rs b/src/assignments/assignment07/my_itertools_grade.rs new file mode 100644 index 0000000..9e9e061 --- /dev/null +++ b/src/assignments/assignment07/my_itertools_grade.rs @@ -0,0 +1,65 @@ +#[cfg(test)] +mod test { + use itertools::Itertools; + use ntest::assert_about_eq; + + use super::super::my_itertools::*; + + #[test] + fn test_itertools() { + assert_eq!( + [10, 1, 1, 1, 2, 3, 4, 1, 3, 2] + .into_iter() + .my_chain(std::iter::repeat(100)) + .my_unique() + .take(4) + .collect::>(), + vec![10, 1, 2, 3] + ); + + assert_eq!( + std::iter::repeat(5) + .my_enumerate() + .map(|(i, e)| { i * e }) + .take(5) + .collect::>(), + vec![0, 5, 10, 15, 20] + ); + + assert_eq!( + vec![0, 1, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,], + [0, 1, 10].into_iter().my_chain(0..10).collect::>(), + ); + + let it = || (1..=5).cycle().my_zip((1..=3).cycle()).map(|(x, y)| x * y); + let take15 = vec![ + 2, // 1 * 1, + 4, // 2 * 2, + 9, // 3 * 3, + 4, // 4 * 1, + 10, // 5 * 2, + 3, // 1 * 3, + 2, // 2 * 1, + 6, // 3 * 2, + 12, // 4 * 3, + 5, // 5 * 1, + 2, // 1 * 2, + 6, // 2 * 3, + 3, // 3 * 1, + 8, // 4 * 2, + 15, // 5 * 3, + ]; + + assert_eq!( + // 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 + // 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 + it().take(15).collect::>(), + take15 + ); + + assert_eq!( + it().take(15).my_fold(0, |elt, acc| elt + acc), + take15.iter().sum() + ); + } +} diff --git a/src/assignments/assignment07/small_exercises.rs b/src/assignments/assignment07/small_exercises.rs new file mode 100644 index 0000000..86c5661 --- /dev/null +++ b/src/assignments/assignment07/small_exercises.rs @@ -0,0 +1,119 @@ +//! Implement functions usint `Iterator` trait + +struct FindIter<'s, T: Eq> { + query: &'s [T], + base: &'s [T], + curr: usize, +} + +impl Iterator for FindIter<'_, T> { + type Item = usize; + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Returns an iterator over substring query indexes in the base. +pub fn find<'s, T: Eq>(query: &'s [T], base: &'s [T]) -> impl 's + Iterator { + FindIter { + query, + base, + curr: 0, + } +} + +/// Implement fibonacci iterator +struct FibIter { + // TODO: remove `_marker` and add necessary fields as you want + _marker: std::marker::PhantomData, +} + +impl + Copy> FibIter { + fn new(first: T, second: T) -> Self { + todo!() + } +} + +impl Iterator for FibIter +where + T: std::ops::Add + Copy, +{ + type Item = T; + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Returns and iterator over the generic fibonacci sequence starting from `first` and `second`. +/// This is a generic version of `fibonacci` function, which works for any types that implements `std::ops::Add` trait. +pub fn fib(first: T, second: T) -> impl Iterator +where + T: std::ops::Add + Copy, +{ + todo!("remove below"); + std::iter::empty() +} + +/// Endpoint of range, inclusive or exclusive. +#[derive(Debug)] +pub enum Endpoint { + /// Inclusive endpoint + Inclusive(isize), + + /// Exclusive endpoint + Exclusive(isize), +} + +struct RangeIter { + // TODO: add necessary fields as you want +} + +impl RangeIter { + fn new(endpoints: (Endpoint, Endpoint), step: isize) -> Self { + todo!() + } +} + +impl Iterator for RangeIter { + type Item = isize; + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Returns an iterator over the range [left, right) with the given step. +pub fn range(left: Endpoint, right: Endpoint, step: isize) -> impl Iterator { + todo!("remove below"); + std::iter::empty() +} + +/// Write an iterator that returns all divisors of n in increasing order. +/// Assume n > 0. +/// +/// Hint: trying all candidates from 1 to n will most likely time out! +/// To optimize it, make use of the following fact: +/// if x is a divisor of n that is greater than sqrt(n), +/// then n/x is a divisor of n that is smaller than sqrt(n). +struct Divisors { + n: u64, + // TODO: you may define additional fields here +} + +impl Iterator for Divisors { + type Item = u64; + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Returns an iterator over the divisors of n. +pub fn divisors(n: u64) -> impl Iterator { + Divisors { + n, + // TODO: you may define additional fields here + } +} diff --git a/src/assignments/assignment07/small_exercises_grade.rs b/src/assignments/assignment07/small_exercises_grade.rs new file mode 100644 index 0000000..fced451 --- /dev/null +++ b/src/assignments/assignment07/small_exercises_grade.rs @@ -0,0 +1,189 @@ +#[cfg(test)] +mod test { + use itertools::Itertools; + use ntest::assert_about_eq; + + use super::super::small_exercises::*; + + #[test] + fn test_find() { + assert_eq!( + find("abc".as_bytes(), "abcdabcd".as_bytes()).collect::>(), + vec![0, 4] + ); + + assert_eq!( + find("aaba".as_bytes(), "aabaacaadaabaaba".as_bytes()).collect::>(), + vec![0, 9, 12] + ); + + assert_eq!( + find("ababac".as_bytes(), "abababcabababcabababc".as_bytes()).collect::>(), + vec![] + ); + + assert_eq!( + find("ababc".as_bytes(), "abc".as_bytes()).collect::>(), + vec![] + ); + } + + #[test] + fn test_find_usize() { + assert_eq!( + find(&[1, 2, 3], &[1, 2, 3, 4, 1, 2, 3, 4]).collect::>(), + vec![0, 4] + ); + + assert_eq!( + find( + &[5, 5, 7, 5], + &[5, 5, 7, 5, 5, 8, 5, 5, 9, 5, 5, 7, 5, 5, 7, 5] + ) + .collect::>(), + vec![0, 9, 12] + ); + } + + #[test] + fn test_fib_iter() { + assert_eq!( + fib(0, 1).take(10).collect::>(), + vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34] + ); + + #[derive(Debug, PartialEq, Eq, Clone, Copy)] + struct Rgb(u8, u8, u8); + + impl std::ops::Add for Rgb { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self( + ((self.0 as u16 + rhs.0 as u16) / 2) as u8, + ((self.1 as u16 + rhs.1 as u16) / 2) as u8, + ((self.2 as u16 + rhs.2 as u16) / 2) as u8, + ) + } + } + + assert_eq!( + fib(Rgb(255, 0, 100), Rgb(1, 128, 0)) + .take(20) + .collect::>(), + vec![ + Rgb(255, 0, 100), + Rgb(1, 128, 0), + Rgb(128, 64, 50), + Rgb(64, 96, 25), + Rgb(96, 80, 37), + Rgb(80, 88, 31), + Rgb(88, 84, 34), + Rgb(84, 86, 32), + Rgb(86, 85, 33), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32), + Rgb(85, 85, 32) + ] + ); + } + + #[test] + fn test_range_iter() { + let one_to_tens = vec![ + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + range(Endpoint::Inclusive(1), Endpoint::Inclusive(10), 1).collect(), + range(Endpoint::Exclusive(0), Endpoint::Inclusive(10), 1).collect(), + range(Endpoint::Inclusive(1), Endpoint::Exclusive(11), 1).collect(), + range(Endpoint::Exclusive(0), Endpoint::Exclusive(11), 1).collect(), + ]; + assert!(one_to_tens.iter().all_equal()); + + let ten_to_ones = vec![ + vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1], + range(Endpoint::Inclusive(10), Endpoint::Inclusive(1), -1).collect(), + range(Endpoint::Exclusive(11), Endpoint::Inclusive(1), -1).collect(), + range(Endpoint::Inclusive(10), Endpoint::Exclusive(0), -1).collect(), + range(Endpoint::Exclusive(11), Endpoint::Exclusive(0), -1).collect(), + ]; + assert!(ten_to_ones.iter().all_equal()); + + let five_evens = vec![ + vec![2, 4, 6, 8, 10], + range(Endpoint::Inclusive(2), Endpoint::Inclusive(10), 2).collect(), + range(Endpoint::Inclusive(2), Endpoint::Inclusive(11), 2).collect(), + range(Endpoint::Exclusive(1), Endpoint::Inclusive(10), 2).collect(), + range(Endpoint::Exclusive(1), Endpoint::Inclusive(11), 2).collect(), + range(Endpoint::Inclusive(2), Endpoint::Exclusive(11), 2).collect(), + range(Endpoint::Inclusive(2), Endpoint::Exclusive(12), 2).collect(), + range(Endpoint::Exclusive(1), Endpoint::Exclusive(11), 2).collect(), + range(Endpoint::Exclusive(1), Endpoint::Exclusive(12), 2).collect(), + ]; + assert!(five_evens.iter().all_equal()); + + let emptys = vec![ + vec![], + range(Endpoint::Inclusive(2), Endpoint::Inclusive(10), -1).collect(), + range(Endpoint::Inclusive(10), Endpoint::Inclusive(-100), 1).collect(), + range(Endpoint::Inclusive(1), Endpoint::Exclusive(1), 1).collect(), + ]; + assert!(emptys.iter().all_equal()); + } + + #[test] + fn test_small() { + assert_eq!(divisors(10).collect::>(), vec![1, 2, 5, 10]); + + assert_eq!(divisors(17).collect::>(), vec![1, 17]); + + assert_eq!(divisors(49).collect::>(), vec![1, 7, 49]); + + assert_eq!( + divisors(120).collect::>(), + vec![1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60, 120] + ); + + assert_eq!(divisors(1).collect::>(), vec![1]); + + assert_eq!(divisors(2).collect::>(), vec![1, 2]); + + assert_eq!(divisors(3).collect::>(), vec![1, 3]); + } + + #[test] + fn test_large() { + assert_eq!( + divisors(1_000_000_000_000_037).collect::>(), + vec![1, 1_000_000_000_000_037] + ); + + assert_eq!( + divisors(99_999_820_000_081).collect::>(), + vec![1, 9_999_991, 99_999_820_000_081] + ); + + assert_eq!( + divisors(1_234_567_890_123).collect::>(), + vec![ + 1, + 3, + 3_541, + 10_623, + 116_216_501, + 348_649_503, + 411_522_630_041, + 1_234_567_890_123 + ] + ); + + assert_eq!(divisors(97_821_761_637_600).count(), 17280); + } +} diff --git a/src/assignments/assignment07/transform.rs b/src/assignments/assignment07/transform.rs new file mode 100644 index 0000000..e24588d --- /dev/null +++ b/src/assignments/assignment07/transform.rs @@ -0,0 +1,95 @@ +//! Tranformer +use std::marker::PhantomData; +use std::ops::Add; + +/// Represents transformation of type `T`. +pub trait Transform { + /// Transforms value. + fn transform(&self, value: T) -> T; +} + +impl, Tr2: Transform> Transform<(T1, T2)> for (Tr1, Tr2) { + fn transform(&self, value: (T1, T2)) -> (T1, T2) { + todo!() + } +} + +/// Identity transformation. +#[derive(Debug, Clone, Copy)] +pub struct Identity; + +impl Transform for Identity { + fn transform(&self, value: T) -> T { + todo!() + } +} + +/// Custom transformation. +#[derive(Debug, Clone, Copy)] +pub struct Custom T> { + f: F, + _marker: PhantomData, +} + +impl T> From for Custom { + fn from(f: F) -> Self { + Self { + f, + _marker: PhantomData, + } + } +} + +impl T> Transform for Custom { + fn transform(&self, value: T) -> T { + todo!() + } +} + +/// Repeats transformation for `n` times. +#[derive(Debug, Clone, Copy)] +pub struct Repeat> { + inner: Tr, + n: u32, + _marker: PhantomData, +} + +impl> Repeat { + /// Creates a new repeat transformation. + pub fn new(inner: Tr, n: u32) -> Self { + Repeat { + inner, + n, + _marker: PhantomData, + } + } +} + +impl> Transform for Repeat { + fn transform(&self, mut value: T) -> T { + todo!() + } +} + +/// Repeats transformation until converges. +#[derive(Debug, Clone, Copy)] +pub struct RepeatUntilConverge> { + inner: Tr, + _marker: PhantomData, +} + +impl> RepeatUntilConverge { + /// Creates a new repeat transformation. + pub fn new(inner: Tr) -> Self { + RepeatUntilConverge { + inner, + _marker: PhantomData, + } + } +} + +impl> Transform for RepeatUntilConverge { + fn transform(&self, mut value: T) -> T { + todo!() + } +} diff --git a/src/assignments/assignment07/transform_grade.rs b/src/assignments/assignment07/transform_grade.rs new file mode 100644 index 0000000..7fb7870 --- /dev/null +++ b/src/assignments/assignment07/transform_grade.rs @@ -0,0 +1,62 @@ +#[cfg(test)] +mod test { + use itertools::Itertools; + use ntest::assert_about_eq; + + use super::super::transform::*; + + #[test] + fn test_transform_identity() { + let tr = Identity; + + assert_eq!(tr.transform(3), 3); + assert_eq!(tr.transform(3.0), 3.0); + assert_eq!(tr.transform("abc"), "abc"); + } + + #[test] + fn test_transform_tuple() { + let f1 = |x: u32| x + 1; + let f2 = |x: String| x.clone() + &x; + + let tr1: Custom<_, _> = f1.into(); + let tr2: Custom<_, _> = f2.into(); + + let list1 = 0u32..10u32; + let list2 = ["a".to_string(), "bb".to_string(), "ccc".to_string()]; + + for v1 in list1 { + for v2 in list2.clone() { + let tr = (tr1, tr2.clone()); + let input = (v1, v2.clone()); + let expected = (f1(v1), f2(v2)); + assert_eq!(tr.transform(input), expected); + } + } + } + + #[test] + fn test_transform_repeat() { + let inc = Custom::from(|x: i32| x + 1); + let dec = Custom::from(|x: i32| x - 1); + + for i in 0..10 { + for j in -10..10 { + assert_eq!(Repeat::new(inc, i as u32).transform(j), j + i); + assert_eq!(Repeat::new(dec, i as u32).transform(j), j - i); + } + } + } + + #[test] + fn test_transform_repeat_until_converge() { + let inc = Custom::from(|x: i32| if x < 50 { x + 1 } else { x }); + let dec = Custom::from(|x: i32| if x > 50 { x - 1 } else { x }); + + assert_eq!(RepeatUntilConverge::new(inc).transform(40), 50); + assert_eq!(RepeatUntilConverge::new(inc).transform(60), 60); + + assert_eq!(RepeatUntilConverge::new(dec).transform(40), 40); + assert_eq!(RepeatUntilConverge::new(dec).transform(60), 50); + } +} diff --git a/src/assignments/assignment09/bigint.rs b/src/assignments/assignment09/bigint.rs new file mode 100644 index 0000000..1c1db51 --- /dev/null +++ b/src/assignments/assignment09/bigint.rs @@ -0,0 +1,94 @@ +//! Big integer with infinite precision. + +use std::fmt; +use std::{iter::zip, ops::*}; + +/// An signed integer with infinite precision implemented with an "carrier" vector of `u32`s. +/// +/// The vector is interpreted as a base 2^(32 * (len(carrier) - 1)) integer, where negative +/// integers are represented in their [2's complement form](https://en.wikipedia.org/wiki/Two%27s_complement). +/// +/// For example, the vector `vec![44,345,3]` represents the integer +/// `44 * (2^32)^2 + 345 * (2^32) + 3`, +/// and the vector `vec![u32::MAX - 5, u32::MAX - 7]` represents the integer +/// `- (5 * 2^32 + 8) +/// +/// You will implement the `Add` and `Sub` trait for this type. +/// +/// Unlike standard fix-sized intergers in Rust where overflow will panic, the carrier is extended to save the overflowed bit. +/// On the contrary, if the precision is too much (e.g, vec![0,0] is used to represent 0, where `vec![0]` is sufficent), the carrier is truncated. +/// +/// See [this section](https://en.wikipedia.org/wiki/Two%27s_complement#Arithmetic_operations) for a rouge guide on implementation, +/// while keeping in mind that the carrier should be extended to deal with overflow. +/// +/// The `sign_extension()`, `two_complement()`, and `truncate()` are non-mandatory helper methods. +/// +/// For testing and debugging pruposes, the `Display` trait is implemented for you, which shows the integer in hexadecimal form. +#[derive(Debug, Clone)] +pub struct BigInt { + /// The carrier for `BigInt`. + /// + /// Note that the carrier should always be non-empty. + pub carrier: Vec, +} + +impl BigInt { + /// Create a new `BigInt` from a `usize`. + pub fn new(n: u32) -> Self { + todo!() + } + + /// Creates a new `BigInt` from a `Vec`. + /// + /// # Panic + /// + /// Panics if `carrier` is empty. + pub fn new_large(carrier: Vec) -> Self { + todo!() + } +} + +const SIGN_MASK: u32 = 1 << 31; + +impl BigInt { + /// Extend `self` to `len` bits. + fn sign_extension(&self, len: usize) -> Self { + todo!() + } + + /// Compute the two's complement of `self`. + fn two_complement(&self) -> Self { + todo!() + } + + /// Truncate a `BigInt` to the minimum length. + fn truncate(&self) -> Self { + todo!() + } +} + +impl Add for BigInt { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl Sub for BigInt { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl fmt::Display for BigInt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Hex formatting so that each u32 can be formatted independently. + for i in self.carrier.iter() { + write!(f, "{:08x}", i)?; + } + Ok(()) + } +} diff --git a/src/assignments/assignment09/bigint_grade.rs b/src/assignments/assignment09/bigint_grade.rs new file mode 100644 index 0000000..a707026 --- /dev/null +++ b/src/assignments/assignment09/bigint_grade.rs @@ -0,0 +1,104 @@ +#[cfg(test)] +mod test { + + use ntest::{assert_false, assert_true}; + + use super::super::bigint::*; + + #[test] + fn test_inf_prec_simple() { + // Basic + assert_eq!("00000000", format!("{}", BigInt::new(0))); + assert_eq!("ffffffff", format!("{}", BigInt::new(u32::MAX))); + assert_eq!("00bc4fdc", format!("{}", BigInt::new(12_341_212))); + assert_eq!("fffffed8", format!("{}", BigInt::new(4_294_967_000u32))); + + // Add Basic + assert_eq!("00000001", format!("{}", BigInt::new(0) + BigInt::new(1))); + + assert_eq!( + "0df655df", + format!("{}", BigInt::new(13_413) + BigInt::new(234_234_234)) + ); + + assert_eq!( + "ffffff03", + format!("{}", BigInt::new(4_294_967_000u32) + BigInt::new(43)) + ); + + // Sub Basic + assert_eq!("ffffffff", format!("{}", BigInt::new(0) - BigInt::new(1))); + + assert_eq!( + "f20a12eb", + format!("{}", BigInt::new(13_413) - BigInt::new(234_234_234)) + ); + + assert_eq!( + "fffffead", + format!("{}", BigInt::new(4_294_967_000u32) - BigInt::new(43)) + ); + } + + #[test] + #[should_panic] + fn test_inf_prec_panic() { + let _ = BigInt::new_large(vec![]); + } + + #[test] + fn test_inf_prec_complex() { + // Positive overflow + assert_eq!( + "0000000080000000", + format!("{}", BigInt::new(i32::MAX as u32) + BigInt::new(1)) + ); + + // Negative overflow + assert_eq!( + "ffffffff7fffffff", + format!("{}", BigInt::new(i32::MIN as u32) - BigInt::new(1)) + ); + + // Larger positive overflow + assert_eq!( + "00000000fffffffe00000000", + format!( + "{}", + BigInt::new_large(vec![i32::MAX as u32, 0]) + + BigInt::new_large(vec![i32::MAX as u32, 0]) + ) + ); + + // Smaller negative overflow + assert_eq!( + "ffffffff000000000119464a", + format!( + "{}", + BigInt::new_large(vec![i32::MIN as u32, 2_871_572]) + + BigInt::new_large(vec![i32::MIN as u32, 15_562_038]) + ) + ); + + // Truncate + assert_eq!( + "00000000", + format!( + "{}", + BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456]) + - BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456]) + ) + ); + + assert_eq!( + "ffffffff", + format!( + "{}", + BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_456]) + - BigInt::new_large(vec![i32::MIN as u32, 2_871_572, 123_457]) + ) + ); + + // TODO: add a test case testing sign extension. + } +} diff --git a/src/assignments/assignment09/mod.rs b/src/assignments/assignment09/mod.rs new file mode 100644 index 0000000..d82be95 --- /dev/null +++ b/src/assignments/assignment09/mod.rs @@ -0,0 +1,12 @@ +//! Assignment 9: Iterators (1/2). +//! +//! The primary goal of this assignment is to get used to iterators. +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-09.sh` works fine. +//! See `assignment09_grade.rs` and `/scripts/grade-09.sh` for the test script. + +pub mod bigint; +pub mod small_exercises; + +mod bigint_grade; +mod small_exercises_grade; diff --git a/src/assignments/assignment09/small_exercises.rs b/src/assignments/assignment09/small_exercises.rs new file mode 100644 index 0000000..b2950a4 --- /dev/null +++ b/src/assignments/assignment09/small_exercises.rs @@ -0,0 +1,211 @@ +//! Small exercises. + +use std::collections::HashMap; + +/// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's first two terms. +/// +/// Returns `true` if the length of sequence is less or equal than 2. +/// +/// # Exmample +/// +/// ``` +/// use cs220::assignments::assignment09::is_fibonacci; +/// +/// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 13].into_iter()), true); +/// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter()), false); +/// ``` +pub fn is_fibonacci(inner: impl Iterator) -> bool { + todo!() +} + +/// Returns the sum of `f(v)` for all element `v` the given array. +/// +/// # Exmaple +/// +/// ``` +/// use cs220::assignments::assignment09::sigma; +/// +/// assert_eq!(sigma([1, 2].into_iter(), |x| x + 2), 7); +/// assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); +/// ``` +pub fn sigma i64>(inner: impl Iterator, f: F) -> i64 { + todo!() +} + +/// Alternate elements from three iterators until they have run out. +/// +/// You can assume that the number of elements of three iterators are same. +/// +/// # Example +/// +/// ``` +/// use cs220::assignments::assignment09::interleave3; +/// +/// assert_eq!( +/// interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), +/// vec![1, 3, 5, 2, 4, 6] +/// ); +/// ``` +pub fn interleave3( + list1: impl Iterator, + list2: impl Iterator, + list3: impl Iterator, +) -> Vec { + todo!() +} + +/// Alternate elements from array of n iterators until they have run out. +/// +/// You can assume that the number of elements of iterators are same. +/// +/// # Example +/// +/// ``` +/// use cs220::assignments::assignment09::interleave_n; +/// +/// assert_eq!( +/// interleave_n(&mut [[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]), +/// vec![1, 3, 5, 2, 4, 6] +/// ); +/// ``` +pub fn interleave_n( + mut iters: [impl Iterator; N], +) -> impl Iterator { + todo!(); + std::iter::empty() +} + +/// Returns mean of k smallest value's mean. +/// +/// # Example +/// +/// ``` +/// use cs220::assignments::assignment09::k_smallest_mean; +/// +/// assert_eq!( +/// k_smallest_mean(vec![1, 3, 2].into_iter(), 2), +/// ((1 + 2) as f64 / 2.0) +/// ); +/// assert_eq!( +/// k_smallest_mean(vec![7, 5, 3, 6].into_iter(), 3), +/// ((3 + 5 + 6) as f64 / 3.0) +/// ); +/// ``` +pub fn k_smallest_mean(inner: impl Iterator, k: usize) -> f64 { + todo!() +} + +/// Returns mean for each class. +/// +/// # Exmaple +/// +/// ``` +/// use cs220::assignments::assignment09::calculate_mean; +/// +/// assert_eq!( +/// calculate_mean( +/// [ +/// ("CS100".to_string(), 60), +/// ("CS200".to_string(), 60), +/// ("CS200".to_string(), 80), +/// ("CS300".to_string(), 100), +/// ] +/// .into_iter() +/// ), +/// [ +/// ("CS100".to_string(), 60.0), +/// ("CS200".to_string(), 70.0), +/// ("CS300".to_string(), 100.0) +/// ] +/// .into_iter() +/// .collect() +/// ); +/// ``` +pub fn calculate_mean(inner: impl Iterator) -> HashMap { + todo!() +} + +/// Among the cartesian product of input vectors, return the number of sets whose sum equals `n`. +/// +/// # Example +/// +/// The cartesian product of [1, 2, 3] and [2, 3] are: +/// [1, 2], [1, 3], [2, 2], [2, 3], [3, 2], [3, 3]. +/// +/// Among these sets, the number of sets whose sum is 4 is 2, which is [1, 3] and [2, 2]. +/// +/// ``` +/// use cs220::assignments::assignment09::sum_is_n; +/// +/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1); +/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2); +/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 5), 2); +/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 6), 1); +/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 2), 0); +/// ``` +pub fn sum_is_n(inner: Vec>, n: i64) -> usize { + todo!() +} + +/// Returns a new vector that contains the item that appears `n` times in the input vector in increasing order. +/// +/// # Example +/// +/// ``` +/// use cs220::assignments::assignment09::find_count_n; +/// +/// assert_eq!(find_count_n(vec![1, 2], 1), vec![1, 2]); +/// assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); +/// assert_eq!(find_count_n(vec![1, 3, 3], 2), vec![3]); +/// assert_eq!(find_count_n(vec![1, 2, 3, 4, 4], 1), vec![1, 2, 3]); +/// ``` +pub fn find_count_n(inner: Vec, n: usize) -> Vec { + todo!() +} + +/// Return the position of the median element in the vector. +/// +/// For a data set `x` of `n` elements, the median can be defined as follows: +/// +/// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`. +/// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`. +/// +/// Please following these rules: +/// +/// - If the list is empty, returns `None`. +/// - If several elements are equally median, the position of the first of them is returned. +/// +/// # Exmaple +/// +/// ``` +/// use cs220::assignments::assignment09::position_median; +/// +/// assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); +/// assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); +/// ``` +pub fn position_median(inner: Vec) -> Option { + todo!() +} + +/// Returns the sum of all elements in a two-dimensional array. +/// +/// # Example +/// ``` +/// assert_eq!( +/// two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()), +/// 21 +/// ); +/// ``` +pub fn two_dimensional_sum(inner: impl Iterator>) -> i64 { + todo!() +} + +/// Returns whether the given string is palindrome or not. +/// +/// A palindrome is a word, number, phrase, or other sequence of characters which reads the same backward as forward. +/// We consider the empty string is palindrome. +/// +/// Consult . +pub fn is_palindrome(s: String) -> bool { + todo!() +} diff --git a/src/assignments/assignment09/small_exercises_grade.rs b/src/assignments/assignment09/small_exercises_grade.rs new file mode 100644 index 0000000..efeeb10 --- /dev/null +++ b/src/assignments/assignment09/small_exercises_grade.rs @@ -0,0 +1,268 @@ +#[cfg(test)] +mod test { + + use ntest::{assert_false, assert_true}; + + use super::super::small_exercises::*; + + #[test] + fn test_is_fibonacci() { + assert!(is_fibonacci([1, 1, 2, 3, 5, 8, 13].into_iter())); + assert!(!is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter())); + assert!(is_fibonacci([2, 4, 6, 10, 16, 26].into_iter())); + assert!(is_fibonacci([4, 9, 13, 22, 35].into_iter())); + assert!(is_fibonacci([0, 0, 0, 0, 0].into_iter())); + assert!(is_fibonacci([1, 1].into_iter())); + assert!(is_fibonacci([1].into_iter())); + assert!(is_fibonacci([].into_iter())); + + assert!(!is_fibonacci([1, 1, 2, 2, 3, 3].into_iter())); + assert!(!is_fibonacci([0, 0, 0, 0, 1].into_iter())); + assert!(!is_fibonacci([1, 1, 1, 1].into_iter())); + assert!(!is_fibonacci([4, 3, 2, 1].into_iter())); + } + + #[test] + fn test_sigma() { + assert_eq!(sigma([].into_iter(), |x: i64| x * 2), 0); + assert_eq!(sigma([1].into_iter(), |x| x * 3), 3); + assert_eq!(sigma([1, 2].into_iter(), |x| x + 2), 7); + assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); + assert_eq!(sigma([1, 2, 3].into_iter(), |x| x * 5), 30); + + assert_eq!( + sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.floor() as i64), + 10 + ); + assert_eq!( + sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.ceil() as i64), + 13 + ); + assert_eq!( + sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.round() as i64), + 12 + ); + + assert_eq!( + sigma(["Hello,", "World!"].into_iter(), |x| x.len() as i64), + 12 + ); + } + + #[test] + fn test_interleave3() { + assert_eq!( + interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), + vec![1, 3, 5, 2, 4, 6] + ); + + assert_eq!( + interleave3( + [1, 2, 3].into_iter(), + [4, 5, 6].into_iter(), + [7, 8, 9].into_iter() + ), + vec![1, 4, 7, 2, 5, 8, 3, 6, 9] + ); + + assert_eq!( + interleave3( + ["a", "b", "c"].into_iter(), + ["d", "e", "f"].into_iter(), + ["g", "h", "i"].into_iter() + ) + .into_iter() + .collect::(), + "adgbehcfi" + ); + } + + #[test] + fn test_interleave_n() { + assert_eq!( + interleave_n([[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()]) + .collect::>(), + vec![1, 3, 5, 2, 4, 6] + ); + + assert_eq!( + interleave_n([ + [1, 2, 3].into_iter(), + [4, 5, 6].into_iter(), + [7, 8, 9].into_iter() + ]) + .collect::>(), + vec![1, 4, 7, 2, 5, 8, 3, 6, 9] + ); + + assert_eq!( + interleave_n([ + ["a", "b", "c"].into_iter(), + ["d", "e", "f"].into_iter(), + ["g", "h", "i"].into_iter() + ]) + .collect::(), + "adgbehcfi" + ); + } + + #[test] + fn test_k_smallest_man() { + assert_eq!( + k_smallest_mean(vec![1, 3, 2].into_iter(), 2), + ((1 + 2) as f64 / 2.0) + ); + assert_eq!( + k_smallest_mean(vec![5, 3, 7, 7].into_iter(), 2), + ((3 + 5) as f64 / 2.0) + ); + assert_eq!( + k_smallest_mean(vec![7, 5, 3, 6].into_iter(), 3), + ((3 + 5 + 6) as f64 / 3.0) + ); + assert_eq!( + k_smallest_mean(vec![1, 3, 2, 4, 4, 5, 6].into_iter(), 3), + ((1 + 2 + 3) as f64 / 3.0) + ); + assert_eq!(k_smallest_mean(vec![].into_iter(), 3), (0 as f64 / 3.0)); + assert_eq!( + k_smallest_mean( + vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5].into_iter(), + 5 + ), + ((1 + 2 + 3 + 4) as f64 / 5.0) + ); + } + + #[test] + fn test_calculate_mean() { + assert_eq!( + calculate_mean( + [ + ("CS100".to_string(), 60), + ("CS200".to_string(), 60), + ("CS200".to_string(), 80), + ("CS300".to_string(), 100), + ] + .into_iter() + ), + [ + ("CS100".to_string(), 60.0), + ("CS200".to_string(), 70.0), + ("CS300".to_string(), 100.0) + ] + .into_iter() + .collect() + ); + + assert_eq!( + calculate_mean( + [ + ("CS220".to_string(), 60), + ("CS420".to_string(), 60), + ("CS220".to_string(), 80), + ("CS431".to_string(), 60), + ("CS420".to_string(), 80), + ("CS220".to_string(), 100) + ] + .into_iter() + ), + [ + ("CS220".to_string(), 80.0), + ("CS420".to_string(), 70.0), + ("CS431".to_string(), 60.0) + ] + .into_iter() + .collect() + ) + } + + #[test] + fn test_sum_is_n() { + assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1); + assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2); + assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 5), 2); + assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 6), 1); + assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 2), 0); + + assert_eq!(sum_is_n(vec![(1..100).collect()], 50), 1); + + assert_eq!( + sum_is_n(vec![(1..10).collect(), (1..10).rev().collect()], 10), + 9 + ); + + assert_eq!( + sum_is_n( + vec![ + (0..10).map(|x| x * 2 + 1).collect(), + (0..20).map(|x| x * 3).collect(), + (0..30).map(|x| x * 5 + 2).collect() + ], + 53 + ), + 30 + ); + } + + // find_count_n + #[test] + fn test_find_count_n() { + assert_eq!(find_count_n(vec![], 1), vec![]); + assert_eq!(find_count_n(vec![1, 2], 1), vec![1, 2]); + assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); + assert_eq!(find_count_n(vec![1, 3, 3], 2), vec![3]); + assert_eq!(find_count_n(vec![1, 2, 3, 4, 4], 1), vec![1, 2, 3]); + assert_eq!(find_count_n(vec![1, 3, 2, 3, 2, 3], 3), vec![3]); + assert_eq!(find_count_n(vec![1, 2, 2, 3, 3, 4], 2), vec![2, 3]); + assert_eq!(find_count_n(vec![1, 3, 2, 2, 3], 2), vec![2, 3]); + assert_eq!(find_count_n(vec![0, 2, 2, 4, 3], 0), vec![]); + assert_eq!(find_count_n(vec![1, 1, 1, 2, 2], 1), vec![]); + } + + #[test] + fn test_position_median() { + assert_eq!(position_median(Vec::::new()), None); + assert_eq!(position_median(vec![3]), Some(0)); + assert_eq!(position_median(vec![3, 3]), Some(0)); + assert_eq!(position_median(vec![3, 3, 3]), Some(0)); + assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); + assert_eq!(position_median(vec![3, 1, 3, 3]), Some(0)); + assert_eq!(position_median(vec![3, 1, 5, 3]), Some(0)); + assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); + assert_eq!(position_median(vec![1, 2, 3, 4, 5, 6, 8, 9]), Some(4)); + } + + #[test] + fn test_two_dimensional_sum() { + assert_eq!( + two_dimensional_sum([[1, 2, 3].into_iter(), [4, 5, 6].into_iter()].into_iter()), + 21 + ); + assert_eq!( + two_dimensional_sum( + [ + [1, 2, 3, 4, 5].into_iter(), + [10, 20, 30, 40, 50].into_iter() + ] + .into_iter() + ), + 165 + ); + } + + #[test] + fn test_is_palindrome() { + assert_true!(is_palindrome("kayak".to_string())); + assert_true!(is_palindrome("dammitimmad".to_string())); + assert_true!(is_palindrome("deified".to_string())); + assert_true!(is_palindrome("rotator".to_string())); + assert_true!(is_palindrome("noon".to_string())); + assert_true!(is_palindrome("".to_string())); + assert_true!(is_palindrome("a".to_string())); + + assert_false!(is_palindrome("moon".to_string())); + assert_false!(is_palindrome("hello".to_string())); + assert_false!(is_palindrome("apple".to_string())); + } +} diff --git a/src/assignments/assignment10/labyrinth.rs b/src/assignments/assignment10/labyrinth.rs new file mode 100644 index 0000000..001b522 --- /dev/null +++ b/src/assignments/assignment10/labyrinth.rs @@ -0,0 +1,50 @@ +//! Labyrinth +//! +//! Look at the [test code](labyrinth_grade.rs) below before you start. +//! HINT: https://en.wikipedia.org/wiki/100_prisoners_problem +//! +//! NOTE: You will have to implement a probabilistic algorithm, which means, the algorithm can fail +//! even if you have implemented the solution. We recommend running multiple times (at least 5 times) to check your +//! solution works well. + +#![allow(missing_docs)] + +use std::cell::RefCell; + +/// Husband +#[derive(Debug)] +pub struct Husband { + brain: RefCell<[usize; 100]>, +} + +impl Husband { + /// What might a husband, who is looking for his wife's ID my_wife, be thinking? + pub fn seeking(my_wife: usize) -> Self { + todo!() + } + + #[allow(missing_docs)] + pub fn has_devised_a_strategy(&self) -> Strategy<'_> { + Strategy { husband: self } + } + + /// Based on the information about currently visited room number and someone's wife ID trapped inside, + /// what the husband should do next? + pub fn carefully_checks_whos_inside(&self, room: usize, wife: usize) { + todo!() + } +} + +/// Strategy of husband +#[derive(Debug)] +pub struct Strategy<'a> { + husband: &'a Husband, +} + +impl Iterator for Strategy<'_> { + type Item = usize; + + fn next(&mut self) -> Option { + todo!() + } +} diff --git a/src/assignments/assignment10/labyrinth_grade.rs b/src/assignments/assignment10/labyrinth_grade.rs new file mode 100644 index 0000000..a7fa5a1 --- /dev/null +++ b/src/assignments/assignment10/labyrinth_grade.rs @@ -0,0 +1,62 @@ +#[cfg(test)] +mod test { + use rand::seq::SliceRandom; + use rand::thread_rng; + + use super::super::labyrinth::*; + + type Wife = usize; + type Rooms = Vec; + + struct Labyrinth { + rooms: Rooms, + } + + impl From for Labyrinth { + fn from(rooms: Rooms) -> Self { + Self { rooms } + } + } + + impl Labyrinth { + fn open_the_door(&self, index: usize) -> Wife { + self.rooms[index] + } + } + + #[test] + fn can_every_husband_rescue_his_wife() { + // HINT: https://en.wikipedia.org/wiki/100_prisoners_problem + const WIVES: usize = 100; + + // One day, wives of 100 husbands were kidnapped by the Minotaur + // and imprisoned in a labyrinth.... 🏰 + let labyrinth = Labyrinth::from({ + let mut rooms: Vec<_> = (0..WIVES).collect(); + rooms.shuffle(&mut thread_rng()); + rooms + }); + + assert!((0..WIVES).all(|his_wife| { + // A new husband steps into the labyrinth to rescue his wife...! + let husband = Box::new(Husband::seeking(his_wife /*👩*/)); + let strategy = Box::new(husband.has_devised_a_strategy()); + + #[allow(clippy::all)] + /* The Minotaur🐂 will arrive in */ + (0..50) /* steps... */ + .zip(strategy) + .find(|(_, room)| { + // The husband contemplates his next move... 🤔 + // and finally, + let someone/*👤*/ = labyrinth.open_the_door(*room); // 🚪 + husband.carefully_checks_whos_inside(*room, someone); + + // Has the husband found his wife...? + someone/*👤*/ == his_wife /*👩*/ + }) + .is_some(/* The husband has successfully rescued his wife! 👫*/) + // or is_none(/* The unfortunate husband has encountered the Minotaur and... 🪓*/) + })); + } +} diff --git a/src/assignments/assignment10/mod.rs b/src/assignments/assignment10/mod.rs new file mode 100644 index 0000000..5b7390a --- /dev/null +++ b/src/assignments/assignment10/mod.rs @@ -0,0 +1,12 @@ +//! +//! Assignment 10: Iterators (2/2). +//! The primary goal of this assignment is to get used to iterators. +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-10.sh` works fine. +//! See `assignment10_grade.rs` and `/scripts/grade-10.sh` for the test script. + +pub mod labyrinth; +pub mod small_exercises; + +mod labyrinth_grade; +mod small_exercises_grade; diff --git a/src/assignments/assignment10/small_exercises.rs b/src/assignments/assignment10/small_exercises.rs new file mode 100644 index 0000000..e4d59cb --- /dev/null +++ b/src/assignments/assignment10/small_exercises.rs @@ -0,0 +1,193 @@ +//! Small exercises. +use itertools::*; + +/// Returns the pairs of `(i, j)` where `i < j` and `inner[i] > inner[j]` in increasing order. +/// +/// For example, the inversions of `[3, 5, 1, 2, 4]` is `[(0, 2), (0, 3), (1, 2), (1, 3), (1, 4)]` because as follows: +/// +/// - `0 < 2`, `inner[0] = 3 > 1 = inner[2]` +/// - `0 < 3`, `inner[0] = 3 > 2 = inner[3]` +/// - `1 < 2`, `inner[1] = 5 > 1 = inner[2]` +/// - `1 < 3`, `inner[1] = 5 > 2 = inner[3]` +/// - `1 < 4`, `inner[1] = 5 > 4 = inner[4]` +/// +/// Consult for more details of inversion. +pub fn inversion(inner: Vec) -> Vec<(usize, usize)> { + todo!() +} + +/// Represents a node of tree data structure. +/// +/// Consult for more details on tree data structure. +#[derive(Debug)] +pub enum Node { + /// Non-leaf node + /// + /// It contains `(the name of node, list of child nodes)`. + NonLeaf((T, Vec>)), + /// Leaf node + /// + /// It contains the name of node. + Leaf(T), +} + +/// Traverses the tree in preorder. +/// +/// The algorithm for preorder traversal is as follows: +/// +/// 1. Visit the root. +/// 2. If the root is a leaf node, end the traverse. +/// 3. If the root is a non-leaf node, traverse each subtree from the child nodes. +/// +/// For example, the result of preorder traversal for the following tree +/// +/// ```text +/// 1 +/// /|\ +/// 2 3 4 +/// /| /|\ +/// 5 6 7 8 9 +/// ``` +/// +/// which can be represented as +/// +/// ```ignore +/// Node::NonLeaf(( +/// 1, +/// vec![ +/// Node::NonLeaf((2, vec![Node::Leaf(5), Node::Leaf(6)])), +/// Node::Leaf(3), +/// Node::NonLeaf((4, vec![Node::Leaf(7), Node::Leaf(8), Node::Leaf(9)])), +/// ] +/// )) +/// ``` +/// +/// is `1 -> 2 -> 5 -> 6 -> 3 -> 4 -> 7 -> 8 -> 9`. +pub fn traverse_preorder(root: Node) -> Vec { + todo!() +} + +/// File +#[derive(Debug)] +pub enum File { + /// Directory + /// + /// It contains `(name of directory, list of files under the directory)` + /// + /// The size of a directory is the sum of the sizes of its sub-files. + Directory(String, Vec), + + /// Data + /// + /// It contains `(name of data, size of data)` + Data(String, usize), +} + +/// Given a file, summarize all subfiles and sizes in ascending order of size. +/// +/// - Its behaviour is the same as the `du | sort -h` command on Linux. +/// - If the file size is the same, sort it by name. +/// - Assume that there are no duplicate file names. +/// +/// # Example +/// +/// Input: +/// +/// ```txt +/// root (Directory) +/// | +/// |__a (Directory) +/// | |__a1 (Data, size: 1) +/// | |__a2 (Data, size: 3) +/// | +/// |__b (Directory) +/// | |__b1 (Data, size: 3) +/// | |__b2 (Data, size: 15) +/// | +/// |__c (Data, size: 8) +/// ``` +/// +/// Output: `[("a1", 1), ("a2", 3), ("b1", 3), ("a", 4), ("c", 8), ("b2", 15), ("b", 18), ("root", 30)]` +pub fn du_sort(root: &File) -> Vec<(&str, usize)> { + todo!() +} + +/// Remove all even numbers inside a vector using the given mutable reference. +/// That is, you must modify the vector using the given mutable reference instead +/// of returning a new vector. +/// +/// # Example +/// ``` +/// let mut vec = vec![1, 2, 3, 4, 5]; +/// remove_even(&mut vec); +/// assert_eq!(*vec, vec![1, 3, 5]); +/// ``` +#[allow(clippy::ptr_arg)] +pub fn remove_even(inner: &mut Vec) { + todo!() +} + +/// Remove all duplicate occurences of a number inside the array. +/// That is, if an integer appears more than once, remove some occurences +/// of it so that it only appears once. Note that you must modify the vector +/// using the given mutable reference instead of returning a new vector. +/// Also, note that the order does not matter. +/// +/// # Example +/// ``` +/// let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7]; +/// remove_duplicate(&mut vec); +/// assert_eq!(*vec, vec![1, 2, 3, 7, 5]); +/// ``` +#[allow(clippy::ptr_arg)] +pub fn remove_duplicate(inner: &mut Vec) { + todo!() +} + +/// Returns the natural join of two tables using the first column as the join argument. +/// That is, for each pair of a row(`Vec`) from table1 and a row(`Vec`) from table2, +/// if the first element of them are equal, then add all elements of the row from table2 +/// except its first element to the row from table1 and add it to the results. +/// Note that the order of results does not matter. +/// +/// # Example +/// +/// table1 table2 +/// ---------------------- ---------------------- +/// 20230001 | Jack 20230001 | CS +/// 20231234 | Mike 20230001 | EE +/// 20231234 | ME +/// +/// +/// result +/// ----------------------------------- +/// 20230001 | Jack | CS +/// 20230001 | Jack | EE +/// 20231234 | Mike | ME +/// +pub fn natural_join(table1: Vec>, table2: Vec>) -> Vec> { + todo!() +} + +struct Pythagorean; + +impl Pythagorean { + fn new() -> Self { + todo!() + } +} + +impl Iterator for Pythagorean { + type Item = (u64, u64, u64); + + fn next(&mut self) -> Option { + todo!() + } +} + +/// Generates sequence of unique [primitive Pythagorean +/// triples](https://en.wikipedia.org/wiki/Pythagorean_triple), i.e. (a,b,c) such that a² + b² = +/// c², a and b are coprimes, and a < b. Generate in the increasing order of c. +pub fn pythagorean() -> impl Iterator { + Pythagorean::new() +} diff --git a/src/assignments/assignment10/small_exercises_grade.rs b/src/assignments/assignment10/small_exercises_grade.rs new file mode 100644 index 0000000..e1d1e54 --- /dev/null +++ b/src/assignments/assignment10/small_exercises_grade.rs @@ -0,0 +1,351 @@ +#[cfg(test)] +mod test { + use std::collections::HashSet; + + use super::super::small_exercises::*; + + #[test] + fn test_inversion() { + assert_eq!(inversion(vec![3, 5, 4]), vec![(1, 2)]); + assert_eq!(inversion(vec!["c", "a", "b", "d"]), vec![(0, 1), (0, 2)]); + assert_eq!( + inversion(vec![2, 5, 4, 6, 3, 1]), + vec![ + (0, 5), + (1, 2), + (1, 4), + (1, 5), + (2, 4), + (2, 5), + (3, 4), + (3, 5), + (4, 5) + ] + ); + } + + #[test] + fn test_traverse_preorder() { + let root = Node::NonLeaf(( + 1, + vec![ + Node::NonLeaf((2, vec![Node::Leaf(5), Node::Leaf(6)])), + Node::Leaf(3), + Node::NonLeaf((4, vec![Node::Leaf(7), Node::Leaf(8), Node::Leaf(9)])), + ], + )); + + assert_eq!(traverse_preorder(root), vec![1, 2, 5, 6, 3, 4, 7, 8, 9]); + } + + #[test] + fn test_du_sort() { + let rootfile = File::Directory( + "root".to_string(), + vec![ + File::Directory( + "a".to_string(), + vec![ + File::Data("a1".to_string(), 1), + File::Data("a2".to_string(), 3), + ], + ), + File::Directory( + "b".to_string(), + vec![ + File::Data("b1".to_string(), 3), + File::Data("b2".to_string(), 15), + ], + ), + File::Data("c".to_string(), 8), + ], + ); + + assert_eq!( + du_sort(&rootfile), + vec![ + ("a1", 1), + ("a2", 3), + ("b1", 3), + ("a", 4), + ("c", 8), + ("b2", 15), + ("b", 18), + ("root", 1 + 3 + 3 + 15 + 8) + ] + ); + + let rootfile = File::Directory( + "root".to_string(), + vec![ + File::Directory( + "b".to_string(), + vec![ + File::Data("b1".to_string(), 3), + File::Data("b2".to_string(), 15), + ], + ), + File::Data("c".to_string(), 8), + File::Directory( + "a".to_string(), + vec![ + File::Data("a1".to_string(), 1), + File::Data("a2".to_string(), 3), + ], + ), + ], + ); + + assert_eq!( + du_sort(&rootfile), + vec![ + ("a1", 1), + ("a2", 3), + ("b1", 3), + ("a", 4), + ("c", 8), + ("b2", 15), + ("b", 18), + ("root", 1 + 3 + 3 + 15 + 8) + ] + ); + + let rootfile = File::Directory( + "root".to_string(), + vec![ + File::Directory( + "a".to_string(), + vec![ + File::Data("a1".to_string(), 1), + File::Data("a2".to_string(), 3), + File::Directory( + "a3".to_string(), + vec![ + File::Data("a31".to_string(), 1), + File::Data("a32".to_string(), 3), + File::Data("a33".to_string(), 6), + ], + ), + ], + ), + File::Directory( + "b".to_string(), + vec![ + File::Data("b1".to_string(), 3), + File::Data("b2".to_string(), 15), + ], + ), + File::Data("c".to_string(), 16), + ], + ); + + assert_eq!( + du_sort(&rootfile), + vec![ + ("a1", 1), + ("a31", 1), + ("a2", 3), + ("a32", 3), + ("b1", 3), + ("a33", 6), + ("a3", 10), + ("a", 14), + ("b2", 15), + ("c", 16), + ("b", 18), + ("root", 48) + ] + ); + } + + #[test] + fn test_remove_even() { + let mut vec = vec![1, 2, 3, 4, 5]; + remove_even(&mut vec); + assert_eq!(*vec, vec![1, 3, 5]); + + let mut vec = vec![11, 1000, 12, 101, 105, 104, 200]; + remove_even(&mut vec); + assert_eq!(*vec, vec![11, 101, 105]); + } + + #[test] + fn test_remove_duplicate() { + let mut vec = vec![1, 2, 1, 1, 3, 7, 5, 7]; + remove_duplicate(&mut vec); + + let set1: HashSet = HashSet::from_iter(vec); + let set2: HashSet = HashSet::from_iter(vec![1, 2, 3, 7, 5]); + assert_eq!(set1, set2); + } + + #[test] + fn test_natural_join() { + let row1: Vec = vec!["20230001", "Jack"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row2: Vec = vec!["20231234", "Mike"] + .iter() + .map(|s| s.to_string()) + .collect(); + let table1 = vec![row1, row2]; + let row1: Vec = vec!["20230001", "CS"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row2: Vec = vec!["20230001", "EE"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row3: Vec = vec!["20231234", "ME"] + .iter() + .map(|s| s.to_string()) + .collect(); + let table2 = vec![row1, row2, row3]; + let row1: Vec = vec!["20230001", "Jack", "CS"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row2: Vec = vec!["20230001", "Jack", "EE"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row3: Vec = vec!["20231234", "Mike", "ME"] + .iter() + .map(|s| s.to_string()) + .collect(); + let table3 = vec![row1, row2, row3]; + + assert_eq!( + HashSet::>::from_iter(natural_join(table1, table2)), + HashSet::>::from_iter(table3) + ); + + let row1: Vec = vec!["20230001", "Alice"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row2: Vec = vec!["20230002", "Bob"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row3: Vec = vec!["20230003", "Charlie"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row4: Vec = vec!["20230004", "David"] + .iter() + .map(|s| s.to_string()) + .collect(); + let table1 = vec![row1, row2, row3, row4]; + let row1: Vec = vec!["20230001", "Apple"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row2: Vec = vec!["20230001", "Avocado"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row3: Vec = vec!["20230002", "Banana"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row4: Vec = vec!["20230002", "Berries"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row5: Vec = vec!["20230004", "Durian"] + .iter() + .map(|s| s.to_string()) + .collect(); + let table2 = vec![row1, row2, row3, row4, row5]; + let row1: Vec = vec!["20230001", "Alice", "Apple"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row2: Vec = vec!["20230001", "Alice", "Avocado"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row3: Vec = vec!["20230002", "Bob", "Banana"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row4: Vec = vec!["20230002", "Bob", "Berries"] + .iter() + .map(|s| s.to_string()) + .collect(); + let row5: Vec = vec!["20230004", "David", "Durian"] + .iter() + .map(|s| s.to_string()) + .collect(); + let table3 = vec![row1, row2, row3, row4, row5]; + + assert_eq!( + HashSet::>::from_iter(natural_join(table1, table2)), + HashSet::>::from_iter(table3) + ); + } + + #[test] + fn test_pythagorean() { + let pythagoreans = [ + (3, 4, 5), + (5, 12, 13), + (8, 15, 17), + (7, 24, 25), + (20, 21, 29), + (12, 35, 37), + (9, 40, 41), + (28, 45, 53), + (11, 60, 61), + (16, 63, 65), + (33, 56, 65), + (48, 55, 73), + (13, 84, 85), + (36, 77, 85), + (39, 80, 89), + (65, 72, 97), + (20, 99, 101), + (60, 91, 109), + (15, 112, 113), + (44, 117, 125), + (88, 105, 137), + (17, 144, 145), + (24, 143, 145), + (51, 140, 149), + (85, 132, 157), + (119, 120, 169), + (52, 165, 173), + (19, 180, 181), + (57, 176, 185), + (104, 153, 185), + (95, 168, 193), + (28, 195, 197), + (84, 187, 205), + (133, 156, 205), + (21, 220, 221), + (140, 171, 221), + (60, 221, 229), + (105, 208, 233), + (120, 209, 241), + (32, 255, 257), + (23, 264, 265), + (96, 247, 265), + (69, 260, 269), + (115, 252, 277), + (160, 231, 281), + (161, 240, 289), + (68, 285, 293), + ]; + + for (i, t) in pythagorean().enumerate().take(1000) { + if i < pythagoreans.len() { + assert_eq!(pythagoreans[i], t) + } + let (a, b, c) = t; + assert_eq!(a * a + b * b, c * c); + } + } +} From ee1f7d0b8fcb2bde836e5216a8e29cfd6073ed32 Mon Sep 17 00:00:00 2001 From: "jungin.rhee" Date: Fri, 18 Aug 2023 16:08:13 +0000 Subject: [PATCH 04/17] assignment 6-7-8-10 --- Cargo.lock | 1 + Cargo.toml | 1 + scripts/grade-06.sh | 22 +-- scripts/grade-07.sh | 22 +-- scripts/grade-09.sh | 22 +-- scripts/grade-10.sh | 22 +-- scripts/grade-11.sh | 2 +- scripts/grade-12.sh | 2 +- src/assignments/assignment06.rs | 142 ------------------ src/assignments/assignment06_grade.rs | 91 ------------ src/assignments/assignment07.rs | 29 ---- src/assignments/assignment07_grade.rs | 44 ------ src/assignments/assignment09.rs | 174 ---------------------- src/assignments/assignment09_grade.rs | 203 -------------------------- src/assignments/assignment10.rs | 119 --------------- src/assignments/assignment10_grade.rs | 158 -------------------- src/assignments/mod.rs | 4 - 17 files changed, 48 insertions(+), 1010 deletions(-) delete mode 100644 src/assignments/assignment06.rs delete mode 100644 src/assignments/assignment06_grade.rs delete mode 100644 src/assignments/assignment07.rs delete mode 100644 src/assignments/assignment07_grade.rs delete mode 100644 src/assignments/assignment09.rs delete mode 100644 src/assignments/assignment09_grade.rs delete mode 100644 src/assignments/assignment10.rs delete mode 100644 src/assignments/assignment10_grade.rs diff --git a/Cargo.lock b/Cargo.lock index 75ed63e..4ab1c58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,6 +227,7 @@ dependencies = [ "num-traits", "pest", "pest_derive", + "rand", "rayon", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 543cac1..f7271a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,4 @@ approx = "0.5.1" num-traits = "0.2" ndarray = "0.15.0" ndarray-rand = "0.14.0" +rand = "0.8.5" diff --git a/scripts/grade-06.sh b/scripts/grade-06.sh index d139dcb..bd89d59 100755 --- a/scripts/grade-06.sh +++ b/scripts/grade-06.sh @@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0") source $BASEDIR/grade-utils.sh RUNNERS=( - "cargo" - "cargo --release" - "cargo_asan" - "cargo_asan --release" - "cargo_tsan" - "cargo_tsan --release" + "cargo" + "cargo --release" + "cargo_asan" + "cargo_asan --release" + "cargo_tsan" + "cargo_tsan --release" ) # Lints. @@ -22,12 +22,12 @@ run_linters || exit 1 # Executes test for each runner. for RUNNER in "${RUNNERS[@]}"; do - echo "Running with $RUNNER..." + echo "Running with $RUNNER..." - TESTS=("--lib assignment06_grade") - if [ $(run_tests) -ne 0 ]; then - exit 1 - fi + TESTS=("--lib assignment06") + if [ $(run_tests) -ne 0 ]; then + exit 1 + fi done exit 0 diff --git a/scripts/grade-07.sh b/scripts/grade-07.sh index e323e09..766286d 100755 --- a/scripts/grade-07.sh +++ b/scripts/grade-07.sh @@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0") source $BASEDIR/grade-utils.sh RUNNERS=( - "cargo" - "cargo --release" - "cargo_asan" - "cargo_asan --release" - "cargo_tsan" - "cargo_tsan --release" + "cargo" + "cargo --release" + "cargo_asan" + "cargo_asan --release" + "cargo_tsan" + "cargo_tsan --release" ) # Lints. @@ -22,12 +22,12 @@ run_linters || exit 1 # Executes test for each runner. for RUNNER in "${RUNNERS[@]}"; do - echo "Running with $RUNNER..." + echo "Running with $RUNNER..." - TESTS=("--lib assignment07_grade") - if [ $(run_tests) -ne 0 ]; then - exit 1 - fi + TESTS=("--lib assignment07") + if [ $(run_tests) -ne 0 ]; then + exit 1 + fi done exit 0 diff --git a/scripts/grade-09.sh b/scripts/grade-09.sh index 8120c66..fc449ea 100755 --- a/scripts/grade-09.sh +++ b/scripts/grade-09.sh @@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0") source $BASEDIR/grade-utils.sh RUNNERS=( - "cargo" - "cargo --release" - "cargo_asan" - "cargo_asan --release" - "cargo_tsan" - "cargo_tsan --release" + "cargo" + "cargo --release" + "cargo_asan" + "cargo_asan --release" + "cargo_tsan" + "cargo_tsan --release" ) # Lints. @@ -22,12 +22,12 @@ run_linters || exit 1 # Executes test for each runner. for RUNNER in "${RUNNERS[@]}"; do - echo "Running with $RUNNER..." + echo "Running with $RUNNER..." - TESTS=("--lib assignment09_grade") - if [ $(run_tests) -ne 0 ]; then - exit 1 - fi + TESTS=("--lib assignment09") + if [ $(run_tests) -ne 0 ]; then + exit 1 + fi done exit 0 diff --git a/scripts/grade-10.sh b/scripts/grade-10.sh index a221be6..87897bb 100755 --- a/scripts/grade-10.sh +++ b/scripts/grade-10.sh @@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0") source $BASEDIR/grade-utils.sh RUNNERS=( - "cargo" - "cargo --release" - "cargo_asan" - "cargo_asan --release" - "cargo_tsan" - "cargo_tsan --release" + "cargo" + "cargo --release" + "cargo_asan" + "cargo_asan --release" + "cargo_tsan" + "cargo_tsan --release" ) # Lints. @@ -22,12 +22,12 @@ run_linters || exit 1 # Executes test for each runner. for RUNNER in "${RUNNERS[@]}"; do - echo "Running with $RUNNER..." + echo "Running with $RUNNER..." - TESTS=("--lib assignment10_grade") - if [ $(run_tests) -ne 0 ]; then - exit 1 - fi + TESTS=("--lib assignment10") + if [ $(run_tests) -ne 0 ]; then + exit 1 + fi done exit 0 diff --git a/scripts/grade-11.sh b/scripts/grade-11.sh index 34fb51a..8666182 100755 --- a/scripts/grade-11.sh +++ b/scripts/grade-11.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment11") + TESTS=("--lib assignment11_grade") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/scripts/grade-12.sh b/scripts/grade-12.sh index 34fb51a..6a87f98 100755 --- a/scripts/grade-12.sh +++ b/scripts/grade-12.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment11") + TESTS=("--lib assignment12_grade") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/src/assignments/assignment06.rs b/src/assignments/assignment06.rs deleted file mode 100644 index e9a9646..0000000 --- a/src/assignments/assignment06.rs +++ /dev/null @@ -1,142 +0,0 @@ -//! Assignment 6: Mastering advanced types (1/2). -//! -//! The primary goal of this assignment is to understand generics, traits, and lifetimes. -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-06.sh` works fine. -//! See `assignment06_grade.rs` and `/scripts/grade-06.sh` for the test script. - -use std::{collections::HashMap, fmt::Debug}; - -/// Semiring. -/// -/// Consult . -pub trait Semiring: Debug + Clone + PartialEq { - /// Additive identity. - fn zero() -> Self; - /// Multiplicative identity. - fn one() -> Self; - /// Addition operation. - fn add(&self, rhs: &Self) -> Self; - /// Multiplication operation. - fn mul(&self, rhs: &Self) -> Self; -} - -/// Converts integer to semiring value. -pub fn from_usize(value: usize) -> T { - let mut result = T::zero(); - let one = T::one(); - - for _ in 0..value { - result = T::add(&result, &one); - } - - result -} - -impl Semiring for u64 { - fn zero() -> Self { - todo!() - } - - fn one() -> Self { - todo!() - } - - fn add(&self, rhs: &Self) -> Self { - todo!() - } - - fn mul(&self, rhs: &Self) -> Self { - todo!() - } -} - -impl Semiring for i64 { - fn zero() -> Self { - todo!() - } - - fn one() -> Self { - todo!() - } - - fn add(&self, rhs: &Self) -> Self { - todo!() - } - - fn mul(&self, rhs: &Self) -> Self { - todo!() - } -} - -impl Semiring for f64 { - fn zero() -> Self { - todo!() - } - - fn one() -> Self { - todo!() - } - - fn add(&self, rhs: &Self) -> Self { - todo!() - } - - fn mul(&self, rhs: &Self) -> Self { - todo!() - } -} - -/// Polynomials with coefficient in `C`. -/// -/// For example, polynomial `x^2 + 5x + 6` is represented in `Polynomial` as follows: -/// -/// ```ignore -/// Polynomial { -/// coefficients: { -/// 2: 1, -/// 1: 5, -/// 0: 6, -/// }, -/// } -/// ``` -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Polynomial { - coefficients: HashMap, -} - -impl Semiring for Polynomial { - fn zero() -> Self { - todo!() - } - - fn one() -> Self { - todo!() - } - - fn add(&self, rhs: &Self) -> Self { - todo!() - } - - fn mul(&self, rhs: &Self) -> Self { - todo!() - } -} - -impl From for Polynomial { - fn from(value: C) -> Self { - todo!() - } -} - -impl Polynomial { - /// Constructs polynomial `x`. - pub fn x() -> Self { - todo!() - } - - /// Evaluates the polynomial with the given value. - pub fn eval(&self, value: C) -> C { - todo!() - } -} diff --git a/src/assignments/assignment06_grade.rs b/src/assignments/assignment06_grade.rs deleted file mode 100644 index 60339f6..0000000 --- a/src/assignments/assignment06_grade.rs +++ /dev/null @@ -1,91 +0,0 @@ -#[cfg(test)] -mod test { - use super::super::assignment06::*; - - fn test_polynomial() { - // x^2 + 5x + 6 - let poly = Polynomial::add( - &Polynomial::add( - &Polynomial::mul( - &Polynomial::from(from_usize::(1)), - &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), - ), - &Polynomial::mul(&Polynomial::from(from_usize::(5)), &Polynomial::x()), - ), - &Polynomial::from(from_usize::(6)), - ); - - // 13^2 + 5*13 + 6 - let value = poly.eval(from_usize(13)); - - assert_eq!(value, from_usize(13 * 13 + 5 * 13 + 6)); - } - - #[test] - fn test_polynomial_u64() { - test_polynomial::(); - } - - #[test] - fn test_polynomial_f64() { - test_polynomial::(); - } - - #[test] - fn test_polynomial_p_u64() { - test_polynomial::>(); - } - - #[test] - fn test_polynomial_xy() { - // (x+1)(y+2) - let poly: Polynomial> = Polynomial::mul( - &Polynomial::from(Polynomial::add( - &Polynomial::x(), - &Polynomial::from(from_usize::(1)), - )), - &(Polynomial::add( - &Polynomial::x(), - &Polynomial::from(Polynomial::from(from_usize::(2))), - )), - ); - - // poly with y = x+3 - let value = poly.eval(Polynomial::add( - &Polynomial::x(), - &Polynomial::from(from_usize::(3)), - )); - - // x^2 + 6x + 5 - let expected = Polynomial::add( - &Polynomial::add( - &Polynomial::mul( - &Polynomial::from(from_usize::(1)), - &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), - ), - &Polynomial::mul(&Polynomial::from(from_usize::(6)), &Polynomial::x()), - ), - &Polynomial::from(from_usize::(5)), - ); - - assert_eq!(value, expected); - } - - #[test] - fn test_zero_remove() { - // (x-1)(x+1) - let poly: Polynomial = Polynomial::mul( - &Polynomial::add(&Polynomial::x(), &Polynomial::from(-1)), - &Polynomial::add(&Polynomial::x(), &Polynomial::from(1)), - ); - - // (x-1)(x+1) == x^2 - 1 - assert_eq!( - poly, - Polynomial::add( - &Polynomial::mul(&Polynomial::x(), &Polynomial::x()), - &Polynomial::from(-1) - ) - ); - } -} diff --git a/src/assignments/assignment07.rs b/src/assignments/assignment07.rs deleted file mode 100644 index e1e4753..0000000 --- a/src/assignments/assignment07.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Assignment 7: Mastering advanced types (2/2). -//! -//! The primary goal of this assignment is to understand generics, traits, and lifetimes. -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-07.sh` works fine. -//! See `assignment07_grade.rs` and `/scripts/grade-07.sh` for the test script. - -struct FindIter<'s, T: Eq> { - query: &'s [T], - base: &'s [T], - curr: usize, -} - -impl Iterator for FindIter<'_, T> { - type Item = usize; - - fn next(&mut self) -> Option { - todo!() - } -} - -/// Returns an iterator over substring query indexes in the base. -pub fn find<'s, T: Eq>(query: &'s [T], base: &'s [T]) -> impl 's + Iterator { - FindIter { - query, - base, - curr: 0, - } -} diff --git a/src/assignments/assignment07_grade.rs b/src/assignments/assignment07_grade.rs deleted file mode 100644 index 1ecf90c..0000000 --- a/src/assignments/assignment07_grade.rs +++ /dev/null @@ -1,44 +0,0 @@ -#[cfg(test)] -mod test { - use super::super::assignment07::*; - - #[test] - fn test_find() { - assert_eq!( - find("abc".as_bytes(), "abcdabcd".as_bytes()).collect::>(), - vec![0, 4] - ); - - assert_eq!( - find("aaba".as_bytes(), "aabaacaadaabaaba".as_bytes()).collect::>(), - vec![0, 9, 12] - ); - - assert_eq!( - find("ababac".as_bytes(), "abababcabababcabababc".as_bytes()).collect::>(), - vec![] - ); - - assert_eq!( - find("ababc".as_bytes(), "abc".as_bytes()).collect::>(), - vec![] - ); - } - - #[test] - fn test_find_usize() { - assert_eq!( - find(&[1, 2, 3], &[1, 2, 3, 4, 1, 2, 3, 4]).collect::>(), - vec![0, 4] - ); - - assert_eq!( - find( - &[5, 5, 7, 5], - &[5, 5, 7, 5, 5, 8, 5, 5, 9, 5, 5, 7, 5, 5, 7, 5] - ) - .collect::>(), - vec![0, 9, 12] - ); - } -} diff --git a/src/assignments/assignment09.rs b/src/assignments/assignment09.rs deleted file mode 100644 index 38dec0e..0000000 --- a/src/assignments/assignment09.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! Assignment 9: Iterators (1/2). -//! -//! The primary goal of this assignment is to get used to iterators. -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-09.sh` works fine. -//! See `assignment09_grade.rs` and `/scripts/grade-09.sh` for the test script. - -use std::collections::HashMap; - -use itertools::*; - -/// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's first two terms. -/// -/// Returns `true` if the length of sequence is less or equal than 2. -/// -/// # Exmample -/// -/// ``` -/// use cs220::assignments::assignment09::is_fibonacci; -/// -/// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 13].into_iter()), true); -/// assert_eq!(is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter()), false); -/// ``` -pub fn is_fibonacci(inner: impl Iterator) -> bool { - todo!() -} - -/// Returns the sum of `f(v)` for all element `v` the given array. -/// -/// # Exmaple -/// -/// ``` -/// use cs220::assignments::assignment09::sigma; -/// -/// assert_eq!(sigma([1, 2].into_iter(), |x| x + 2), 7); -/// assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); -/// ``` -pub fn sigma i64>(inner: impl Iterator, f: F) -> i64 { - todo!() -} - -/// Alternate elements from three iterators until they have run out. -/// -/// You can assume that the number of elements of three iterators are same. -/// -/// # Example -/// -/// ``` -/// use cs220::assignments::assignment09::interleave3; -/// -/// assert_eq!( -/// interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), -/// vec![1, 3, 5, 2, 4, 6] -/// ); -/// ``` -pub fn interleave3( - list1: impl Iterator, - list2: impl Iterator, - list3: impl Iterator, -) -> Vec { - todo!() -} - -/// Returns mean of k smallest value's mean. -/// -/// # Example -/// -/// ``` -/// use cs220::assignments::assignment09::k_smallest_mean; -/// -/// assert_eq!( -/// k_smallest_mean(vec![1, 3, 2].into_iter(), 2), -/// ((1 + 2) as f64 / 2.0) -/// ); -/// assert_eq!( -/// k_smallest_mean(vec![7, 5, 3, 6].into_iter(), 3), -/// ((3 + 5 + 6) as f64 / 3.0) -/// ); -/// ``` -pub fn k_smallest_mean(inner: impl Iterator, k: usize) -> f64 { - todo!() -} - -/// Returns mean for each class. -/// -/// # Exmaple -/// -/// ``` -/// use cs220::assignments::assignment09::calculate_mean; -/// -/// assert_eq!( -/// calculate_mean( -/// [ -/// ("CS100".to_string(), 60), -/// ("CS200".to_string(), 60), -/// ("CS200".to_string(), 80), -/// ("CS300".to_string(), 100), -/// ] -/// .into_iter() -/// ), -/// [ -/// ("CS100".to_string(), 60.0), -/// ("CS200".to_string(), 70.0), -/// ("CS300".to_string(), 100.0) -/// ] -/// .into_iter() -/// .collect() -/// ); -/// ``` -pub fn calculate_mean(inner: impl Iterator) -> HashMap { - todo!() -} - -/// Among the cartesian product of input vectors, return the number of sets whose sum equals `n`. -/// -/// # Example -/// -/// The cartesian product of [1, 2, 3] and [2, 3] are: -/// [1, 2], [1, 3], [2, 2], [2, 3], [3, 2], [3, 3]. -/// -/// Among these sets, the number of sets whose sum is 4 is 2, which is [1, 3] and [2, 2]. -/// -/// ``` -/// use cs220::assignments::assignment09::sum_is_n; -/// -/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1); -/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2); -/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 5), 2); -/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 6), 1); -/// assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 2), 0); -/// ``` -pub fn sum_is_n(inner: Vec>, n: i64) -> usize { - todo!() -} - -/// Returns a new vector that contains the item that appears `n` times in the input vector in increasing order. -/// -/// # Example -/// -/// ``` -/// use cs220::assignments::assignment09::find_count_n; -/// -/// assert_eq!(find_count_n(vec![1, 2], 1), vec![1, 2]); -/// assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); -/// assert_eq!(find_count_n(vec![1, 3, 3], 2), vec![3]); -/// assert_eq!(find_count_n(vec![1, 2, 3, 4, 4], 1), vec![1, 2, 3]); -/// ``` -pub fn find_count_n(inner: Vec, n: usize) -> Vec { - todo!() -} - -/// Return the position of the median element in the vector. -/// -/// For a data set `x` of `n` elements, the median can be defined as follows: -/// -/// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`. -/// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`. -/// -/// Please following these rules: -/// -/// - If the list is empty, returns `None`. -/// - If several elements are equally median, the position of the first of them is returned. -/// -/// # Exmaple -/// -/// ``` -/// use cs220::assignments::assignment09::position_median; -/// -/// assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); -/// assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); -/// ``` -pub fn position_median(inner: Vec) -> Option { - todo!() -} diff --git a/src/assignments/assignment09_grade.rs b/src/assignments/assignment09_grade.rs deleted file mode 100644 index ed8c293..0000000 --- a/src/assignments/assignment09_grade.rs +++ /dev/null @@ -1,203 +0,0 @@ -#[cfg(test)] -mod test { - use super::super::assignment09::*; - - #[test] - fn test_is_fibonacci() { - assert!(is_fibonacci([1, 1, 2, 3, 5, 8, 13].into_iter())); - assert!(!is_fibonacci([1, 1, 2, 3, 5, 8, 14].into_iter())); - assert!(is_fibonacci([2, 4, 6, 10, 16, 26].into_iter())); - assert!(is_fibonacci([4, 9, 13, 22, 35].into_iter())); - assert!(is_fibonacci([0, 0, 0, 0, 0].into_iter())); - assert!(is_fibonacci([1, 1].into_iter())); - assert!(is_fibonacci([1].into_iter())); - assert!(is_fibonacci([].into_iter())); - - assert!(!is_fibonacci([1, 1, 2, 2, 3, 3].into_iter())); - assert!(!is_fibonacci([0, 0, 0, 0, 1].into_iter())); - assert!(!is_fibonacci([1, 1, 1, 1].into_iter())); - assert!(!is_fibonacci([4, 3, 2, 1].into_iter())); - } - - #[test] - fn test_sigma() { - assert_eq!(sigma([].into_iter(), |x: i64| x * 2), 0); - assert_eq!(sigma([1].into_iter(), |x| x * 3), 3); - assert_eq!(sigma([1, 2].into_iter(), |x| x + 2), 7); - assert_eq!(sigma([1, 2].into_iter(), |x| x * 4), 12); - assert_eq!(sigma([1, 2, 3].into_iter(), |x| x * 5), 30); - - assert_eq!( - sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.floor() as i64), - 10 - ); - assert_eq!( - sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.ceil() as i64), - 13 - ); - assert_eq!( - sigma([-1.2, 3.0, 4.2, 5.8].into_iter(), |x: f64| x.round() as i64), - 12 - ); - - assert_eq!( - sigma(["Hello,", "World!"].into_iter(), |x| x.len() as i64), - 12 - ); - } - - #[test] - fn test_interleave3() { - assert_eq!( - interleave3([1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()), - vec![1, 3, 5, 2, 4, 6] - ); - - assert_eq!( - interleave3( - [1, 2, 3].into_iter(), - [4, 5, 6].into_iter(), - [7, 8, 9].into_iter() - ), - vec![1, 4, 7, 2, 5, 8, 3, 6, 9] - ); - - assert_eq!( - interleave3( - ["a", "b", "c"].into_iter(), - ["d", "e", "f"].into_iter(), - ["g", "h", "i"].into_iter() - ) - .into_iter() - .collect::(), - "adgbehcfi" - ); - } - - #[test] - fn test_k_smallest_man() { - assert_eq!( - k_smallest_mean(vec![1, 3, 2].into_iter(), 2), - ((1 + 2) as f64 / 2.0) - ); - assert_eq!( - k_smallest_mean(vec![5, 3, 7, 7].into_iter(), 2), - ((3 + 5) as f64 / 2.0) - ); - assert_eq!( - k_smallest_mean(vec![7, 5, 3, 6].into_iter(), 3), - ((3 + 5 + 6) as f64 / 3.0) - ); - assert_eq!( - k_smallest_mean(vec![1, 3, 2, 4, 4, 5, 6].into_iter(), 3), - ((1 + 2 + 3) as f64 / 3.0) - ); - assert_eq!(k_smallest_mean(vec![].into_iter(), 3), (0 as f64 / 3.0)); - assert_eq!( - k_smallest_mean( - vec![6, 9, 1, 14, 0, 4, 8, 7, 11, 2, 10, 3, 13, 12, 5].into_iter(), - 5 - ), - ((1 + 2 + 3 + 4) as f64 / 5.0) - ); - } - - #[test] - fn test_calculate_mean() { - assert_eq!( - calculate_mean( - [ - ("CS100".to_string(), 60), - ("CS200".to_string(), 60), - ("CS200".to_string(), 80), - ("CS300".to_string(), 100), - ] - .into_iter() - ), - [ - ("CS100".to_string(), 60.0), - ("CS200".to_string(), 70.0), - ("CS300".to_string(), 100.0) - ] - .into_iter() - .collect() - ); - - assert_eq!( - calculate_mean( - [ - ("CS220".to_string(), 60), - ("CS420".to_string(), 60), - ("CS220".to_string(), 80), - ("CS431".to_string(), 60), - ("CS420".to_string(), 80), - ("CS220".to_string(), 100) - ] - .into_iter() - ), - [ - ("CS220".to_string(), 80.0), - ("CS420".to_string(), 70.0), - ("CS431".to_string(), 60.0) - ] - .into_iter() - .collect() - ) - } - - #[test] - fn test_sum_is_n() { - assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 3), 1); - assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 4), 2); - assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 5), 2); - assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 6), 1); - assert_eq!(sum_is_n(vec![vec![1, 2, 3], vec![2, 3]], 2), 0); - - assert_eq!(sum_is_n(vec![(1..100).collect()], 50), 1); - - assert_eq!( - sum_is_n(vec![(1..10).collect(), (1..10).rev().collect()], 10), - 9 - ); - - assert_eq!( - sum_is_n( - vec![ - (0..10).map(|x| x * 2 + 1).collect(), - (0..20).map(|x| x * 3).collect(), - (0..30).map(|x| x * 5 + 2).collect() - ], - 53 - ), - 30 - ); - } - - // find_count_n - #[test] - fn test_find_count_n() { - assert_eq!(find_count_n(vec![], 1), vec![]); - assert_eq!(find_count_n(vec![1, 2], 1), vec![1, 2]); - assert_eq!(find_count_n(vec![1, 3, 3], 1), vec![1]); - assert_eq!(find_count_n(vec![1, 3, 3], 2), vec![3]); - assert_eq!(find_count_n(vec![1, 2, 3, 4, 4], 1), vec![1, 2, 3]); - assert_eq!(find_count_n(vec![1, 3, 2, 3, 2, 3], 3), vec![3]); - assert_eq!(find_count_n(vec![1, 2, 2, 3, 3, 4], 2), vec![2, 3]); - assert_eq!(find_count_n(vec![1, 3, 2, 2, 3], 2), vec![2, 3]); - assert_eq!(find_count_n(vec![0, 2, 2, 4, 3], 0), vec![]); - assert_eq!(find_count_n(vec![1, 1, 1, 2, 2], 1), vec![]); - } - - #[test] - fn test_position_median() { - assert_eq!(position_median(Vec::::new()), None); - assert_eq!(position_median(vec![3]), Some(0)); - assert_eq!(position_median(vec![3, 3]), Some(0)); - assert_eq!(position_median(vec![3, 3, 3]), Some(0)); - assert_eq!(position_median(vec![1, 3, 3, 3]), Some(1)); - assert_eq!(position_median(vec![3, 1, 3, 3]), Some(0)); - assert_eq!(position_median(vec![3, 1, 5, 3]), Some(0)); - assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); - assert_eq!(position_median(vec![1, 2, 3, 4, 5, 6, 8, 9]), Some(4)); - } -} diff --git a/src/assignments/assignment10.rs b/src/assignments/assignment10.rs deleted file mode 100644 index 6e3e510..0000000 --- a/src/assignments/assignment10.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! Assignment 10: Iterators (2/2). -//! -//! The primary goal of this assignment is to get used to iterators. -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-10.sh` works fine. -//! See `assignment10_grade.rs` and `/scripts/grade-10.sh` for the test script. - -use itertools::*; - -/// Returns the pairs of `(i, j)` where `i < j` and `inner[i] > inner[j]` in increasing order. -/// -/// For example, the inversions of `[3, 5, 1, 2, 4]` is `[(0, 2), (0, 3), (1, 2), (1, 3), (1, 4)]` because as follows: -/// -/// - `0 < 2`, `inner[0] = 3 > 1 = inner[2]` -/// - `0 < 3`, `inner[0] = 3 > 2 = inner[3]` -/// - `1 < 2`, `inner[1] = 5 > 1 = inner[2]` -/// - `1 < 3`, `inner[1] = 5 > 2 = inner[3]` -/// - `1 < 4`, `inner[1] = 5 > 4 = inner[4]` -/// -/// Consult for more details of inversion. -pub fn inversion(inner: Vec) -> Vec<(usize, usize)> { - todo!() -} - -/// Represents a node of tree data structure. -/// -/// Consult for more details on tree data structure. -#[derive(Debug)] -pub enum Node { - /// Non-leaf node - /// - /// It contains `(the name of node, list of child nodes)`. - NonLeaf((T, Vec>)), - /// Leaf node - /// - /// It contains the name of node. - Leaf(T), -} - -/// Traverses the tree in preorder. -/// -/// The algorithm for preorder traversal is as follows: -/// -/// 1. Visit the root. -/// 2. If the root is a leaf node, end the traverse. -/// 3. If the root is a non-leaf node, traverse each subtree from the child nodes. -/// -/// For example, the result of preorder traversal for the following tree -/// -/// ```text -/// 1 -/// /|\ -/// 2 3 4 -/// /| /|\ -/// 5 6 7 8 9 -/// ``` -/// -/// which can be represented as -/// -/// ```ignore -/// Node::NonLeaf(( -/// 1, -/// vec![ -/// Node::NonLeaf((2, vec![Node::Leaf(5), Node::Leaf(6)])), -/// Node::Leaf(3), -/// Node::NonLeaf((4, vec![Node::Leaf(7), Node::Leaf(8), Node::Leaf(9)])), -/// ] -/// )) -/// ``` -/// -/// is `1 -> 2 -> 5 -> 6 -> 3 -> 4 -> 7 -> 8 -> 9`. -pub fn traverse_preorder(root: Node) -> Vec { - todo!() -} - -/// File -#[derive(Debug)] -pub enum File { - /// Directory - /// - /// It contains `(name of directory, list of files under the directory)` - /// - /// The size of a directory is the sum of the sizes of its sub-files. - Directory(String, Vec), - - /// Data - /// - /// It contains `(name of data, size of data)` - Data(String, usize), -} - -/// Given a file, summarize all subfiles and sizes in ascending order of size. -/// -/// - Its behaviour is the same as the `du | sort -h` command on Linux. -/// - If the file size is the same, sort it by name. -/// - Assume that there are no duplicate file names. -/// -/// # Example -/// -/// Input: -/// -/// ```txt -/// root (Directory) -/// | -/// |__a (Directory) -/// | |__a1 (Data, size: 1) -/// | |__a2 (Data, size: 3) -/// | -/// |__b (Directory) -/// | |__b1 (Data, size: 3) -/// | |__b2 (Data, size: 15) -/// | -/// |__c (Data, size: 8) -/// ``` -/// -/// Output: `[("a1", 1), ("a2", 3), ("b1", 3), ("a", 4), ("c", 8), ("b2", 15), ("b", 18), ("root", 30)]` -pub fn du_sort(root: &File) -> Vec<(&str, usize)> { - todo!() -} diff --git a/src/assignments/assignment10_grade.rs b/src/assignments/assignment10_grade.rs deleted file mode 100644 index e7c8b5d..0000000 --- a/src/assignments/assignment10_grade.rs +++ /dev/null @@ -1,158 +0,0 @@ -#[cfg(test)] -mod test { - use super::super::assignment10::*; - - #[test] - fn test_inversion() { - assert_eq!(inversion(vec![3, 5, 4]), vec![(1, 2)]); - assert_eq!(inversion(vec!["c", "a", "b", "d"]), vec![(0, 1), (0, 2)]); - assert_eq!( - inversion(vec![2, 5, 4, 6, 3, 1]), - vec![ - (0, 5), - (1, 2), - (1, 4), - (1, 5), - (2, 4), - (2, 5), - (3, 4), - (3, 5), - (4, 5) - ] - ); - } - - #[test] - fn test_traverse_preorder() { - let root = Node::NonLeaf(( - 1, - vec![ - Node::NonLeaf((2, vec![Node::Leaf(5), Node::Leaf(6)])), - Node::Leaf(3), - Node::NonLeaf((4, vec![Node::Leaf(7), Node::Leaf(8), Node::Leaf(9)])), - ], - )); - - assert_eq!(traverse_preorder(root), vec![1, 2, 5, 6, 3, 4, 7, 8, 9]); - } - - #[test] - fn test_du_sort() { - let rootfile = File::Directory( - "root".to_string(), - vec![ - File::Directory( - "a".to_string(), - vec![ - File::Data("a1".to_string(), 1), - File::Data("a2".to_string(), 3), - ], - ), - File::Directory( - "b".to_string(), - vec![ - File::Data("b1".to_string(), 3), - File::Data("b2".to_string(), 15), - ], - ), - File::Data("c".to_string(), 8), - ], - ); - - assert_eq!( - du_sort(&rootfile), - vec![ - ("a1", 1), - ("a2", 3), - ("b1", 3), - ("a", 4), - ("c", 8), - ("b2", 15), - ("b", 18), - ("root", 1 + 3 + 3 + 15 + 8) - ] - ); - - let rootfile = File::Directory( - "root".to_string(), - vec![ - File::Directory( - "b".to_string(), - vec![ - File::Data("b1".to_string(), 3), - File::Data("b2".to_string(), 15), - ], - ), - File::Data("c".to_string(), 8), - File::Directory( - "a".to_string(), - vec![ - File::Data("a1".to_string(), 1), - File::Data("a2".to_string(), 3), - ], - ), - ], - ); - - assert_eq!( - du_sort(&rootfile), - vec![ - ("a1", 1), - ("a2", 3), - ("b1", 3), - ("a", 4), - ("c", 8), - ("b2", 15), - ("b", 18), - ("root", 1 + 3 + 3 + 15 + 8) - ] - ); - - let rootfile = File::Directory( - "root".to_string(), - vec![ - File::Directory( - "a".to_string(), - vec![ - File::Data("a1".to_string(), 1), - File::Data("a2".to_string(), 3), - File::Directory( - "a3".to_string(), - vec![ - File::Data("a31".to_string(), 1), - File::Data("a32".to_string(), 3), - File::Data("a33".to_string(), 6), - ], - ), - ], - ), - File::Directory( - "b".to_string(), - vec![ - File::Data("b1".to_string(), 3), - File::Data("b2".to_string(), 15), - ], - ), - File::Data("c".to_string(), 16), - ], - ); - - assert_eq!( - du_sort(&rootfile), - vec![ - ("a1", 1), - ("a31", 1), - ("a2", 3), - ("a32", 3), - ("b1", 3), - ("a33", 6), - ("a3", 10), - ("a", 14), - ("b2", 15), - ("c", 16), - ("b", 18), - ("root", 48) - ] - ); - } -} diff --git a/src/assignments/mod.rs b/src/assignments/mod.rs index ff16701..e7e80a2 100644 --- a/src/assignments/mod.rs +++ b/src/assignments/mod.rs @@ -15,15 +15,11 @@ mod assignment03_grade; pub mod assignment04; mod assignment04_grade; pub mod assignment06; -mod assignment06_grade; pub mod assignment07; -mod assignment07_grade; pub mod assignment08; mod assignment08_grade; pub mod assignment09; -mod assignment09_grade; pub mod assignment10; -mod assignment10_grade; pub mod assignment11; pub mod assignment12; pub mod assignment13; From 5caaac6c42be00f0aa6814582536d2f558a87eed Mon Sep 17 00:00:00 2001 From: AnHaechan Date: Sat, 19 Aug 2023 16:52:42 +0000 Subject: [PATCH 05/17] copy-paste assignment 2~5 --- assets/why3/eucl_div.mlw | 30 ++++ assets/why3/ex1_eucl_div.mlw | 34 ---- assets/why3/{ex2_fact.mlw => fact.mlw} | 26 ++- assets/why3/max.mlw | 29 ++++ assets/why3/pascal.mlw | 32 ++++ assets/why3/{ex4_two_way.mlw => two_way.mlw} | 33 ++-- src/assignments/assignment02.rs | 33 ++++ src/assignments/assignment02_grade.rs | 42 +++++ src/assignments/assignment03.rs | 128 +++++++++++++- src/assignments/assignment03_grade.rs | 158 ++++++++++++++++++ src/assignments/assignment11/linked_list.rs | 82 ++++++++- .../assignment11/linked_list_grade.rs | 103 +++++++++++- src/assignments/assignment11/mod.rs | 26 ++- src/assignments/assignment11/peano_nat.rs | 56 +++++++ .../assignment11/peano_nat_grade.rs | 38 +++++ 15 files changed, 763 insertions(+), 87 deletions(-) create mode 100644 assets/why3/eucl_div.mlw delete mode 100644 assets/why3/ex1_eucl_div.mlw rename assets/why3/{ex2_fact.mlw => fact.mlw} (54%) create mode 100644 assets/why3/max.mlw create mode 100644 assets/why3/pascal.mlw rename assets/why3/{ex4_two_way.mlw => two_way.mlw} (50%) create mode 100644 src/assignments/assignment11/peano_nat.rs create mode 100644 src/assignments/assignment11/peano_nat_grade.rs diff --git a/assets/why3/eucl_div.mlw b/assets/why3/eucl_div.mlw new file mode 100644 index 0000000..27cf0d1 --- /dev/null +++ b/assets/why3/eucl_div.mlw @@ -0,0 +1,30 @@ +(* Euclidean division + + 1. Prove correctness of euclideian divison: + `division a b` returns an integer `q` such that + `a = bq+r` and `0 <= r < b` for some `r`. + + - You have to strengthen the loop invariant. +*) + +module Division + + use int.Int + + (* IMPORTANT: DON'T MODIFY LINES EXCEPT `TODO`s OR YOU WILL GET ZERO POINTS *) + let division (a b: int) : int + requires { a >= 0 } + requires { b > 0 } + ensures { exists r: int. a = b * result + r /\ 0 <= r < b } + = + let ref q = 0 in + let ref r = a in + while r >= b do + invariant { true (*TODO*) } + variant { r } + q <- q + 1; + r <- r - b + done; + q + +end diff --git a/assets/why3/ex1_eucl_div.mlw b/assets/why3/ex1_eucl_div.mlw deleted file mode 100644 index 00e7d58..0000000 --- a/assets/why3/ex1_eucl_div.mlw +++ /dev/null @@ -1,34 +0,0 @@ -(* Euclidean division - - 1. Prove soundness, i.e. (division a b) returns an integer q such that - a = bq+r and 0 <= r < b for some r. - (You have to strengthen the precondition.) - - Do you have to require b <> 0? Why? - - 2. Prove termination. - (You may have to strengthen the precondition even further.) -*) - -module Division - - use int.Int - - let division (a b: int) : int - requires { a > 0 /\ b > 0 } - ensures { exists r: int. a = b * result + r /\ 0 <= r < b } - = - let ref q = 0 in - let ref r = a in - while r >= b do - invariant { a = b * q + r /\ r >= 0 } - variant { r } - q <- q + 1; - r <- r - b - done; - q - - let main () = - division 1000 42 - -end diff --git a/assets/why3/ex2_fact.mlw b/assets/why3/fact.mlw similarity index 54% rename from assets/why3/ex2_fact.mlw rename to assets/why3/fact.mlw index 343ae67..42d995d 100644 --- a/assets/why3/ex2_fact.mlw +++ b/assets/why3/fact.mlw @@ -1,23 +1,17 @@ (* Two programs to compute the factorial - Note: function "fact" from module int.Fact (already imported) - can be used in specifications. - Questions: 1. In module FactRecursive: - a. Prove soundness of function fact_rec. - - b. Prove its termination. + a. Implement the program that satisfies specification. 2. In module FactLoop: - a. Prove soundness of function fact_loop. + a. Strengthen the invariant to prove correctness of the given implementation. - b. Prove its termination. - - c. Change the code to use a for loop instead of a while loop. + b. Select a correct variant to prove the termination. + *) module FactRecursive @@ -29,9 +23,9 @@ module FactRecursive requires { n >= 0 } ensures { result = fact n } variant { n } - = - if n = 0 then 1 else n * fact_rec (n - 1) - + = (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) + 0 (*TODO*) + end module FactLoop @@ -45,8 +39,10 @@ module FactLoop = let ref m = 0 in let ref r = 1 in while m < n do - invariant { 0 <= m <= n /\ r = fact m } - variant { n - m } + (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) + invariant { true (* TODO *) } + variant { n (* TODO *) } + (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) m <- m + 1; r <- r * m done; diff --git a/assets/why3/max.mlw b/assets/why3/max.mlw new file mode 100644 index 0000000..92ef8dd --- /dev/null +++ b/assets/why3/max.mlw @@ -0,0 +1,29 @@ +(* Max + + Given an array `a` of natural numbers with length `n`, + return the maximum element of the array. + + You should stengthen the loop invariant. + +*) + +module Max + + use int.Int + use ref.Ref + use array.Array + + let max (a: array int) (n: int) : (max: int) + requires { n = length a } + requires { forall i. 0 <= i < n -> a[i] >= 0 } + ensures { forall i. 0 <= i < n -> a[i] <= max } + ensures { exists i. 0 <= i < n -> a[i] = max } + = let ref max = 0 in + for i = 0 to n - 1 do + (* IMPORTANT: MODIFY ONLY THIS INVARIANT, OR YOU'LL GET ZERO POINTS *) + invariant { true (*TODO*) } + if max < a[i] then max <- a[i]; + done; + max + +end diff --git a/assets/why3/pascal.mlw b/assets/why3/pascal.mlw new file mode 100644 index 0000000..7b838ca --- /dev/null +++ b/assets/why3/pascal.mlw @@ -0,0 +1,32 @@ +module Pascal + use int.Int + use ref.Ref + use array.Array + + (* HINT: https://en.wikipedia.org/wiki/Pascal%27s_triangle *) + (* You should understand the Pascal's triangle first to find good invariants *) + let rec function comb (n k: int) : int + requires { 0 <= k <= n } + variant { n } + ensures { result >= 1 } + = if k = 0 || k = n then 1 else comb (n-1) k + comb (n-1) (k-1) + + (* Insert appropriate invariants so that Why3 can verify this function. *) + let chooses (n : int) : array int + requires { n > 0 } + ensures { forall i: int. + 0 <= i < length result -> result[i] = comb n i } + = + let ref row = Array.make 1 1 in + for r = 1 to n do + invariant { length row = r } + invariant { true (*TODO*) } + let new_row = Array.make (r+1) 1 in + for c = 1 to r-1 do + invariant { true (*TODO*) } + new_row[c] <- row[c-1] + row[c] + done; + row <- new_row + done; + row +end \ No newline at end of file diff --git a/assets/why3/ex4_two_way.mlw b/assets/why3/two_way.mlw similarity index 50% rename from assets/why3/ex4_two_way.mlw rename to assets/why3/two_way.mlw index bfbe00e..371ce71 100644 --- a/assets/why3/ex4_two_way.mlw +++ b/assets/why3/two_way.mlw @@ -1,22 +1,12 @@ (* Two Way Sort The following program sorts an array of Boolean values, with False a[i1] << a[i2] let two_way_sort (a: array bool) : unit - ensures { true } + ensures { sorted a } + ensures { permut_all (old a) a } = - label Init in let ref i = 0 in let ref j = length a - 1 in while i < j do - invariant { forall i1: int. 0 <= i1 < i -> a[i1] = False } - invariant { forall i2: int. j < i2 < length a -> a[i2] = True } invariant { 0 <= i /\ j < length a } + (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) + invariant { forall i1: int. 0 <= i1 < i + -> true (* TODO *) } + invariant { forall i2: int. j < i2 < length a + -> true (* TODO *) } + invariant { true (* TODO *) } + (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) variant { j - i } if not a[i] then incr i diff --git a/src/assignments/assignment02.rs b/src/assignments/assignment02.rs index e0944eb..b747baf 100644 --- a/src/assignments/assignment02.rs +++ b/src/assignments/assignment02.rs @@ -135,6 +135,39 @@ pub fn fibonacci(n: u64) -> u64 { (FIBONACCI_MAT.power(n) * FIBONACCI_VEC).get_upper() } +/// 2x2 floating-point matrix of the following configuration: +/// +/// a, b +/// c, d +#[derive(Debug, Clone, Copy)] +pub struct FMat2 { + /// row 1, column 1 + pub a: f64, + /// row 1, column 2 + pub b: f64, + /// row 2, column 1 + pub c: f64, + /// row 2, column 2 + pub d: f64, +} + +impl FMat2 { + /// Returns the inverse of the given matrix. (We assume the given matrix is always invertible.) + /// Hint: https://www.cuemath.com/algebra/inverse-of-2x2-matrix/ + /// + /// # Example + /// + /// ``` + /// assert_eq!( + /// Mat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(), + /// Mat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0} + /// ); + /// ``` + pub fn inverse(self) -> Self { + todo!() + } +} + /// Writes down the lyrics of "twelve days of christmas". /// /// Hint: Google the song title for lyrics and look at the test code for the expected result. diff --git a/src/assignments/assignment02_grade.rs b/src/assignments/assignment02_grade.rs index de75737..6fd72ac 100644 --- a/src/assignments/assignment02_grade.rs +++ b/src/assignments/assignment02_grade.rs @@ -149,6 +149,48 @@ mod test { assert_eq!(fibonacci(92), 12200160415121876738); } + // Equivalence between two floating-point matrices, as element-wise equivalence + use std::cmp::PartialEq; + impl PartialEq for FMat2 { + fn eq(&self, other: &FMat2) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d + } + } + + #[test] + fn test_inverse() { + assert_eq!( + FMat2 { + a: 1.0, + b: 1.0, + c: 2.0, + d: 3.0 + } + .inverse(), + FMat2 { + a: 3.0, + b: -1.0, + c: -2.0, + d: 1.0 + } + ); + assert_eq!( + FMat2 { + a: 2.0, + b: 3.0, + c: 5.0, + d: 7.0 + } + .inverse(), + FMat2 { + a: -7.0, + b: 3.0, + c: 5.0, + d: -2.0 + } + ); + } + #[test] fn test_lyrics() { assert_eq!(twelve_days_of_christmas_lyrics(), LYRICS) diff --git a/src/assignments/assignment03.rs b/src/assignments/assignment03.rs index 68d22da..ce37c1f 100644 --- a/src/assignments/assignment03.rs +++ b/src/assignments/assignment03.rs @@ -1,12 +1,10 @@ -//! Assignment 3: Mastering common programming concepts (2/2). -//! -//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, especially those in the Rust Book chapters 6, 7, 8, and 9. -//! Please make sure you're comfortable with the concepts to proceed on to the next assignments. +//! Assignment 3: Mastering common programming concepts (2/2) //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-03.sh` works fine. //! See `assignment03_grade.rs` and `/scripts/grade-03.sh` for the test script. use std::collections::{HashMap, HashSet}; +use std::fmt; /// Day of week. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -166,3 +164,125 @@ pub fn piglatin(input: String) -> String { pub fn organize(commands: Vec) -> HashMap> { todo!() } + +/// Custom operator: `option_op_or(v1, v2, f)` +/// If neither `v1` nor `v2` is `Some`, returns `None`. +/// If exactly one is `Some`, returns the same `Some` value. +/// If both are `Some`, apply the values inside `Some` to `f` and wrap the resulting value inside `Some`. +/// +/// # Examples +/// +/// ``` +/// fn product(a: i32, b: i32) -> i32 { +/// a * b +/// } +/// +/// assert_eq!(option_op_or(None, None, product), None); +/// assert_eq!(option_op_or(Some(3), None, product), Some(3)); +/// assert_eq!(option_op_or(Some(3), Some(5), product), Some(15)); +/// ``` +pub fn option_op_or T>(v1: Option, v2: Option, f: F) -> Option { + todo!() +} + +/// Events in a text editor. +#[derive(Debug)] +pub enum TypeEvent { + /// A character is typed. + Type(char), + /// The last character is removed. + Backspace, + /// The whole string is copied to the clipboard. + Copy, + /// The string in the clipboard is appended. + Paste, +} + +/// Starting from an empty string and an empty clipboard, +/// processes the given `events` in order and returns the resulting string. +/// +/// See the test function `test_editor` for examples. +pub fn use_editor(events: Vec) -> String { + todo!() +} + +/// Parse the string as a shell command. +/// +/// Usually, a shell command is whitespace-separated array of strings. +/// ```text +/// cat file --> ["cat", "file"] +/// ``` +/// But sometimes, you may want to include whitespaces in each argument. +/// In that case, you can use quotes. +/// ```text +/// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs'] +/// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs'] +/// ``` +/// +/// For simplicity, you may assume that the string only contains alphanumeric characters, spaces +/// (" "), and single quotes ("'"). +/// +/// See `test_shell` for more examples. +pub fn parse_shell_command(command: &str) -> Vec { + todo!() +} + +/// Represents a JSON value. See https://en.wikipedia.org/wiki/JSON. +/// +/// For simplicity, you may assume that numbers are of type `i64`, and strings do not contain +/// special characters that need to be escaped (e.g. '"', '\n', ...). +#[derive(Debug, PartialEq, Eq)] +pub enum JsonValue { + /// null + Null, + /// true, false + Boolean(bool), + /// integers + Number(i64), + /// strings + String(String), + /// array of JSON values + Array(Vec), + /// objects + Object(HashMap), +} + +/// Parse a string into a JSON value. Returns `Err(())` if it contains syntax errors. +/// +/// See `test_json` for examples. +pub fn parse_json(json_string: &str) -> Result { + todo!() +} + +impl fmt::Display for JsonValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + JsonValue::Null => write!(f, "null"), + JsonValue::Boolean(b) => write!(f, "{}", b), + JsonValue::Number(n) => write!(f, "{}", n), + JsonValue::String(s) => write!(f, "\"{}\"", s), + JsonValue::Array(arr) => { + write!(f, "[")?; + let mut iter = arr.iter(); + if let Some(item) = iter.next() { + write!(f, "{}", item)?; + for item in iter { + write!(f, ", {}", item)?; + } + } + write!(f, "]") + } + JsonValue::Object(obj) => { + write!(f, "{{")?; + let mut iter = obj.iter(); + if let Some((key, value)) = iter.next() { + write!(f, "\"{}\": {}", key, value)?; + for (key, value) in iter { + write!(f, ", \"{}\": {}", key, value)?; + } + } + write!(f, "}}") + } + } + } +} diff --git a/src/assignments/assignment03_grade.rs b/src/assignments/assignment03_grade.rs index f72f64b..04980eb 100644 --- a/src/assignments/assignment03_grade.rs +++ b/src/assignments/assignment03_grade.rs @@ -165,4 +165,162 @@ mod test { .into() ); } + + fn product(a: i32, b: i32) -> i32 { + a * b + } + + #[test] + fn test_option_op_or() { + assert_eq!(option_op_or(None, None, product), None); + assert_eq!(option_op_or(Some(3), None, product), Some(3)); + assert_eq!(option_op_or(None, Some(5), product), Some(5)); + assert_eq!(option_op_or(Some(3), Some(5), product), Some(15)); + } + + #[test] + fn test_editor() { + assert_eq!( + use_editor(vec![ + TypeEvent::Type('a'), + TypeEvent::Backspace, + TypeEvent::Backspace, + TypeEvent::Type('b'), + TypeEvent::Type('c') + ]), + "bc" + ); + + assert_eq!( + use_editor(vec![ + TypeEvent::Type('a'), + TypeEvent::Copy, + TypeEvent::Paste, + TypeEvent::Paste, + TypeEvent::Type('b'), + TypeEvent::Copy, + TypeEvent::Paste + ]), + "aaabaaab" + ); + + assert_eq!( + use_editor(vec![ + TypeEvent::Paste, // clipboard starts empty + TypeEvent::Type('a'), + TypeEvent::Type('n'), + TypeEvent::Copy, + TypeEvent::Backspace, + TypeEvent::Backspace, + TypeEvent::Type('b'), + TypeEvent::Paste, + TypeEvent::Paste, + TypeEvent::Paste, + TypeEvent::Backspace + ]), + "banana" + ); + + assert_eq!( + use_editor(vec![ + TypeEvent::Copy, + TypeEvent::Backspace, + TypeEvent::Backspace, + TypeEvent::Paste, + TypeEvent::Paste, + TypeEvent::Copy, + TypeEvent::Backspace + ]), + "" + ); + } + + #[test] + fn test_shell() { + assert_eq!( + parse_shell_command("cat file"), + vec!["cat".to_string(), "file".to_string()] + ); + assert_eq!( + parse_shell_command("ls 'VirtualBox VMs'"), + vec!["ls".to_string(), "VirtualBox VMs".to_string()] + ); + assert_eq!( + parse_shell_command("ls VirtualBox' 'VMs"), + vec!["ls".to_string(), "VirtualBox VMs".to_string()] + ); + assert_eq!( + parse_shell_command("echo once upon a midnight dreary"), + vec![ + "echo".to_string(), + "once".to_string(), + "upon".to_string(), + "a".to_string(), + "midnight".to_string(), + "dreary".to_string(), + ] + ); + assert_eq!( + parse_shell_command("echo 'once upon a midnight dreary'"), + vec![ + "echo".to_string(), + "once upon a midnight dreary".to_string(), + ] + ); + } + + #[test] + fn test_json() { + use std::collections::HashMap; + let json_str = r#"{ + "name": "John Doe", + "age": 30, + "city": "New York", + "active": true, + "address": { + "street": "123 Main St", + "zipCode": "10001" + }, + "skills": ["Rust", "Python", "JavaScript"], + "organization": null + }"#; + println!("{}", parse_json(json_str).unwrap()); + assert_eq!( + parse_json(json_str), + Ok(JsonValue::Object(HashMap::from([ + ( + "name".to_string(), + JsonValue::String("John Doe".to_string()) + ), + ("age".to_string(), JsonValue::Number(30)), + ( + "city".to_string(), + JsonValue::String("New York".to_string()) + ), + ("active".to_string(), JsonValue::Boolean(true)), + ( + "address".to_string(), + JsonValue::Object(HashMap::from([ + ( + "street".to_string(), + JsonValue::String("123 Main St".to_string()) + ), + ( + "zipCode".to_string(), + JsonValue::String("10001".to_string()) + ) + ])) + ), + ( + "skills".to_string(), + JsonValue::Array(vec![ + JsonValue::String("Rust".to_string()), + JsonValue::String("Python".to_string()), + JsonValue::String("JavaScript".to_string()) + ]) + ), + ("organization".to_string(), JsonValue::Null), + ]))) + ); + } } diff --git a/src/assignments/assignment11/linked_list.rs b/src/assignments/assignment11/linked_list.rs index 704b6e9..161a7a4 100644 --- a/src/assignments/assignment11/linked_list.rs +++ b/src/assignments/assignment11/linked_list.rs @@ -1,8 +1,6 @@ //! Singly linked list. //! -//! Hint: Consult . -//! -//! Refer `linked_list_grade.rs` for test cases. +//! Consult . use std::fmt::Debug; @@ -61,4 +59,82 @@ impl SinglyLinkedList { pub fn pop_back(&mut self) -> Option { todo!() } + + /// Create a new list from the given vector `vec`. + pub fn from_vec(vec: Vec) -> Self { + todo!() + } + + /// Convert the current list into a vector. + pub fn as_vec(&self) -> Vec { + todo!() + } + + /// Return the length (i.e., number of nodes) of the list. + pub fn length(&self) -> usize { + todo!() + } + + /// Apply function `f` on every element of the list. + /// + /// # Examples + /// + /// `self`: `[1, 2]`, `f`: `|x| x + 1` ==> `[2, 3]` + pub fn map T>(&mut self, f: F) { + todo!() + } + + /// Insert given list `another` at the specified index `idx`. + /// If `idx` is out-of-bound of `self`, append `another` at the end of `self`. + /// + /// # Examples + /// + /// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `1` ==> `[1, 3, 4, 2]` + /// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `5` ==> `[1, 2, 3, 4]` + pub fn insert(&mut self, another: &Self, idx: usize) { + todo!() + } + + /// Reverse the list in a chunk of size `n`. + /// If `n == 0`, do nothing. + /// + /// # Examples + /// + /// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `3` + /// // each chunk of size `3`: `[1, 2, 3]`, `[4, 5, 6]`, `[7, 8, 9]` + /// // reversed sequence of chunks: `[7, 8, 9]`, `[4, 5, 6]`, `[1, 2, 3]` + /// ==> `[7, 8, 9, 4, 5, 6, 1, 2, 3]`, + /// + /// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `4` + /// // each chunk of size `4`: `[1, 2, 3, 4]`, `[5, 6, 7, 8]`, `[9]` + /// // reversed sequence of chunks: `[9]`, `[5, 6, 7, 8]`, `[1, 2, 3, 4]` + /// ==> `[9, 5, 6, 7, 8, 1, 2, 3, 4]` + pub fn chunk_reverse(&mut self, n: usize) { + todo!() + } + + /// Apply given function `f` for each adjacent pair of elements in the list. + /// If `self.length() < 2`, do nothing. + /// + /// # Examples + /// + /// `self`: `[1, 2, 3, 4]`, `f`: `|x, y| x + y` + /// // each adjacent pair of elements: `(1, 2)`, `(2, 3)`, `(3, 4)` + /// // apply `f` to each pair: `f(1, 2) == 3`, `f(2, 3) == 5`, `f(3, 4) == 7` + /// ==> `[3, 5, 7]` + pub fn pair_map T>(&mut self, f: F) { + todo!() + } +} + +// A list of lists. +impl SinglyLinkedList> { + /// Flatten the list of lists into a single list. + /// + /// # Examples + /// `self`: `[[1, 2, 3], [4, 5, 6], [7, 8]]` + /// ==> `[1, 2, 3, 4, 5, 6, 7, 8]` + pub fn flatten(self) -> SinglyLinkedList { + todo!() + } } diff --git a/src/assignments/assignment11/linked_list_grade.rs b/src/assignments/assignment11/linked_list_grade.rs index 2db6fe0..6805972 100644 --- a/src/assignments/assignment11/linked_list_grade.rs +++ b/src/assignments/assignment11/linked_list_grade.rs @@ -1,14 +1,12 @@ -//! Test cases for assignment11/linked_list.rs - #[cfg(test)] mod test_linked_list { - use super::super::linked_list::*; + use crate::assignments::assignment11::linked_list::*; #[derive(Debug, PartialEq, Eq)] struct V(usize); #[test] - fn test_linked_list() { + fn test_push_pop() { let mut list = SinglyLinkedList::new(); list.push_back(V(3)); list.push_front(V(2)); @@ -24,4 +22,101 @@ mod test_linked_list { assert_eq!(list.pop_back(), None); assert_eq!(list.pop_front(), None); } + + #[test] + fn test_from_as_vec() { + assert_eq!(SinglyLinkedList::::new().as_vec(), vec![]); + assert_eq!( + SinglyLinkedList::from_vec(vec![1, 2, 3]).as_vec(), + vec![1, 2, 3] + ); + } + + #[test] + fn test_length() { + let list = SinglyLinkedList::from_vec(vec![1, 2, 3]); + assert_eq!(list.length(), 3); + } + + #[test] + fn test_map() { + let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let incr = |x: i32| x + 1; + list.map(incr); + assert_eq!(list.as_vec(), vec![2, 3, 4]); + } + + #[test] + fn test_insert() { + let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let list4 = SinglyLinkedList::from_vec(vec![4, 5, 6]); + + list1.insert(&list4, 0); + assert_eq!(list1.as_vec(), vec![4, 5, 6, 1, 2, 3]); + + list2.insert(&list4, 1); + assert_eq!(list2.as_vec(), vec![1, 4, 5, 6, 2, 3]); + + list3.insert(&list4, 4); + assert_eq!(list3.as_vec(), vec![1, 2, 3, 4, 5, 6]); + } + + #[test] + fn test_chunk_reverse() { + let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); + list1.chunk_reverse(3); + assert_eq!(list1.as_vec(), vec![7, 8, 9, 3, 4, 5, 1, 2, 3]); + + let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8]); + list2.chunk_reverse(3); + assert_eq!(list2.as_vec(), vec![7, 8, 4, 5, 6, 1, 2, 3]); + + let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + list3.chunk_reverse(4); + assert_eq!(list3.as_vec(), vec![1, 2, 3]); + + let mut list4 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]); + list4.chunk_reverse(1); + assert_eq!(list4.as_vec(), vec![4, 3, 2, 1]); + + let mut list5 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]); + list4.chunk_reverse(0); + assert_eq!(list4.as_vec(), vec![1, 2, 3, 4]); + } + + #[test] + fn test_pair_map() { + let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); + let add = |x: i32, y: i32| x + y; + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![3, 5, 7, 9, 11, 13, 15, 17]); + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![8, 12, 16, 20, 24, 28, 32]); + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![20, 28, 36, 44, 52, 60]); + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![48, 64, 80, 96, 112]); + } + + #[test] + fn test_flatten() { + let list1 = SinglyLinkedList::from_vec(vec![1, 2]); + let list2 = SinglyLinkedList::from_vec(vec![3]); + let list3 = SinglyLinkedList::from_vec(vec![4, 5, 6, 7]); + let list4 = SinglyLinkedList::::new(); + let list5 = SinglyLinkedList::from_vec(vec![8, 9, 10]); + + let list_list = SinglyLinkedList::from_vec(vec![list1, list2, list3, list4, list5]); + + assert_eq!( + list_list.flatten().as_vec(), + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ); + } } diff --git a/src/assignments/assignment11/mod.rs b/src/assignments/assignment11/mod.rs index 266f7d7..53dacb5 100644 --- a/src/assignments/assignment11/mod.rs +++ b/src/assignments/assignment11/mod.rs @@ -4,16 +4,26 @@ //! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to . -pub mod bst; -pub mod bst_grade; -pub mod doubly_linked_list; -pub mod doubly_linked_list_grade; -pub mod graph; -pub mod graph_grade; pub mod linked_list; +mod linked_list_grade; + +pub mod peano_nat; +mod peano_nat_grade; + +pub mod bst; +mod bst_grade; + +pub mod doubly_linked_list; +mod doubly_linked_list_grade; + +pub mod graph; +mod graph_grade; + pub mod mock_storage; pub mod mock_storage_grade; -pub mod turing_machine; -pub mod turing_machine_grade; + pub mod tv_room; pub mod tv_room_grade; + +pub mod turing_machine; +pub mod turing_machine_grade; diff --git a/src/assignments/assignment11/peano_nat.rs b/src/assignments/assignment11/peano_nat.rs new file mode 100644 index 0000000..c79ab3c --- /dev/null +++ b/src/assignments/assignment11/peano_nat.rs @@ -0,0 +1,56 @@ +//! Peano natural number. + +/// We can represent any natural number using only two symbols: 0 and S. +/// +/// E.g. +/// O == 0 +/// S(O) == 1 +/// S(S(O)) == 2 +/// ... so on. +#[derive(Debug, Clone, PartialEq)] +pub enum Nat { + /// Zero + O, + /// Plus one + S(Box), +} + +impl Nat { + /// Create `Nat` from `usize` + pub fn from_usize(n: usize) -> Nat { + todo!() + } + + /// Convert `Nat` into nonnegative integer + pub fn as_usize(&self) -> usize { + todo!() + } +} + +// Implement `Add` operator (i.e. `+`) for `Nat`. +impl std::ops::Add for Nat { + type Output = Nat; + + fn add(self, rhs: Self) -> Self::Output { + todo!() + } +} + +// Implement `Sub` operator (i.e. `-`) for `Nat`. +// If the result is negative, return `Nat::O`. +impl std::ops::Sub for Nat { + type Output = Nat; + + fn sub(self, rhs: Self) -> Self::Output { + todo!() + } +} + +// Implement `Mul` operator (i.e. `*`) for `Nat`. +impl std::ops::Mul for Nat { + type Output = Nat; + + fn mul(self, rhs: Self) -> Self::Output { + todo!() + } +} diff --git a/src/assignments/assignment11/peano_nat_grade.rs b/src/assignments/assignment11/peano_nat_grade.rs new file mode 100644 index 0000000..edada7f --- /dev/null +++ b/src/assignments/assignment11/peano_nat_grade.rs @@ -0,0 +1,38 @@ +#[cfg(test)] +mod test_peano_nat { + use crate::assignments::assignment11::peano_nat::*; + + #[test] + fn test_from_as_usize() { + assert_eq!(Nat::from_usize(0), Nat::O); + assert_eq!( + Nat::from_usize(2), + Nat::S(Box::new(Nat::S(Box::new(Nat::O)))) + ); + + for n in 0..100 { + assert_eq!(Nat::from_usize(n).as_usize(), n); + } + } + + fn safe_sub(i: usize, j: usize) -> usize { + if i > j { + i - j + } else { + 0 + } + } + + #[test] + fn test_add_sub_mul() { + for i in 0..30 { + let n = Nat::from_usize(i); + for j in 0..30 { + let m = Nat::from_usize(j); + assert_eq!((n.clone() + m.clone()).as_usize(), i + j); + assert_eq!((n.clone() - m.clone()).as_usize(), safe_sub(i, j)); + assert_eq!((n.clone() * m.clone()).as_usize(), i * j); + } + } + } +} From ce3051cbd71aa3365e785df419af461cb45ce794 Mon Sep 17 00:00:00 2001 From: AnHaechan Date: Sat, 19 Aug 2023 16:53:31 +0000 Subject: [PATCH 06/17] grading script for 12 fixed --- scripts/grade-12.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/grade-12.sh b/scripts/grade-12.sh index 34fb51a..3c1609e 100755 --- a/scripts/grade-12.sh +++ b/scripts/grade-12.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment11") + TESTS=("--lib assignment12") if [ $(run_tests) -ne 0 ]; then exit 1 fi From 24dc47a7cf44bcc9176ba21036fe292459408fb6 Mon Sep 17 00:00:00 2001 From: AnHaechan Date: Mon, 21 Aug 2023 01:58:29 +0000 Subject: [PATCH 07/17] minor format & typo fixes --- scripts/grade-11.sh | 2 +- .../grade.rs} | 3 +- src/assignments/assignment04/mod.rs | 1 + src/assignments/assignment11_grade.rs | 81 ------------------ src/assignments/assignment12/mod.rs | 8 +- src/assignments/assignment12_grade.rs | 84 ------------------- src/assignments/mod.rs | 1 - 7 files changed, 7 insertions(+), 173 deletions(-) rename src/assignments/{assignment04_grade.rs => assignment04/grade.rs} (99%) delete mode 100644 src/assignments/assignment11_grade.rs delete mode 100644 src/assignments/assignment12_grade.rs diff --git a/scripts/grade-11.sh b/scripts/grade-11.sh index 8666182..34fb51a 100755 --- a/scripts/grade-11.sh +++ b/scripts/grade-11.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment11_grade") + TESTS=("--lib assignment11") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/src/assignments/assignment04_grade.rs b/src/assignments/assignment04/grade.rs similarity index 99% rename from src/assignments/assignment04_grade.rs rename to src/assignments/assignment04/grade.rs index 64ddf35..c37073e 100644 --- a/src/assignments/assignment04_grade.rs +++ b/src/assignments/assignment04/grade.rs @@ -1,8 +1,7 @@ #[cfg(test)] mod test { use crate::assignments::assignment04::syntax::*; - - use super::super::assignment04::*; + use crate::assignments::assignment04::*; #[test] fn test_parse() { diff --git a/src/assignments/assignment04/mod.rs b/src/assignments/assignment04/mod.rs index 7c6a681..4b927d8 100644 --- a/src/assignments/assignment04/mod.rs +++ b/src/assignments/assignment04/mod.rs @@ -16,5 +16,6 @@ //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment04.zip` to . pub mod context; +mod grade; pub mod parser; pub mod syntax; diff --git a/src/assignments/assignment11_grade.rs b/src/assignments/assignment11_grade.rs deleted file mode 100644 index 94d2902..0000000 --- a/src/assignments/assignment11_grade.rs +++ /dev/null @@ -1,81 +0,0 @@ -#[cfg(test)] -mod test { - - #[test] - fn test_tv_room() { - use crate::assignments::assignment11::tv_room::*; - - let tv_room = TVRoom::new(); - assert!(!tv_room.is_opened()); - - // Turn on and add new guests. - let manager = tv_room.open().unwrap(); - assert!(tv_room.is_opened()); - let guest1 = manager.new_guest(); - let guest2 = manager.new_guest(); - drop(manager); - drop(guest1); - assert!(tv_room.open().is_none()); - drop(guest2); - assert!(!tv_room.is_opened()); - - // Turn on and add new guests. - let manager = tv_room.open().unwrap(); - assert!(tv_room.is_opened()); - let guest3 = manager.new_guest(); - drop(guest3); - assert!(tv_room.is_opened()); - drop(manager); - assert!(!tv_room.is_opened()); - } - - #[test] - fn test_mock_storage() { - use crate::assignments::assignment11::mock_storage::*; - - let mock_storage = MockStorage::new(100); - - let uploader1 = FileUploader::new(&mock_storage); - let uploader2 = FileUploader::new(&mock_storage); - - let usage_analyzer = UsageAnalyzer::new(&mock_storage, 0.75); - - assert!(uploader1.upload("file1.txt", 20).is_ok()); - assert!(usage_analyzer.is_usage_under_bound()); - - assert!(uploader2.upload("file2.txt", 30).is_ok()); - assert!(usage_analyzer.is_usage_under_bound()); - - assert!(uploader1.upload("file3.txt", 40).is_ok()); - assert!(!usage_analyzer.is_usage_under_bound()); - - assert_eq!(uploader2.upload("file4.txt", 50), Err(40)); - assert!(!usage_analyzer.is_usage_under_bound()); - - assert!(uploader1.upload("file3.txt", 10).is_ok()); - assert!(usage_analyzer.is_usage_under_bound()); - } - - #[derive(Debug, PartialEq, Eq)] - struct V(usize); - - #[test] - fn test_linked_list() { - use crate::assignments::assignment11::linked_list::*; - - let mut list = SinglyLinkedList::new(); - list.push_back(V(3)); - list.push_front(V(2)); - list.push_back(V(4)); - list.push_front(V(1)); - list.push_back(V(5)); - - assert_eq!(list.pop_front(), Some(V(1))); - assert_eq!(list.pop_back(), Some(V(5))); - assert_eq!(list.pop_front(), Some(V(2))); - assert_eq!(list.pop_back(), Some(V(4))); - assert_eq!(list.pop_front(), Some(V(3))); - assert_eq!(list.pop_back(), None); - assert_eq!(list.pop_front(), None); - } -} diff --git a/src/assignments/assignment12/mod.rs b/src/assignments/assignment12/mod.rs index ae03552..7b82d6e 100644 --- a/src/assignments/assignment12/mod.rs +++ b/src/assignments/assignment12/mod.rs @@ -6,10 +6,10 @@ //! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script. pub mod card; -pub mod card_grade; +mod card_grade; pub mod demux; -pub mod demux_grade; +mod demux_grade; pub mod funnel; -pub mod funnel_grade; +mod funnel_grade; pub mod small_exercises; -pub mod small_exercises_grade; +mod small_exercises_grade; diff --git a/src/assignments/assignment12_grade.rs b/src/assignments/assignment12_grade.rs deleted file mode 100644 index ced664d..0000000 --- a/src/assignments/assignment12_grade.rs +++ /dev/null @@ -1,84 +0,0 @@ -#[cfg(test)] -mod test { - use super::super::assignment12::*; - use ntest::timeout; - - use std::sync::mpsc::channel; - use std::thread; - - #[test] - fn test_ping_pong() { - let (tx1, mut rx1) = channel(); - let (mut tx2, rx2) = channel(); - - let thread_ping = thread::spawn(move || { - for i in 0..100 { - tx1.send(i).unwrap(); - let x = rx2.recv().unwrap(); - assert_eq!(x, i + 1); - } - }); - - let thread_pong = thread::spawn(move || while pong(&mut rx1, &mut tx2) {}); - - thread_ping.join().unwrap(); - thread_pong.join().unwrap(); - } - - #[test] - fn test_scoped_thread() { - for i in 0..100 { - let v = (0..i).collect::>(); - - thread::scope(|s| { - let (r1, r2) = use_scoped_thread( - s, - || v.iter().sum::(), - || v.windows(2).map(|x| x[0] * x[1]).sum::(), - ); - - assert_eq!(r1, v.iter().sum()); - assert_eq!(r2, v.windows(2).map(|x| x[0] * x[1]).sum()); - }); - } - } - - #[test] - #[timeout(5000)] - fn test_scoped_thread_concurrent() { - use std::sync::Mutex; - - let m = Mutex::new(0); - let (r1, r2) = thread::scope(|s| { - use_scoped_thread( - s, - || { - for i in 0..100 { - loop { - let mut a = m.lock().unwrap(); - if *a == 2 * i { - *a += 1; - break; - } - } - } - thread::current().id() - }, - || { - for i in 0..100 { - loop { - let mut a = m.lock().unwrap(); - if *a == 2 * i + 1 { - *a += 1; - break; - } - } - } - thread::current().id() - }, - ) - }); - - assert!(r1 != r2); - } -} diff --git a/src/assignments/mod.rs b/src/assignments/mod.rs index e7e80a2..ecc70a2 100644 --- a/src/assignments/mod.rs +++ b/src/assignments/mod.rs @@ -13,7 +13,6 @@ mod assignment02_grade; pub mod assignment03; mod assignment03_grade; pub mod assignment04; -mod assignment04_grade; pub mod assignment06; pub mod assignment07; pub mod assignment08; From d28bca2b181bc72cd187879707f68fe0399a6e90 Mon Sep 17 00:00:00 2001 From: AnHaechan Date: Mon, 21 Aug 2023 07:13:27 +0000 Subject: [PATCH 08/17] assignment 1~5: fixes - assignment05/pascal.mlw: lowered the difficulty (one more invariant given) - assignment02, 03: minor fixes & divide into sub-problems --- .../why3/{ => assignment05}/binary_search.mlw | 2 +- assets/why3/{ => assignment05}/max.mlw | 6 +- assets/why3/{ => assignment05}/pascal.mlw | 15 +- .../ex1_eucl_div.mlw} | 3 +- .../why3/{fact.mlw => exercises/ex2_fact.mlw} | 6 +- .../ex3_two_way.mlw} | 8 +- .../exercises/solutions/ex1_eucl_div_sol.mlw | 30 ++ .../why3/exercises/solutions/ex2_fact_sol.mlw | 37 +++ .../exercises/solutions/ex3_two_way_sol.mlw | 49 +++ scripts/grade-02.sh | 2 +- scripts/grade-03.sh | 2 +- src/assignments/assignment02.rs | 176 ---------- src/assignments/assignment02/mod.rs | 13 + .../assignment02/small_problems.rs | 46 +++ .../assignment02/small_problems_grade.rs | 137 ++++++++ src/assignments/assignment02/vec_and_mat.rs | 121 +++++++ .../assignment02/vec_and_mat_grade.rs | 60 ++++ src/assignments/assignment02_grade.rs | 303 ------------------ src/assignments/assignment03.rs | 288 ----------------- .../assignment03/custom_operators.rs | 79 +++++ .../assignment03/custom_operators_grade.rs | 58 ++++ src/assignments/assignment03/mod.rs | 13 + src/assignments/assignment03/parse_shell.rs | 28 ++ .../assignment03/parse_shell_grade.rs | 38 +++ .../assignment03/small_problems.rs | 130 ++++++++ .../small_problems_grade.rs} | 149 +-------- src/assignments/mod.rs | 2 - 27 files changed, 863 insertions(+), 938 deletions(-) rename assets/why3/{ => assignment05}/binary_search.mlw (99%) rename assets/why3/{ => assignment05}/max.mlw (76%) rename assets/why3/{ => assignment05}/pascal.mlw (60%) rename assets/why3/{eucl_div.mlw => exercises/ex1_eucl_div.mlw} (82%) rename assets/why3/{fact.mlw => exercises/ex2_fact.mlw} (82%) rename assets/why3/{two_way.mlw => exercises/ex3_two_way.mlw} (84%) create mode 100644 assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw create mode 100644 assets/why3/exercises/solutions/ex2_fact_sol.mlw create mode 100644 assets/why3/exercises/solutions/ex3_two_way_sol.mlw delete mode 100644 src/assignments/assignment02.rs create mode 100644 src/assignments/assignment02/mod.rs create mode 100644 src/assignments/assignment02/small_problems.rs create mode 100644 src/assignments/assignment02/small_problems_grade.rs create mode 100644 src/assignments/assignment02/vec_and_mat.rs create mode 100644 src/assignments/assignment02/vec_and_mat_grade.rs delete mode 100644 src/assignments/assignment02_grade.rs delete mode 100644 src/assignments/assignment03.rs create mode 100644 src/assignments/assignment03/custom_operators.rs create mode 100644 src/assignments/assignment03/custom_operators_grade.rs create mode 100644 src/assignments/assignment03/mod.rs create mode 100644 src/assignments/assignment03/parse_shell.rs create mode 100644 src/assignments/assignment03/parse_shell_grade.rs create mode 100644 src/assignments/assignment03/small_problems.rs rename src/assignments/{assignment03_grade.rs => assignment03/small_problems_grade.rs} (58%) diff --git a/assets/why3/binary_search.mlw b/assets/why3/assignment05/binary_search.mlw similarity index 99% rename from assets/why3/binary_search.mlw rename to assets/why3/assignment05/binary_search.mlw index e00e19f..931cc48 100644 --- a/assets/why3/binary_search.mlw +++ b/assets/why3/assignment05/binary_search.mlw @@ -19,4 +19,4 @@ module BinarySearch = (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) 0 (* TODO *) -end +end \ No newline at end of file diff --git a/assets/why3/max.mlw b/assets/why3/assignment05/max.mlw similarity index 76% rename from assets/why3/max.mlw rename to assets/why3/assignment05/max.mlw index 92ef8dd..b0b858b 100644 --- a/assets/why3/max.mlw +++ b/assets/why3/assignment05/max.mlw @@ -4,7 +4,6 @@ return the maximum element of the array. You should stengthen the loop invariant. - *) module Max @@ -20,8 +19,9 @@ module Max ensures { exists i. 0 <= i < n -> a[i] = max } = let ref max = 0 in for i = 0 to n - 1 do - (* IMPORTANT: MODIFY ONLY THIS INVARIANT, OR YOU'LL GET ZERO POINTS *) - invariant { true (*TODO*) } + (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) + invariant { true (* TODO: Replace `true` with your solution *) } + (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) if max < a[i] then max <- a[i]; done; max diff --git a/assets/why3/pascal.mlw b/assets/why3/assignment05/pascal.mlw similarity index 60% rename from assets/why3/pascal.mlw rename to assets/why3/assignment05/pascal.mlw index 7b838ca..2d0fa93 100644 --- a/assets/why3/pascal.mlw +++ b/assets/why3/assignment05/pascal.mlw @@ -1,10 +1,14 @@ +(* Pascal + + Prove that the Pascal's triangle indeed computes combinations. + HINT: https://en.wikipedia.org/wiki/Pascal%27s_triangle +*) + module Pascal use int.Int use ref.Ref use array.Array - (* HINT: https://en.wikipedia.org/wiki/Pascal%27s_triangle *) - (* You should understand the Pascal's triangle first to find good invariants *) let rec function comb (n k: int) : int requires { 0 <= k <= n } variant { n } @@ -12,6 +16,7 @@ module Pascal = if k = 0 || k = n then 1 else comb (n-1) k + comb (n-1) (k-1) (* Insert appropriate invariants so that Why3 can verify this function. *) + (* You SHOULD understand the Pascal's triangle first to find good invariants. *) let chooses (n : int) : array int requires { n > 0 } ensures { forall i: int. @@ -20,10 +25,12 @@ module Pascal let ref row = Array.make 1 1 in for r = 1 to n do invariant { length row = r } - invariant { true (*TODO*) } + invariant { forall c: int. 0 <= c < r -> row[c] = comb (r-1) c } let new_row = Array.make (r+1) 1 in for c = 1 to r-1 do - invariant { true (*TODO*) } + (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) + invariant { true (* TODO: Replace `true` with your solution *) } + (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) new_row[c] <- row[c-1] + row[c] done; row <- new_row diff --git a/assets/why3/eucl_div.mlw b/assets/why3/exercises/ex1_eucl_div.mlw similarity index 82% rename from assets/why3/eucl_div.mlw rename to assets/why3/exercises/ex1_eucl_div.mlw index 27cf0d1..c4aaf20 100644 --- a/assets/why3/eucl_div.mlw +++ b/assets/why3/exercises/ex1_eucl_div.mlw @@ -11,7 +11,6 @@ module Division use int.Int - (* IMPORTANT: DON'T MODIFY LINES EXCEPT `TODO`s OR YOU WILL GET ZERO POINTS *) let division (a b: int) : int requires { a >= 0 } requires { b > 0 } @@ -20,7 +19,7 @@ module Division let ref q = 0 in let ref r = a in while r >= b do - invariant { true (*TODO*) } + invariant { true (* TODO: Replace `true` with your solution *) } variant { r } q <- q + 1; r <- r - b diff --git a/assets/why3/fact.mlw b/assets/why3/exercises/ex2_fact.mlw similarity index 82% rename from assets/why3/fact.mlw rename to assets/why3/exercises/ex2_fact.mlw index 42d995d..adad25e 100644 --- a/assets/why3/fact.mlw +++ b/assets/why3/exercises/ex2_fact.mlw @@ -39,10 +39,8 @@ module FactLoop = let ref m = 0 in let ref r = 1 in while m < n do - (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) - invariant { true (* TODO *) } - variant { n (* TODO *) } - (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) + invariant { true (* TODO: Replace `true` with your solution *) } + variant { n (* TODO: Replace `n` with your solution *) } m <- m + 1; r <- r * m done; diff --git a/assets/why3/two_way.mlw b/assets/why3/exercises/ex3_two_way.mlw similarity index 84% rename from assets/why3/two_way.mlw rename to assets/why3/exercises/ex3_two_way.mlw index 371ce71..24705bd 100644 --- a/assets/why3/two_way.mlw +++ b/assets/why3/exercises/ex3_two_way.mlw @@ -31,13 +31,11 @@ module TwoWaySort let ref j = length a - 1 in while i < j do invariant { 0 <= i /\ j < length a } - (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) invariant { forall i1: int. 0 <= i1 < i - -> true (* TODO *) } + -> true (* TODO: Replace `true` with your solution *) } invariant { forall i2: int. j < i2 < length a - -> true (* TODO *) } - invariant { true (* TODO *) } - (* IMPORTANT: DON'T MODIFY THE BELOW LINES *) + -> true (* TODO: Replace `true` with your solution *) } + invariant { true (* TODO: Replace `true` with your solution *) } variant { j - i } if not a[i] then incr i diff --git a/assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw b/assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw new file mode 100644 index 0000000..f8580e7 --- /dev/null +++ b/assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw @@ -0,0 +1,30 @@ +(* Euclidean division + + 1. Prove correctness of euclideian divison: + `division a b` returns an integer `q` such that + `a = bq+r` and `0 <= r < b` for some `r`. + + - You have to strengthen the precondition. + - You have to strengthen the loop invariant. +*) + +module Division + + use int.Int + + let division (a b: int) : int + requires { a >= 0 } + requires { b > 0 } + ensures { exists r: int. a = b * result + r /\ 0 <= r < b } + = + let ref q = 0 in + let ref r = a in + while r >= b do + invariant { a = b * q + r /\ 0 <= r } + variant { r } + q <- q + 1; + r <- r - b + done; + q + +end \ No newline at end of file diff --git a/assets/why3/exercises/solutions/ex2_fact_sol.mlw b/assets/why3/exercises/solutions/ex2_fact_sol.mlw new file mode 100644 index 0000000..cfd514b --- /dev/null +++ b/assets/why3/exercises/solutions/ex2_fact_sol.mlw @@ -0,0 +1,37 @@ +(* Two programs to compute the factorial + +*) + +module FactRecursive + + use int.Int + use int.Fact + + let rec fact_rec (n: int) : int + requires { n >= 0 } + ensures { result = fact n } + variant { n } + = + if n = 0 then 1 else n * fact_rec (n - 1) + +end + +module FactLoop + + use int.Int + use int.Fact + + let fact_loop (n: int) : int + requires { 0 < n } + ensures { result = fact n } + = let ref m = 0 in + let ref r = 1 in + while m < n do + invariant { 0 <= m <= n /\ r = fact m } + variant { n - m } + m <- m + 1; + r <- r * m + done; + r + +end \ No newline at end of file diff --git a/assets/why3/exercises/solutions/ex3_two_way_sol.mlw b/assets/why3/exercises/solutions/ex3_two_way_sol.mlw new file mode 100644 index 0000000..72a6bb7 --- /dev/null +++ b/assets/why3/exercises/solutions/ex3_two_way_sol.mlw @@ -0,0 +1,49 @@ +(* Two Way Sort + + The following program sorts an array of Boolean values, with False a[i1] << a[i2] + + let two_way_sort (a: array bool) : unit + ensures { sorted a } + ensures { permut_all (old a) a } + = + let ref i = 0 in + let ref j = length a - 1 in + while i < j do + invariant { 0 <= i /\ j < length a } + invariant { forall i1: int. 0 <= i1 < i -> a[i1] = False } + invariant { forall i2: int. j < i2 < length a -> a[i2] = True } + invariant { permut_all (old a) a } + variant { j - i } + if not a[i] then + incr i + else if a[j] then + decr j + else begin + swap a i j; + incr i; + decr j + end + done + +end \ No newline at end of file diff --git a/scripts/grade-02.sh b/scripts/grade-02.sh index 570f0e4..2d50a5c 100755 --- a/scripts/grade-02.sh +++ b/scripts/grade-02.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment02_grade") + TESTS=("--lib assignment02") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/scripts/grade-03.sh b/scripts/grade-03.sh index bce3607..4e9f47e 100755 --- a/scripts/grade-03.sh +++ b/scripts/grade-03.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment03_grade") + TESTS=("--lib assignment03") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/src/assignments/assignment02.rs b/src/assignments/assignment02.rs deleted file mode 100644 index b747baf..0000000 --- a/src/assignments/assignment02.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! Assignment 2: Mastering common programming concepts (1/2). -//! -//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, especially those in the Rust Book chapters 3 and 5. -//! Please make sure you're comfortable with the concepts to proceed on to the next assignments. -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-02.sh` works fine. -//! See `assignment02_grade.rs` and `/scripts/grade-02.sh` for the test script. - -use std::ops::Mul; - -const FAHRENHEIT_OFFSET: f64 = 32.0; -const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0; - -/// Converts Fahrenheit to Celsius temperature degree. -pub fn fahrenheit_to_celsius(degree: f64) -> f64 { - todo!() -} - -/// Capitalizes English alphabets (leaving the other characters intact). -pub fn capitalize(input: String) -> String { - todo!() -} - -/// Returns the sum of the given array. (We assume the absence of integer overflow.) -pub fn sum_array(input: &[u64]) -> u64 { - todo!() -} - -/// Given a non-negative integer, say `n`, return the smallest integer of the form `3^m` that's greater than or equal to `n`. -/// -/// For instance, up3(6) = 9, up3(9) = 9, up3(10) = 27. (We assume the absence of integer overflow.) -pub fn up3(n: u64) -> u64 { - todo!() -} - -/// Returns the greatest common divisor (GCD) of two non-negative integers. (We assume the absence of integer overflow.) -pub fn gcd(lhs: u64, rhs: u64) -> u64 { - todo!() -} - -/// Returns the array of nC0, nC1, nC2, ..., nCn, where nCk = n! / (k! * (n-k)!). (We assume the absence of integer overflow.) -/// -/// Consult for computation of binomial coefficients without integer overflow. -pub fn chooses(n: u64) -> Vec { - todo!() -} - -/// Returns the "zip" of two vectors. -/// -/// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`. -/// Here, `3` is ignored because it doesn't have a partner. -pub fn zip(lhs: Vec, rhs: Vec) -> Vec<(u64, u64)> { - todo!() -} - -/// 2x2 matrix of the following configuration: -/// -/// a, b -/// c, d -#[derive(Debug, Clone, Copy)] -struct Mat2 { - a: u64, - b: u64, - c: u64, - d: u64, -} - -/// 2x1 matrix of the following configuration: -/// -/// a -/// b -#[derive(Debug, Clone, Copy)] -struct Vec2 { - a: u64, - b: u64, -} - -impl Mat2 { - /// Creates an identity matrix. - fn new() -> Self { - Self { - a: 1, - b: 0, - c: 0, - d: 1, - } - } -} - -impl Mul for Mat2 { - type Output = Mat2; - - fn mul(self, rhs: Mat2) -> Self::Output { - todo!() - } -} - -impl Mul for Mat2 { - type Output = Vec2; - - fn mul(self, rhs: Vec2) -> Self::Output { - todo!() - } -} - -impl Mat2 { - /// Calculates the power of matrix. - fn power(self, power: u64) -> Mat2 { - todo!() - } -} - -impl Vec2 { - /// Gets the upper value of vector. - fn get_upper(self) -> u64 { - todo!() - } -} - -/// The matrix used for calculating Fibonacci numbers. -const FIBONACCI_MAT: Mat2 = Mat2 { - a: 1, - b: 1, - c: 1, - d: 0, -}; - -/// The vector used for calculating Fibonacci numbers. -const FIBONACCI_VEC: Vec2 = Vec2 { a: 1, b: 0 }; - -/// Calculates the Fibonacci number. (We assume the absence of integer overflow.) -/// -/// Consult for matrix computation of Fibonacci numbers. -pub fn fibonacci(n: u64) -> u64 { - (FIBONACCI_MAT.power(n) * FIBONACCI_VEC).get_upper() -} - -/// 2x2 floating-point matrix of the following configuration: -/// -/// a, b -/// c, d -#[derive(Debug, Clone, Copy)] -pub struct FMat2 { - /// row 1, column 1 - pub a: f64, - /// row 1, column 2 - pub b: f64, - /// row 2, column 1 - pub c: f64, - /// row 2, column 2 - pub d: f64, -} - -impl FMat2 { - /// Returns the inverse of the given matrix. (We assume the given matrix is always invertible.) - /// Hint: https://www.cuemath.com/algebra/inverse-of-2x2-matrix/ - /// - /// # Example - /// - /// ``` - /// assert_eq!( - /// Mat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(), - /// Mat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0} - /// ); - /// ``` - pub fn inverse(self) -> Self { - todo!() - } -} - -/// Writes down the lyrics of "twelve days of christmas". -/// -/// Hint: Google the song title for lyrics and look at the test code for the expected result. -pub fn twelve_days_of_christmas_lyrics() -> String { - todo!() -} diff --git a/src/assignments/assignment02/mod.rs b/src/assignments/assignment02/mod.rs new file mode 100644 index 0000000..86a15c7 --- /dev/null +++ b/src/assignments/assignment02/mod.rs @@ -0,0 +1,13 @@ +//! Assignment 2: Mastering common programming concepts (1/2). +//! +//! The primary goal of this assignment is to re-learn the common programming concepts in Rust, especially those in the Rust Book chapters 3 and 5. +//! Please make sure you're comfortable with the concepts to proceed on to the next assignments. +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-02.sh` works fine. +//! See `*_grade.rs` and `/scripts/grade-02.sh` for the test script. + +pub mod small_problems; +mod small_problems_grade; + +pub mod vec_and_mat; +mod vec_and_mat_grade; diff --git a/src/assignments/assignment02/small_problems.rs b/src/assignments/assignment02/small_problems.rs new file mode 100644 index 0000000..8f962b7 --- /dev/null +++ b/src/assignments/assignment02/small_problems.rs @@ -0,0 +1,46 @@ +//! Small problems. + +const FAHRENHEIT_OFFSET: f64 = 32.0; +const FAHRENHEIT_SCALE: f64 = 5.0 / 9.0; + +/// Converts Fahrenheit to Celsius temperature degree. +pub fn fahrenheit_to_celsius(degree: f64) -> f64 { + todo!() +} + +/// Capitalizes English alphabets (leaving the other characters intact). +pub fn capitalize(input: String) -> String { + todo!() +} + +/// Returns the sum of the given array. (We assume the absence of integer overflow.) +pub fn sum_array(input: &[u64]) -> u64 { + todo!() +} + +/// Given a non-negative integer, say `n`, return the smallest integer of the form `3^m` that's greater than or equal to `n`. +/// +/// For instance, up3(6) = 9, up3(9) = 9, up3(10) = 27. (We assume the absence of integer overflow.) +pub fn up3(n: u64) -> u64 { + todo!() +} + +/// Returns the greatest common divisor (GCD) of two non-negative integers. (We assume the absence of integer overflow.) +pub fn gcd(lhs: u64, rhs: u64) -> u64 { + todo!() +} + +/// Returns the array of nC0, nC1, nC2, ..., nCn, where nCk = n! / (k! * (n-k)!). (We assume the absence of integer overflow.) +/// +/// Consult for computation of binomial coefficients without integer overflow. +pub fn chooses(n: u64) -> Vec { + todo!() +} + +/// Returns the "zip" of two vectors. +/// +/// For instance, `zip(vec![1, 2, 3], vec![4, 5])` equals to `vec![(1, 4), (2, 5)]`. +/// Here, `3` is ignored because it doesn't have a partner. +pub fn zip(lhs: Vec, rhs: Vec) -> Vec<(u64, u64)> { + todo!() +} diff --git a/src/assignments/assignment02/small_problems_grade.rs b/src/assignments/assignment02/small_problems_grade.rs new file mode 100644 index 0000000..ae33ff1 --- /dev/null +++ b/src/assignments/assignment02/small_problems_grade.rs @@ -0,0 +1,137 @@ +#[cfg(test)] +mod test { + use crate::assignments::assignment02::small_problems::*; + + #[test] + fn test_fahrenheit() { + assert_eq!(fahrenheit_to_celsius(32.0), 0.0); + assert_eq!(fahrenheit_to_celsius(212.0), 100.0); + } + + #[test] + fn test_capitalize() { + assert_eq!( + capitalize(String::from("aAbbBcccCddddD❤한글과✓")), + String::from("AABBBCCCCDDDDD❤한글과✓"), + ); + assert_eq!(capitalize(String::from("Tschüß")), String::from("TSCHüß")); + } + + #[test] + fn test_up3() { + assert_eq!(up3(0), 1); + assert_eq!(up3(1), 1); + assert_eq!(up3(6), 9); + assert_eq!(up3(9), 9); + assert_eq!(up3(10), 27); + assert_eq!(up3(1_000_000), 1_594_323); + assert_eq!(up3(3u64.pow(39).wrapping_add(1)), 3u64.pow(40)); + assert_eq!(up3(3u64.pow(40)), 3u64.pow(40)); + } + + #[test] + fn test_gcd() { + assert_eq!(gcd(5, 1), 1); + assert_eq!(gcd(3, 3), 3); + assert_eq!(gcd(2, 6), 2); + assert_eq!(gcd(24, 18), 6); + assert_eq!(gcd(20, 63), 1); + assert_eq!(gcd(0, 33), 33); + } + + #[test] + fn test_sum_array() { + assert_eq!(sum_array(&[]), 0); + assert_eq!(sum_array(&[1]), 1); + assert_eq!(sum_array(&[1, 2, 3, 4, 5, 100]), 115); + } + + #[test] + fn test_chooses() { + assert_eq!(chooses(0), vec![1]); + assert_eq!(chooses(1), vec![1, 1]); + assert_eq!(chooses(5), vec![1, 5, 10, 10, 5, 1]); + assert_eq!(chooses(6), vec![1, 6, 15, 20, 15, 6, 1]); + assert_eq!( + chooses(67), + vec![ + 1, + 67, + 2211, + 47905, + 766480, + 9657648, + 99795696, + 869648208, + 6522361560, + 42757703560, + 247994680648, + 1285063345176, + 5996962277488, + 25371763481680, + 97862516286480, + 345780890878896, + 1123787895356412, + 3371363686069236, + 9364899127970100, + 24151581961607100, + 57963796707857040, + 129728497393775280, + 271250494550621040, + 530707489338171600, + 972963730453314600, + 1673497616379701112, + 2703342303382594104, + 4105075349580976232, + 5864393356544251760, + 7886597962249166160, + 9989690752182277136, + 11923179284862717872, + 13413576695470557606, + 14226520737620288370, + 14226520737620288370, + 13413576695470557606, + 11923179284862717872, + 9989690752182277136, + 7886597962249166160, + 5864393356544251760, + 4105075349580976232, + 2703342303382594104, + 1673497616379701112, + 972963730453314600, + 530707489338171600, + 271250494550621040, + 129728497393775280, + 57963796707857040, + 24151581961607100, + 9364899127970100, + 3371363686069236, + 1123787895356412, + 345780890878896, + 97862516286480, + 25371763481680, + 5996962277488, + 1285063345176, + 247994680648, + 42757703560, + 6522361560, + 869648208, + 99795696, + 9657648, + 766480, + 47905, + 2211, + 67, + 1 + ] + ); + } + + #[test] + fn test_zip() { + assert_eq!(zip(vec![1, 2], vec![4, 5]), vec![(1, 4), (2, 5)]); + assert_eq!(zip(vec![1, 2, 3], vec![4, 5]), vec![(1, 4), (2, 5)]); + assert_eq!(zip(vec![1, 2], vec![4, 5, 6]), vec![(1, 4), (2, 5)]); + assert_eq!(zip(vec![], vec![4, 5]), vec![]); + } +} diff --git a/src/assignments/assignment02/vec_and_mat.rs b/src/assignments/assignment02/vec_and_mat.rs new file mode 100644 index 0000000..df969b3 --- /dev/null +++ b/src/assignments/assignment02/vec_and_mat.rs @@ -0,0 +1,121 @@ +//! Vector and matrices. +//! +//! You will implement simple operations on vectors and matrices. + +use std::ops::Mul; + +/// 2x2 matrix of the following configuration: +/// +/// a, b +/// c, d +#[derive(Debug, Clone, Copy)] +struct Mat2 { + a: u64, + b: u64, + c: u64, + d: u64, +} + +/// 2x1 matrix of the following configuration: +/// +/// a +/// b +#[derive(Debug, Clone, Copy)] +struct Vec2 { + a: u64, + b: u64, +} + +impl Mat2 { + /// Creates an identity matrix. + fn new() -> Self { + Self { + a: 1, + b: 0, + c: 0, + d: 1, + } + } +} + +impl Mul for Mat2 { + type Output = Mat2; + + fn mul(self, rhs: Mat2) -> Self::Output { + todo!() + } +} + +impl Mul for Mat2 { + type Output = Vec2; + + /// Multiplies the matrix by the vector. + fn mul(self, rhs: Vec2) -> Self::Output { + todo!() + } +} + +impl Mat2 { + /// Calculates the power of matrix. + fn power(self, power: u64) -> Mat2 { + todo!() + } +} + +impl Vec2 { + /// Gets the upper value of vector. + fn get_upper(self) -> u64 { + todo!() + } +} + +/// The matrix used for calculating Fibonacci numbers. +const FIBONACCI_MAT: Mat2 = Mat2 { + a: 1, + b: 1, + c: 1, + d: 0, +}; + +/// The vector used for calculating Fibonacci numbers. +const FIBONACCI_VEC: Vec2 = Vec2 { a: 1, b: 0 }; + +/// Calculates the Fibonacci number. (We assume the absence of integer overflow.) +/// +/// Consult for matrix computation of Fibonacci numbers. +pub fn fibonacci(n: u64) -> u64 { + (FIBONACCI_MAT.power(n) * FIBONACCI_VEC).get_upper() +} + +/// 2x2 floating-point matrix of the following configuration: +/// +/// a, b +/// c, d +#[derive(Debug, Clone, Copy)] +pub struct FMat2 { + /// row 1, column 1 + pub a: f64, + /// row 1, column 2 + pub b: f64, + /// row 2, column 1 + pub c: f64, + /// row 2, column 2 + pub d: f64, +} + +impl FMat2 { + /// Returns the inverse of the given matrix. (We assume the given matrix is always invertible.) + /// HINT: https://www.mathcentre.ac.uk/resources/uploaded/sigma-matrices7-2009-1.pdf + /// + /// # Example + /// + /// ``` + /// assert_eq!( + /// Mat2 { a: 1.0, b: 1.0, c: 2.0, d: 3.0 }.inverse(), + /// Mat2 { a: 3.0, b: -1.0, c: -2.0, d: 1.0} + /// ); + /// ``` + pub fn inverse(self) -> Self { + todo!() + } +} diff --git a/src/assignments/assignment02/vec_and_mat_grade.rs b/src/assignments/assignment02/vec_and_mat_grade.rs new file mode 100644 index 0000000..bf47fa7 --- /dev/null +++ b/src/assignments/assignment02/vec_and_mat_grade.rs @@ -0,0 +1,60 @@ +#[cfg(test)] +mod test { + use crate::assignments::assignment02::vec_and_mat::*; + + #[test] + fn test_fibonacci() { + assert_eq!(fibonacci(0), 1); + assert_eq!(fibonacci(1), 1); + assert_eq!(fibonacci(2), 2); + assert_eq!(fibonacci(3), 3); + assert_eq!(fibonacci(4), 5); + assert_eq!(fibonacci(5), 8); + assert_eq!(fibonacci(6), 13); + assert_eq!(fibonacci(7), 21); + assert_eq!(fibonacci(50), 20365011074); + assert_eq!(fibonacci(92), 12200160415121876738); + } + + // Equivalence between two floating-point matrices, as element-wise equivalence + use std::cmp::PartialEq; + impl PartialEq for FMat2 { + fn eq(&self, other: &FMat2) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d + } + } + + #[test] + fn test_inverse() { + assert_eq!( + FMat2 { + a: 1.0, + b: 1.0, + c: 2.0, + d: 3.0 + } + .inverse(), + FMat2 { + a: 3.0, + b: -1.0, + c: -2.0, + d: 1.0 + } + ); + assert_eq!( + FMat2 { + a: 2.0, + b: 3.0, + c: 5.0, + d: 7.0 + } + .inverse(), + FMat2 { + a: -7.0, + b: 3.0, + c: 5.0, + d: -2.0 + } + ); + } +} diff --git a/src/assignments/assignment02_grade.rs b/src/assignments/assignment02_grade.rs deleted file mode 100644 index 6fd72ac..0000000 --- a/src/assignments/assignment02_grade.rs +++ /dev/null @@ -1,303 +0,0 @@ -#[cfg(test)] -mod test { - use super::super::assignment02::*; - - #[test] - fn test_fahrenheit() { - assert_eq!(fahrenheit_to_celsius(32.0), 0.0); - assert_eq!(fahrenheit_to_celsius(212.0), 100.0); - } - - #[test] - fn test_capitalize() { - assert_eq!( - capitalize(String::from("aAbbBcccCddddD❤한글과✓")), - String::from("AABBBCCCCDDDDD❤한글과✓"), - ); - assert_eq!(capitalize(String::from("Tschüß")), String::from("TSCHüß")); - } - - #[test] - fn test_up3() { - assert_eq!(up3(0), 1); - assert_eq!(up3(1), 1); - assert_eq!(up3(6), 9); - assert_eq!(up3(9), 9); - assert_eq!(up3(10), 27); - assert_eq!(up3(1_000_000), 1_594_323); - assert_eq!(up3(3u64.pow(39).wrapping_add(1)), 3u64.pow(40)); - assert_eq!(up3(3u64.pow(40)), 3u64.pow(40)); - } - - #[test] - fn test_gcd() { - assert_eq!(gcd(5, 1), 1); - assert_eq!(gcd(3, 3), 3); - assert_eq!(gcd(2, 6), 2); - assert_eq!(gcd(24, 18), 6); - assert_eq!(gcd(20, 63), 1); - assert_eq!(gcd(0, 33), 33); - } - - #[test] - fn test_sum_array() { - assert_eq!(sum_array(&[]), 0); - assert_eq!(sum_array(&[1]), 1); - assert_eq!(sum_array(&[1, 2, 3, 4, 5, 100]), 115); - } - - #[test] - fn test_chooses() { - assert_eq!(chooses(0), vec![1]); - assert_eq!(chooses(1), vec![1, 1]); - assert_eq!(chooses(5), vec![1, 5, 10, 10, 5, 1]); - assert_eq!(chooses(6), vec![1, 6, 15, 20, 15, 6, 1]); - assert_eq!( - chooses(67), - vec![ - 1, - 67, - 2211, - 47905, - 766480, - 9657648, - 99795696, - 869648208, - 6522361560, - 42757703560, - 247994680648, - 1285063345176, - 5996962277488, - 25371763481680, - 97862516286480, - 345780890878896, - 1123787895356412, - 3371363686069236, - 9364899127970100, - 24151581961607100, - 57963796707857040, - 129728497393775280, - 271250494550621040, - 530707489338171600, - 972963730453314600, - 1673497616379701112, - 2703342303382594104, - 4105075349580976232, - 5864393356544251760, - 7886597962249166160, - 9989690752182277136, - 11923179284862717872, - 13413576695470557606, - 14226520737620288370, - 14226520737620288370, - 13413576695470557606, - 11923179284862717872, - 9989690752182277136, - 7886597962249166160, - 5864393356544251760, - 4105075349580976232, - 2703342303382594104, - 1673497616379701112, - 972963730453314600, - 530707489338171600, - 271250494550621040, - 129728497393775280, - 57963796707857040, - 24151581961607100, - 9364899127970100, - 3371363686069236, - 1123787895356412, - 345780890878896, - 97862516286480, - 25371763481680, - 5996962277488, - 1285063345176, - 247994680648, - 42757703560, - 6522361560, - 869648208, - 99795696, - 9657648, - 766480, - 47905, - 2211, - 67, - 1 - ] - ); - } - - #[test] - fn test_zip() { - assert_eq!(zip(vec![1, 2], vec![4, 5]), vec![(1, 4), (2, 5)]); - assert_eq!(zip(vec![1, 2, 3], vec![4, 5]), vec![(1, 4), (2, 5)]); - assert_eq!(zip(vec![1, 2], vec![4, 5, 6]), vec![(1, 4), (2, 5)]); - assert_eq!(zip(vec![], vec![4, 5]), vec![]); - } - - #[test] - fn test_fibonacci() { - assert_eq!(fibonacci(0), 1); - assert_eq!(fibonacci(1), 1); - assert_eq!(fibonacci(2), 2); - assert_eq!(fibonacci(3), 3); - assert_eq!(fibonacci(4), 5); - assert_eq!(fibonacci(5), 8); - assert_eq!(fibonacci(6), 13); - assert_eq!(fibonacci(7), 21); - assert_eq!(fibonacci(50), 20365011074); - assert_eq!(fibonacci(92), 12200160415121876738); - } - - // Equivalence between two floating-point matrices, as element-wise equivalence - use std::cmp::PartialEq; - impl PartialEq for FMat2 { - fn eq(&self, other: &FMat2) -> bool { - self.a == other.a && self.b == other.b && self.c == other.c && self.d == other.d - } - } - - #[test] - fn test_inverse() { - assert_eq!( - FMat2 { - a: 1.0, - b: 1.0, - c: 2.0, - d: 3.0 - } - .inverse(), - FMat2 { - a: 3.0, - b: -1.0, - c: -2.0, - d: 1.0 - } - ); - assert_eq!( - FMat2 { - a: 2.0, - b: 3.0, - c: 5.0, - d: 7.0 - } - .inverse(), - FMat2 { - a: -7.0, - b: 3.0, - c: 5.0, - d: -2.0 - } - ); - } - - #[test] - fn test_lyrics() { - assert_eq!(twelve_days_of_christmas_lyrics(), LYRICS) - } - - const LYRICS: &str = r#"On the first day of Christmas, my true love sent to me -A partridge in a pear tree - -On the second day of Christmas, my true love sent to me -Two turtledoves -And a partridge in a pear tree - -On the third day of Christmas, my true love sent to me -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the fourth day of Christmas, my true love sent to me -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the fifth day of Christmas, my true love sent to me -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the sixth day of Christmas, my true love sent to me -Six geese a-laying -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the seventh day of Christmas, my true love sent to me -Seven swans a-swimming -Six geese a-laying -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the eighth day of Christmas, my true love sent to me -Eight maids a-milking -Seven swans a-swimming -Six geese a-laying -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the ninth day of Christmas, my true love sent to me -Nine ladies dancing -Eight maids a-milking -Seven swans a-swimming -Six geese a-laying -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the tenth day of Christmas, my true love sent to me -Ten lords a-leaping -Nine ladies dancing -Eight maids a-milking -Seven swans a-swimming -Six geese a-laying -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the eleventh day of Christmas, my true love sent to me -I sent eleven pipers piping -Ten lords a-leaping -Nine ladies dancing -Eight maids a-milking -Seven swans a-swimming -Six geese a-laying -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -On the twelfth day of Christmas, my true love sent to me -Twelve drummers drumming -Eleven pipers piping -Ten lords a-leaping -Nine ladies dancing -Eight maids a-milking -Seven swans a-swimming -Six geese a-laying -Five gold rings (five golden rings) -Four calling birds -Three French hens -Two turtledoves -And a partridge in a pear tree - -And a partridge in a pear tree -"#; -} diff --git a/src/assignments/assignment03.rs b/src/assignments/assignment03.rs deleted file mode 100644 index ce37c1f..0000000 --- a/src/assignments/assignment03.rs +++ /dev/null @@ -1,288 +0,0 @@ -//! Assignment 3: Mastering common programming concepts (2/2) -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-03.sh` works fine. -//! See `assignment03_grade.rs` and `/scripts/grade-03.sh` for the test script. - -use std::collections::{HashMap, HashSet}; -use std::fmt; - -/// Day of week. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DayOfWeek { - /// Sunday. - Sun, - /// Monday. - Mon, - /// Tuesday. - Tue, - /// Wednesday. - Wed, - /// Thursday. - Thu, - /// Friday. - Fri, - /// Saturday. - Sat, -} - -/// The next day of week. -/// -/// `next_weekday(Thu)` is `Fri`; and `next_weekday(Fri)` is `Mon`. -pub fn next_weekday(day: DayOfWeek) -> DayOfWeek { - todo!() -} - -/// Custom option type. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum MyOption { - /// Some value of type `T`. - MySome(T), - /// No value. - MyNone, -} - -/// Maps an `MyOption` to `MyOption` by applying a function to a contained value. -/// -/// # Examples -/// -/// Converts an `MyOption` into an `MyOption`, consuming the original: -/// -/// ``` -/// use cs220::assignments::assignment03::{my_map, MyOption}; -/// -/// fn len(s: String) -> usize { -/// s.len() -/// } -/// -/// assert_eq!(my_map(MyOption::MySome(String::from("Hello, World!")), len), MyOption::MySome(13)); -/// assert_eq!(my_map(MyOption::MyNone, len), MyOption::MyNone); -/// ``` -pub fn my_map U>(v: MyOption, f: F) -> MyOption { - todo!() -} - -/// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and returns the result. -/// -/// Some languages call this operation flatmap. -/// -/// # Examples -/// -/// ``` -/// use cs220::assignments::assignment03::{MyOption, my_and_then}; -/// -/// fn pos_then_to_string(x: isize) -> MyOption { -/// if x > 0 { -/// MyOption::MySome(x.to_string()) -/// } else { -/// MyOption::MyNone -/// } -/// } -/// -/// assert_eq!(my_and_then(MyOption::MySome(2), pos_then_to_string), MyOption::MySome(2.to_string())); -/// assert_eq!(my_and_then(MyOption::MySome(-3), pos_then_to_string), MyOption::MyNone); -/// assert_eq!(my_and_then(MyOption::MyNone, pos_then_to_string), MyOption::MyNone); -/// ``` -pub fn my_and_then MyOption>(v: MyOption, f: F) -> MyOption { - todo!() -} - -/// Given a list of integers, returns its median (when sorted, the value in the middle position). -/// -/// For a data set `x` of `n` elements, the median can be defined as follows: -/// -/// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`. -/// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`. -/// -/// For example, the following list of seven numbers, -/// -/// ```ignore -/// vec![1, 3, 3, 6, 7, 8, 9] -/// ``` -/// -/// has the median of 6, which is the fourth value. And for this data set of eight numbers, -/// -/// ```ignore -/// vec![1, 2, 3, 4, 5, 6, 8, 9] -/// ``` -/// -/// it has the median of 5, which is the fifth value. -/// -/// Returns `None` if the list is empty. -pub fn median(values: Vec) -> Option { - todo!() -} - -/// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash map will be helpful here). -/// -/// Returns `None` if the list is empty. -pub fn mode(values: Vec) -> Option { - todo!() -} - -/// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig Latin. -/// -/// 1. If a word starts with a consonant and a vowel, move the first letter of the word at the end of the word and add "ay". -/// -/// Example: "happy" -> "appyh" + "ay" -> "appyhay" -/// -/// 2. If a word starts with multiple consonants, move them to the end of the word and add "ay". -/// -/// Example: "string" -> "ingstr" + "ay" -> "ingstray" -/// -/// 3. If a word starts with a vowel, add the word "hay" at the end of the word. -/// -/// Example: "explain" -> "explain" + "hay" -> "explainhay" -/// -/// Keep in mind the details about UTF-8 encoding! -/// -/// You may assume the string only contains lowercase alphabets, and it contains at least one vowel. -pub fn piglatin(input: String) -> String { - todo!() -} - -/// Converts HR commands to the organization table. -/// -/// If the commands are as follows: -/// -/// ```ignore -/// vec!["Add Amir to Engineering", "Add Sally to Sales", "Remove Jeehoon from Sales", "Move Amir from Engineering to Sales"] -/// ``` -/// -/// The return value should be: -/// -/// ```ignore -/// ["Sales" -> ["Amir", "Sally"]] -/// ``` -/// -/// - The result is a map from department to the list of its employees. -/// - An empty department should not appear in the result. -/// - There are three commands: "Add {person} to {department}", "Remove {person} from {department}", and "Move {person} from {department} to {department}". -/// - If a command is not executable, then it's ignored. -/// - There is no space in the name of the person and department. -/// -/// See the test function for more details. -pub fn organize(commands: Vec) -> HashMap> { - todo!() -} - -/// Custom operator: `option_op_or(v1, v2, f)` -/// If neither `v1` nor `v2` is `Some`, returns `None`. -/// If exactly one is `Some`, returns the same `Some` value. -/// If both are `Some`, apply the values inside `Some` to `f` and wrap the resulting value inside `Some`. -/// -/// # Examples -/// -/// ``` -/// fn product(a: i32, b: i32) -> i32 { -/// a * b -/// } -/// -/// assert_eq!(option_op_or(None, None, product), None); -/// assert_eq!(option_op_or(Some(3), None, product), Some(3)); -/// assert_eq!(option_op_or(Some(3), Some(5), product), Some(15)); -/// ``` -pub fn option_op_or T>(v1: Option, v2: Option, f: F) -> Option { - todo!() -} - -/// Events in a text editor. -#[derive(Debug)] -pub enum TypeEvent { - /// A character is typed. - Type(char), - /// The last character is removed. - Backspace, - /// The whole string is copied to the clipboard. - Copy, - /// The string in the clipboard is appended. - Paste, -} - -/// Starting from an empty string and an empty clipboard, -/// processes the given `events` in order and returns the resulting string. -/// -/// See the test function `test_editor` for examples. -pub fn use_editor(events: Vec) -> String { - todo!() -} - -/// Parse the string as a shell command. -/// -/// Usually, a shell command is whitespace-separated array of strings. -/// ```text -/// cat file --> ["cat", "file"] -/// ``` -/// But sometimes, you may want to include whitespaces in each argument. -/// In that case, you can use quotes. -/// ```text -/// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs'] -/// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs'] -/// ``` -/// -/// For simplicity, you may assume that the string only contains alphanumeric characters, spaces -/// (" "), and single quotes ("'"). -/// -/// See `test_shell` for more examples. -pub fn parse_shell_command(command: &str) -> Vec { - todo!() -} - -/// Represents a JSON value. See https://en.wikipedia.org/wiki/JSON. -/// -/// For simplicity, you may assume that numbers are of type `i64`, and strings do not contain -/// special characters that need to be escaped (e.g. '"', '\n', ...). -#[derive(Debug, PartialEq, Eq)] -pub enum JsonValue { - /// null - Null, - /// true, false - Boolean(bool), - /// integers - Number(i64), - /// strings - String(String), - /// array of JSON values - Array(Vec), - /// objects - Object(HashMap), -} - -/// Parse a string into a JSON value. Returns `Err(())` if it contains syntax errors. -/// -/// See `test_json` for examples. -pub fn parse_json(json_string: &str) -> Result { - todo!() -} - -impl fmt::Display for JsonValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - JsonValue::Null => write!(f, "null"), - JsonValue::Boolean(b) => write!(f, "{}", b), - JsonValue::Number(n) => write!(f, "{}", n), - JsonValue::String(s) => write!(f, "\"{}\"", s), - JsonValue::Array(arr) => { - write!(f, "[")?; - let mut iter = arr.iter(); - if let Some(item) = iter.next() { - write!(f, "{}", item)?; - for item in iter { - write!(f, ", {}", item)?; - } - } - write!(f, "]") - } - JsonValue::Object(obj) => { - write!(f, "{{")?; - let mut iter = obj.iter(); - if let Some((key, value)) = iter.next() { - write!(f, "\"{}\": {}", key, value)?; - for (key, value) in iter { - write!(f, ", \"{}\": {}", key, value)?; - } - } - write!(f, "}}") - } - } - } -} diff --git a/src/assignments/assignment03/custom_operators.rs b/src/assignments/assignment03/custom_operators.rs new file mode 100644 index 0000000..137547b --- /dev/null +++ b/src/assignments/assignment03/custom_operators.rs @@ -0,0 +1,79 @@ +//! You will implement a number of custom operators. + +/// Custom option type. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MyOption { + /// Some value of type `T`. + MySome(T), + /// No value. + MyNone, +} + +/// Maps an `MyOption` to `MyOption` by applying a function to a contained value. +/// +/// # Examples +/// +/// Converts an `MyOption` into an `MyOption`, consuming the original: +/// +/// ``` +/// use cs220::assignments::assignment03::{my_map, MyOption}; +/// +/// fn len(s: String) -> usize { +/// s.len() +/// } +/// +/// assert_eq!(my_map(MyOption::MySome(String::from("Hello, World!")), len), MyOption::MySome(13)); +/// assert_eq!(my_map(MyOption::MyNone, len), MyOption::MyNone); +/// ``` +pub fn my_map U>(v: MyOption, f: F) -> MyOption { + todo!() +} + +/// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and returns the result. +/// +/// Some languages call this operation flatmap. +/// +/// # Examples +/// +/// ``` +/// use cs220::assignments::assignment03::{MyOption, my_and_then}; +/// +/// fn pos_then_to_string(x: isize) -> MyOption { +/// if x > 0 { +/// MyOption::MySome(x.to_string()) +/// } else { +/// MyOption::MyNone +/// } +/// } +/// +/// assert_eq!(my_and_then(MyOption::MySome(2), pos_then_to_string), MyOption::MySome(2.to_string())); +/// assert_eq!(my_and_then(MyOption::MySome(-3), pos_then_to_string), MyOption::MyNone); +/// assert_eq!(my_and_then(MyOption::MyNone, pos_then_to_string), MyOption::MyNone); +/// ``` +pub fn my_and_then MyOption>(v: MyOption, f: F) -> MyOption { + todo!() +} + +/// Custom operator: `option_op_or(v1, v2, f)` +/// If neither `v1` nor `v2` is `Some`, returns `None`. +/// If exactly one is `Some`, returns the same `Some` value. +/// If both are `Some`, apply the values inside `Some` to `f` and wrap the resulting value inside `Some`. +/// +/// # Examples +/// +/// ``` +/// fn product(a: i32, b: i32) -> i32 { +/// a * b +/// } +/// +/// assert_eq!(option_op_or(None, None, product), None); +/// assert_eq!(option_op_or(Some(3), None, product), Some(3)); +/// assert_eq!(option_op_or(Some(3), Some(5), product), Some(15)); +/// ``` +pub fn my_option_op_or T>( + v1: MyOption, + v2: MyOption, + f: F, +) -> MyOption { + todo!() +} diff --git a/src/assignments/assignment03/custom_operators_grade.rs b/src/assignments/assignment03/custom_operators_grade.rs new file mode 100644 index 0000000..c2dda4f --- /dev/null +++ b/src/assignments/assignment03/custom_operators_grade.rs @@ -0,0 +1,58 @@ +#[cfg(test)] +mod test { + use crate::assignments::assignment03::custom_operators::{MyOption::*, *}; + + #[test] + fn test_my_map() { + fn len(s: &str) -> usize { + s.len() + } + + fn plus_one(x: isize) -> isize { + x + 1 + } + + fn is_positive(x: f64) -> bool { + x > 0.0f64 + } + + assert_eq!(my_map(MySome("Hello, World!"), len), MySome(13)); + assert_eq!(my_map(MyNone, len), MyNone); + + assert_eq!(my_map(MySome(1), plus_one), MySome(2)); + assert_eq!(my_map(MyNone, plus_one), MyNone); + + assert_eq!(my_map(MySome(5.0f64), is_positive), MySome(true)); + assert_eq!(my_map(MySome(-3.0f64), is_positive), MySome(false)); + assert_eq!(my_map(MyNone::, is_positive), MyNone); + } + + #[test] + fn test_my_and_then() { + fn plus_one(x: isize) -> MyOption { + MySome(x + 1) + } + + fn none(_: isize) -> MyOption { + MyNone + } + + assert_eq!(my_and_then(MySome(1), plus_one), MySome(2)); + assert_eq!(my_and_then(MySome(1), none), MyNone); + + assert_eq!(my_and_then(MyNone, plus_one), MyNone); + assert_eq!(my_and_then(MyNone, none), MyNone); + } + + fn product(a: i32, b: i32) -> i32 { + a * b + } + + #[test] + fn test_my_option_op_or() { + assert_eq!(my_option_op_or(MyNone, MyNone, product), MyNone); + assert_eq!(my_option_op_or(MySome(3), MyNone, product), MySome(3)); + assert_eq!(my_option_op_or(MyNone, MySome(5), product), MySome(5)); + assert_eq!(my_option_op_or(MySome(3), MySome(5), product), MySome(15)); + } +} diff --git a/src/assignments/assignment03/mod.rs b/src/assignments/assignment03/mod.rs new file mode 100644 index 0000000..be8a24c --- /dev/null +++ b/src/assignments/assignment03/mod.rs @@ -0,0 +1,13 @@ +//! Assignment 3: Mastering common programming concepts (2/2) +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-03.sh` works fine. +//! See `*_grade.rs` and `/scripts/grade-03.sh` for the test script. + +pub mod small_problems; +mod small_problems_grade; + +pub mod parse_shell; +mod parse_shell_grade; + +pub mod custom_operators; +mod custom_operators_grade; diff --git a/src/assignments/assignment03/parse_shell.rs b/src/assignments/assignment03/parse_shell.rs new file mode 100644 index 0000000..1016149 --- /dev/null +++ b/src/assignments/assignment03/parse_shell.rs @@ -0,0 +1,28 @@ +//! Parsing a shell command. +//! +//! Shell commands are text-based instructions that you can enter in a command-line interface (CLI) +//! to interact with operating systems (e.g. Linux) and others. +//! For example, you can use the `ls` command to list files in a directory. +//! +//! You will parse a given string consists of a small number of shell commands. + +/// Parse the string as a shell command. +/// +/// Usually, a shell command is whitespace-separated array of strings. +/// ```text +/// cat file --> ["cat", "file"] +/// ``` +/// But sometimes, you may want to include whitespaces in each argument. +/// In that case, you can use quotes. +/// ```text +/// ls 'VirtualBox VMs' --> ["ls", 'VirtualBox VMs'] +/// ls VirtualBox' 'VMs --> ["ls", 'VirtualBox VMs'] +/// ``` +/// +/// For simplicity, you may assume that the string only contains alphanumeric characters, spaces +/// (" "), and single quotes ("'"). +/// +/// See `test_shell` for more examples. +pub fn parse_shell_command(command: &str) -> Vec { + todo!() +} diff --git a/src/assignments/assignment03/parse_shell_grade.rs b/src/assignments/assignment03/parse_shell_grade.rs new file mode 100644 index 0000000..d359860 --- /dev/null +++ b/src/assignments/assignment03/parse_shell_grade.rs @@ -0,0 +1,38 @@ +#[cfg(test)] +mod test { + use crate::assignments::assignment03::parse_shell::*; + + #[test] + fn test_shell() { + assert_eq!( + parse_shell_command("cat file"), + vec!["cat".to_string(), "file".to_string()] + ); + assert_eq!( + parse_shell_command("ls 'VirtualBox VMs'"), + vec!["ls".to_string(), "VirtualBox VMs".to_string()] + ); + assert_eq!( + parse_shell_command("ls VirtualBox' 'VMs"), + vec!["ls".to_string(), "VirtualBox VMs".to_string()] + ); + assert_eq!( + parse_shell_command("echo once upon a midnight dreary"), + vec![ + "echo".to_string(), + "once".to_string(), + "upon".to_string(), + "a".to_string(), + "midnight".to_string(), + "dreary".to_string(), + ] + ); + assert_eq!( + parse_shell_command("echo 'once upon a midnight dreary'"), + vec![ + "echo".to_string(), + "once upon a midnight dreary".to_string(), + ] + ); + } +} diff --git a/src/assignments/assignment03/small_problems.rs b/src/assignments/assignment03/small_problems.rs new file mode 100644 index 0000000..ed9d703 --- /dev/null +++ b/src/assignments/assignment03/small_problems.rs @@ -0,0 +1,130 @@ +//! Small problems. + +use std::collections::{HashMap, HashSet}; +use std::fmt; + +/// Day of week. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DayOfWeek { + /// Sunday. + Sun, + /// Monday. + Mon, + /// Tuesday. + Tue, + /// Wednesday. + Wed, + /// Thursday. + Thu, + /// Friday. + Fri, + /// Saturday. + Sat, +} + +/// The next day of week. +/// +/// `next_weekday(Thu)` is `Fri`; and `next_weekday(Fri)` is `Mon`. +pub fn next_weekday(day: DayOfWeek) -> DayOfWeek { + todo!() +} + +/// Given a list of integers, returns its median (when sorted, the value in the middle position). +/// +/// For a data set `x` of `n` elements, the median can be defined as follows: +/// +/// - If `n` is odd, the median is `(n+1)/2`-th smallest element of `x`. +/// - If `n` is even, the median is `(n/2)+1`-th smallest element of `x`. +/// +/// For example, the following list of seven numbers, +/// +/// ```ignore +/// vec![1, 3, 3, 6, 7, 8, 9] +/// ``` +/// +/// has the median of 6, which is the fourth value. And for this data set of eight numbers, +/// +/// ```ignore +/// vec![1, 2, 3, 4, 5, 6, 8, 9] +/// ``` +/// +/// it has the median of 5, which is the fifth value. +/// +/// Returns `None` if the list is empty. +pub fn median(values: Vec) -> Option { + todo!() +} + +/// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash map will be helpful here). +/// +/// Returns `None` if the list is empty. +pub fn mode(values: Vec) -> Option { + todo!() +} + +/// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig Latin. +/// +/// 1. If a word starts with a consonant and a vowel, move the first letter of the word at the end of the word and add "ay". +/// +/// Example: "happy" -> "appyh" + "ay" -> "appyhay" +/// +/// 2. If a word starts with multiple consonants, move them to the end of the word and add "ay". +/// +/// Example: "string" -> "ingstr" + "ay" -> "ingstray" +/// +/// 3. If a word starts with a vowel, add the word "hay" at the end of the word. +/// +/// Example: "explain" -> "explain" + "hay" -> "explainhay" +/// +/// Keep in mind the details about UTF-8 encoding! +/// +/// You may assume the string only contains lowercase alphabets, and it contains at least one vowel. +pub fn piglatin(input: String) -> String { + todo!() +} + +/// Converts HR commands to the organization table. +/// +/// If the commands are as follows: +/// +/// ```ignore +/// vec!["Add Amir to Engineering", "Add Sally to Sales", "Remove Jeehoon from Sales", "Move Amir from Engineering to Sales"] +/// ``` +/// +/// The return value should be: +/// +/// ```ignore +/// ["Sales" -> ["Amir", "Sally"]] +/// ``` +/// +/// - The result is a map from department to the list of its employees. +/// - An empty department should not appear in the result. +/// - There are three commands: "Add {person} to {department}", "Remove {person} from {department}", and "Move {person} from {department} to {department}". +/// - If a command is not executable, then it's ignored. +/// - There is no space in the name of the person and department. +/// +/// See the test function for more details. +pub fn organize(commands: Vec) -> HashMap> { + todo!() +} + +/// Events in a text editor. +#[derive(Debug)] +pub enum TypeEvent { + /// A character is typed. + Type(char), + /// The last character is removed. + Backspace, + /// The whole string is copied to the clipboard. + Copy, + /// The string in the clipboard is appended. + Paste, +} + +/// Starting from an empty string and an empty clipboard, +/// processes the given `events` in order and returns the resulting string. +/// +/// See the test function `test_editor` for examples. +pub fn use_editor(events: Vec) -> String { + todo!() +} diff --git a/src/assignments/assignment03_grade.rs b/src/assignments/assignment03/small_problems_grade.rs similarity index 58% rename from src/assignments/assignment03_grade.rs rename to src/assignments/assignment03/small_problems_grade.rs index 04980eb..21390ec 100644 --- a/src/assignments/assignment03_grade.rs +++ b/src/assignments/assignment03/small_problems_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use super::super::assignment03::*; + use crate::assignments::assignment03::small_problems::*; #[test] fn test_next_weekday() { @@ -13,52 +13,6 @@ mod test { assert_eq!(next_weekday(DayOfWeek::Sat), DayOfWeek::Mon); } - #[test] - fn test_my_map() { - use MyOption::*; - - fn len(s: &str) -> usize { - s.len() - } - - fn plus_one(x: isize) -> isize { - x + 1 - } - - fn is_positive(x: f64) -> bool { - x > 0.0f64 - } - - assert_eq!(my_map(MySome("Hello, World!"), len), MySome(13)); - assert_eq!(my_map(MyNone, len), MyNone); - - assert_eq!(my_map(MySome(1), plus_one), MySome(2)); - assert_eq!(my_map(MyNone, plus_one), MyNone); - - assert_eq!(my_map(MySome(5.0f64), is_positive), MySome(true)); - assert_eq!(my_map(MySome(-3.0f64), is_positive), MySome(false)); - assert_eq!(my_map(MyNone::, is_positive), MyNone); - } - - #[test] - fn test_my_and_then() { - use MyOption::*; - - fn plus_one(x: isize) -> MyOption { - MySome(x + 1) - } - - fn none(_: isize) -> MyOption { - MyNone - } - - assert_eq!(my_and_then(MySome(1), plus_one), MySome(2)); - assert_eq!(my_and_then(MySome(1), none), MyNone); - - assert_eq!(my_and_then(MyNone, plus_one), MyNone); - assert_eq!(my_and_then(MyNone, none), MyNone); - } - #[test] fn test_median() { assert_eq!(median(vec![]), None); @@ -166,18 +120,6 @@ mod test { ); } - fn product(a: i32, b: i32) -> i32 { - a * b - } - - #[test] - fn test_option_op_or() { - assert_eq!(option_op_or(None, None, product), None); - assert_eq!(option_op_or(Some(3), None, product), Some(3)); - assert_eq!(option_op_or(None, Some(5), product), Some(5)); - assert_eq!(option_op_or(Some(3), Some(5), product), Some(15)); - } - #[test] fn test_editor() { assert_eq!( @@ -234,93 +176,4 @@ mod test { "" ); } - - #[test] - fn test_shell() { - assert_eq!( - parse_shell_command("cat file"), - vec!["cat".to_string(), "file".to_string()] - ); - assert_eq!( - parse_shell_command("ls 'VirtualBox VMs'"), - vec!["ls".to_string(), "VirtualBox VMs".to_string()] - ); - assert_eq!( - parse_shell_command("ls VirtualBox' 'VMs"), - vec!["ls".to_string(), "VirtualBox VMs".to_string()] - ); - assert_eq!( - parse_shell_command("echo once upon a midnight dreary"), - vec![ - "echo".to_string(), - "once".to_string(), - "upon".to_string(), - "a".to_string(), - "midnight".to_string(), - "dreary".to_string(), - ] - ); - assert_eq!( - parse_shell_command("echo 'once upon a midnight dreary'"), - vec![ - "echo".to_string(), - "once upon a midnight dreary".to_string(), - ] - ); - } - - #[test] - fn test_json() { - use std::collections::HashMap; - let json_str = r#"{ - "name": "John Doe", - "age": 30, - "city": "New York", - "active": true, - "address": { - "street": "123 Main St", - "zipCode": "10001" - }, - "skills": ["Rust", "Python", "JavaScript"], - "organization": null - }"#; - println!("{}", parse_json(json_str).unwrap()); - assert_eq!( - parse_json(json_str), - Ok(JsonValue::Object(HashMap::from([ - ( - "name".to_string(), - JsonValue::String("John Doe".to_string()) - ), - ("age".to_string(), JsonValue::Number(30)), - ( - "city".to_string(), - JsonValue::String("New York".to_string()) - ), - ("active".to_string(), JsonValue::Boolean(true)), - ( - "address".to_string(), - JsonValue::Object(HashMap::from([ - ( - "street".to_string(), - JsonValue::String("123 Main St".to_string()) - ), - ( - "zipCode".to_string(), - JsonValue::String("10001".to_string()) - ) - ])) - ), - ( - "skills".to_string(), - JsonValue::Array(vec![ - JsonValue::String("Rust".to_string()), - JsonValue::String("Python".to_string()), - JsonValue::String("JavaScript".to_string()) - ]) - ), - ("organization".to_string(), JsonValue::Null), - ]))) - ); - } } diff --git a/src/assignments/mod.rs b/src/assignments/mod.rs index ecc70a2..c490e61 100644 --- a/src/assignments/mod.rs +++ b/src/assignments/mod.rs @@ -9,9 +9,7 @@ pub mod assignment01; mod assignment01_grade; pub mod assignment02; -mod assignment02_grade; pub mod assignment03; -mod assignment03_grade; pub mod assignment04; pub mod assignment06; pub mod assignment07; From 20a892a264de9ed739f8d7b0d04c30bbe6ed08fb Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 21 Aug 2023 19:43:04 +0900 Subject: [PATCH 09/17] apply comments --- scripts/grade-01.sh | 2 +- scripts/grade-08.sh | 2 +- scripts/grade-13.sh | 2 +- .../{assignment01.rs => assignment01/mod.rs} | 13 +- .../assignment01/small_problems.rs | 12 + .../small_problems_grade.rs} | 2 +- .../assignment06/semiring_grade.rs | 2 +- .../assignment06/square_matrix_grade.rs | 2 +- .../symbolic_differentiation_grade.rs | 2 +- .../assignment07/generator_grade.rs | 2 +- src/assignments/assignment07/hubo_grade.rs | 2 +- .../assignment07/my_itertools_grade.rs | 2 +- .../assignment07/small_exercises_grade.rs | 2 +- .../assignment07/transform_grade.rs | 2 +- src/assignments/assignment08/mod.rs | 9 + .../small_problems.rs} | 7 +- .../small_problems_grade.rs} | 2 +- src/assignments/assignment09/bigint_grade.rs | 2 +- src/assignments/assignment09/matmul.rs | 6 + .../assignment09/small_exercises_grade.rs | 2 +- .../assignment10/labyrinth_grade.rs | 2 +- .../assignment10/small_exercises_grade.rs | 2 +- src/assignments/assignment11/bst.rs | 202 ------------ src/assignments/assignment11/bst_grade.rs | 53 --- .../assignment11/doubly_linked_list_grade.rs | 2 +- src/assignments/assignment11/graph_grade.rs | 2 +- src/assignments/assignment11/linked_list.rs | 140 -------- .../assignment11/linked_list_grade.rs | 122 ------- .../assignment11/mock_storage_grade.rs | 2 +- src/assignments/assignment11/mod.rs | 12 - src/assignments/assignment11/peano_nat.rs | 56 ---- .../assignment11/peano_nat_grade.rs | 38 --- .../assignment11/turing_machine.rs | 139 -------- .../assignment11/turing_machine_grade.rs | 309 ------------------ src/assignments/assignment11/tv_room_grade.rs | 2 +- src/assignments/assignment12/card_grade.rs | 3 +- src/assignments/assignment12/demux_grade.rs | 2 +- src/assignments/assignment12/funnel_grade.rs | 2 +- .../assignment12/small_exercises_grade.rs | 2 +- src/assignments/assignment13/mod.rs | 10 + .../small_problems.rs} | 13 +- .../small_problems_grade.rs} | 4 +- src/assignments/mod.rs | 3 - 43 files changed, 77 insertions(+), 1122 deletions(-) rename src/assignments/{assignment01.rs => assignment01/mod.rs} (58%) create mode 100644 src/assignments/assignment01/small_problems.rs rename src/assignments/{assignment01_grade.rs => assignment01/small_problems_grade.rs} (86%) create mode 100644 src/assignments/assignment08/mod.rs rename src/assignments/{assignment08.rs => assignment08/small_problems.rs} (85%) rename src/assignments/{assignment08_grade.rs => assignment08/small_problems_grade.rs} (95%) delete mode 100644 src/assignments/assignment11/bst.rs delete mode 100644 src/assignments/assignment11/bst_grade.rs delete mode 100644 src/assignments/assignment11/linked_list.rs delete mode 100644 src/assignments/assignment11/linked_list_grade.rs delete mode 100644 src/assignments/assignment11/peano_nat.rs delete mode 100644 src/assignments/assignment11/peano_nat_grade.rs delete mode 100644 src/assignments/assignment11/turing_machine.rs delete mode 100644 src/assignments/assignment11/turing_machine_grade.rs create mode 100644 src/assignments/assignment13/mod.rs rename src/assignments/{assignment13.rs => assignment13/small_problems.rs} (87%) rename src/assignments/{assignment13_grade.rs => assignment13/small_problems_grade.rs} (98%) diff --git a/scripts/grade-01.sh b/scripts/grade-01.sh index 5579366..4add88a 100755 --- a/scripts/grade-01.sh +++ b/scripts/grade-01.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment01_grade") + TESTS=("--lib assignment01") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/scripts/grade-08.sh b/scripts/grade-08.sh index 99b7b27..815f90d 100755 --- a/scripts/grade-08.sh +++ b/scripts/grade-08.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment08_grade") + TESTS=("--lib assignment08") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/scripts/grade-13.sh b/scripts/grade-13.sh index 6c180d4..c490775 100755 --- a/scripts/grade-13.sh +++ b/scripts/grade-13.sh @@ -24,7 +24,7 @@ run_linters || exit 1 for RUNNER in "${RUNNERS[@]}"; do echo "Running with $RUNNER..." - TESTS=("--lib assignment13_grade") + TESTS=("--lib assignment13") if [ $(run_tests) -ne 0 ]; then exit 1 fi diff --git a/src/assignments/assignment01.rs b/src/assignments/assignment01/mod.rs similarity index 58% rename from src/assignments/assignment01.rs rename to src/assignments/assignment01/mod.rs index 058e21a..9a022d3 100644 --- a/src/assignments/assignment01.rs +++ b/src/assignments/assignment01/mod.rs @@ -4,16 +4,9 @@ //! Please make sure you're comfortable with developing Rust programs before moving on to the next assignments. //! //! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade-01.sh` works fine. -//! See `assignment01_grade.rs` and `/scripts/grade-01.sh` for the test script. +//! See `small_problems_grade.rs` and `/scripts/grade-01.sh` for the test script. //! //! Hint: -/// Adds two unsigned words. If overflow happens, just wrap around. -pub fn add(lhs: usize, rhs: usize) -> usize { - todo!() -} - -/// Subtracts two unsigned words. If overflow happens, just wrap around. -pub fn sub(lhs: usize, rhs: usize) -> usize { - todo!() -} +pub mod small_problems; +mod small_problems_grade; diff --git a/src/assignments/assignment01/small_problems.rs b/src/assignments/assignment01/small_problems.rs new file mode 100644 index 0000000..aaf3727 --- /dev/null +++ b/src/assignments/assignment01/small_problems.rs @@ -0,0 +1,12 @@ +//! Assignment 1: Preparing Rust Development Environment. +//! Welcome to the CS220 course! + +/// Adds two unsigned words. If overflow happens, just wrap around. +pub fn add(lhs: usize, rhs: usize) -> usize { + todo!() +} + +/// Subtracts two unsigned words. If overflow happens, just wrap around. +pub fn sub(lhs: usize, rhs: usize) -> usize { + todo!() +} diff --git a/src/assignments/assignment01_grade.rs b/src/assignments/assignment01/small_problems_grade.rs similarity index 86% rename from src/assignments/assignment01_grade.rs rename to src/assignments/assignment01/small_problems_grade.rs index 3580df9..dbdd99e 100644 --- a/src/assignments/assignment01_grade.rs +++ b/src/assignments/assignment01/small_problems_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use super::super::assignment01::*; + use crate::assignments::assignment01::small_problems::*; #[test] fn test_add_7_3() { diff --git a/src/assignments/assignment06/semiring_grade.rs b/src/assignments/assignment06/semiring_grade.rs index bca3278..3b553a6 100644 --- a/src/assignments/assignment06/semiring_grade.rs +++ b/src/assignments/assignment06/semiring_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use super::super::semiring::*; + use crate::assignments::assignment06::semiring::*; use ntest::assert_about_eq; fn test_from_str(s: &str, f: impl Fn(i64) -> i64) { diff --git a/src/assignments/assignment06/square_matrix_grade.rs b/src/assignments/assignment06/square_matrix_grade.rs index 7270c73..2ca244c 100644 --- a/src/assignments/assignment06/square_matrix_grade.rs +++ b/src/assignments/assignment06/square_matrix_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use super::super::square_matrix::*; + use crate::assignments::assignment06::square_matrix::*; use ntest::assert_about_eq; #[test] diff --git a/src/assignments/assignment06/symbolic_differentiation_grade.rs b/src/assignments/assignment06/symbolic_differentiation_grade.rs index 0526219..26ce172 100644 --- a/src/assignments/assignment06/symbolic_differentiation_grade.rs +++ b/src/assignments/assignment06/symbolic_differentiation_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use super::super::symbolic_differentiation::*; + use crate::assignments::assignment06::symbolic_differentiation::*; use ntest::assert_about_eq; // Constant rationals to use diff --git a/src/assignments/assignment07/generator_grade.rs b/src/assignments/assignment07/generator_grade.rs index 5ff51d7..6ac4323 100644 --- a/src/assignments/assignment07/generator_grade.rs +++ b/src/assignments/assignment07/generator_grade.rs @@ -3,7 +3,7 @@ mod test { use itertools::Itertools; use ntest::assert_about_eq; - use super::super::generator::*; + use crate::assignments::assignment07::generator::*; #[test] fn test_generator() { diff --git a/src/assignments/assignment07/hubo_grade.rs b/src/assignments/assignment07/hubo_grade.rs index 50a636a..e67fec3 100644 --- a/src/assignments/assignment07/hubo_grade.rs +++ b/src/assignments/assignment07/hubo_grade.rs @@ -3,7 +3,7 @@ mod test { use itertools::Itertools; use ntest::assert_about_eq; - use super::super::hubo::*; + use crate::assignments::assignment07::hubo::*; #[test] fn test_hubo_dir4_movement() { diff --git a/src/assignments/assignment07/my_itertools_grade.rs b/src/assignments/assignment07/my_itertools_grade.rs index 9e9e061..d6e5111 100644 --- a/src/assignments/assignment07/my_itertools_grade.rs +++ b/src/assignments/assignment07/my_itertools_grade.rs @@ -3,7 +3,7 @@ mod test { use itertools::Itertools; use ntest::assert_about_eq; - use super::super::my_itertools::*; + use crate::assignments::assignment07::my_itertools::*; #[test] fn test_itertools() { diff --git a/src/assignments/assignment07/small_exercises_grade.rs b/src/assignments/assignment07/small_exercises_grade.rs index fced451..841d811 100644 --- a/src/assignments/assignment07/small_exercises_grade.rs +++ b/src/assignments/assignment07/small_exercises_grade.rs @@ -3,7 +3,7 @@ mod test { use itertools::Itertools; use ntest::assert_about_eq; - use super::super::small_exercises::*; + use crate::assignments::assignment07::small_exercises::*; #[test] fn test_find() { diff --git a/src/assignments/assignment07/transform_grade.rs b/src/assignments/assignment07/transform_grade.rs index 7fb7870..4355964 100644 --- a/src/assignments/assignment07/transform_grade.rs +++ b/src/assignments/assignment07/transform_grade.rs @@ -3,7 +3,7 @@ mod test { use itertools::Itertools; use ntest::assert_about_eq; - use super::super::transform::*; + use crate::assignments::assignment07::transform::*; #[test] fn test_transform_identity() { diff --git a/src/assignments/assignment08/mod.rs b/src/assignments/assignment08/mod.rs new file mode 100644 index 0000000..8bf6f8c --- /dev/null +++ b/src/assignments/assignment08/mod.rs @@ -0,0 +1,9 @@ +//! Assignment 8: First-class functions. +//! +//! The primary goal of this assignment is to get used to first-class functions. +//! +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine. +//! See `small_problems_grade.rs` and `/scripts/grade-08.sh` for the test script. + +pub mod small_problems; +mod small_problems_grade; diff --git a/src/assignments/assignment08.rs b/src/assignments/assignment08/small_problems.rs similarity index 85% rename from src/assignments/assignment08.rs rename to src/assignments/assignment08/small_problems.rs index d6ce58d..829d5a7 100644 --- a/src/assignments/assignment08.rs +++ b/src/assignments/assignment08/small_problems.rs @@ -1,9 +1,4 @@ -//! Assignment 8: First-class functions. -//! -//! The primary goal of this assignment is to get used to first-class functions. -//! -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine. -//! See `assignment08_grade.rs` and `/scripts/grade-08.sh` for the test script. +//! Assignment 08: First-class functions. /// Repeat /// diff --git a/src/assignments/assignment08_grade.rs b/src/assignments/assignment08/small_problems_grade.rs similarity index 95% rename from src/assignments/assignment08_grade.rs rename to src/assignments/assignment08/small_problems_grade.rs index bce3398..2549b0c 100644 --- a/src/assignments/assignment08_grade.rs +++ b/src/assignments/assignment08/small_problems_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use super::super::assignment08::*; + use crate::assignments::assignment08::small_problems::*; #[test] fn test_repeat() { diff --git a/src/assignments/assignment09/bigint_grade.rs b/src/assignments/assignment09/bigint_grade.rs index a707026..02be492 100644 --- a/src/assignments/assignment09/bigint_grade.rs +++ b/src/assignments/assignment09/bigint_grade.rs @@ -3,7 +3,7 @@ mod test { use ntest::{assert_false, assert_true}; - use super::super::bigint::*; + use crate::assignments::assignment09::bigint::*; #[test] fn test_inf_prec_simple() { diff --git a/src/assignments/assignment09/matmul.rs b/src/assignments/assignment09/matmul.rs index 273742b..dd21a25 100644 --- a/src/assignments/assignment09/matmul.rs +++ b/src/assignments/assignment09/matmul.rs @@ -20,6 +20,9 @@ pub fn vec_add(lhs: &[f64], rhs: &[f64]) -> Vec { /// dot product of two arrays /// +/// You don't know how to calculate dot product? +/// See +/// /// # Exmaple /// /// ``` @@ -37,6 +40,9 @@ pub fn dot_product(lhs: &[f64], rhs: &[f64]) -> f64 { /// Matrix multiplication /// +/// You don't know how to multiply matrix? +/// Quite simple! See +/// /// Assume rhs is transposed /// - lhs: (m, n) /// - rhs: (p, n) diff --git a/src/assignments/assignment09/small_exercises_grade.rs b/src/assignments/assignment09/small_exercises_grade.rs index efeeb10..be4e085 100644 --- a/src/assignments/assignment09/small_exercises_grade.rs +++ b/src/assignments/assignment09/small_exercises_grade.rs @@ -3,7 +3,7 @@ mod test { use ntest::{assert_false, assert_true}; - use super::super::small_exercises::*; + use crate::assignments::assignment09::small_exercises::*; #[test] fn test_is_fibonacci() { diff --git a/src/assignments/assignment10/labyrinth_grade.rs b/src/assignments/assignment10/labyrinth_grade.rs index a7fa5a1..934e5ae 100644 --- a/src/assignments/assignment10/labyrinth_grade.rs +++ b/src/assignments/assignment10/labyrinth_grade.rs @@ -3,7 +3,7 @@ mod test { use rand::seq::SliceRandom; use rand::thread_rng; - use super::super::labyrinth::*; + use crate::assignments::assignment10::labyrinth::*; type Wife = usize; type Rooms = Vec; diff --git a/src/assignments/assignment10/small_exercises_grade.rs b/src/assignments/assignment10/small_exercises_grade.rs index e1d1e54..8cbc96f 100644 --- a/src/assignments/assignment10/small_exercises_grade.rs +++ b/src/assignments/assignment10/small_exercises_grade.rs @@ -2,7 +2,7 @@ mod test { use std::collections::HashSet; - use super::super::small_exercises::*; + use crate::assignments::assignment10::small_exercises::*; #[test] fn test_inversion() { diff --git a/src/assignments/assignment11/bst.rs b/src/assignments/assignment11/bst.rs deleted file mode 100644 index 8d78a57..0000000 --- a/src/assignments/assignment11/bst.rs +++ /dev/null @@ -1,202 +0,0 @@ -//! Binary Search Tree -//! -//! Refer `bst_grade.rs` for test cases. - -use std::cell::RefCell; -use std::cmp::Ordering; -use std::fmt::Debug; -use std::ops::Deref; -use std::rc::{Rc, Weak}; - -/// Node struct of tree -#[derive(Debug, Clone)] -struct Node -where - T: Ord, -{ - value: T, - parent: Option>>>, - left: Option>>>, - right: Option>>>, -} - -impl Node -where - T: Ord, -{ - fn new(value: T) -> Rc>> { - Rc::new(RefCell::new(Node { - value, - parent: None, - left: None, - right: None, - })) - } - - fn with_parent(value: T, parent: Weak>>) -> Rc>> { - Rc::new(RefCell::new(Node { - value, - parent: Some(parent), - left: None, - right: None, - })) - } - - /// Minimum node starting from cursor - fn min_node(mut cursor: Rc>>) -> Rc>> { - todo!(); - } - - /// Upgraded parent node. - /// `None` if the node has no parent. - fn parent(&self) -> Option>>> { - self.parent.as_ref().and_then(|p| p.upgrade()) - } -} - -/// Binary Search Tree -#[derive(Debug)] -pub struct Tree -where - T: Ord, -{ - root: Option>>>, - len: usize, -} - -impl Default for Tree { - fn default() -> Self { - Self::new() - } -} - -impl Tree -where - T: Ord, -{ - /// New tree - pub fn new() -> Tree { - Tree { root: None, len: 0 } - } - - /// Length of the tree - pub fn len(&self) -> usize { - self.len - } - - /// Check if the tree is empty. - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Check if the tree contains the value. - pub fn contains(&self, value: &T) -> bool { - if let Some(mut cursor) = self.root.clone() { - todo!(); - } else { - false - } - } - - /// Insert the value into the tree. - /// If there was no equal value in the tree, it returns `true`. - /// Otherwise, it returns `false`. - pub fn insert(&mut self, value: T) -> bool { - self.len += 1; - if let Some(mut cursor) = self.root.clone() { - todo!(); - } else { - self.root = Some(Node::new(value)); - true - } - } - - /// Remove the node from the tree. - /// Returns the value of the removed node. - fn remove_node(&mut self, mut node: Rc>>) -> T { - todo!(); - } - - /// Remove the value from the tree. - /// If there is an equal value in the tree, it returns `true`. - /// Otherwise, it returns `false`. - pub fn remove(&mut self, value: &T) -> Option { - let res = if let Some(root) = self.root.clone() { - let mut cursor = root; - - loop { - let mut cursor_ref = cursor.deref().borrow_mut(); - let child = match value.cmp(&cursor_ref.value) { - Ordering::Less => cursor_ref.left.clone(), - Ordering::Greater => cursor_ref.right.clone(), - Ordering::Equal => { - drop(cursor_ref); - break Some(self.remove_node(cursor)); - } - }; - - if let Some(child) = child { - drop(cursor_ref); - cursor = child; - } else { - break None; - } - } - } else { - None - }; - - self.len -= res.is_some() as usize; - res - } -} - -impl Clone for Tree -where - T: Ord + Clone, -{ - fn clone(&self) -> Self { - Tree { - root: self.root.clone(), - len: self.len, - } - } -} - -/// IntoIterator for Tree -#[derive(Debug)] -pub struct IntoIter -where - T: Ord, -{ - tree: Tree, - len: usize, -} - -impl IntoIterator for Tree -where - T: Ord, -{ - type Item = T; - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - let len = self.len; - IntoIter { tree: self, len } - } -} - -impl Iterator for IntoIter -where - T: Ord, -{ - type Item = T; - - fn next(&mut self) -> Option { - todo!(); - } - - fn size_hint(&self) -> (usize, Option) { - (self.len, Some(self.len)) - } -} diff --git a/src/assignments/assignment11/bst_grade.rs b/src/assignments/assignment11/bst_grade.rs deleted file mode 100644 index 40b82cb..0000000 --- a/src/assignments/assignment11/bst_grade.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Test cases for assignment11/bst.rs - -#[cfg(test)] -mod test_bst { - use super::super::bst::*; - - #[test] - fn bst_insert_test() { - let mut tree = Tree::new(); - - let _ = tree.insert(1); - let _ = tree.insert(5); - let _ = tree.insert(3); - let _ = tree.insert(7); - - assert_eq!(tree.into_iter().collect::>(), vec![1, 3, 5, 7]); - } - - #[test] - fn bst_remove_test() { - let mut tree = Tree::new(); - - let _ = tree.insert(1); - let _ = tree.insert(5); - let _ = tree.insert(3); - let _ = tree.insert(7); - let _ = tree.remove(&7); - - assert_eq!(tree.into_iter().collect::>(), vec![1, 3, 5]); - } - - #[test] - fn bst_complex_test() { - let mut tree = Tree::new(); - - let _ = tree.insert(1); - let _ = tree.insert(5); - let _ = tree.insert(3); - let _ = tree.insert(7); - let _ = tree.remove(&7); - let _ = tree.insert(7); - let _ = tree.insert(6); - let _ = tree.insert(8); - let _ = tree.remove(&5); - let _ = tree.remove(&1); - let _ = tree.remove(&3); - let _ = tree.remove(&7); - let _ = tree.remove(&6); - let _ = tree.remove(&8); - - assert_eq!(tree.into_iter().collect::>(), vec![]); - } -} diff --git a/src/assignments/assignment11/doubly_linked_list_grade.rs b/src/assignments/assignment11/doubly_linked_list_grade.rs index 0827f11..ebdc19a 100644 --- a/src/assignments/assignment11/doubly_linked_list_grade.rs +++ b/src/assignments/assignment11/doubly_linked_list_grade.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_doubly_linked_list { - use super::super::doubly_linked_list::*; + use crate::assignments::assignment11::doubly_linked_list::*; #[test] fn test_works() { diff --git a/src/assignments/assignment11/graph_grade.rs b/src/assignments/assignment11/graph_grade.rs index fcdac3b..4949ea4 100644 --- a/src/assignments/assignment11/graph_grade.rs +++ b/src/assignments/assignment11/graph_grade.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_graph { - use super::super::graph::*; + use crate::assignments::assignment11::graph::*; #[test] fn test_graph() { diff --git a/src/assignments/assignment11/linked_list.rs b/src/assignments/assignment11/linked_list.rs deleted file mode 100644 index 161a7a4..0000000 --- a/src/assignments/assignment11/linked_list.rs +++ /dev/null @@ -1,140 +0,0 @@ -//! Singly linked list. -//! -//! Consult . - -use std::fmt::Debug; - -/// Node of the list. -#[derive(Debug)] -pub struct Node { - /// Value of current node. - pub value: T, - - /// Pointer to the next node. If it is `None`, there is no next node. - pub next: Option>>, -} - -impl Node { - /// Creates a new node. - pub fn new(value: T) -> Self { - Self { value, next: None } - } -} - -/// A singly-linked list. -#[derive(Debug)] -pub struct SinglyLinkedList { - /// Head node of the list. If it is `None`, the list is empty. - head: Option>, -} - -impl Default for SinglyLinkedList { - fn default() -> Self { - Self::new() - } -} - -impl SinglyLinkedList { - /// Creates a new list. - pub fn new() -> Self { - Self { head: None } - } - - /// Adds the given node to the front of the list. - pub fn push_front(&mut self, value: T) { - todo!() - } - - /// Adds the given node to the back of the list. - pub fn push_back(&mut self, value: T) { - todo!() - } - - /// Removes and returns the node at the front of the list. - pub fn pop_front(&mut self) -> Option { - todo!() - } - - /// Removes and returns the node at the back of the list. - pub fn pop_back(&mut self) -> Option { - todo!() - } - - /// Create a new list from the given vector `vec`. - pub fn from_vec(vec: Vec) -> Self { - todo!() - } - - /// Convert the current list into a vector. - pub fn as_vec(&self) -> Vec { - todo!() - } - - /// Return the length (i.e., number of nodes) of the list. - pub fn length(&self) -> usize { - todo!() - } - - /// Apply function `f` on every element of the list. - /// - /// # Examples - /// - /// `self`: `[1, 2]`, `f`: `|x| x + 1` ==> `[2, 3]` - pub fn map T>(&mut self, f: F) { - todo!() - } - - /// Insert given list `another` at the specified index `idx`. - /// If `idx` is out-of-bound of `self`, append `another` at the end of `self`. - /// - /// # Examples - /// - /// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `1` ==> `[1, 3, 4, 2]` - /// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `5` ==> `[1, 2, 3, 4]` - pub fn insert(&mut self, another: &Self, idx: usize) { - todo!() - } - - /// Reverse the list in a chunk of size `n`. - /// If `n == 0`, do nothing. - /// - /// # Examples - /// - /// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `3` - /// // each chunk of size `3`: `[1, 2, 3]`, `[4, 5, 6]`, `[7, 8, 9]` - /// // reversed sequence of chunks: `[7, 8, 9]`, `[4, 5, 6]`, `[1, 2, 3]` - /// ==> `[7, 8, 9, 4, 5, 6, 1, 2, 3]`, - /// - /// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `4` - /// // each chunk of size `4`: `[1, 2, 3, 4]`, `[5, 6, 7, 8]`, `[9]` - /// // reversed sequence of chunks: `[9]`, `[5, 6, 7, 8]`, `[1, 2, 3, 4]` - /// ==> `[9, 5, 6, 7, 8, 1, 2, 3, 4]` - pub fn chunk_reverse(&mut self, n: usize) { - todo!() - } - - /// Apply given function `f` for each adjacent pair of elements in the list. - /// If `self.length() < 2`, do nothing. - /// - /// # Examples - /// - /// `self`: `[1, 2, 3, 4]`, `f`: `|x, y| x + y` - /// // each adjacent pair of elements: `(1, 2)`, `(2, 3)`, `(3, 4)` - /// // apply `f` to each pair: `f(1, 2) == 3`, `f(2, 3) == 5`, `f(3, 4) == 7` - /// ==> `[3, 5, 7]` - pub fn pair_map T>(&mut self, f: F) { - todo!() - } -} - -// A list of lists. -impl SinglyLinkedList> { - /// Flatten the list of lists into a single list. - /// - /// # Examples - /// `self`: `[[1, 2, 3], [4, 5, 6], [7, 8]]` - /// ==> `[1, 2, 3, 4, 5, 6, 7, 8]` - pub fn flatten(self) -> SinglyLinkedList { - todo!() - } -} diff --git a/src/assignments/assignment11/linked_list_grade.rs b/src/assignments/assignment11/linked_list_grade.rs deleted file mode 100644 index 6805972..0000000 --- a/src/assignments/assignment11/linked_list_grade.rs +++ /dev/null @@ -1,122 +0,0 @@ -#[cfg(test)] -mod test_linked_list { - use crate::assignments::assignment11::linked_list::*; - - #[derive(Debug, PartialEq, Eq)] - struct V(usize); - - #[test] - fn test_push_pop() { - let mut list = SinglyLinkedList::new(); - list.push_back(V(3)); - list.push_front(V(2)); - list.push_back(V(4)); - list.push_front(V(1)); - list.push_back(V(5)); - - assert_eq!(list.pop_front(), Some(V(1))); - assert_eq!(list.pop_back(), Some(V(5))); - assert_eq!(list.pop_front(), Some(V(2))); - assert_eq!(list.pop_back(), Some(V(4))); - assert_eq!(list.pop_front(), Some(V(3))); - assert_eq!(list.pop_back(), None); - assert_eq!(list.pop_front(), None); - } - - #[test] - fn test_from_as_vec() { - assert_eq!(SinglyLinkedList::::new().as_vec(), vec![]); - assert_eq!( - SinglyLinkedList::from_vec(vec![1, 2, 3]).as_vec(), - vec![1, 2, 3] - ); - } - - #[test] - fn test_length() { - let list = SinglyLinkedList::from_vec(vec![1, 2, 3]); - assert_eq!(list.length(), 3); - } - - #[test] - fn test_map() { - let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3]); - let incr = |x: i32| x + 1; - list.map(incr); - assert_eq!(list.as_vec(), vec![2, 3, 4]); - } - - #[test] - fn test_insert() { - let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3]); - let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3]); - let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]); - let list4 = SinglyLinkedList::from_vec(vec![4, 5, 6]); - - list1.insert(&list4, 0); - assert_eq!(list1.as_vec(), vec![4, 5, 6, 1, 2, 3]); - - list2.insert(&list4, 1); - assert_eq!(list2.as_vec(), vec![1, 4, 5, 6, 2, 3]); - - list3.insert(&list4, 4); - assert_eq!(list3.as_vec(), vec![1, 2, 3, 4, 5, 6]); - } - - #[test] - fn test_chunk_reverse() { - let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); - list1.chunk_reverse(3); - assert_eq!(list1.as_vec(), vec![7, 8, 9, 3, 4, 5, 1, 2, 3]); - - let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8]); - list2.chunk_reverse(3); - assert_eq!(list2.as_vec(), vec![7, 8, 4, 5, 6, 1, 2, 3]); - - let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]); - list3.chunk_reverse(4); - assert_eq!(list3.as_vec(), vec![1, 2, 3]); - - let mut list4 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]); - list4.chunk_reverse(1); - assert_eq!(list4.as_vec(), vec![4, 3, 2, 1]); - - let mut list5 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]); - list4.chunk_reverse(0); - assert_eq!(list4.as_vec(), vec![1, 2, 3, 4]); - } - - #[test] - fn test_pair_map() { - let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); - let add = |x: i32, y: i32| x + y; - - list.pair_map(add); - assert_eq!(list.as_vec(), vec![3, 5, 7, 9, 11, 13, 15, 17]); - - list.pair_map(add); - assert_eq!(list.as_vec(), vec![8, 12, 16, 20, 24, 28, 32]); - - list.pair_map(add); - assert_eq!(list.as_vec(), vec![20, 28, 36, 44, 52, 60]); - - list.pair_map(add); - assert_eq!(list.as_vec(), vec![48, 64, 80, 96, 112]); - } - - #[test] - fn test_flatten() { - let list1 = SinglyLinkedList::from_vec(vec![1, 2]); - let list2 = SinglyLinkedList::from_vec(vec![3]); - let list3 = SinglyLinkedList::from_vec(vec![4, 5, 6, 7]); - let list4 = SinglyLinkedList::::new(); - let list5 = SinglyLinkedList::from_vec(vec![8, 9, 10]); - - let list_list = SinglyLinkedList::from_vec(vec![list1, list2, list3, list4, list5]); - - assert_eq!( - list_list.flatten().as_vec(), - vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - ); - } -} diff --git a/src/assignments/assignment11/mock_storage_grade.rs b/src/assignments/assignment11/mock_storage_grade.rs index b8e62d3..97d05aa 100644 --- a/src/assignments/assignment11/mock_storage_grade.rs +++ b/src/assignments/assignment11/mock_storage_grade.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_mock_storage { - use super::super::mock_storage::*; + use crate::assignments::assignment11::mock_storage::*; #[test] fn test_mock_storage() { diff --git a/src/assignments/assignment11/mod.rs b/src/assignments/assignment11/mod.rs index 53dacb5..be8f452 100644 --- a/src/assignments/assignment11/mod.rs +++ b/src/assignments/assignment11/mod.rs @@ -4,15 +4,6 @@ //! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to . -pub mod linked_list; -mod linked_list_grade; - -pub mod peano_nat; -mod peano_nat_grade; - -pub mod bst; -mod bst_grade; - pub mod doubly_linked_list; mod doubly_linked_list_grade; @@ -24,6 +15,3 @@ pub mod mock_storage_grade; pub mod tv_room; pub mod tv_room_grade; - -pub mod turing_machine; -pub mod turing_machine_grade; diff --git a/src/assignments/assignment11/peano_nat.rs b/src/assignments/assignment11/peano_nat.rs deleted file mode 100644 index c79ab3c..0000000 --- a/src/assignments/assignment11/peano_nat.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! Peano natural number. - -/// We can represent any natural number using only two symbols: 0 and S. -/// -/// E.g. -/// O == 0 -/// S(O) == 1 -/// S(S(O)) == 2 -/// ... so on. -#[derive(Debug, Clone, PartialEq)] -pub enum Nat { - /// Zero - O, - /// Plus one - S(Box), -} - -impl Nat { - /// Create `Nat` from `usize` - pub fn from_usize(n: usize) -> Nat { - todo!() - } - - /// Convert `Nat` into nonnegative integer - pub fn as_usize(&self) -> usize { - todo!() - } -} - -// Implement `Add` operator (i.e. `+`) for `Nat`. -impl std::ops::Add for Nat { - type Output = Nat; - - fn add(self, rhs: Self) -> Self::Output { - todo!() - } -} - -// Implement `Sub` operator (i.e. `-`) for `Nat`. -// If the result is negative, return `Nat::O`. -impl std::ops::Sub for Nat { - type Output = Nat; - - fn sub(self, rhs: Self) -> Self::Output { - todo!() - } -} - -// Implement `Mul` operator (i.e. `*`) for `Nat`. -impl std::ops::Mul for Nat { - type Output = Nat; - - fn mul(self, rhs: Self) -> Self::Output { - todo!() - } -} diff --git a/src/assignments/assignment11/peano_nat_grade.rs b/src/assignments/assignment11/peano_nat_grade.rs deleted file mode 100644 index edada7f..0000000 --- a/src/assignments/assignment11/peano_nat_grade.rs +++ /dev/null @@ -1,38 +0,0 @@ -#[cfg(test)] -mod test_peano_nat { - use crate::assignments::assignment11::peano_nat::*; - - #[test] - fn test_from_as_usize() { - assert_eq!(Nat::from_usize(0), Nat::O); - assert_eq!( - Nat::from_usize(2), - Nat::S(Box::new(Nat::S(Box::new(Nat::O)))) - ); - - for n in 0..100 { - assert_eq!(Nat::from_usize(n).as_usize(), n); - } - } - - fn safe_sub(i: usize, j: usize) -> usize { - if i > j { - i - j - } else { - 0 - } - } - - #[test] - fn test_add_sub_mul() { - for i in 0..30 { - let n = Nat::from_usize(i); - for j in 0..30 { - let m = Nat::from_usize(j); - assert_eq!((n.clone() + m.clone()).as_usize(), i + j); - assert_eq!((n.clone() - m.clone()).as_usize(), safe_sub(i, j)); - assert_eq!((n.clone() * m.clone()).as_usize(), i * j); - } - } - } -} diff --git a/src/assignments/assignment11/turing_machine.rs b/src/assignments/assignment11/turing_machine.rs deleted file mode 100644 index 438f30a..0000000 --- a/src/assignments/assignment11/turing_machine.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! Simple Turing machien emulator -//! -//! Simple One-head, One-tape turing machine -//! See that describes what turing machine is. -//! See `test_turing_machine` module in `assignment11_grade.rs` for examples. -//! -//! Goal: To be accustomed with `RefCell`, `HashMap` -//! -//! Refer `turing_machine.rs` for test cases. - -use std::cell::RefCell; -use std::collections::HashMap; -use std::fmt::{self, Formatter}; -use thiserror::Error; - -/// Error type for Turing machine -/// -#[derive(Debug, Error, PartialEq, Eq)] -pub enum TuringMachineError { - /// Invalid movement - /// You can't move left from the leftmost location - /// or move right from the rightmost location. - #[error("Invalid movement")] - InvalidMovement, - - /// Exceeded maximum steps - #[error("Exceeded maximum steps")] - ExceedMaxSteps, - - /// Invalid state or value - /// Occurs when you cannot find instruction for the current state and value - #[error("Invalid state or value")] - InvalidStateOrValue, -} - -/// Turing Machine implementation -#[derive(Debug)] -pub struct TuringMachine -where - TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, - TMValue: Eq + PartialEq + std::hash::Hash + Clone, -{ - /// Number of steps taken by the Turing machine - pub steps: RefCell, - - /// Table of instructions for the Turing machine - pub table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>, - - /// Tape of the Turing machine. Finite length - pub tape: Vec>, -} - -/// Implementation of the movement instructions of the head of the tape. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Move { - /// Move Left - L, - /// Move Right - R, - /// Don't move - N, -} - -/// Cursor for Turing machine -#[derive(Debug)] -pub struct Cursor<'a, TMState, TMValue> -where - TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, - TMValue: Eq + PartialEq + std::hash::Hash + Clone, -{ - // Turing mahcine - tm: &'a TuringMachine, - // Index of the tape - index: usize, - // Current state of the Turing machine - state: TMState, -} - -impl<'a, TMState, TMValue> Cursor<'a, TMState, TMValue> -where - TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, - TMValue: Eq + PartialEq + std::hash::Hash + Clone, -{ - /// Generate new cursor - pub fn new(tm: &'a TuringMachine, state: TMState, index: usize) -> Self { - Cursor { tm, index, state } - } - - /// Run the Turing machine until it halts (if it halts). Print every step of that. - pub fn run(&mut self, max_step: usize) -> Result<(TMValue, usize), TuringMachineError> { - let mut steps = self.tm.steps.borrow_mut(); - while self.state != TMState::default() { - *steps += 1; - if *steps > max_step { - return Err(TuringMachineError::ExceedMaxSteps); - } - self.step()?; - // println!("{}", self); - } - Ok((self.get(), *steps)) - } - - /// Set tape value at the current index with `value` - /// You may need this function for `mov` function - fn set(&mut self, value: TMValue) -> TMValue { - todo!(); - } - - /// Step the Turing machine - /// Look at the `run` function to see how this function is used. - fn step(&mut self) -> Result<(), TuringMachineError> { - todo!(); - } - - /// Move the cursor while setting the value of the current index - fn mov(&mut self, new_value: TMValue, movement: &Move) -> Result<(), TuringMachineError> { - todo!(); - } - - /// Get the value of the current index - /// Look at the `run` function to see how this function is used. - fn get(&self) -> TMValue { - todo!(); - } -} - -impl TuringMachine -where - TMState: Default + Eq + PartialEq + std::hash::Hash + Clone, - TMValue: Eq + PartialEq + std::hash::Hash + Clone, -{ - /// Generate new Turing machine - pub fn new( - table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>, - tape: Vec>, - ) -> Self { - todo!() - } -} diff --git a/src/assignments/assignment11/turing_machine_grade.rs b/src/assignments/assignment11/turing_machine_grade.rs deleted file mode 100644 index 89b617b..0000000 --- a/src/assignments/assignment11/turing_machine_grade.rs +++ /dev/null @@ -1,309 +0,0 @@ -//! Test cases for assignment11/turing_machine.rs - -#[cfg(test)] -mod test_turing_machine { - use super::super::turing_machine::*; - use std::cell::RefCell; - use std::collections::HashMap; - - #[test] - fn test_invalid_movement() { - /// Cell value of the tape - #[derive(Debug, Clone, Hash, Eq, PartialEq)] - enum TMValue { - /// Zero - Zero, - - /// One - One, - } - - /// State for Turing machine - /// TODO: Modify this so that users can implement their own state - #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] - enum TMState { - /// Halt - #[default] - Halt, - - /// A - A, - - /// B - B, - } - - let tape: Vec> = vec![ - TMValue::One, - TMValue::Zero, - TMValue::One, - TMValue::One, - TMValue::One, - TMValue::Zero, - TMValue::One, - ] - .into_iter() - .map(|x| RefCell::new(x)) - .collect(); - - let instr = HashMap::from([ - ( - (TMState::A, TMValue::Zero), - (TMState::B, Move::R, TMValue::One), - ), - ( - (TMState::A, TMValue::One), - (TMState::B, Move::L, TMValue::Zero), - ), - ( - (TMState::B, TMValue::Zero), - (TMState::A, Move::L, TMValue::One), - ), - ( - (TMState::B, TMValue::One), - (TMState::A, Move::R, TMValue::Zero), - ), - ]); - - let mut tm = TuringMachine::new(instr, tape); - let mut cursor = Cursor::new(&tm, TMState::A, 0); - - let result = cursor.run(1000); - assert_eq!(result, Err(TuringMachineError::InvalidMovement)); - } - - #[test] - fn test_write_15_fail_move() { - /// Cell value of the tape - #[derive(Debug, Clone, Hash, Eq, PartialEq)] - enum TMValue { - /// Zero - Zero, - - /// One - One, - } - - /// State for Turing machine - /// TODO: Modify this so that users can implement their own state - #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] - enum TMState { - /// Halt - #[default] - Halt, - - /// A - A, - - /// B - B, - } - - let tape: Vec> = vec![TMValue::Zero; 10] - .into_iter() - .map(|x| RefCell::new(x)) - .collect(); - - let instr = HashMap::from([ - ( - (TMState::A, TMValue::Zero), - (TMState::B, Move::R, TMValue::One), - ), - ( - (TMState::A, TMValue::One), - (TMState::B, Move::L, TMValue::One), - ), - ( - (TMState::B, TMValue::Zero), - (TMState::A, Move::L, TMValue::One), - ), - ( - (TMState::B, TMValue::One), - (TMState::Halt, Move::R, TMValue::One), - ), - ]); - - let mut tm = TuringMachine::new(instr, tape); - let mut cursor = Cursor::new(&tm, TMState::A, 0); - - let result = cursor.run(1000); - assert_eq!(result, Err(TuringMachineError::InvalidMovement)); - } - - #[test] - fn test_write_15_pass() { - /// Cell value of the tape - #[derive(Debug, Clone, Hash, Eq, PartialEq)] - enum TMValue { - /// Zero - Zero, - - /// One - One, - } - - /// State for Turing machine - /// TODO: Modify this so that users can implement their own state - #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] - enum TMState { - /// Halt - #[default] - Halt, - - /// A - A, - - /// B - B, - } - - let tape: Vec> = vec![TMValue::Zero; 10] - .into_iter() - .map(|x| RefCell::new(x)) - .collect(); - - let instr = HashMap::from([ - ( - (TMState::A, TMValue::Zero), - (TMState::B, Move::R, TMValue::One), - ), - ( - (TMState::A, TMValue::One), - (TMState::B, Move::L, TMValue::One), - ), - ( - (TMState::B, TMValue::Zero), - (TMState::A, Move::L, TMValue::One), - ), - ( - (TMState::B, TMValue::One), - (TMState::Halt, Move::R, TMValue::One), - ), - ]); - - let mut tm = TuringMachine::new(instr, tape); - let mut cursor = Cursor::new(&tm, TMState::A, 2); - - let result = cursor.run(1000); - for (idx, val) in tm.tape.iter().enumerate() { - if idx < 4 { - assert_eq!(*val.borrow(), TMValue::One); - } else { - assert_eq!(*val.borrow(), TMValue::Zero); - } - } - } - - #[test] - fn test_write_zero_ones_fail_step() { - /// Cell value of the tape - #[derive(Debug, Clone, Hash, Eq, PartialEq)] - enum TMValue { - /// Empty - Empty, - - /// Zero - Zero, - - /// One - One, - } - - /// State for Turing machine - /// TODO: Modify this so that users can implement their own state - #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] - enum TMState { - /// Halt - #[default] - Halt, - - /// A - A, - - /// B - B, - } - - let tape: Vec> = vec![TMValue::Empty; 100] - .into_iter() - .map(|x| RefCell::new(x)) - .collect(); - - let instr = HashMap::from([ - ( - (TMState::A, TMValue::Empty), - (TMState::B, Move::R, TMValue::Zero), - ), - ( - (TMState::B, TMValue::Empty), - (TMState::A, Move::R, TMValue::One), - ), - ]); - - let mut tm = TuringMachine::new(instr, tape); - let mut cursor = Cursor::new(&tm, TMState::A, 0); - - let result = cursor.run(10); - assert_eq!(result, Err(TuringMachineError::ExceedMaxSteps)); - } - - #[test] - fn test_write_zero_ones() { - /// Cell value of the tape - #[derive(Debug, Clone, Hash, Eq, PartialEq)] - enum TMValue { - /// Empty - Empty, - - /// Zero - Zero, - - /// One - One, - } - - /// State for Turing machine - /// TODO: Modify this so that users can implement their own state - #[derive(Default, Debug, Eq, PartialEq, Hash, Clone)] - enum TMState { - /// Halt - #[default] - Halt, - - /// A - A, - - /// B - B, - } - - let tape: Vec> = vec![TMValue::Empty; 100] - .into_iter() - .map(|x| RefCell::new(x)) - .collect(); - - let instr = HashMap::from([ - ( - (TMState::A, TMValue::Empty), - (TMState::B, Move::R, TMValue::Zero), - ), - ( - (TMState::B, TMValue::Empty), - (TMState::A, Move::R, TMValue::One), - ), - ]); - - let mut tm = TuringMachine::new(instr, tape); - let mut cursor = Cursor::new(&tm, TMState::A, 0); - - let result = cursor.run(1000); - assert_eq!(result, Err(TuringMachineError::InvalidMovement)); - for (idx, val) in tm.tape.iter().enumerate() { - if idx % 2 == 0 { - assert_eq!(*val.borrow(), TMValue::Zero); - } else { - assert_eq!(*val.borrow(), TMValue::One); - } - } - } -} diff --git a/src/assignments/assignment11/tv_room_grade.rs b/src/assignments/assignment11/tv_room_grade.rs index 63495eb..9500e1c 100644 --- a/src/assignments/assignment11/tv_room_grade.rs +++ b/src/assignments/assignment11/tv_room_grade.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_tv_room { - use super::super::tv_room::*; + use crate::assignments::assignment11::tv_room::*; #[test] fn test_tv_room() { diff --git a/src/assignments/assignment12/card_grade.rs b/src/assignments/assignment12/card_grade.rs index 4f3ec84..f74d435 100644 --- a/src/assignments/assignment12/card_grade.rs +++ b/src/assignments/assignment12/card_grade.rs @@ -2,7 +2,8 @@ #[cfg(test)] mod test_card { - use super::super::card::*; + use crate::assignments::assignment12::card::*; + use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Barrier, Mutex}; use std::thread; diff --git a/src/assignments/assignment12/demux_grade.rs b/src/assignments/assignment12/demux_grade.rs index 66e11f7..145ff0e 100644 --- a/src/assignments/assignment12/demux_grade.rs +++ b/src/assignments/assignment12/demux_grade.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_demux { - use super::super::demux::*; + use crate::assignments::assignment12::demux::*; use ntest::timeout; use std::sync::mpsc::channel; diff --git a/src/assignments/assignment12/funnel_grade.rs b/src/assignments/assignment12/funnel_grade.rs index 8de4b99..6672419 100644 --- a/src/assignments/assignment12/funnel_grade.rs +++ b/src/assignments/assignment12/funnel_grade.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_funnel { - use super::super::funnel::*; + use crate::assignments::assignment12::funnel::*; use ntest::timeout; use std::sync::mpsc::channel; diff --git a/src/assignments/assignment12/small_exercises_grade.rs b/src/assignments/assignment12/small_exercises_grade.rs index e043ace..b9f59e8 100644 --- a/src/assignments/assignment12/small_exercises_grade.rs +++ b/src/assignments/assignment12/small_exercises_grade.rs @@ -2,7 +2,7 @@ #[cfg(test)] mod test_pingpong { - use super::super::small_exercises::*; + use crate::assignments::assignment12::small_exercises::*; use ntest::timeout; use std::sync::mpsc::channel; diff --git a/src/assignments/assignment13/mod.rs b/src/assignments/assignment13/mod.rs new file mode 100644 index 0000000..34b3587 --- /dev/null +++ b/src/assignments/assignment13/mod.rs @@ -0,0 +1,10 @@ +//! Assignment 13: Parallelism. +//! +//! The primary goal of this assignment is to get used to data parallelism. +//! +//! Refer to your solution for assignment 09. You will implement the parallelized version of assignment 09. +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-13.sh` works fine. +//! See `assignment13_grade.rs` and `/scripts/grade-13.sh` for the test script. + +pub mod small_problems; +mod small_problems_grade; diff --git a/src/assignments/assignment13.rs b/src/assignments/assignment13/small_problems.rs similarity index 87% rename from src/assignments/assignment13.rs rename to src/assignments/assignment13/small_problems.rs index 1ee00f0..893bba0 100644 --- a/src/assignments/assignment13.rs +++ b/src/assignments/assignment13/small_problems.rs @@ -1,10 +1,7 @@ //! Assignment 13: Parallelism. //! -//! The primary goal of this assignment is to get used to data parallelism. -//! -//! Refer to your solution for assignment 09. You will implement the parallelized version of assignment 09. -//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-13.sh` works fine. -//! See `assignment13_grade.rs` and `/scripts/grade-13.sh` for the test script. +//! If you did well on assignment 09, you will do well on this assignment. +//! Take it easy! use rayon::prelude::*; @@ -65,6 +62,9 @@ pub fn vec_add_par(lhs: &[f64], rhs: &[f64]) -> Vec { /// Parallel dot product of two arrays /// +/// You don't know how to calculate dot product? +/// See +/// /// # Exmaple /// /// ``` @@ -82,6 +82,9 @@ pub fn dot_product_par(lhs: &[f64], rhs: &[f64]) -> f64 { /// Parallel Matrix multiplication /// +/// You don't know how to multiply matrix? +/// Quite simple! See +/// /// Assume rhs is transposed /// - lhs: (m, n) /// - rhs: (p, n) diff --git a/src/assignments/assignment13_grade.rs b/src/assignments/assignment13/small_problems_grade.rs similarity index 98% rename from src/assignments/assignment13_grade.rs rename to src/assignments/assignment13/small_problems_grade.rs index 68c75a8..8d315ee 100644 --- a/src/assignments/assignment13_grade.rs +++ b/src/assignments/assignment13/small_problems_grade.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod test { - use super::super::assignment09::matmul::*; - use super::super::assignment13::*; + use crate::assignments::assignment09::matmul::*; + use crate::assignments::assignment13::small_problems::*; use approx::*; use itertools::Itertools; use ndarray::prelude::*; diff --git a/src/assignments/mod.rs b/src/assignments/mod.rs index c490e61..93c8839 100644 --- a/src/assignments/mod.rs +++ b/src/assignments/mod.rs @@ -7,17 +7,14 @@ #![allow(unreachable_code)] pub mod assignment01; -mod assignment01_grade; pub mod assignment02; pub mod assignment03; pub mod assignment04; pub mod assignment06; pub mod assignment07; pub mod assignment08; -mod assignment08_grade; pub mod assignment09; pub mod assignment10; pub mod assignment11; pub mod assignment12; pub mod assignment13; -mod assignment13_grade; From bba6cd99797b507b0fa04690bace4ad1304b72bd Mon Sep 17 00:00:00 2001 From: "jungin.rhee" Date: Mon, 21 Aug 2023 11:52:05 +0000 Subject: [PATCH 10/17] polish --- src/assignments/assignment01/mod.rs | 4 +- .../{small_problems.rs => small_exercises.rs} | 0 ...lems_grade.rs => small_exercises_grade.rs} | 2 +- src/assignments/assignment02/mod.rs | 4 +- .../{small_problems.rs => small_exercises.rs} | 0 ...lems_grade.rs => small_exercises_grade.rs} | 2 +- src/assignments/assignment03/mod.rs | 4 +- .../{small_problems.rs => small_exercises.rs} | 0 ...lems_grade.rs => small_exercises_grade.rs} | 2 +- src/assignments/assignment06/mod.rs | 2 - src/assignments/assignment06/square_matrix.rs | 88 ------------------- .../assignment06/square_matrix_grade.rs | 72 --------------- .../assignment06/symbolic_differentiation.rs | 5 ++ src/assignments/assignment07/generator.rs | 10 ++- src/assignments/assignment07/hubo.rs | 84 ------------------ src/assignments/assignment07/hubo_grade.rs | 40 --------- src/assignments/assignment07/mod.rs | 2 - .../assignment07/small_exercises.rs | 2 +- src/assignments/assignment08/mod.rs | 4 +- .../{small_problems.rs => small_exercises.rs} | 0 ...lems_grade.rs => small_exercises_grade.rs} | 2 +- src/assignments/assignment11/graph_grade.rs | 4 +- src/assignments/assignment13/mod.rs | 4 +- .../{small_problems.rs => small_exercises.rs} | 0 ...lems_grade.rs => small_exercises_grade.rs} | 2 +- 25 files changed, 32 insertions(+), 307 deletions(-) rename src/assignments/assignment01/{small_problems.rs => small_exercises.rs} (100%) rename src/assignments/assignment01/{small_problems_grade.rs => small_exercises_grade.rs} (86%) rename src/assignments/assignment02/{small_problems.rs => small_exercises.rs} (100%) rename src/assignments/assignment02/{small_problems_grade.rs => small_exercises_grade.rs} (98%) rename src/assignments/assignment03/{small_problems.rs => small_exercises.rs} (100%) rename src/assignments/assignment03/{small_problems_grade.rs => small_exercises_grade.rs} (99%) delete mode 100644 src/assignments/assignment06/square_matrix.rs delete mode 100644 src/assignments/assignment06/square_matrix_grade.rs delete mode 100644 src/assignments/assignment07/hubo.rs delete mode 100644 src/assignments/assignment07/hubo_grade.rs rename src/assignments/assignment08/{small_problems.rs => small_exercises.rs} (100%) rename src/assignments/assignment08/{small_problems_grade.rs => small_exercises_grade.rs} (95%) rename src/assignments/assignment13/{small_problems.rs => small_exercises.rs} (100%) rename src/assignments/assignment13/{small_problems_grade.rs => small_exercises_grade.rs} (99%) diff --git a/src/assignments/assignment01/mod.rs b/src/assignments/assignment01/mod.rs index 9a022d3..5c279c8 100644 --- a/src/assignments/assignment01/mod.rs +++ b/src/assignments/assignment01/mod.rs @@ -8,5 +8,5 @@ //! //! Hint: -pub mod small_problems; -mod small_problems_grade; +pub mod small_exercises; +mod small_exercises_grade; diff --git a/src/assignments/assignment01/small_problems.rs b/src/assignments/assignment01/small_exercises.rs similarity index 100% rename from src/assignments/assignment01/small_problems.rs rename to src/assignments/assignment01/small_exercises.rs diff --git a/src/assignments/assignment01/small_problems_grade.rs b/src/assignments/assignment01/small_exercises_grade.rs similarity index 86% rename from src/assignments/assignment01/small_problems_grade.rs rename to src/assignments/assignment01/small_exercises_grade.rs index dbdd99e..3039dee 100644 --- a/src/assignments/assignment01/small_problems_grade.rs +++ b/src/assignments/assignment01/small_exercises_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use crate::assignments::assignment01::small_problems::*; + use crate::assignments::assignment01::small_exercises::*; #[test] fn test_add_7_3() { diff --git a/src/assignments/assignment02/mod.rs b/src/assignments/assignment02/mod.rs index 86a15c7..90b3f2c 100644 --- a/src/assignments/assignment02/mod.rs +++ b/src/assignments/assignment02/mod.rs @@ -6,8 +6,8 @@ //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-02.sh` works fine. //! See `*_grade.rs` and `/scripts/grade-02.sh` for the test script. -pub mod small_problems; -mod small_problems_grade; +pub mod small_exercises; +mod small_exercises_grade; pub mod vec_and_mat; mod vec_and_mat_grade; diff --git a/src/assignments/assignment02/small_problems.rs b/src/assignments/assignment02/small_exercises.rs similarity index 100% rename from src/assignments/assignment02/small_problems.rs rename to src/assignments/assignment02/small_exercises.rs diff --git a/src/assignments/assignment02/small_problems_grade.rs b/src/assignments/assignment02/small_exercises_grade.rs similarity index 98% rename from src/assignments/assignment02/small_problems_grade.rs rename to src/assignments/assignment02/small_exercises_grade.rs index ae33ff1..cca1426 100644 --- a/src/assignments/assignment02/small_problems_grade.rs +++ b/src/assignments/assignment02/small_exercises_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use crate::assignments::assignment02::small_problems::*; + use crate::assignments::assignment02::small_exercises::*; #[test] fn test_fahrenheit() { diff --git a/src/assignments/assignment03/mod.rs b/src/assignments/assignment03/mod.rs index be8a24c..76a311c 100644 --- a/src/assignments/assignment03/mod.rs +++ b/src/assignments/assignment03/mod.rs @@ -3,8 +3,8 @@ //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-03.sh` works fine. //! See `*_grade.rs` and `/scripts/grade-03.sh` for the test script. -pub mod small_problems; -mod small_problems_grade; +pub mod small_exercises; +mod small_exercises_grade; pub mod parse_shell; mod parse_shell_grade; diff --git a/src/assignments/assignment03/small_problems.rs b/src/assignments/assignment03/small_exercises.rs similarity index 100% rename from src/assignments/assignment03/small_problems.rs rename to src/assignments/assignment03/small_exercises.rs diff --git a/src/assignments/assignment03/small_problems_grade.rs b/src/assignments/assignment03/small_exercises_grade.rs similarity index 99% rename from src/assignments/assignment03/small_problems_grade.rs rename to src/assignments/assignment03/small_exercises_grade.rs index 21390ec..45c4c57 100644 --- a/src/assignments/assignment03/small_problems_grade.rs +++ b/src/assignments/assignment03/small_exercises_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use crate::assignments::assignment03::small_problems::*; + use crate::assignments::assignment03::small_exercises::*; #[test] fn test_next_weekday() { diff --git a/src/assignments/assignment06/mod.rs b/src/assignments/assignment06/mod.rs index da14417..e809694 100644 --- a/src/assignments/assignment06/mod.rs +++ b/src/assignments/assignment06/mod.rs @@ -8,9 +8,7 @@ use std::{collections::HashMap, fmt::Debug}; pub mod semiring; -pub mod square_matrix; pub mod symbolic_differentiation; mod semiring_grade; -mod square_matrix_grade; mod symbolic_differentiation_grade; diff --git a/src/assignments/assignment06/square_matrix.rs b/src/assignments/assignment06/square_matrix.rs deleted file mode 100644 index f81209e..0000000 --- a/src/assignments/assignment06/square_matrix.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Square matrix - -/// Square matrix -pub trait SquareMatrix { - /// The type of the submatrix of this square matrix. - /// For example, the submatrix of a 3 x 3 matrix is a 2 x 2 matrix. - /// https://en.wikipedia.org/wiki/Matrix_(mathematics)#Submatrix - type Submatrix; - - /// Returns the submatrix obtained by removing the `row`th row and `col`th column - /// from the original matrix. - /// https://en.wikipedia.org/wiki/Matrix_(mathematics)#Submatrix - fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix; - - /// Returns the determinant of the matrix. - fn det(&self) -> i64; - - /// Returns the determinant of ab, where a is self, b is given, and ab is the matrix product of them. - /// Note that the size of a and b are the same. - /// Hint: Use the fact that det(ab) = det(a) * det(b) - /// https://en.wikipedia.org/wiki/Determinant#Multiplicativity_and_matrix_groups - fn det_ab(&self, b: &Self) -> i64 { - todo!() - } -} - -/// 2 x 2 matrix -#[derive(Debug, PartialEq)] -pub struct Mat2 { - /// inner is a 2 dimensional array (size: 2 x 2) - pub inner: [[i64; 2]; 2], -} - -impl SquareMatrix for Mat2 { - type Submatrix = i64; - - fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix { - // Hint: The submatrix of a 2 x 2 matrix is simply a single number. - todo!() - } - - // Hint: https://en.wikipedia.org/wiki/Determinant - fn det(&self) -> i64 { - todo!() - } -} - -/// 3 x 3 matrix -#[derive(Debug, PartialEq)] -pub struct Mat3 { - /// inner is a 2 dimensional array (size: 3 x 3) - pub inner: [[i64; 3]; 3], -} - -impl SquareMatrix for Mat3 { - type Submatrix = Mat2; - - fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix { - todo!() - } - - // Hint: Use the determinant of the sub-matrices. - // https://semath.info/src/determinant-three-by-three.html - fn det(&self) -> i64 { - todo!() - } -} - -/// 4 x 4 matrix -#[derive(Debug, PartialEq)] -pub struct Mat4 { - /// inner is a 2 dimensional array (size: 4 x 4) - pub inner: [[i64; 4]; 4], -} - -impl SquareMatrix for Mat4 { - type Submatrix = Mat3; - - fn sub_matrix(&self, row: usize, col: usize) -> Self::Submatrix { - todo!() - } - - // Hint: Use the determinant of the sub-matrices. - // https://semath.info/src/determinant-four-by-four.html - fn det(&self) -> i64 { - todo!() - } -} diff --git a/src/assignments/assignment06/square_matrix_grade.rs b/src/assignments/assignment06/square_matrix_grade.rs deleted file mode 100644 index 2ca244c..0000000 --- a/src/assignments/assignment06/square_matrix_grade.rs +++ /dev/null @@ -1,72 +0,0 @@ -#[cfg(test)] -mod test { - use crate::assignments::assignment06::square_matrix::*; - use ntest::assert_about_eq; - - #[test] - fn test_mat2() { - let mat = Mat2 { - inner: [[1, 2], [3, 4]], - }; - assert_eq!(mat.sub_matrix(1, 1), 4); - assert_eq!(mat.sub_matrix(1, 2), 3); - assert_eq!(mat.sub_matrix(2, 1), 2); - assert_eq!(mat.sub_matrix(2, 2), 1); - assert_eq!(mat.det(), -2); - - let mat2 = Mat2 { - inner: [[2, 3], [5, 7]], - }; - assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det()); - } - - #[test] - fn test_mat3() { - let mat = Mat3 { - inner: [[1, 2, 3], [5, 5, 6], [7, 8, 10]], - }; - assert_eq!( - mat.sub_matrix(1, 2), - Mat2 { - inner: [[5, 6], [7, 10]] - } - ); - assert_eq!(mat.det(), 1); - - let mat2 = Mat3 { - inner: [[2, 3, 5], [7, 10, 11], [12, 14, 20]], - }; - assert_eq!(mat2.det(), -42); - assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det()); - } - - #[test] - fn test_mat4() { - let mat = Mat4 { - inner: [ - [1, 11, 3, 4], - [5, 6, 7, 9], - [25, 10, 11, 20], - [36, 14, 15, 30], - ], - }; - assert_eq!( - mat.sub_matrix(2, 3), - Mat3 { - inner: [[1, 11, 4], [25, 10, 20], [36, 14, 30]] - } - ); - assert_eq!(mat.det(), 2089); - - let mat2 = Mat4 { - inner: [ - [2, 3, 5, 5], - [7, 10, 11, 20], - [12, 14, 20, 30], - [1, 2, 5, 10], - ], - }; - assert_eq!(mat2.det(), -340); - assert_eq!(mat.det_ab(&mat2), mat.det() * mat2.det()); - } -} diff --git a/src/assignments/assignment06/symbolic_differentiation.rs b/src/assignments/assignment06/symbolic_differentiation.rs index 28d3b4a..9e33d2b 100644 --- a/src/assignments/assignment06/symbolic_differentiation.rs +++ b/src/assignments/assignment06/symbolic_differentiation.rs @@ -79,6 +79,7 @@ pub trait Differentiable: Clone { fn diff(&self) -> Self; } +/// HINT: Consult impl Differentiable for Rational { fn diff(&self) -> Self { todo!() @@ -115,6 +116,7 @@ impl SingletonPolynomial { } impl Differentiable for SingletonPolynomial { + /// HINT: Consult fn diff(&self) -> Self { todo!() } @@ -138,6 +140,7 @@ impl Default for Exp { } impl Differentiable for Exp { + /// HINT: Consult fn diff(&self) -> Self { todo!() } @@ -173,6 +176,7 @@ impl Trignometric { } impl Differentiable for Trignometric { + /// HINT: Consult fn diff(&self) -> Self { todo!() } @@ -221,6 +225,7 @@ impl Differentiable for Box { } impl Differentiable for ComplexFuncs { + /// HINT: Consult fn diff(&self) -> Self { todo!() } diff --git a/src/assignments/assignment07/generator.rs b/src/assignments/assignment07/generator.rs index fb0243b..e95eb6a 100644 --- a/src/assignments/assignment07/generator.rs +++ b/src/assignments/assignment07/generator.rs @@ -1,11 +1,17 @@ //! Generators +//! +//! HINT: Look at the `generator_grade.rs` file to see how the generator is used. +/// Yielded value. It can be either a value or a stop signal. enum Yielded { Value(T), Stop, } /// Generator +/// - kk +/// - You can call `next()` method to get the next value. +/// - The generator should stop when it yields `Yielded::Stop`. /// /// Reference: /// - [Python generator](https://python-reference.readthedocs.io/en/latest/docs/generator/) @@ -24,13 +30,15 @@ impl Iterator for Generator { } /// Returns a generator that yields fibonacci numbers. +/// +/// HINT: Consult pub fn fib_generator(first: usize, second: usize) -> Generator { todo!() } /// Returns a generator that yields collatz numbers. /// -/// The generator stops when it reaches to 1. +/// HINT: Consult pub fn collatz_conjecture(start: usize) -> Generator { todo!() } diff --git a/src/assignments/assignment07/hubo.rs b/src/assignments/assignment07/hubo.rs deleted file mode 100644 index 581cea9..0000000 --- a/src/assignments/assignment07/hubo.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Hubo is back! - -/// Types that represent a direction. -pub trait Direction { - /// Get the direction in the form of a 2-dimensional vector. - /// The resulting value doesn't have to be normalized. - fn get_vector(&self) -> (f32, f32); -} - -/// 4-way enum to indicate directions. -#[derive(Debug)] -pub enum Dir4 { - /// +x direction - Right, - /// -x direction - Left, - /// +y direction - Up, - /// -y direction - Down, -} - -impl Direction for Dir4 { - fn get_vector(&self) -> (f32, f32) { - todo!() - } -} - -impl Direction for (f32, f32) { - fn get_vector(&self) -> (f32, f32) { - todo!() - } -} - -/// Hubo. -/// It's direction can be represented by an arbitrary type. -/// -/// It can be controlled by [HuboController] only if the direction type implements the [Direction] trait. -#[derive(Debug)] -pub struct Hubo { - direction: TDir, - x: f32, - y: f32, -} - -/// Controller of the Hubo -#[derive(Debug)] -pub struct HuboController<'s, TDir> { - hubo: &'s mut Hubo, -} - -impl Hubo { - /// Create a Hubo. - pub fn new(direction: TDir, x: f32, y: f32) -> Self { - Self { direction, x, y } - } - - /// Return the current position of Hubo. - pub fn get_position(&self) -> (f32, f32) { - (self.x, self.y) - } -} - -impl<'s, TDir: Direction> HuboController<'s, TDir> { - /// Return the controller of the given Hubo. - /// Note that the lifetime of hubo's mutable reference \['s\] is repeated in the return type. - /// - /// This represents that the controller cannot live longer than the mutable reference, - /// since the controller takes and stores the reference. - pub fn new(hubo: &'s mut Hubo) -> HuboController<'s, TDir> { - todo!() - } - - /// Make Hubo move forward by the given distance. You might need to normalize the vector - /// acquired from `Direction::get_move_vector`. - pub fn move_hubo_forward(&mut self, distance: f32) { - todo!() - } - - /// Make Hubo turn to the given direction. - pub fn set_hubo_direction(&mut self, dir: TDir) { - todo!() - } -} diff --git a/src/assignments/assignment07/hubo_grade.rs b/src/assignments/assignment07/hubo_grade.rs deleted file mode 100644 index e67fec3..0000000 --- a/src/assignments/assignment07/hubo_grade.rs +++ /dev/null @@ -1,40 +0,0 @@ -#[cfg(test)] -mod test { - use itertools::Itertools; - use ntest::assert_about_eq; - - use crate::assignments::assignment07::hubo::*; - - #[test] - fn test_hubo_dir4_movement() { - let mut hubo = Hubo::new(Dir4::Right, 0.0, 0.0); - let mut controller = HuboController::new(&mut hubo); - - // Test moving forward - controller.move_hubo_forward(5.0); - - controller.set_hubo_direction(Dir4::Up); - controller.move_hubo_forward(3.0); - - controller.set_hubo_direction(Dir4::Left); - controller.move_hubo_forward(2.0); - - assert_eq!(hubo.get_position(), (3.0, 3.0)); - } - - #[test] - fn test_hubo_tuple_movement() { - let mut hubo = Hubo::new((1., 0.), 0.0, 0.0); - let mut controller = HuboController::new(&mut hubo); - - // Test moving forward - controller.move_hubo_forward(5.0); - - controller.set_hubo_direction((3., 4.)); - controller.move_hubo_forward(5.0); - - controller.set_hubo_direction((-8., -6.)); - controller.move_hubo_forward(15.0); - assert_eq!(hubo.get_position(), (-4., -5.)); - } -} diff --git a/src/assignments/assignment07/mod.rs b/src/assignments/assignment07/mod.rs index 87c48ed..06232aa 100644 --- a/src/assignments/assignment07/mod.rs +++ b/src/assignments/assignment07/mod.rs @@ -6,13 +6,11 @@ //! See `assignment07_grade.rs` and `/scripts/grade-07.sh` for the test script. pub mod generator; -pub mod hubo; pub mod my_itertools; pub mod small_exercises; pub mod transform; mod generator_grade; -mod hubo_grade; mod my_itertools_grade; mod small_exercises_grade; mod transform_grade; diff --git a/src/assignments/assignment07/small_exercises.rs b/src/assignments/assignment07/small_exercises.rs index 86c5661..7c210bb 100644 --- a/src/assignments/assignment07/small_exercises.rs +++ b/src/assignments/assignment07/small_exercises.rs @@ -23,7 +23,7 @@ pub fn find<'s, T: Eq>(query: &'s [T], base: &'s [T]) -> impl 's + Iterator { // TODO: remove `_marker` and add necessary fields as you want _marker: std::marker::PhantomData, diff --git a/src/assignments/assignment08/mod.rs b/src/assignments/assignment08/mod.rs index 8bf6f8c..260a00a 100644 --- a/src/assignments/assignment08/mod.rs +++ b/src/assignments/assignment08/mod.rs @@ -5,5 +5,5 @@ //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine. //! See `small_problems_grade.rs` and `/scripts/grade-08.sh` for the test script. -pub mod small_problems; -mod small_problems_grade; +pub mod small_exercises; +mod small_exercises_grade; diff --git a/src/assignments/assignment08/small_problems.rs b/src/assignments/assignment08/small_exercises.rs similarity index 100% rename from src/assignments/assignment08/small_problems.rs rename to src/assignments/assignment08/small_exercises.rs diff --git a/src/assignments/assignment08/small_problems_grade.rs b/src/assignments/assignment08/small_exercises_grade.rs similarity index 95% rename from src/assignments/assignment08/small_problems_grade.rs rename to src/assignments/assignment08/small_exercises_grade.rs index 2549b0c..dfcb550 100644 --- a/src/assignments/assignment08/small_problems_grade.rs +++ b/src/assignments/assignment08/small_exercises_grade.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use crate::assignments::assignment08::small_problems::*; + use crate::assignments::assignment08::small_exercises::*; #[test] fn test_repeat() { diff --git a/src/assignments/assignment11/graph_grade.rs b/src/assignments/assignment11/graph_grade.rs index 4949ea4..a7ea493 100644 --- a/src/assignments/assignment11/graph_grade.rs +++ b/src/assignments/assignment11/graph_grade.rs @@ -23,9 +23,9 @@ mod test_graph { } let mut graph1 = SubGraph::new(); - for n in 0..6 { + (0..6).for_each(|n| { assert!(graph1.add_node(nodes[n].clone())); - } + }); assert!(graph1.detect_cycle()); assert!(!graph1.add_node(nodes[0].clone())); diff --git a/src/assignments/assignment13/mod.rs b/src/assignments/assignment13/mod.rs index 34b3587..504c1e3 100644 --- a/src/assignments/assignment13/mod.rs +++ b/src/assignments/assignment13/mod.rs @@ -6,5 +6,5 @@ //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-13.sh` works fine. //! See `assignment13_grade.rs` and `/scripts/grade-13.sh` for the test script. -pub mod small_problems; -mod small_problems_grade; +pub mod small_exercises; +mod small_exercises_grade; diff --git a/src/assignments/assignment13/small_problems.rs b/src/assignments/assignment13/small_exercises.rs similarity index 100% rename from src/assignments/assignment13/small_problems.rs rename to src/assignments/assignment13/small_exercises.rs diff --git a/src/assignments/assignment13/small_problems_grade.rs b/src/assignments/assignment13/small_exercises_grade.rs similarity index 99% rename from src/assignments/assignment13/small_problems_grade.rs rename to src/assignments/assignment13/small_exercises_grade.rs index 8d315ee..494acd9 100644 --- a/src/assignments/assignment13/small_problems_grade.rs +++ b/src/assignments/assignment13/small_exercises_grade.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod test { use crate::assignments::assignment09::matmul::*; - use crate::assignments::assignment13::small_problems::*; + use crate::assignments::assignment13::small_exercises::*; use approx::*; use itertools::Itertools; use ndarray::prelude::*; From 9311cd8bae240b717f19d3ca43253841246ad6ba Mon Sep 17 00:00:00 2001 From: woojin Date: Tue, 22 Aug 2023 11:21:08 +0900 Subject: [PATCH 11/17] update readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3a5e2c..83f66d0 100644 --- a/README.md +++ b/README.md @@ -33,12 +33,13 @@ + Mathematics (MAS101): proposition statement and proof + Programming (CS101): basic programming skills - Without a proper understanding of these topics, you will likely struggle in this course. +- Without a proper understanding of these topics, you will likely struggle in this course. +- In the assignment, for the concepts that don't come out in prerequisite courses, we tried to comment on the relevant resources in the assignment code. Please read them carefully. ### Tools -Make sure you're capable of using the following development tools: +Make sure that you're capable of using the following development tools: - [Git](https://git-scm.com/): for downloading the homework skeleton and version-controlling your development. If you're not familiar with Git, walk through [this @@ -97,6 +98,8 @@ Make sure you're capable of using the following development tools: - [Visual Studio Code](https://code.visualstudio.com/) (optional): for developing your homework. If you prefer other editors, you're good to go. - [ChatGPT](https://chat.openai.com/) or other LLMs (optional): for your homework. + - In the era of LLM, we believe that it is important to learn how to use AI as a programming partner. + - We adjusted the difficulty of homework so that you can challenge using ChatGPT as your programming partner. We checked with ChatGPT version 3.5, and verified that it can be a nice tool. Cooperatie with LLM actively to write skeleton code, explain, and debug. - [Development server](https://cloud.fearless.systems/) @@ -181,6 +184,7 @@ Make sure you're capable of using the following development tools: - Ask questions on course materials and assignments in [this repository's issue tracker](https://github.com/kaist-cp/cs220/issues). + Don't send emails to the instructor or TAs for course materials and assignments. + Before asking a question, search for it in Google and Stack Overflow. + + When creating a new issue, you are going to be asked to fill out a template. Make sure that you fill out the template properly. + Describe your question in as much detail as possible. It should include the following things: * Environment (OS, gcc, g++ version, and any other related program information). * Command(s) that you used and the result. Any logs should be formatted in code. Refer to [this](https://guides.github.com/features/mastering-markdown/). From afe2c7b2d2a305b38ffd39b2281ab349934e60b7 Mon Sep 17 00:00:00 2001 From: "jungin.rhee" Date: Tue, 22 Aug 2023 05:16:34 +0000 Subject: [PATCH 12/17] polish --- src/assignments/assignment01/mod.rs | 6 +- .../assignment01/small_exercises.rs | 5 + src/assignments/assignment02/mod.rs | 2 +- src/assignments/assignment02/vec_and_mat.rs | 5 +- src/assignments/assignment03/mod.rs | 2 +- src/assignments/assignment04/mod.rs | 2 +- src/assignments/assignment06/mod.rs | 4 +- src/assignments/assignment06/semiring.rs | 2 +- .../assignment06/symbolic_differentiation.rs | 4 +- src/assignments/assignment07/generator.rs | 1 - src/assignments/assignment07/mod.rs | 2 +- .../assignment07/small_exercises.rs | 4 +- src/assignments/assignment08/mod.rs | 4 +- src/assignments/assignment09/bigint.rs | 5 +- src/assignments/assignment09/mod.rs | 2 +- src/assignments/assignment10/labyrinth.rs | 6 +- src/assignments/assignment10/mod.rs | 3 +- .../assignment10/small_exercises.rs | 6 +- .../assignment11/doubly_linked_list.rs | 101 ------------- .../assignment11/doubly_linked_list_grade.rs | 43 ------ src/assignments/assignment11/graph.rs | 4 + src/assignments/assignment11/linked_list.rs | 140 ++++++++++++++++++ .../assignment11/linked_list_grade.rs | 122 +++++++++++++++ src/assignments/assignment11/mod.rs | 16 +- src/assignments/assignment12/card.rs | 2 +- src/assignments/assignment12/mod.rs | 9 +- src/assignments/assignment13/mod.rs | 2 +- 27 files changed, 312 insertions(+), 192 deletions(-) delete mode 100644 src/assignments/assignment11/doubly_linked_list.rs delete mode 100644 src/assignments/assignment11/doubly_linked_list_grade.rs create mode 100644 src/assignments/assignment11/linked_list.rs create mode 100644 src/assignments/assignment11/linked_list_grade.rs diff --git a/src/assignments/assignment01/mod.rs b/src/assignments/assignment01/mod.rs index 5c279c8..dfcc07f 100644 --- a/src/assignments/assignment01/mod.rs +++ b/src/assignments/assignment01/mod.rs @@ -3,10 +3,8 @@ //! The primary goal of this assignment is bringing up SSH, VSCode, and all the other necessary tools to develop Rust programs. //! Please make sure you're comfortable with developing Rust programs before moving on to the next assignments. //! -//! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade-01.sh` works fine. -//! See `small_problems_grade.rs` and `/scripts/grade-01.sh` for the test script. -//! -//! Hint: +//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-01.sh` works fine. +//! See `assigment01/small_exercises_grade.rs` and `/scripts/grade-01.sh` for the test script. pub mod small_exercises; mod small_exercises_grade; diff --git a/src/assignments/assignment01/small_exercises.rs b/src/assignments/assignment01/small_exercises.rs index aaf3727..a85884d 100644 --- a/src/assignments/assignment01/small_exercises.rs +++ b/src/assignments/assignment01/small_exercises.rs @@ -1,5 +1,10 @@ //! Assignment 1: Preparing Rust Development Environment. //! Welcome to the CS220 course! +//! +//! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade-01.sh` works fine. +//! See `small_problems_grade.rs` and `/scripts/grade-01.sh` for the test script. +//! +//! Hint: /// Adds two unsigned words. If overflow happens, just wrap around. pub fn add(lhs: usize, rhs: usize) -> usize { diff --git a/src/assignments/assignment02/mod.rs b/src/assignments/assignment02/mod.rs index 90b3f2c..282c04c 100644 --- a/src/assignments/assignment02/mod.rs +++ b/src/assignments/assignment02/mod.rs @@ -4,7 +4,7 @@ //! Please make sure you're comfortable with the concepts to proceed on to the next assignments. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-02.sh` works fine. -//! See `*_grade.rs` and `/scripts/grade-02.sh` for the test script. +//! See `assigment02/*_grade.rs` and `/scripts/grade-02.sh` for the test script. pub mod small_exercises; mod small_exercises_grade; diff --git a/src/assignments/assignment02/vec_and_mat.rs b/src/assignments/assignment02/vec_and_mat.rs index df969b3..0054fff 100644 --- a/src/assignments/assignment02/vec_and_mat.rs +++ b/src/assignments/assignment02/vec_and_mat.rs @@ -41,6 +41,7 @@ impl Mat2 { impl Mul for Mat2 { type Output = Mat2; + /// Consult fn mul(self, rhs: Mat2) -> Self::Output { todo!() } @@ -50,6 +51,8 @@ impl Mul for Mat2 { type Output = Vec2; /// Multiplies the matrix by the vector. + /// + /// Consult fn mul(self, rhs: Vec2) -> Self::Output { todo!() } @@ -105,7 +108,7 @@ pub struct FMat2 { impl FMat2 { /// Returns the inverse of the given matrix. (We assume the given matrix is always invertible.) - /// HINT: https://www.mathcentre.ac.uk/resources/uploaded/sigma-matrices7-2009-1.pdf + /// HINT: /// /// # Example /// diff --git a/src/assignments/assignment03/mod.rs b/src/assignments/assignment03/mod.rs index 76a311c..1c950e0 100644 --- a/src/assignments/assignment03/mod.rs +++ b/src/assignments/assignment03/mod.rs @@ -1,7 +1,7 @@ //! Assignment 3: Mastering common programming concepts (2/2) //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-03.sh` works fine. -//! See `*_grade.rs` and `/scripts/grade-03.sh` for the test script. +//! See `assignment03/*_grade.rs` and `/scripts/grade-03.sh` for the test script. pub mod small_exercises; mod small_exercises_grade; diff --git a/src/assignments/assignment04/mod.rs b/src/assignments/assignment04/mod.rs index 4b927d8..ceb0a8c 100644 --- a/src/assignments/assignment04/mod.rs +++ b/src/assignments/assignment04/mod.rs @@ -12,7 +12,7 @@ //! For calculator, just reading `syntax.rs` would suffice for you to understand what to do. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-04.sh` works fine. -//! See `assignment04_grade.rs` and `/scripts/grade-04.sh` for the test script. +//! See `assignment04/grade.rs` and `/scripts/grade-04.sh` for the test script. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment04.zip` to . pub mod context; diff --git a/src/assignments/assignment06/mod.rs b/src/assignments/assignment06/mod.rs index e809694..8727bc1 100644 --- a/src/assignments/assignment06/mod.rs +++ b/src/assignments/assignment06/mod.rs @@ -3,9 +3,7 @@ //! The primary goal of this assignment is to understand generics, traits, and lifetimes. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-06.sh` works fine. -//! See `assignment06_grade.rs` and `/scripts/grade-06.sh` for the test script. - -use std::{collections::HashMap, fmt::Debug}; +//! See `assignment06/*_grade.rs` and `/scripts/grade-06.sh` for the test script. pub mod semiring; pub mod symbolic_differentiation; diff --git a/src/assignments/assignment06/semiring.rs b/src/assignments/assignment06/semiring.rs index 1add902..57cb5bb 100644 --- a/src/assignments/assignment06/semiring.rs +++ b/src/assignments/assignment06/semiring.rs @@ -156,7 +156,7 @@ impl From for Polynomial { /// - In `x^n` and `ax^n`, it is guaranteed that `n >= 2`. /// - All terms have unique degrees. /// -/// Consult `assignment06_jaemin_choi_grade.rs` for example valid strings. +/// Consult `assignment06/grade.rs` for example valid strings. /// /// Hint: `.split`, `.parse`, and `Polynomial::term` impl std::str::FromStr for Polynomial { diff --git a/src/assignments/assignment06/symbolic_differentiation.rs b/src/assignments/assignment06/symbolic_differentiation.rs index 9e33d2b..2269d13 100644 --- a/src/assignments/assignment06/symbolic_differentiation.rs +++ b/src/assignments/assignment06/symbolic_differentiation.rs @@ -79,8 +79,8 @@ pub trait Differentiable: Clone { fn diff(&self) -> Self; } -/// HINT: Consult impl Differentiable for Rational { + /// HINT: Consult fn diff(&self) -> Self { todo!() } @@ -122,7 +122,7 @@ impl Differentiable for SingletonPolynomial { } } -/// Expoential function. +/// Expoential function.(`e^x`) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Exp; diff --git a/src/assignments/assignment07/generator.rs b/src/assignments/assignment07/generator.rs index e95eb6a..57f8172 100644 --- a/src/assignments/assignment07/generator.rs +++ b/src/assignments/assignment07/generator.rs @@ -9,7 +9,6 @@ enum Yielded { } /// Generator -/// - kk /// - You can call `next()` method to get the next value. /// - The generator should stop when it yields `Yielded::Stop`. /// diff --git a/src/assignments/assignment07/mod.rs b/src/assignments/assignment07/mod.rs index 06232aa..0dbfcd7 100644 --- a/src/assignments/assignment07/mod.rs +++ b/src/assignments/assignment07/mod.rs @@ -3,7 +3,7 @@ //! The primary goal of this assignment is to understand generics, traits, and lifetimes. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-07.sh` works fine. -//! See `assignment07_grade.rs` and `/scripts/grade-07.sh` for the test script. +//! See `assignment07/*_grade.rs` and `/scripts/grade-07.sh` for the test script. pub mod generator; pub mod my_itertools; diff --git a/src/assignments/assignment07/small_exercises.rs b/src/assignments/assignment07/small_exercises.rs index 7c210bb..ece7f41 100644 --- a/src/assignments/assignment07/small_exercises.rs +++ b/src/assignments/assignment07/small_exercises.rs @@ -52,7 +52,7 @@ pub fn fib(first: T, second: T) -> impl Iterator where T: std::ops::Add + Copy, { - todo!("remove below"); + todo!("replace `std::iter::empty() with your owm implementation`"); std::iter::empty() } @@ -86,7 +86,7 @@ impl Iterator for RangeIter { /// Returns an iterator over the range [left, right) with the given step. pub fn range(left: Endpoint, right: Endpoint, step: isize) -> impl Iterator { - todo!("remove below"); + todo!("replace `std::iter::empty() with your owm implementation`"); std::iter::empty() } diff --git a/src/assignments/assignment08/mod.rs b/src/assignments/assignment08/mod.rs index 260a00a..c601b9a 100644 --- a/src/assignments/assignment08/mod.rs +++ b/src/assignments/assignment08/mod.rs @@ -3,7 +3,9 @@ //! The primary goal of this assignment is to get used to first-class functions. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine. -//! See `small_problems_grade.rs` and `/scripts/grade-08.sh` for the test script. +//! See `assignment08/*_grade.rs` and `/scripts/grade-08.sh` for the test script. pub mod small_exercises; mod small_exercises_grade; + +// TODO: add kyeongmin's church encoding asignment diff --git a/src/assignments/assignment09/bigint.rs b/src/assignments/assignment09/bigint.rs index 1c1db51..33a96e5 100644 --- a/src/assignments/assignment09/bigint.rs +++ b/src/assignments/assignment09/bigint.rs @@ -39,11 +39,8 @@ impl BigInt { } /// Creates a new `BigInt` from a `Vec`. - /// - /// # Panic - /// - /// Panics if `carrier` is empty. pub fn new_large(carrier: Vec) -> Self { + assert!(!carrier.is_empty()); todo!() } } diff --git a/src/assignments/assignment09/mod.rs b/src/assignments/assignment09/mod.rs index 9601827..9fa8940 100644 --- a/src/assignments/assignment09/mod.rs +++ b/src/assignments/assignment09/mod.rs @@ -3,7 +3,7 @@ //! The primary goal of this assignment is to get used to iterators. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-09.sh` works fine. -//! See `assignment09_grade.rs` and `/scripts/grade-09.sh` for the test script. +//! See `assignment09/*_grade.rs` and `/scripts/grade-09.sh` for the test script. pub mod bigint; pub mod matmul; diff --git a/src/assignments/assignment10/labyrinth.rs b/src/assignments/assignment10/labyrinth.rs index 001b522..0b9e8e1 100644 --- a/src/assignments/assignment10/labyrinth.rs +++ b/src/assignments/assignment10/labyrinth.rs @@ -1,14 +1,12 @@ //! Labyrinth //! -//! Look at the [test code](labyrinth_grade.rs) below before you start. -//! HINT: https://en.wikipedia.org/wiki/100_prisoners_problem +//! Look at the `labyrinth_grade.rs` below before you start. +//! HINT: //! //! NOTE: You will have to implement a probabilistic algorithm, which means, the algorithm can fail //! even if you have implemented the solution. We recommend running multiple times (at least 5 times) to check your //! solution works well. -#![allow(missing_docs)] - use std::cell::RefCell; /// Husband diff --git a/src/assignments/assignment10/mod.rs b/src/assignments/assignment10/mod.rs index 5b7390a..7fc988f 100644 --- a/src/assignments/assignment10/mod.rs +++ b/src/assignments/assignment10/mod.rs @@ -1,9 +1,8 @@ -//! //! Assignment 10: Iterators (2/2). //! The primary goal of this assignment is to get used to iterators. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-10.sh` works fine. -//! See `assignment10_grade.rs` and `/scripts/grade-10.sh` for the test script. +//! See `assignment10/*_grade.rs` and `/scripts/grade-10.sh` for the test script. pub mod labyrinth; pub mod small_exercises; diff --git a/src/assignments/assignment10/small_exercises.rs b/src/assignments/assignment10/small_exercises.rs index e4d59cb..4cb8f74 100644 --- a/src/assignments/assignment10/small_exercises.rs +++ b/src/assignments/assignment10/small_exercises.rs @@ -1,4 +1,5 @@ //! Small exercises. + use itertools::*; /// Returns the pairs of `(i, j)` where `i < j` and `inner[i] > inner[j]` in increasing order. @@ -185,9 +186,8 @@ impl Iterator for Pythagorean { } } -/// Generates sequence of unique [primitive Pythagorean -/// triples](https://en.wikipedia.org/wiki/Pythagorean_triple), i.e. (a,b,c) such that a² + b² = -/// c², a and b are coprimes, and a < b. Generate in the increasing order of c. +/// Generates sequence of unique [primitive Pythagorean triples](https://en.wikipedia.org/wiki/Pythagorean_triple), +/// i.e. (a,b,c) such that a² + b² = c², a and b are coprimes, and a < b. Generate in the increasing order of c. pub fn pythagorean() -> impl Iterator { Pythagorean::new() } diff --git a/src/assignments/assignment11/doubly_linked_list.rs b/src/assignments/assignment11/doubly_linked_list.rs deleted file mode 100644 index d3cc7bf..0000000 --- a/src/assignments/assignment11/doubly_linked_list.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Doubly Linked List. -//! -//! Refer `doubly_linked_list_grade.rs` for test cases. - -use std::{cell::RefCell, fmt::Debug, rc::Rc}; - -type Link = Option>>>; - -/// Node of a doubly-linked list. -#[derive(Debug)] -pub struct Node { - /// Value of current node. - value: RefCell, - - /// Pointer to the next node. If it is `None`, there is no next node. - next: Link, - - /// Pointer to the previous node. If it is `None`, there is no previous node. - prev: Link, -} - -impl Node { - /// Creates a new node. - fn new(value: T) -> Self { - Self { - value: RefCell::new(value), - next: None, - prev: None, - } - } - - /// Fetch the value contained in node - pub fn get(&self) -> T { - self.value.borrow().clone() - } - - /// Replace the data contained in the node - pub fn replace(&self, new_value: T) -> T { - self.value.replace(new_value) - } - - /// Fetch previous node - pub fn prev(&self) -> Link { - self.prev.clone() - } - - /// Fetch next node - pub fn next(&self) -> Link { - self.next.clone() - } -} - -/// A doubly-linked list. -#[derive(Default, Debug)] -pub struct DoublyLinkedList { - /// Head node of the list. If it is `None`, the list is empty. - head: Link, - - /// Tail node of the list. If it is `None`, the list is empty. - tail: Link, -} - -impl DoublyLinkedList { - /// Creates a new list. - pub fn new() -> Self { - Self { - head: None, - tail: None, - } - } - - /// Adds the given node to the front of the list. - pub fn push_front(&mut self, value: T) { - todo!() - } - - /// Adds the given node to the back of the list. - pub fn push_back(&mut self, value: T) { - todo!() - } - - /// Removes and returns the node at the front of the list. - pub fn pop_front(&mut self) -> Option { - todo!() - } - - /// Removes and returns the node at the back of the list. - pub fn pop_back(&mut self) -> Option { - todo!() - } -} - -impl Drop for DoublyLinkedList { - fn drop(&mut self) { - while let Some(node) = self.head.take() { - let _ = node.borrow_mut().prev.take(); - self.head = node.borrow_mut().next.take(); - } - let _unused = self.tail.take(); - } -} diff --git a/src/assignments/assignment11/doubly_linked_list_grade.rs b/src/assignments/assignment11/doubly_linked_list_grade.rs deleted file mode 100644 index ebdc19a..0000000 --- a/src/assignments/assignment11/doubly_linked_list_grade.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Test cases for assignment11/doubly_linked_list.rs - -#[cfg(test)] -mod test_doubly_linked_list { - use crate::assignments::assignment11::doubly_linked_list::*; - - #[test] - fn test_works() { - let mut list = DoublyLinkedList::new(); - - list.push_back(3); - list.push_back(4); - assert_eq!(list.pop_front(), Some(3)); - - list.push_front(5); - assert_eq!(list.pop_back(), Some(4)); - assert_eq!(list.pop_back(), Some(5)); - assert_eq!(list.pop_back(), None); - assert_eq!(list.pop_front(), None); - } - - #[test] - fn test_can_push_back() { - let mut list = DoublyLinkedList::new(); - assert_eq!(list.pop_back(), None); - - list.push_back(3); - list.push_back(4); - list.push_back(5); - assert_eq!(list.pop_back(), Some(5)); - - list.push_back(6); - list.push_back(7); - assert_eq!(list.pop_back(), Some(7)); - assert_eq!(list.pop_back(), Some(6)); - assert_eq!(list.pop_back(), Some(4)); - assert_eq!(list.pop_back(), Some(3)); - - list.push_back(2); - assert_eq!(list.pop_back(), Some(2)); - assert_eq!(list.pop_back(), None); - } -} diff --git a/src/assignments/assignment11/graph.rs b/src/assignments/assignment11/graph.rs index 65a92f3..7c3ca6f 100644 --- a/src/assignments/assignment11/graph.rs +++ b/src/assignments/assignment11/graph.rs @@ -23,6 +23,8 @@ enum VisitStatus { /// `NodeHandle` should implement `Clone`, which clones the handle without cloning the underlying /// node. That is, there can be multiple handles to the same node. /// The user can access the node through a handle if it does not violate Rust's aliasing rules. +/// +/// TODO: You can freely add fields to this struct. #[derive(Debug, Clone)] pub struct NodeHandle; @@ -31,6 +33,8 @@ pub struct NodeHandle; pub struct GraphError; /// Subgraph +/// +/// TODO: You can freely add fields to this struct. #[derive(Debug)] pub struct SubGraph; diff --git a/src/assignments/assignment11/linked_list.rs b/src/assignments/assignment11/linked_list.rs new file mode 100644 index 0000000..161a7a4 --- /dev/null +++ b/src/assignments/assignment11/linked_list.rs @@ -0,0 +1,140 @@ +//! Singly linked list. +//! +//! Consult . + +use std::fmt::Debug; + +/// Node of the list. +#[derive(Debug)] +pub struct Node { + /// Value of current node. + pub value: T, + + /// Pointer to the next node. If it is `None`, there is no next node. + pub next: Option>>, +} + +impl Node { + /// Creates a new node. + pub fn new(value: T) -> Self { + Self { value, next: None } + } +} + +/// A singly-linked list. +#[derive(Debug)] +pub struct SinglyLinkedList { + /// Head node of the list. If it is `None`, the list is empty. + head: Option>, +} + +impl Default for SinglyLinkedList { + fn default() -> Self { + Self::new() + } +} + +impl SinglyLinkedList { + /// Creates a new list. + pub fn new() -> Self { + Self { head: None } + } + + /// Adds the given node to the front of the list. + pub fn push_front(&mut self, value: T) { + todo!() + } + + /// Adds the given node to the back of the list. + pub fn push_back(&mut self, value: T) { + todo!() + } + + /// Removes and returns the node at the front of the list. + pub fn pop_front(&mut self) -> Option { + todo!() + } + + /// Removes and returns the node at the back of the list. + pub fn pop_back(&mut self) -> Option { + todo!() + } + + /// Create a new list from the given vector `vec`. + pub fn from_vec(vec: Vec) -> Self { + todo!() + } + + /// Convert the current list into a vector. + pub fn as_vec(&self) -> Vec { + todo!() + } + + /// Return the length (i.e., number of nodes) of the list. + pub fn length(&self) -> usize { + todo!() + } + + /// Apply function `f` on every element of the list. + /// + /// # Examples + /// + /// `self`: `[1, 2]`, `f`: `|x| x + 1` ==> `[2, 3]` + pub fn map T>(&mut self, f: F) { + todo!() + } + + /// Insert given list `another` at the specified index `idx`. + /// If `idx` is out-of-bound of `self`, append `another` at the end of `self`. + /// + /// # Examples + /// + /// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `1` ==> `[1, 3, 4, 2]` + /// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `5` ==> `[1, 2, 3, 4]` + pub fn insert(&mut self, another: &Self, idx: usize) { + todo!() + } + + /// Reverse the list in a chunk of size `n`. + /// If `n == 0`, do nothing. + /// + /// # Examples + /// + /// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `3` + /// // each chunk of size `3`: `[1, 2, 3]`, `[4, 5, 6]`, `[7, 8, 9]` + /// // reversed sequence of chunks: `[7, 8, 9]`, `[4, 5, 6]`, `[1, 2, 3]` + /// ==> `[7, 8, 9, 4, 5, 6, 1, 2, 3]`, + /// + /// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `4` + /// // each chunk of size `4`: `[1, 2, 3, 4]`, `[5, 6, 7, 8]`, `[9]` + /// // reversed sequence of chunks: `[9]`, `[5, 6, 7, 8]`, `[1, 2, 3, 4]` + /// ==> `[9, 5, 6, 7, 8, 1, 2, 3, 4]` + pub fn chunk_reverse(&mut self, n: usize) { + todo!() + } + + /// Apply given function `f` for each adjacent pair of elements in the list. + /// If `self.length() < 2`, do nothing. + /// + /// # Examples + /// + /// `self`: `[1, 2, 3, 4]`, `f`: `|x, y| x + y` + /// // each adjacent pair of elements: `(1, 2)`, `(2, 3)`, `(3, 4)` + /// // apply `f` to each pair: `f(1, 2) == 3`, `f(2, 3) == 5`, `f(3, 4) == 7` + /// ==> `[3, 5, 7]` + pub fn pair_map T>(&mut self, f: F) { + todo!() + } +} + +// A list of lists. +impl SinglyLinkedList> { + /// Flatten the list of lists into a single list. + /// + /// # Examples + /// `self`: `[[1, 2, 3], [4, 5, 6], [7, 8]]` + /// ==> `[1, 2, 3, 4, 5, 6, 7, 8]` + pub fn flatten(self) -> SinglyLinkedList { + todo!() + } +} diff --git a/src/assignments/assignment11/linked_list_grade.rs b/src/assignments/assignment11/linked_list_grade.rs new file mode 100644 index 0000000..6805972 --- /dev/null +++ b/src/assignments/assignment11/linked_list_grade.rs @@ -0,0 +1,122 @@ +#[cfg(test)] +mod test_linked_list { + use crate::assignments::assignment11::linked_list::*; + + #[derive(Debug, PartialEq, Eq)] + struct V(usize); + + #[test] + fn test_push_pop() { + let mut list = SinglyLinkedList::new(); + list.push_back(V(3)); + list.push_front(V(2)); + list.push_back(V(4)); + list.push_front(V(1)); + list.push_back(V(5)); + + assert_eq!(list.pop_front(), Some(V(1))); + assert_eq!(list.pop_back(), Some(V(5))); + assert_eq!(list.pop_front(), Some(V(2))); + assert_eq!(list.pop_back(), Some(V(4))); + assert_eq!(list.pop_front(), Some(V(3))); + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_front(), None); + } + + #[test] + fn test_from_as_vec() { + assert_eq!(SinglyLinkedList::::new().as_vec(), vec![]); + assert_eq!( + SinglyLinkedList::from_vec(vec![1, 2, 3]).as_vec(), + vec![1, 2, 3] + ); + } + + #[test] + fn test_length() { + let list = SinglyLinkedList::from_vec(vec![1, 2, 3]); + assert_eq!(list.length(), 3); + } + + #[test] + fn test_map() { + let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let incr = |x: i32| x + 1; + list.map(incr); + assert_eq!(list.as_vec(), vec![2, 3, 4]); + } + + #[test] + fn test_insert() { + let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + let list4 = SinglyLinkedList::from_vec(vec![4, 5, 6]); + + list1.insert(&list4, 0); + assert_eq!(list1.as_vec(), vec![4, 5, 6, 1, 2, 3]); + + list2.insert(&list4, 1); + assert_eq!(list2.as_vec(), vec![1, 4, 5, 6, 2, 3]); + + list3.insert(&list4, 4); + assert_eq!(list3.as_vec(), vec![1, 2, 3, 4, 5, 6]); + } + + #[test] + fn test_chunk_reverse() { + let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); + list1.chunk_reverse(3); + assert_eq!(list1.as_vec(), vec![7, 8, 9, 3, 4, 5, 1, 2, 3]); + + let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8]); + list2.chunk_reverse(3); + assert_eq!(list2.as_vec(), vec![7, 8, 4, 5, 6, 1, 2, 3]); + + let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]); + list3.chunk_reverse(4); + assert_eq!(list3.as_vec(), vec![1, 2, 3]); + + let mut list4 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]); + list4.chunk_reverse(1); + assert_eq!(list4.as_vec(), vec![4, 3, 2, 1]); + + let mut list5 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]); + list4.chunk_reverse(0); + assert_eq!(list4.as_vec(), vec![1, 2, 3, 4]); + } + + #[test] + fn test_pair_map() { + let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); + let add = |x: i32, y: i32| x + y; + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![3, 5, 7, 9, 11, 13, 15, 17]); + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![8, 12, 16, 20, 24, 28, 32]); + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![20, 28, 36, 44, 52, 60]); + + list.pair_map(add); + assert_eq!(list.as_vec(), vec![48, 64, 80, 96, 112]); + } + + #[test] + fn test_flatten() { + let list1 = SinglyLinkedList::from_vec(vec![1, 2]); + let list2 = SinglyLinkedList::from_vec(vec![3]); + let list3 = SinglyLinkedList::from_vec(vec![4, 5, 6, 7]); + let list4 = SinglyLinkedList::::new(); + let list5 = SinglyLinkedList::from_vec(vec![8, 9, 10]); + + let list_list = SinglyLinkedList::from_vec(vec![list1, list2, list3, list4, list5]); + + assert_eq!( + list_list.flatten().as_vec(), + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + ); + } +} diff --git a/src/assignments/assignment11/mod.rs b/src/assignments/assignment11/mod.rs index be8f452..1802da6 100644 --- a/src/assignments/assignment11/mod.rs +++ b/src/assignments/assignment11/mod.rs @@ -1,17 +1,15 @@ //! Assignment 11: Familiarizing with smart pointers. //! //! You should fill out `todo!()` placeholders in such a way that `/scripts/grade-11.sh` works fine. -//! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script. +//! See `assignment11/*_grade.rs` and `/scripts/grade-11.sh` for the test script. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to . -pub mod doubly_linked_list; -mod doubly_linked_list_grade; - pub mod graph; -mod graph_grade; - +pub mod linked_list; pub mod mock_storage; -pub mod mock_storage_grade; - pub mod tv_room; -pub mod tv_room_grade; + +mod graph_grade; +mod linked_list_grade; +mod mock_storage_grade; +mod tv_room_grade; diff --git a/src/assignments/assignment12/card.rs b/src/assignments/assignment12/card.rs index 1a00da9..c7f6e51 100644 --- a/src/assignments/assignment12/card.rs +++ b/src/assignments/assignment12/card.rs @@ -1,6 +1,6 @@ //! Flipping card game. //! -//! For this assignment, you have to see `play` function in `card_grade.rs` file. +//! HINT: For this assignment, you have to see `play` function in `card_grade.rs` file. //! Multiple threads will be created and they will run as enemy bots(`bot_threads`). //! Strategy of the enemy bots is implemented in the closure of the `thread::spawn` function. //! Your goal is to beat them so that there are more white cards than blue cards in the ground. diff --git a/src/assignments/assignment12/mod.rs b/src/assignments/assignment12/mod.rs index 7b82d6e..3dd2a96 100644 --- a/src/assignments/assignment12/mod.rs +++ b/src/assignments/assignment12/mod.rs @@ -3,13 +3,14 @@ //! The primary goal of this assignment is to get used to concurrency. //! //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-12.sh` works fine. -//! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script. +//! See `assignment12/*_grade.rs` and `/scripts/grade-12.sh` for the test script. pub mod card; -mod card_grade; pub mod demux; -mod demux_grade; pub mod funnel; -mod funnel_grade; pub mod small_exercises; + +mod card_grade; +mod demux_grade; +mod funnel_grade; mod small_exercises_grade; diff --git a/src/assignments/assignment13/mod.rs b/src/assignments/assignment13/mod.rs index 504c1e3..3ea15d4 100644 --- a/src/assignments/assignment13/mod.rs +++ b/src/assignments/assignment13/mod.rs @@ -4,7 +4,7 @@ //! //! Refer to your solution for assignment 09. You will implement the parallelized version of assignment 09. //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-13.sh` works fine. -//! See `assignment13_grade.rs` and `/scripts/grade-13.sh` for the test script. +//! See `assignment13/small_exercises_grade.rs` and `/scripts/grade-13.sh` for the test script. pub mod small_exercises; mod small_exercises_grade; From 4ae52a5ee9f2fca730dbea661dcc197cf2b6f200 Mon Sep 17 00:00:00 2001 From: woojin Date: Tue, 22 Aug 2023 14:28:17 +0900 Subject: [PATCH 13/17] add church --- src/assignments/assignment08/church.rs | 71 +++++++++++++++++++ src/assignments/assignment08/church_grade.rs | 73 ++++++++++++++++++++ src/assignments/assignment08/mod.rs | 3 + 3 files changed, 147 insertions(+) create mode 100644 src/assignments/assignment08/church.rs create mode 100644 src/assignments/assignment08/church_grade.rs diff --git a/src/assignments/assignment08/church.rs b/src/assignments/assignment08/church.rs new file mode 100644 index 0000000..251fda4 --- /dev/null +++ b/src/assignments/assignment08/church.rs @@ -0,0 +1,71 @@ +//! Church Numerals +//! +//! This exercise involves the use of "Church numerals", a +//! representation of natural numbers using lambda calculus, named after +//! Alonzo Church. Each Church numeral corresponds to a natural number `n` +//! and is represented as a higher-order function that applies a given function `f` `n` times. +//! +//! For more information, see: +//! - +//! - + +use std::rc::Rc; + +/// Church numerals are represented as higher-order functions that take a function `f` +pub type Church = Rc T>) -> Rc T>>; + +/// This function returns a Church numeral equivalent of the natural number 1. +/// It takes a function `f` and applies it exactly once. +pub fn one() -> Church { + Rc::new(move |f| Rc::new(move |x| f(x))) +} + +/// This function returns a Church numeral equivalent of the natural number 2. +/// It takes a function `f` and applies it twice. +pub fn two() -> Church { + Rc::new(move |f| Rc::new(move |x| f(f(x)))) +} + +/// This function represents the Church numeral for zero. As zero applications +/// of `f` should leave the argument unchanged, the function simply returns the input. +pub fn zero() -> Church { + Rc::new(|_| Rc::new(|x| x)) +} + +/// Implement a function to add 1 to a given Church numeral. +pub fn succ(n: Church) -> Church { + todo!() +} + +/// Implement a function to add two Church numerals. +pub fn add(n: Church, m: Church) -> Church { + todo!() +} + +/// Implement a function to multiply (mult) two Church numerals. +pub fn mult(n: Church, m: Church) -> Church { + todo!() +} + +/// Implement a function to raise one Church numeral to the power of another. +/// This is the Church numeral equivalent of the natural number operation of exponentiation. +/// Given two natural numbers `n` and `m`, the function should return a Church numeral +/// that represents `n` to the power of `m`. The key is to convert `n` and `m` to Church numerals, +/// and then apply the Church numeral for `m` (the exponent) to the Church numeral for `n` (the base). +/// Note: This function should be implemented *WITHOUT* using the `to_usize` or any `pow`-like method. +pub fn exp(n: usize, m: usize) -> Church { + // ACTION ITEM: Uncomment the following lines and replace `todo!()` with your code. + // let n = from_usize(n); + // let m = from_usize(m); + todo!() +} + +/// Implement a function to convert a Church numeral to a usize type. +pub fn to_usize(n: Church) -> usize { + todo!() +} + +/// Implement a function to convert a usize type to a Church numeral. +pub fn from_usize(n: usize) -> Church { + todo!() +} diff --git a/src/assignments/assignment08/church_grade.rs b/src/assignments/assignment08/church_grade.rs new file mode 100644 index 0000000..1df5db4 --- /dev/null +++ b/src/assignments/assignment08/church_grade.rs @@ -0,0 +1,73 @@ +#[cfg(test)] +mod test { + use rand::Rng; + + use crate::assignments::assignment08::church::*; + + #[test] + fn you_must_pass_these_examples() { + let c_zero = zero::(); + assert_eq!(to_usize(c_zero.clone()), 0); + + let c_one = succ(c_zero.clone()); + assert_eq!(to_usize(c_one.clone()), to_usize(one::<()>())); + + let c_two = add(c_one.clone(), c_one.clone()); + let c_three = add(c_one.clone(), c_two.clone()); + assert_eq!(to_usize(c_three.clone()), 3); + + let c_product = mult(c_three.clone(), c_two.clone()); + assert_eq!(to_usize(c_product.clone()), 6); + + let c_exponent = exp::<()>(6, 3); + assert_eq!(to_usize(c_exponent), 216); + + let c_exponent2 = exp::<()>(3, 0); + assert_eq!(to_usize(c_exponent2), 1); + } + + fn id(n: usize) -> usize { + to_usize(from_usize::<()>(n)) + } + + fn c_id(n: Church) -> Church { + from_usize(to_usize(n)) + } + + #[test] + fn engineering_isnt_just_mathematics() { + const N: usize = 77777; + assert_eq!(N, id(N)); + } + + /// This test case is an optional challenge. + /// While it's not necessary to pass this test, + /// successfully doing so could provide a sense of satisfaction and achievement. + // #[test] + // fn i_said_engineering_isnt_just_mathematics() { + // const N: usize = 777777777777777; + // assert_eq!(N, id(N)); + // } + + #[test] + fn be_honest() { + let mut rng = rand::thread_rng(); + + for _ in 0..77 { + let x = rng.gen_range(0..=7); + let y = rng.gen_range(0..=7); + + let c_x = from_usize(x); + let c_y = from_usize(y); + + let c_sum = add(c_x.clone(), c_y.clone()); + assert_eq!(to_usize(c_id(c_sum)), x + y); + + let c_prod = mult(c_x.clone(), c_y.clone()); + assert_eq!(to_usize(c_id(c_prod)), x * y); + + let c_exp = exp(x, y); + assert_eq!(to_usize(c_id(c_exp)), x.pow(y as u32)); + } + } +} diff --git a/src/assignments/assignment08/mod.rs b/src/assignments/assignment08/mod.rs index 260a00a..0a6bf5f 100644 --- a/src/assignments/assignment08/mod.rs +++ b/src/assignments/assignment08/mod.rs @@ -5,5 +5,8 @@ //! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine. //! See `small_problems_grade.rs` and `/scripts/grade-08.sh` for the test script. +pub mod church; pub mod small_exercises; + +mod church_grade; mod small_exercises_grade; From d74a8e0b4358bc472de6605ac4f408e7fb087825 Mon Sep 17 00:00:00 2001 From: Jeehoon Kang Date: Tue, 22 Aug 2023 16:21:46 +0900 Subject: [PATCH 14/17] Revise readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 83f66d0..e49a8b4 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,8 @@ Make sure that you're capable of using the following development tools: - [Visual Studio Code](https://code.visualstudio.com/) (optional): for developing your homework. If you prefer other editors, you're good to go. - [ChatGPT](https://chat.openai.com/) or other LLMs (optional): for your homework. - - In the era of LLM, we believe that it is important to learn how to use AI as a programming partner. - - We adjusted the difficulty of homework so that you can challenge using ChatGPT as your programming partner. We checked with ChatGPT version 3.5, and verified that it can be a nice tool. Cooperatie with LLM actively to write skeleton code, explain, and debug. + - In the era of AI, we believe that it is crucial to learn how to wisely use AI in programming. + - So we adjusted the difficulty of homework assuming that you'll use ChatGPT 3.5 (or equivalent) to solve it. - [Development server](https://cloud.fearless.systems/) @@ -183,7 +183,7 @@ Make sure that you're capable of using the following development tools: - Ask questions on course materials and assignments in [this repository's issue tracker](https://github.com/kaist-cp/cs220/issues). + Don't send emails to the instructor or TAs for course materials and assignments. - + Before asking a question, search for it in Google and Stack Overflow. + + Before asking a question, consult with the issue tracker, Google, Stack Overflow, and LLMs. + When creating a new issue, you are going to be asked to fill out a template. Make sure that you fill out the template properly. + Describe your question in as much detail as possible. It should include the following things: * Environment (OS, gcc, g++ version, and any other related program information). From 57d994107d927e6c81515c805af13ad7119504e3 Mon Sep 17 00:00:00 2001 From: AnHaechan Date: Tue, 22 Aug 2023 11:12:46 +0000 Subject: [PATCH 15/17] why3: removed unnecessary newlines --- assets/why3/assignment05/binary_search.mlw | 1 + assets/why3/assignment05/max.mlw | 2 +- assets/why3/assignment05/pascal.mlw | 2 ++ assets/why3/exercises/ex1_eucl_div.mlw | 2 +- assets/why3/exercises/ex2_fact.mlw | 2 +- assets/why3/exercises/ex3_two_way.mlw | 2 +- 6 files changed, 7 insertions(+), 4 deletions(-) diff --git a/assets/why3/assignment05/binary_search.mlw b/assets/why3/assignment05/binary_search.mlw index 931cc48..17cd0c9 100644 --- a/assets/why3/assignment05/binary_search.mlw +++ b/assets/why3/assignment05/binary_search.mlw @@ -19,4 +19,5 @@ module BinarySearch = (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) 0 (* TODO *) + end \ No newline at end of file diff --git a/assets/why3/assignment05/max.mlw b/assets/why3/assignment05/max.mlw index b0b858b..49c168e 100644 --- a/assets/why3/assignment05/max.mlw +++ b/assets/why3/assignment05/max.mlw @@ -26,4 +26,4 @@ module Max done; max -end +end \ No newline at end of file diff --git a/assets/why3/assignment05/pascal.mlw b/assets/why3/assignment05/pascal.mlw index 2d0fa93..c3cd28f 100644 --- a/assets/why3/assignment05/pascal.mlw +++ b/assets/why3/assignment05/pascal.mlw @@ -5,6 +5,7 @@ *) module Pascal + use int.Int use ref.Ref use array.Array @@ -36,4 +37,5 @@ module Pascal row <- new_row done; row + end \ No newline at end of file diff --git a/assets/why3/exercises/ex1_eucl_div.mlw b/assets/why3/exercises/ex1_eucl_div.mlw index c4aaf20..24fa3af 100644 --- a/assets/why3/exercises/ex1_eucl_div.mlw +++ b/assets/why3/exercises/ex1_eucl_div.mlw @@ -26,4 +26,4 @@ module Division done; q -end +end \ No newline at end of file diff --git a/assets/why3/exercises/ex2_fact.mlw b/assets/why3/exercises/ex2_fact.mlw index adad25e..bef4c59 100644 --- a/assets/why3/exercises/ex2_fact.mlw +++ b/assets/why3/exercises/ex2_fact.mlw @@ -46,4 +46,4 @@ module FactLoop done; r -end +end \ No newline at end of file diff --git a/assets/why3/exercises/ex3_two_way.mlw b/assets/why3/exercises/ex3_two_way.mlw index 24705bd..836722e 100644 --- a/assets/why3/exercises/ex3_two_way.mlw +++ b/assets/why3/exercises/ex3_two_way.mlw @@ -48,4 +48,4 @@ module TwoWaySort end done -end +end \ No newline at end of file From 7768e670abd4c7529e572147cefc605127cb363a Mon Sep 17 00:00:00 2001 From: AnHaechan Date: Tue, 22 Aug 2023 11:29:47 +0000 Subject: [PATCH 16/17] removed resolved todo comment --- src/assignments/assignment08/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/assignments/assignment08/mod.rs b/src/assignments/assignment08/mod.rs index a63077f..4125a1a 100644 --- a/src/assignments/assignment08/mod.rs +++ b/src/assignments/assignment08/mod.rs @@ -10,5 +10,3 @@ pub mod small_exercises; mod church_grade; mod small_exercises_grade; - -// TODO: add kyeongmin's church encoding asignment From 1dbbdefe7ea8c7ddaed548966eab50dbda5cb268 Mon Sep 17 00:00:00 2001 From: "jungin.rhee" Date: Tue, 22 Aug 2023 12:13:05 +0000 Subject: [PATCH 17/17] bump dependencies & toolchain --- Cargo.lock | 48 ++++++++++++++++++++++++------------------------ Cargo.toml | 18 +++++++++--------- rust-toolchain | 2 +- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ab1c58..cf2e00a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,9 +89,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -104,9 +104,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.3.22" +version = "4.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b417ae4361bca3f5de378294fc7472d3c4ed86a5ef9f49e93ae722f432aae8d2" +checksum = "03aef18ddf7d879c15ce20f04826ef8418101c7e528014c3eeea13321047dca3" dependencies = [ "clap_builder", "clap_derive", @@ -115,9 +115,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.22" +version = "4.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90dc0f0e42c64bff177ca9d7be6fcc9ddb0f26a6e062174a61c84dd6c644d4" +checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98" dependencies = [ "anstream", "anstyle", @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -789,9 +789,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f51fb4c64f8b770a823c043c7fad036323e1c48f55287b7bbb7987b2fcdf3b" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -804,45 +804,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fde1bb55ae4ce76a597a8566d82c57432bc69c039449d61572a7a353da28f68c" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1513e8d48365a78adad7322fd6b5e4c4e99d92a69db8df2d435b25b1f1f286d4" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60587c0265d2b842298f5858e1a5d79d146f9ee0c37be5782e92a6eb5e1d7a83" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224fe0e0ffff5d2ea6a29f82026c8f43870038a0ffc247aa95a52b47df381ac4" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62fc52a0f50a088de499712cbc012df7ebd94e2d6eb948435449d76a6287e7ad" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2093925509d91ea3d69bcd20238f4c2ecdb1a29d3c281d026a09705d0dd35f3d" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.3" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6ade45bc8bf02ae2aa34a9d54ba660a1a58204da34ba793c00d83ca3730b5f1" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index f7271a5..d5e48c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,18 +6,18 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.66" -clap = { version = "4.0.29", features = ["derive"] } +anyhow = "1.0.75" +clap = { version = "4.3.23", features = ["derive"] } etrace = "1.1.1" -itertools = "0.10.5" +itertools = "0.11.0" lazy_static = "1.4.0" -pest = "2.5.1" -pest_derive = "2.5.1" -rayon = "1.6.0" -thiserror = "1.0" +pest = "2.7.2" +pest_derive = "2.7.2" +rayon = "1.7.0" +thiserror = "1.0.47" ntest = "0.9.0" approx = "0.5.1" -num-traits = "0.2" -ndarray = "0.15.0" +num-traits = "0.2.16" +ndarray = "0.15.6" ndarray-rand = "0.14.0" rand = "0.8.5" diff --git a/rust-toolchain b/rust-toolchain index 832e9af..df484cb 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.70.0 +1.71.0