Merge pull request #242 from AnHaechan/main

Merge from cs220-private + Update info on safe exam browser, ChatGPT
This commit is contained in:
Jeehoon Kang
2023-08-25 13:54:29 +09:00
committed by GitHub
104 changed files with 5100 additions and 1249 deletions

616
Cargo.lock generated
View File

@@ -3,10 +3,68 @@
version = 3 version = 3
[[package]] [[package]]
name = "anyhow" name = "anstream"
version = "1.0.66" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" 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"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
@@ -16,24 +74,27 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.3" version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [ dependencies = [
"generic-array", "generic-array",
] ]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.77" version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -43,55 +104,65 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.0.29" version = "4.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" checksum = "03aef18ddf7d879c15ce20f04826ef8418101c7e528014c3eeea13321047dca3"
dependencies = [ dependencies = [
"bitflags", "clap_builder",
"clap_derive", "clap_derive",
"clap_lex",
"is-terminal",
"once_cell", "once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim", "strsim",
"termcolor",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.0.21" version = "4.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.29",
] ]
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.3.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
dependencies = [
"os_str_bytes", [[package]]
] name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.5" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.6" version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"crossbeam-utils", "crossbeam-utils",
@@ -99,9 +170,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.2" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"crossbeam-epoch", "crossbeam-epoch",
@@ -110,9 +181,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.13" version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if", "cfg-if",
@@ -123,9 +194,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.14" version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@@ -145,21 +216,27 @@ name = "cs220"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"approx",
"clap", "clap",
"etrace", "etrace",
"itertools", "itertools",
"lazy_static", "lazy_static",
"ndarray",
"ndarray-rand",
"ntest", "ntest",
"num-traits",
"pest", "pest",
"pest_derive", "pest_derive",
"rand",
"rayon", "rayon",
"thiserror",
] ]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.6" version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"crypto-common", "crypto-common",
@@ -167,19 +244,25 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "errno" name = "errno"
version = "0.2.8" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [ dependencies = [
"errno-dragonfly", "errno-dragonfly",
"libc", "libc",
"winapi", "windows-sys",
] ]
[[package]] [[package]]
@@ -200,65 +283,69 @@ checksum = "f17311e68ea07046ee809b8513f6c259518bc10173681d98c21f8c3926f56f40"
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.6" version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check", "version_check",
] ]
[[package]]
name = "getrandom"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "indexmap"
version = "0.2.6" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
dependencies = [ dependencies = [
"libc", "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]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.1" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [ dependencies = [
"hermit-abi 0.2.6", "hermit-abi",
"io-lifetimes",
"rustix", "rustix",
"windows-sys", "windows-sys",
] ]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [ dependencies = [
"either", "either",
] ]
@@ -271,25 +358,71 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.138" version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libm"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.1.3" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[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]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.7.1" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [ dependencies = [
"autocfg", "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]] [[package]]
name = "ntest" name = "ntest"
version = "0.9.0" version = "0.9.0"
@@ -308,7 +441,7 @@ checksum = "be7d33be719c6f4d09e64e27c1ef4e73485dc4cc1f4d22201f89860a7fe22e22"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
@@ -320,36 +453,59 @@ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "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]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.14.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [ dependencies = [
"hermit-abi 0.1.19", "hermit-abi",
"libc", "libc",
] ]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.16.0" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "os_str_bytes"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.5.1" version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a"
dependencies = [ dependencies = [
"thiserror", "thiserror",
"ucd-trie", "ucd-trie",
@@ -357,9 +513,9 @@ dependencies = [
[[package]] [[package]]
name = "pest_derive" name = "pest_derive"
version = "2.5.1" version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853"
dependencies = [ dependencies = [
"pest", "pest",
"pest_generator", "pest_generator",
@@ -367,97 +523,123 @@ dependencies = [
[[package]] [[package]]
name = "pest_generator" name = "pest_generator"
version = "2.5.1" version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929"
dependencies = [ dependencies = [
"pest", "pest",
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.29",
] ]
[[package]] [[package]]
name = "pest_meta" name = "pest_meta"
version = "2.5.1" version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"pest", "pest",
"sha1", "sha2",
] ]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "1.2.1" version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"thiserror", "toml_edit",
"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",
] ]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.47" version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.21" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "rayon" name = "rand"
version = "1.6.0" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" 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.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [ dependencies = [
"crossbeam-deque",
"either", "either",
"rayon-core", "rayon-core",
] ]
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.10.1" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"crossbeam-deque", "crossbeam-deque",
@@ -467,13 +649,12 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.36.4" version = "0.38.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
"io-lifetimes",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys", "windows-sys",
@@ -481,21 +662,15 @@ dependencies = [
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "serde" name = "sha2"
version = "1.0.149" version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
[[package]]
name = "sha1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
@@ -510,9 +685,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.105" version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -520,60 +695,76 @@ dependencies = [
] ]
[[package]] [[package]]
name = "termcolor" name = "syn"
version = "1.1.3" version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
dependencies = [ dependencies = [
"winapi-util", "proc-macro2",
"quote",
"unicode-ident",
] ]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.37" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.37" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.29",
] ]
[[package]] [[package]]
name = "toml" name = "toml_datetime"
version = "0.5.9" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" 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 = [ dependencies = [
"serde", "indexmap",
"toml_datetime",
"winnow",
] ]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.15.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]] [[package]]
name = "ucd-trie" name = "ucd-trie"
version = "0.1.5" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.5" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "version_check" name = "version_check"
@@ -582,41 +773,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "winapi" name = "wasi"
version = "0.3.9" version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
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"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.42.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
@@ -629,42 +804,51 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.42.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "winnow"
version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97"
dependencies = [
"memchr",
]

View File

@@ -6,12 +6,18 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0.66" anyhow = "1.0.75"
clap = { version = "4.0.29", features = ["derive"] } clap = { version = "4.3.23", features = ["derive"] }
etrace = "1.1.1" etrace = "1.1.1"
itertools = "0.10.5" itertools = "0.11.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
pest = "2.5.1" pest = "2.7.2"
pest_derive = "2.5.1" pest_derive = "2.7.2"
rayon = "1.6.0" rayon = "1.7.0"
thiserror = "1.0.47"
ntest = "0.9.0" ntest = "0.9.0"
approx = "0.5.1"
num-traits = "0.2.16"
ndarray = "0.15.6"
ndarray-rand = "0.14.0"
rand = "0.8.5"

View File

@@ -33,12 +33,13 @@
+ Mathematics (MAS101): proposition statement and proof + Mathematics (MAS101): proposition statement and proof
+ Programming (CS101): basic programming skills + 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 ### 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 - [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 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. - [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. - [ChatGPT](https://chat.openai.com/) or other LLMs (optional): for your homework.
- 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/) - [Development server](https://cloud.fearless.systems/)
@@ -146,8 +149,11 @@ Make sure you're capable of using the following development tools:
- Your physical apperance is required. If online participation is **absolutely necessary**, we'll use Zoom. - Your physical apperance is required. If online participation is **absolutely necessary**, we'll use Zoom.
- You'll bring your own laptop. (You can also borrow one from School of Computing Admin Team.) - You should bring your own laptop. (You can also borrow one from School of Computing Admin Team.)
We will use surveillance tools such as [Safe Exam Browser](https://safeexambrowser.org/) to monitor your laptop.
- We will use [Safe Exam Browser](https://safeexambrowser.org/) to prevent cheatings.
- You should have your laptop configured with Safe Exam Browser before the exam.
- TBA: Details will be announced later.
### Attendance (?%) ### Attendance (?%)
@@ -180,7 +186,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). - 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. + 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, ask it to [ChatGPT](https://chat.openai.com/). Or search for it in Google and Stack Overflow.
+ Describe your question in as much detail as possible. It should include the following things: + 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). * 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/). * 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/).
@@ -188,6 +194,7 @@ Make sure you're capable of using the following development tools:
* Googling result. Search before asking, and share the keyword used for searching and what you've learned from it. * Googling result. Search before asking, and share the keyword used for searching and what you've learned from it.
+ Give a proper title to your issue. + Give a proper title to your issue.
+ Read [this](https://github.com/kaist-cp/cs220#communication) for more instructions. + Read [this](https://github.com/kaist-cp/cs220#communication) for more instructions.
+ Questions will be answered within 2 days mostly.
+ I'm requiring you to ask questions online first for two reasons. First, clearly writing a + I'm requiring you to ask questions online first for two reasons. First, clearly writing a
question is the first step to reaching an answer. Second, you can benefit from the questions and answers of other students. question is the first step to reaching an answer. Second, you can benefit from the questions and answers of other students.

View File

@@ -19,4 +19,5 @@ module BinarySearch
= =
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *) (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
0 (* TODO *) 0 (* TODO *)
end end

View File

@@ -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: 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
end

View File

@@ -0,0 +1,41 @@
(* 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
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. *)
(* 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.
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 { forall c: int. 0 <= c < r -> row[c] = comb (r-1) c }
let new_row = Array.make (r+1) 1 in
for c = 1 to r-1 do
(* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
invariant { true (* TODO: Replace `true` with your solution *) }
(* IMPORTANT: DON'T MODIFY THE BELOW LINES *)
new_row[c] <- row[c-1] + row[c]
done;
row <- new_row
done;
row
end

View File

@@ -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

View File

@@ -0,0 +1,29 @@
(* 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
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: Replace `true` with your solution *) }
variant { r }
q <- q + 1;
r <- r - b
done;
q
end

View File

@@ -0,0 +1,49 @@
(* Two programs to compute the factorial
Questions:
1. In module FactRecursive:
a. Implement the program that satisfies specification.
2. In module FactLoop:
a. Strengthen the invariant to prove correctness of the given implementation.
b. Select a correct variant to prove the termination.
*)
module FactRecursive
use int.Int
use int.Fact
let rec fact_rec (n: int) : int
requires { n >= 0 }
ensures { result = fact n }
variant { n }
= (* IMPORTANT: DON'T MODIFY THE ABOVE LINES *)
0 (*TODO*)
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 { true (* TODO: Replace `true` with your solution *) }
variant { n (* TODO: Replace `n` with your solution *) }
m <- m + 1;
r <- r * m
done;
r
end

View File

@@ -0,0 +1,51 @@
(* Two Way Sort
The following program sorts an array of Boolean values, with False<True.
E.g.
two_way_sorted [True; False; False; True; False]
= [False; False; False; True; True]
- Strengthen the invariants to prove correctness.
*)
module TwoWaySort
use int.Int
use bool.Bool
use ref.Refint
use array.Array
use array.ArraySwap
use array.ArrayPermut
predicate (<<) (x y: bool) = x = False \/ y = True
predicate sorted (a: array bool) =
forall i1 i2: int. 0 <= i1 <= i2 < a.length -> 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
-> true (* TODO: Replace `true` with your solution *) }
invariant { forall i2: int. j < i2 < length a
-> 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
else if a[j] then
decr j
else begin
swap a i j;
incr i;
decr j
end
done
end

View File

@@ -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

View File

@@ -1,23 +1,5 @@
(* Two programs to compute the factorial (* 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.
2. In module FactLoop:
a. Prove soundness of function fact_loop.
b. Prove its termination.
c. Change the code to use a for loop instead of a while loop.
*) *)
module FactRecursive module FactRecursive

View File

@@ -1,22 +1,12 @@
(* Two Way Sort (* Two Way Sort
The following program sorts an array of Boolean values, with False<True. The following program sorts an array of Boolean values, with False<True.
E.g.
two_way_sorted [True; False; False; True; False]
= [False; False; False; True; True]
Questions: - Strengthen the invariant to prove correctness.
1. Prove safety i.e. the absence of array access out of bounds.
2. Prove termination.
3. Prove that array a is sorted after execution of function two_way_sort
(using the predicate sorted that is provided).
4. Show that after execution the array contents is a permutation of its
initial contents. Use the library predicate "permut_all" to do so
(the corresponding module ArrayPermut is already imported).
You can refer to the contents of array a at the beginning of the
function with notation "a at Init".
*) *)
module TwoWaySort module TwoWaySort
@@ -34,15 +24,16 @@ module TwoWaySort
forall i1 i2: int. 0 <= i1 <= i2 < a.length -> a[i1] << a[i2] forall i1 i2: int. 0 <= i1 <= i2 < a.length -> a[i1] << a[i2]
let two_way_sort (a: array bool) : unit 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 i = 0 in
let ref j = length a - 1 in let ref j = length a - 1 in
while i < j do while i < j do
invariant { 0 <= i /\ j < length a }
invariant { forall i1: int. 0 <= i1 < i -> a[i1] = False } invariant { forall i1: int. 0 <= i1 < i -> a[i1] = False }
invariant { forall i2: int. j < i2 < length a -> a[i2] = True } invariant { forall i2: int. j < i2 < length a -> a[i2] = True }
invariant { 0 <= i /\ j < length a } invariant { permut_all (old a) a }
variant { j - i } variant { j - i }
if not a[i] then if not a[i] then
incr i incr i

View File

@@ -1 +1 @@
1.70.0 1.71.0

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment01_grade") TESTS=("--lib assignment01")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment02_grade") TESTS=("--lib assignment02")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment03_grade") TESTS=("--lib assignment03")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment04_grade") TESTS=("--lib assignment04")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
source $BASEDIR/grade-utils.sh source $BASEDIR/grade-utils.sh
RUNNERS=( RUNNERS=(
"cargo" "cargo"
"cargo --release" "cargo --release"
"cargo_asan" "cargo_asan"
"cargo_asan --release" "cargo_asan --release"
"cargo_tsan" "cargo_tsan"
"cargo_tsan --release" "cargo_tsan --release"
) )
# Lints. # Lints.
@@ -22,12 +22,12 @@ run_linters || exit 1
# Executes test for each runner. # Executes test for each runner.
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment06_grade") TESTS=("--lib assignment06")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi
done done
exit 0 exit 0

View File

@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
source $BASEDIR/grade-utils.sh source $BASEDIR/grade-utils.sh
RUNNERS=( RUNNERS=(
"cargo" "cargo"
"cargo --release" "cargo --release"
"cargo_asan" "cargo_asan"
"cargo_asan --release" "cargo_asan --release"
"cargo_tsan" "cargo_tsan"
"cargo_tsan --release" "cargo_tsan --release"
) )
# Lints. # Lints.
@@ -22,12 +22,12 @@ run_linters || exit 1
# Executes test for each runner. # Executes test for each runner.
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment07_grade") TESTS=("--lib assignment07")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi
done done
exit 0 exit 0

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment08_grade") TESTS=("--lib assignment08")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
source $BASEDIR/grade-utils.sh source $BASEDIR/grade-utils.sh
RUNNERS=( RUNNERS=(
"cargo" "cargo"
"cargo --release" "cargo --release"
"cargo_asan" "cargo_asan"
"cargo_asan --release" "cargo_asan --release"
"cargo_tsan" "cargo_tsan"
"cargo_tsan --release" "cargo_tsan --release"
) )
# Lints. # Lints.
@@ -22,12 +22,12 @@ run_linters || exit 1
# Executes test for each runner. # Executes test for each runner.
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment09_grade") TESTS=("--lib assignment09")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi
done done
exit 0 exit 0

View File

@@ -9,12 +9,12 @@ BASEDIR=$(dirname "$0")
source $BASEDIR/grade-utils.sh source $BASEDIR/grade-utils.sh
RUNNERS=( RUNNERS=(
"cargo" "cargo"
"cargo --release" "cargo --release"
"cargo_asan" "cargo_asan"
"cargo_asan --release" "cargo_asan --release"
"cargo_tsan" "cargo_tsan"
"cargo_tsan --release" "cargo_tsan --release"
) )
# Lints. # Lints.
@@ -22,12 +22,12 @@ run_linters || exit 1
# Executes test for each runner. # Executes test for each runner.
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment10_grade") TESTS=("--lib assignment10")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi
done done
exit 0 exit 0

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment11_grade") TESTS=("--lib assignment11")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment12_grade") TESTS=("--lib assignment12")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -24,7 +24,7 @@ run_linters || exit 1
for RUNNER in "${RUNNERS[@]}"; do for RUNNER in "${RUNNERS[@]}"; do
echo "Running with $RUNNER..." echo "Running with $RUNNER..."
TESTS=("--lib assignment13_grade") TESTS=("--lib assignment13")
if [ $(run_tests) -ne 0 ]; then if [ $(run_tests) -ne 0 ]; then
exit 1 exit 1
fi fi

View File

@@ -0,0 +1,10 @@
//! Assignment 1: Preparing Rust Development Environment.
//!
//! The primary goal of this assignment is bringing up SSH, VSCode, and all the other necessary tools to develop Rust programs.
//! Please make sure you're comfortable with developing Rust programs before moving on to the next assignments.
//!
//! 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;

View File

@@ -1,10 +1,8 @@
//! Assignment 1: Preparing Rust Development Environment. //! Assignment 1: Preparing Rust Development Environment.
//! //! Welcome to the CS220 course!
//! 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. //! 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: <https://doc.rust-lang.org/std/primitive.usize.html> //! Hint: <https://doc.rust-lang.org/std/primitive.usize.html>

View File

@@ -1,6 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::assignment01::*; use crate::assignments::assignment01::small_exercises::*;
#[test] #[test]
fn test_add_7_3() { fn test_add_7_3() {

View File

@@ -1,143 +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 <https://en.wikipedia.org/wiki/Pascal%27s_triangle> for computation of binomial coefficients without integer overflow.
pub fn chooses(n: u64) -> Vec<u64> {
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<u64>, rhs: Vec<u64>) -> 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<Mat2> for Mat2 {
type Output = Mat2;
fn mul(self, rhs: Mat2) -> Self::Output {
todo!()
}
}
impl Mul<Vec2> 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 <https://web.media.mit.edu/~holbrow/post/calculating-fibonacci-numbers-with-matrices-and-linear-algebra/> for matrix computation of Fibonacci numbers.
pub fn fibonacci(n: u64) -> u64 {
(FIBONACCI_MAT.power(n) * FIBONACCI_VEC).get_upper()
}
/// 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!()
}

View File

@@ -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 `assigment02/*_grade.rs` and `/scripts/grade-02.sh` for the test script.
pub mod small_exercises;
mod small_exercises_grade;
pub mod vec_and_mat;
mod vec_and_mat_grade;

View File

@@ -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 <https://en.wikipedia.org/wiki/Pascal%27s_triangle> for computation of binomial coefficients without integer overflow.
pub fn chooses(n: u64) -> Vec<u64> {
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<u64>, rhs: Vec<u64>) -> Vec<(u64, u64)> {
todo!()
}

View File

@@ -1,6 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::assignment02::*; use crate::assignments::assignment02::small_exercises::*;
#[test] #[test]
fn test_fahrenheit() { fn test_fahrenheit() {
@@ -134,128 +134,4 @@ mod test {
assert_eq!(zip(vec![1, 2], vec![4, 5, 6]), 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![]); 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);
}
#[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
"#;
} }

View File

@@ -0,0 +1,124 @@
//! 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<Mat2> for Mat2 {
type Output = Mat2;
/// Consult <https://www.mathsisfun.com/algebra/matrix-multiplying.html>
fn mul(self, rhs: Mat2) -> Self::Output {
todo!()
}
}
impl Mul<Vec2> for Mat2 {
type Output = Vec2;
/// Multiplies the matrix by the vector.
///
/// Consult <https://www.mathsisfun.com/algebra/matrix-multiplying.html>
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 <https://web.media.mit.edu/~holbrow/post/calculating-fibonacci-numbers-with-matrices-and-linear-algebra/> 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!()
}
}

View File

@@ -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
}
);
}
}

View File

@@ -0,0 +1,79 @@
//! You will implement a number of custom operators.
/// Custom option type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MyOption<T> {
/// Some value of type `T`.
MySome(T),
/// No value.
MyNone,
}
/// Maps an `MyOption<T>` to `MyOption<U>` by applying a function to a contained value.
///
/// # Examples
///
/// Converts an `MyOption<String>` into an `MyOption<usize>`, 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<T, U, F: FnOnce(T) -> U>(v: MyOption<T>, f: F) -> MyOption<U> {
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<String> {
/// 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<T, U, F: FnOnce(T) -> MyOption<U>>(v: MyOption<T>, f: F) -> MyOption<U> {
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, F: FnOnce(T, T) -> T>(
v1: MyOption<T>,
v2: MyOption<T>,
f: F,
) -> MyOption<T> {
todo!()
}

View File

@@ -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::<f64>, is_positive), MyNone);
}
#[test]
fn test_my_and_then() {
fn plus_one(x: isize) -> MyOption<isize> {
MySome(x + 1)
}
fn none(_: isize) -> MyOption<isize> {
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));
}
}

View File

@@ -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 `assignment03/*_grade.rs` and `/scripts/grade-03.sh` for the test script.
pub mod small_exercises;
mod small_exercises_grade;
pub mod parse_shell;
mod parse_shell_grade;
pub mod custom_operators;
mod custom_operators_grade;

View File

@@ -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<String> {
todo!()
}

View File

@@ -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(),
]
);
}
}

View File

@@ -1,12 +1,7 @@
//! Assignment 3: Mastering common programming concepts (2/2). //! Small problems.
//!
//! 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.
//!
//! 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::collections::{HashMap, HashSet};
use std::fmt;
/// Day of week. /// Day of week.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -34,60 +29,6 @@ pub fn next_weekday(day: DayOfWeek) -> DayOfWeek {
todo!() todo!()
} }
/// Custom option type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MyOption<T> {
/// Some value of type `T`.
MySome(T),
/// No value.
MyNone,
}
/// Maps an `MyOption<T>` to `MyOption<U>` by applying a function to a contained value.
///
/// # Examples
///
/// Converts an `MyOption<String>` into an `MyOption<usize>`, 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<T, U, F: FnOnce(T) -> U>(v: MyOption<T>, f: F) -> MyOption<U> {
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<String> {
/// 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<T, U, F: FnOnce(T) -> MyOption<U>>(v: MyOption<T>, f: F) -> MyOption<U> {
todo!()
}
/// Given a list of integers, returns its median (when sorted, the value in the middle position). /// 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: /// For a data set `x` of `n` elements, the median can be defined as follows:
@@ -166,3 +107,24 @@ pub fn piglatin(input: String) -> String {
pub fn organize(commands: Vec<String>) -> HashMap<String, HashSet<String>> { pub fn organize(commands: Vec<String>) -> HashMap<String, HashSet<String>> {
todo!() 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<TypeEvent>) -> String {
todo!()
}

View File

@@ -1,6 +1,6 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::assignment03::*; use crate::assignments::assignment03::small_exercises::*;
#[test] #[test]
fn test_next_weekday() { fn test_next_weekday() {
@@ -13,52 +13,6 @@ mod test {
assert_eq!(next_weekday(DayOfWeek::Sat), DayOfWeek::Mon); 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::<f64>, is_positive), MyNone);
}
#[test]
fn test_my_and_then() {
use MyOption::*;
fn plus_one(x: isize) -> MyOption<isize> {
MySome(x + 1)
}
fn none(_: isize) -> MyOption<isize> {
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] #[test]
fn test_median() { fn test_median() {
assert_eq!(median(vec![]), None); assert_eq!(median(vec![]), None);
@@ -165,4 +119,61 @@ mod test {
.into() .into()
); );
} }
#[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
]),
""
);
}
} }

View File

@@ -1,8 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::assignments::assignment04::syntax::*; use crate::assignments::assignment04::syntax::*;
use crate::assignments::assignment04::*;
use super::super::assignment04::*;
#[test] #[test]
fn test_parse() { fn test_parse() {

View File

@@ -12,9 +12,10 @@
//! For calculator, just reading `syntax.rs` would suffice for you to understand what to do. //! For calculator, just reading `syntax.rs` would suffice for you to understand what to do.
//! //!
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-04.sh` works fine. //! 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 <https://gg.kaist.ac.kr>. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment04.zip` to <https://gg.kaist.ac.kr>.
pub mod context; pub mod context;
mod grade;
pub mod parser; pub mod parser;
pub mod syntax; pub mod syntax;

View File

@@ -0,0 +1,12 @@
//! 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.
pub mod semiring;
pub mod symbolic_differentiation;
mod semiring_grade;
mod symbolic_differentiation_grade;

View File

@@ -1,9 +1,4 @@
//! Assignment 6: Mastering advanced types (1/2). //! Semiring
//!
//! 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}; use std::{collections::HashMap, fmt::Debug};
@@ -123,12 +118,6 @@ impl<C: Semiring> Semiring for Polynomial<C> {
} }
} }
impl<C: Semiring> From<C> for Polynomial<C> {
fn from(value: C) -> Self {
todo!()
}
}
impl<C: Semiring> Polynomial<C> { impl<C: Semiring> Polynomial<C> {
/// Constructs polynomial `x`. /// Constructs polynomial `x`.
pub fn x() -> Self { pub fn x() -> Self {
@@ -139,4 +128,41 @@ impl<C: Semiring> Polynomial<C> {
pub fn eval(&self, value: C) -> C { pub fn eval(&self, value: C) -> C {
todo!() todo!()
} }
/// Constructs polynomial `ax^n`.
pub fn term(a: C, n: u64) -> Self {
todo!()
}
}
impl<C: Semiring> From<C> for Polynomial<C> {
fn from(value: C) -> Self {
todo!()
}
}
/// Given a string `s`, parse it into a `Polynomial<C>`.
/// 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/grade.rs` for example valid strings.
///
/// Hint: `.split`, `.parse`, and `Polynomial::term`
impl<C: Semiring> std::str::FromStr for Polynomial<C> {
type Err = (); // Ignore this for now...
fn from_str(s: &str) -> Result<Self, Self::Err> {
todo!()
}
} }

View File

@@ -1,6 +1,14 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::assignment06::*; use crate::assignments::assignment06::semiring::*;
use ntest::assert_about_eq;
fn test_from_str(s: &str, f: impl Fn(i64) -> i64) {
let poly = s.parse::<Polynomial<i64>>().unwrap();
for i in 0..10 {
assert_eq!(poly.eval(i), f(i));
}
}
fn test_polynomial<T: Semiring>() { fn test_polynomial<T: Semiring>() {
// x^2 + 5x + 6 // x^2 + 5x + 6
@@ -21,6 +29,43 @@ mod test {
assert_eq!(value, from_usize(13 * 13 + 5 * 13 + 6)); 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] #[test]
fn test_polynomial_u64() { fn test_polynomial_u64() {
test_polynomial::<u64>(); test_polynomial::<u64>();

View File

@@ -0,0 +1,365 @@
//! 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 {
/// HINT: Consult <https://en.wikipedia.org/wiki/Differentiation_rules#Constant_term_rule>
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 {
/// HINT: Consult <https://en.wikipedia.org/wiki/Power_rule>
fn diff(&self) -> Self {
todo!()
}
}
/// Expoential function.(`e^x`)
#[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 {
/// HINT: Consult <https://en.wikipedia.org/wiki/Differentiation_rules#Derivatives_of_exponential_and_logarithmic_functions>
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 {
/// HINT: Consult <https://en.wikipedia.org/wiki/Differentiation_rules#Derivatives_of_trigonometric_functions>
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<F> {
/// Basic functions
Func(F),
/// Addition
Add(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
/// Subtraction
Sub(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
/// Multipliciation
Mul(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
/// Division
Div(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
/// Composition
Comp(Box<ComplexFuncs<F>>, Box<ComplexFuncs<F>>),
}
impl<F: Differentiable> Differentiable for Box<F> {
fn diff(&self) -> Self {
todo!()
}
}
impl<F: Differentiable> Differentiable for ComplexFuncs<F> {
/// HINT: Consult <https://en.wikipedia.org/wiki/Differentiation_rules#Elementary_rules_of_differentiation>
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<F: Evaluate> Evaluate for ComplexFuncs<F> {
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<F: Differentiable + fmt::Display> fmt::Display for ComplexFuncs<F> {
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})"),
}
}
}

View File

@@ -0,0 +1,216 @@
#[cfg(test)]
mod test {
use crate::assignments::assignment06::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<BF>;
// 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);
}
}

View File

@@ -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<T: Eq> Iterator for FindIter<'_, T> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
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<Item = usize> {
FindIter {
query,
base,
curr: 0,
}
}

View File

@@ -0,0 +1,43 @@
//! 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<T> {
Value(T),
Stop,
}
/// Generator
/// - 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/)
#[allow(missing_debug_implementations)]
pub struct Generator<T, S> {
state: S,
f: fn(&mut S) -> Yielded<T>,
}
impl<T, S> Iterator for Generator<T, S> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
/// Returns a generator that yields fibonacci numbers.
///
/// HINT: Consult <https://en.wikipedia.org/wiki/Fibonacci_sequence>
pub fn fib_generator(first: usize, second: usize) -> Generator<usize, (usize, usize)> {
todo!()
}
/// Returns a generator that yields collatz numbers.
///
/// HINT: Consult <https://en.wikipedia.org/wiki/Collatz_conjecture>
pub fn collatz_conjecture(start: usize) -> Generator<usize, usize> {
todo!()
}

View File

@@ -0,0 +1,38 @@
#[cfg(test)]
mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use crate::assignments::assignment07::generator::*;
#[test]
fn test_generator() {
assert_eq!(
fib_generator(0, 1).take(10).collect::<Vec<_>>(),
vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
);
assert_eq!(
collatz_conjecture(12).collect::<Vec<_>>(),
vec![12, 6, 3, 10, 5, 16, 8, 4, 2, 1]
);
assert_eq!(
collatz_conjecture(19).collect::<Vec<_>>(),
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<_>>(),
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
]
);
}
}

View File

@@ -0,0 +1,16 @@
//! 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 my_itertools;
pub mod small_exercises;
pub mod transform;
mod generator_grade;
mod my_itertools_grade;
mod small_exercises_grade;
mod transform_grade;

View File

@@ -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<I: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<I>,
}
impl<I: Iterator> Iterator for Unique<I>
where
I::Item: Eq + Hash + Clone,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
/// Iterator that chains two iterators together.
#[allow(missing_debug_implementations)]
pub struct Chain<I1: Iterator, I2: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<(I1, I2)>,
}
impl<T: Eq + Hash + Clone, I1: Iterator<Item = T>, I2: Iterator<Item = T>> Iterator
for Chain<I1, I2>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
/// Iterator that iterates over given iterator and enumerates each element.
#[allow(missing_debug_implementations)]
pub struct Enumerate<I: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<I>,
}
impl<I: Iterator> Iterator for Enumerate<I> {
type Item = (usize, I::Item);
fn next(&mut self) -> Option<Self::Item> {
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<I1: Iterator, I2: Iterator> {
// TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<(I1, I2)>,
}
impl<I1: Iterator, I2: Iterator> Iterator for Zip<I1, I2> {
type Item = (I1::Item, I2::Item);
fn next(&mut self) -> Option<Self::Item> {
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<Self>
where
Self: Sized,
{
todo!()
}
/// Returns an iterator that chains `self` and `other` together.
fn my_chain<I: Iterator>(self, other: I) -> Chain<Self, I>
where
Self: Sized,
{
todo!()
}
/// Returns an iterator that iterates over `self` and enumerates each element.
fn my_enumerate(self) -> Enumerate<Self>
where
Self: Sized,
{
todo!()
}
/// Returns an iterator that zips `self` and `other` together.
fn my_zip<I: Iterator>(self, other: I) -> Zip<Self, I>
where
Self: Sized,
{
todo!()
}
/// Foldleft for `MyIterTools`
fn my_fold<T, F>(mut self, init: T, mut f: F) -> T
where
Self: Sized,
F: FnMut(Self::Item, T) -> T,
{
todo!()
}
}
impl<T: ?Sized> MyIterTools for T where T: Iterator {}

View File

@@ -0,0 +1,65 @@
#[cfg(test)]
mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use crate::assignments::assignment07::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<_>>(),
vec![10, 1, 2, 3]
);
assert_eq!(
std::iter::repeat(5)
.my_enumerate()
.map(|(i, e)| { i * e })
.take(5)
.collect::<Vec<_>>(),
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::<Vec<_>>(),
);
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::<Vec<_>>(),
take15
);
assert_eq!(
it().take(15).my_fold(0, |elt, acc| elt + acc),
take15.iter().sum()
);
}
}

View File

@@ -0,0 +1,119 @@
//! Implement functions usint `Iterator` trait
struct FindIter<'s, T: Eq> {
query: &'s [T],
base: &'s [T],
curr: usize,
}
impl<T: Eq> Iterator for FindIter<'_, T> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
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<Item = usize> {
FindIter {
query,
base,
curr: 0,
}
}
/// Implement generic fibonacci iterator
struct FibIter<T> {
// TODO: remove `_marker` and add necessary fields as you want
_marker: std::marker::PhantomData<T>,
}
impl<T: std::ops::Add<Output = T> + Copy> FibIter<T> {
fn new(first: T, second: T) -> Self {
todo!()
}
}
impl<T> Iterator for FibIter<T>
where
T: std::ops::Add<Output = T> + Copy,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
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<T>(first: T, second: T) -> impl Iterator<Item = T>
where
T: std::ops::Add<Output = T> + Copy,
{
todo!("replace `std::iter::empty() with your owm implementation`");
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<Self::Item> {
todo!()
}
}
/// Returns an iterator over the range [left, right) with the given step.
pub fn range(left: Endpoint, right: Endpoint, step: isize) -> impl Iterator<Item = isize> {
todo!("replace `std::iter::empty() with your owm implementation`");
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<Self::Item> {
todo!()
}
}
/// Returns an iterator over the divisors of n.
pub fn divisors(n: u64) -> impl Iterator<Item = u64> {
Divisors {
n,
// TODO: you may define additional fields here
}
}

View File

@@ -0,0 +1,189 @@
#[cfg(test)]
mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use crate::assignments::assignment07::small_exercises::*;
#[test]
fn test_find() {
assert_eq!(
find("abc".as_bytes(), "abcdabcd".as_bytes()).collect::<Vec<usize>>(),
vec![0, 4]
);
assert_eq!(
find("aaba".as_bytes(), "aabaacaadaabaaba".as_bytes()).collect::<Vec<usize>>(),
vec![0, 9, 12]
);
assert_eq!(
find("ababac".as_bytes(), "abababcabababcabababc".as_bytes()).collect::<Vec<usize>>(),
vec![]
);
assert_eq!(
find("ababc".as_bytes(), "abc".as_bytes()).collect::<Vec<usize>>(),
vec![]
);
}
#[test]
fn test_find_usize() {
assert_eq!(
find(&[1, 2, 3], &[1, 2, 3, 4, 1, 2, 3, 4]).collect::<Vec<usize>>(),
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<usize>>(),
vec![0, 9, 12]
);
}
#[test]
fn test_fib_iter() {
assert_eq!(
fib(0, 1).take(10).collect::<Vec<_>>(),
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<_>>(),
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<u64>>(), vec![1, 2, 5, 10]);
assert_eq!(divisors(17).collect::<Vec<u64>>(), vec![1, 17]);
assert_eq!(divisors(49).collect::<Vec<u64>>(), vec![1, 7, 49]);
assert_eq!(
divisors(120).collect::<Vec<u64>>(),
vec![1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 24, 30, 40, 60, 120]
);
assert_eq!(divisors(1).collect::<Vec<u64>>(), vec![1]);
assert_eq!(divisors(2).collect::<Vec<u64>>(), vec![1, 2]);
assert_eq!(divisors(3).collect::<Vec<u64>>(), vec![1, 3]);
}
#[test]
fn test_large() {
assert_eq!(
divisors(1_000_000_000_000_037).collect::<Vec<u64>>(),
vec![1, 1_000_000_000_000_037]
);
assert_eq!(
divisors(99_999_820_000_081).collect::<Vec<u64>>(),
vec![1, 9_999_991, 99_999_820_000_081]
);
assert_eq!(
divisors(1_234_567_890_123).collect::<Vec<u64>>(),
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);
}
}

View File

@@ -0,0 +1,95 @@
//! Tranformer
use std::marker::PhantomData;
use std::ops::Add;
/// Represents transformation of type `T`.
pub trait Transform<T> {
/// Transforms value.
fn transform(&self, value: T) -> T;
}
impl<T1, T2, Tr1: Transform<T1>, Tr2: Transform<T2>> 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<T> Transform<T> for Identity {
fn transform(&self, value: T) -> T {
todo!()
}
}
/// Custom transformation.
#[derive(Debug, Clone, Copy)]
pub struct Custom<T, F: Fn(T) -> T> {
f: F,
_marker: PhantomData<T>,
}
impl<T, F: Fn(T) -> T> From<F> for Custom<T, F> {
fn from(f: F) -> Self {
Self {
f,
_marker: PhantomData,
}
}
}
impl<T, F: Fn(T) -> T> Transform<T> for Custom<T, F> {
fn transform(&self, value: T) -> T {
todo!()
}
}
/// Repeats transformation for `n` times.
#[derive(Debug, Clone, Copy)]
pub struct Repeat<T, Tr: Transform<T>> {
inner: Tr,
n: u32,
_marker: PhantomData<T>,
}
impl<T, Tr: Transform<T>> Repeat<T, Tr> {
/// Creates a new repeat transformation.
pub fn new(inner: Tr, n: u32) -> Self {
Repeat {
inner,
n,
_marker: PhantomData,
}
}
}
impl<T, Tr: Transform<T>> Transform<T> for Repeat<T, Tr> {
fn transform(&self, mut value: T) -> T {
todo!()
}
}
/// Repeats transformation until converges.
#[derive(Debug, Clone, Copy)]
pub struct RepeatUntilConverge<T: Eq, Tr: Transform<T>> {
inner: Tr,
_marker: PhantomData<T>,
}
impl<T: Clone + Eq, Tr: Transform<T>> RepeatUntilConverge<T, Tr> {
/// Creates a new repeat transformation.
pub fn new(inner: Tr) -> Self {
RepeatUntilConverge {
inner,
_marker: PhantomData,
}
}
}
impl<T: Clone + Eq, Tr: Transform<T>> Transform<T> for RepeatUntilConverge<T, Tr> {
fn transform(&self, mut value: T) -> T {
todo!()
}
}

View File

@@ -0,0 +1,62 @@
#[cfg(test)]
mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use crate::assignments::assignment07::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);
}
}

View File

@@ -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<usize>>(),
vec![0, 4]
);
assert_eq!(
find("aaba".as_bytes(), "aabaacaadaabaaba".as_bytes()).collect::<Vec<usize>>(),
vec![0, 9, 12]
);
assert_eq!(
find("ababac".as_bytes(), "abababcabababcabababc".as_bytes()).collect::<Vec<usize>>(),
vec![]
);
assert_eq!(
find("ababc".as_bytes(), "abc".as_bytes()).collect::<Vec<usize>>(),
vec![]
);
}
#[test]
fn test_find_usize() {
assert_eq!(
find(&[1, 2, 3], &[1, 2, 3, 4, 1, 2, 3, 4]).collect::<Vec<usize>>(),
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<usize>>(),
vec![0, 9, 12]
);
}
}

View File

@@ -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:
//! - <https://en.wikipedia.org/wiki/Church_encoding>
//! - <https://opendsa-server.cs.vt.edu/OpenDSA/Books/PL/html/ChurchNumerals.html>
use std::rc::Rc;
/// Church numerals are represented as higher-order functions that take a function `f`
pub type Church<T> = Rc<dyn Fn(Rc<dyn Fn(T) -> T>) -> Rc<dyn Fn(T) -> 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<T: 'static>() -> Church<T> {
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<T: 'static>() -> Church<T> {
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<T: 'static>() -> Church<T> {
Rc::new(|_| Rc::new(|x| x))
}
/// Implement a function to add 1 to a given Church numeral.
pub fn succ<T: 'static>(n: Church<T>) -> Church<T> {
todo!()
}
/// Implement a function to add two Church numerals.
pub fn add<T: 'static>(n: Church<T>, m: Church<T>) -> Church<T> {
todo!()
}
/// Implement a function to multiply (mult) two Church numerals.
pub fn mult<T: 'static>(n: Church<T>, m: Church<T>) -> Church<T> {
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<T: 'static>(n: usize, m: usize) -> Church<T> {
// 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<T: 'static + Default>(n: Church<T>) -> usize {
todo!()
}
/// Implement a function to convert a usize type to a Church numeral.
pub fn from_usize<T: 'static>(n: usize) -> Church<T> {
todo!()
}

View File

@@ -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::<usize>();
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<usize>) -> Church<usize> {
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));
}
}
}

View File

@@ -0,0 +1,12 @@
//! 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.
pub mod church;
pub mod small_exercises;
mod church_grade;
mod small_exercises_grade;

View File

@@ -1,26 +1,44 @@
//! Assignment 8: First-class functions. //! Assignment 08: 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.
/// 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)))`. /// 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, F: FnMut(T) -> T>(n: usize, mut f: F) -> impl FnMut(T) -> T { pub fn repeat<T, F: FnMut(T) -> T>(n: usize, mut f: F) -> impl FnMut(T) -> T {
todo!(); todo!();
f // This line has been added to prevent compile error. You can erase this line. 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. /// Applies the given function `f` for `i` times for the `i`-th element of the given vector.
/// ///
/// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), f(f(f(v3)))]`. /// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), f(f(f(v3)))]`.
///
/// Refer `test_funny_map` in `assignment08_grade.rs` for detailed examples.
pub fn funny_map<T, F: Fn(T) -> T>(f: F, vs: Vec<T>) -> Vec<T> { pub fn funny_map<T, F: Fn(T) -> T>(f: F, vs: Vec<T>) -> Vec<T> {
todo!() 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: Fn(T) -> T>(f: F, x: T) -> usize
where
T: PartialEq + Copy,
{
todo!()
}
/// Either `T1`, or `T2`. /// Either `T1`, or `T2`.
///
/// Fill out `map` method for this type.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum Either2<T1, T2> { pub enum Either2<T1, T2> {
/// Case 1. /// Case 1.
@@ -39,6 +57,8 @@ impl<T1, T2> Either2<T1, T2> {
/// Maps the inner value. /// Maps the inner value.
/// ///
/// If the inner value is case 1, apply `f1`, and if it is case 2, apply `f2`. /// 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<U1, U2, F1, F2>(self, f1: F1, f2: F2) -> Either2<U1, U2> pub fn map<U1, U2, F1, F2>(self, f1: F1, f2: F2) -> Either2<U1, U2>
where where
F1: FnOnce(T1) -> U1, F1: FnOnce(T1) -> U1,

View File

@@ -0,0 +1,47 @@
#[cfg(test)]
mod test {
use crate::assignments::assignment08::small_exercises::*;
#[test]
fn test_repeat() {
for i in 0..10 {
assert_eq!(42 + 2 * i, repeat(i, |x| x + 2)(42));
}
}
#[test]
fn test_funny_map() {
assert_eq!(
vec![0, 3, 6, 9, 12],
funny_map(|x| x + 2, vec![0, 1, 2, 3, 4])
);
}
#[test]
fn test_either2_map() {
let v1 = Either2::<u32, f32>::Case1 { inner: 42 };
let u1 = Either2::<u32, f32>::Case1 { inner: 43 };
assert_eq!(u1, v1.map(|i| i + 1, |f| f + 1.0));
let v2 = Either2::<u32, f32>::Case2 { inner: 42.0 };
let u2 = Either2::<u32, f32>::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);
}
}

View File

@@ -1,30 +0,0 @@
#[cfg(test)]
mod test {
use super::super::assignment08::*;
#[test]
fn test_repeat() {
for i in 0..10 {
assert_eq!(42 + 2 * i, repeat(i, |x| x + 2)(42));
}
}
#[test]
fn test_funny_map() {
assert_eq!(
vec![0, 3, 6, 9, 12],
funny_map(|x| x + 2, vec![0, 1, 2, 3, 4])
);
}
#[test]
fn test_either2_map() {
let v1 = Either2::<u32, f32>::Case1 { inner: 42 };
let u1 = Either2::<u32, f32>::Case1 { inner: 43 };
assert_eq!(u1, v1.map(|i| i + 1, |f| f + 1.0));
let v2 = Either2::<u32, f32>::Case2 { inner: 42.0 };
let u2 = Either2::<u32, f32>::Case2 { inner: 43.0 };
assert_eq!(u2, v2.map(|i| i + 1, |f| f + 1.0));
}
}

View File

@@ -0,0 +1,91 @@
//! 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<u32>,
}
impl BigInt {
/// Create a new `BigInt` from a `usize`.
pub fn new(n: u32) -> Self {
todo!()
}
/// Creates a new `BigInt` from a `Vec<u32>`.
pub fn new_large(carrier: Vec<u32>) -> Self {
assert!(!carrier.is_empty());
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(())
}
}

View File

@@ -0,0 +1,104 @@
#[cfg(test)]
mod test {
use ntest::{assert_false, assert_true};
use crate::assignments::assignment09::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.
}
}

View File

@@ -0,0 +1,72 @@
//! Simple matrix multiplication
use itertools::*;
/// elementwise vector addition
///
/// # Exmaple
///
/// ```
/// use cs220::assignments::assignment09::vec_add;
///
/// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
/// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
/// let res = vec_add(&vec1, &vec2);
/// assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]);
/// ```
pub fn vec_add(lhs: &[f64], rhs: &[f64]) -> Vec<f64> {
todo!()
}
/// dot product of two arrays
///
/// You don't know how to calculate dot product?
/// See <https://mathinsight.org/dot_product_examples>
///
/// # Exmaple
///
/// ```
/// use cs220::assignments::assignment09::dot_product;
///
/// let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
/// let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
/// let res = dot_product(&vec1, &vec2);
///
/// assert_eq!(res, 55.0);
/// ```
pub fn dot_product(lhs: &[f64], rhs: &[f64]) -> f64 {
todo!()
}
/// Matrix multiplication
///
/// You don't know how to multiply matrix?
/// Quite simple! See <https://www.mathsisfun.com/algebra/matrix-multiplying.html>
///
/// Assume rhs is transposed
/// - lhs: (m, n)
/// - rhs: (p, n)
/// - output: (m, p)
///
/// # Exmaple
///
/// ```
/// use cs220::assignments::assignment09::matmul;
///
/// let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]];
/// let mat2 = vec![
/// vec![7.0, 8.0, 9.0],
/// vec![10.0, 11.0, 12.0],
/// vec![13.0, 14.0, 15.0],
/// vec![16.0, 17.0, 18.0],
/// ];
/// let ans = vec![
/// vec![50.0, 68.0, 86.0, 104.0],
/// vec![122.0, 167.0, 212.0, 257.0],
/// ];
/// let res = matmul(&mat1, &mat2);
/// assert_eq!(ans, res);
/// ```
pub fn matmul(lhs: &[Vec<f64>], rhs: &[Vec<f64>]) -> Vec<Vec<f64>> {
todo!()
}

View File

@@ -0,0 +1,106 @@
#[cfg(test)]
mod test {
use crate::assignments::assignment09::matmul::*;
use approx::*;
use itertools::Itertools;
use ndarray::prelude::*;
use ndarray_rand::{rand_distr::Uniform, RandomExt};
#[test]
fn vec_add_test() {
let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let res = vec_add(&vec1, &vec2);
assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]);
for _ in 0..5 {
let vec1 = Array::random(500000, Uniform::new(0., 10.));
let vec2 = Array::random(500000, Uniform::new(0., 10.));
let res = vec_add(vec1.as_slice().unwrap(), vec2.as_slice().unwrap());
let ans = vec1 + vec2;
assert_eq!(Array::from_vec(res), ans);
}
}
#[test]
fn dot_product_test() {
let vec1 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let vec2 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let res = dot_product(&vec1, &vec2);
assert_eq!(res, 55.0);
for _ in 0..5 {
let vec1 = Array::random(1000000, Uniform::new(0., 10.));
let vec2 = Array::random(1000000, Uniform::new(0., 10.));
let res = dot_product(vec1.as_slice().unwrap(), vec2.as_slice().unwrap());
let _res = relative_eq!(res, vec1.dot(&vec2), epsilon = f64::EPSILON);
}
}
/// Reference: <https://github.com/rust-ndarray/ndarray/issues/590>
/// Converts nested `Vec`s to a 2-D array by cloning the elements.
///
/// **Panics** if the length of any axis overflows `isize`, if the
/// size in bytes of all the data overflows `isize`, or if not all the
/// rows have the same length.
fn vec_to_array<T: Clone>(v: Vec<Vec<T>>) -> Array2<T> {
if v.is_empty() {
return Array2::from_shape_vec((0, 0), Vec::new()).unwrap();
}
let nrows = v.len();
let ncols = v[0].len();
let mut data = Vec::with_capacity(nrows * ncols);
for row in &v {
assert_eq!(row.len(), ncols);
data.extend_from_slice(row);
}
Array2::from_shape_vec((nrows, ncols), data).unwrap()
}
#[test]
fn matmul_test() {
let mat1 = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]];
let mat2 = vec![
vec![7.0, 8.0, 9.0],
vec![10.0, 11.0, 12.0],
vec![13.0, 14.0, 15.0],
vec![16.0, 17.0, 18.0],
];
let ans = vec![
vec![50.0, 68.0, 86.0, 104.0],
vec![122.0, 167.0, 212.0, 257.0],
];
let res = matmul(&mat1, &mat2);
assert_eq!(ans, res);
for _ in 0..5 {
let mat1 = Array::random((500, 500), Uniform::new(0., 10.));
let mat2 = Array::random((500, 500), Uniform::new(0., 10.));
let ans = mat1.dot(&mat2);
let mat2_transposed = mat2.t();
// Run sequential matrix multiplication
let res = matmul(
mat1.axis_iter(Axis(0))
.map(|row| row.to_vec())
.collect::<Vec<_>>()
.as_slice(),
mat2_transposed
.axis_iter(Axis(0))
.map(|row| row.to_vec())
.collect::<Vec<_>>()
.as_slice(),
);
// Check answer
for it in ans.iter().zip(vec_to_array(res).iter()) {
let (ans, res) = it;
let _res = relative_eq!(ans, res);
}
}
}
}

View File

@@ -0,0 +1,14 @@
//! 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 matmul;
pub mod small_exercises;
mod bigint_grade;
mod matmul_grade;
mod small_exercises_grade;

View File

@@ -1,14 +1,7 @@
//! Assignment 9: Iterators (1/2). //! Small exercises.
//!
//! 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 std::collections::HashMap;
use itertools::*;
/// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's first two terms. /// Returns whether the given sequence is a fibonacci sequence starts from the given sequence's first two terms.
/// ///
/// Returns `true` if the length of sequence is less or equal than 2. /// Returns `true` if the length of sequence is less or equal than 2.
@@ -61,6 +54,27 @@ pub fn interleave3<T>(
todo!() 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<T, const N: usize>(
mut iters: [impl Iterator<Item = T>; N],
) -> impl Iterator<Item = T> {
todo!();
std::iter::empty()
}
/// Returns mean of k smallest value's mean. /// Returns mean of k smallest value's mean.
/// ///
/// # Example /// # Example
@@ -172,3 +186,26 @@ pub fn find_count_n(inner: Vec<usize>, n: usize) -> Vec<usize> {
pub fn position_median<T: Ord>(inner: Vec<T>) -> Option<usize> { pub fn position_median<T: Ord>(inner: Vec<T>) -> Option<usize> {
todo!() 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<Item = impl Iterator<Item = i64>>) -> 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 <https://en.wikipedia.org/wiki/Palindrome>.
pub fn is_palindrome(s: String) -> bool {
todo!()
}

View File

@@ -1,6 +1,9 @@
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::assignment09::*;
use ntest::{assert_false, assert_true};
use crate::assignments::assignment09::small_exercises::*;
#[test] #[test]
fn test_is_fibonacci() { fn test_is_fibonacci() {
@@ -74,6 +77,35 @@ mod test {
); );
} }
#[test]
fn test_interleave_n() {
assert_eq!(
interleave_n([[1, 2].into_iter(), [3, 4].into_iter(), [5, 6].into_iter()])
.collect::<Vec<_>>(),
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<_>>(),
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::<String>(),
"adgbehcfi"
);
}
#[test] #[test]
fn test_k_smallest_man() { fn test_k_smallest_man() {
assert_eq!( assert_eq!(
@@ -200,4 +232,37 @@ mod test {
assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3)); assert_eq!(position_median(vec![1, 3, 3, 6, 7, 8, 9]), Some(3));
assert_eq!(position_median(vec![1, 2, 3, 4, 5, 6, 8, 9]), Some(4)); 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()));
}
} }

View File

@@ -0,0 +1,48 @@
//! Labyrinth
//!
//! Look at the `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.
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<Self::Item> {
todo!()
}
}

View File

@@ -0,0 +1,62 @@
#[cfg(test)]
mod test {
use rand::seq::SliceRandom;
use rand::thread_rng;
use crate::assignments::assignment10::labyrinth::*;
type Wife = usize;
type Rooms = Vec<Wife>;
struct Labyrinth {
rooms: Rooms,
}
impl From<Rooms> 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... 🪓*/)
}));
}
}

View File

@@ -0,0 +1,11 @@
//! 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;

View File

@@ -1,9 +1,4 @@
//! Assignment 10: Iterators (2/2). //! Small exercises.
//!
//! 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::*; use itertools::*;
@@ -117,3 +112,82 @@ pub enum File {
pub fn du_sort(root: &File) -> Vec<(&str, usize)> { pub fn du_sort(root: &File) -> Vec<(&str, usize)> {
todo!() 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<i64>) {
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<i64>) {
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<String>`) from table1 and a row(`Vec<String>`) 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<Vec<String>>, table2: Vec<Vec<String>>) -> Vec<Vec<String>> {
todo!()
}
struct Pythagorean;
impl Pythagorean {
fn new() -> Self {
todo!()
}
}
impl Iterator for Pythagorean {
type Item = (u64, u64, u64);
fn next(&mut self) -> Option<Self::Item> {
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<Item = (u64, u64, u64)> {
Pythagorean::new()
}

View File

@@ -0,0 +1,351 @@
#[cfg(test)]
mod test {
use std::collections::HashSet;
use crate::assignments::assignment10::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<i64> = HashSet::from_iter(vec);
let set2: HashSet<i64> = HashSet::from_iter(vec![1, 2, 3, 7, 5]);
assert_eq!(set1, set2);
}
#[test]
fn test_natural_join() {
let row1: Vec<String> = vec!["20230001", "Jack"]
.iter()
.map(|s| s.to_string())
.collect();
let row2: Vec<String> = vec!["20231234", "Mike"]
.iter()
.map(|s| s.to_string())
.collect();
let table1 = vec![row1, row2];
let row1: Vec<String> = vec!["20230001", "CS"]
.iter()
.map(|s| s.to_string())
.collect();
let row2: Vec<String> = vec!["20230001", "EE"]
.iter()
.map(|s| s.to_string())
.collect();
let row3: Vec<String> = vec!["20231234", "ME"]
.iter()
.map(|s| s.to_string())
.collect();
let table2 = vec![row1, row2, row3];
let row1: Vec<String> = vec!["20230001", "Jack", "CS"]
.iter()
.map(|s| s.to_string())
.collect();
let row2: Vec<String> = vec!["20230001", "Jack", "EE"]
.iter()
.map(|s| s.to_string())
.collect();
let row3: Vec<String> = vec!["20231234", "Mike", "ME"]
.iter()
.map(|s| s.to_string())
.collect();
let table3 = vec![row1, row2, row3];
assert_eq!(
HashSet::<Vec<String>>::from_iter(natural_join(table1, table2)),
HashSet::<Vec<String>>::from_iter(table3)
);
let row1: Vec<String> = vec!["20230001", "Alice"]
.iter()
.map(|s| s.to_string())
.collect();
let row2: Vec<String> = vec!["20230002", "Bob"]
.iter()
.map(|s| s.to_string())
.collect();
let row3: Vec<String> = vec!["20230003", "Charlie"]
.iter()
.map(|s| s.to_string())
.collect();
let row4: Vec<String> = vec!["20230004", "David"]
.iter()
.map(|s| s.to_string())
.collect();
let table1 = vec![row1, row2, row3, row4];
let row1: Vec<String> = vec!["20230001", "Apple"]
.iter()
.map(|s| s.to_string())
.collect();
let row2: Vec<String> = vec!["20230001", "Avocado"]
.iter()
.map(|s| s.to_string())
.collect();
let row3: Vec<String> = vec!["20230002", "Banana"]
.iter()
.map(|s| s.to_string())
.collect();
let row4: Vec<String> = vec!["20230002", "Berries"]
.iter()
.map(|s| s.to_string())
.collect();
let row5: Vec<String> = vec!["20230004", "Durian"]
.iter()
.map(|s| s.to_string())
.collect();
let table2 = vec![row1, row2, row3, row4, row5];
let row1: Vec<String> = vec!["20230001", "Alice", "Apple"]
.iter()
.map(|s| s.to_string())
.collect();
let row2: Vec<String> = vec!["20230001", "Alice", "Avocado"]
.iter()
.map(|s| s.to_string())
.collect();
let row3: Vec<String> = vec!["20230002", "Bob", "Banana"]
.iter()
.map(|s| s.to_string())
.collect();
let row4: Vec<String> = vec!["20230002", "Bob", "Berries"]
.iter()
.map(|s| s.to_string())
.collect();
let row5: Vec<String> = vec!["20230004", "David", "Durian"]
.iter()
.map(|s| s.to_string())
.collect();
let table3 = vec![row1, row2, row3, row4, row5];
assert_eq!(
HashSet::<Vec<String>>::from_iter(natural_join(table1, table2)),
HashSet::<Vec<String>>::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);
}
}
}

View File

@@ -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)
]
);
}
}

View File

@@ -0,0 +1,97 @@
//! 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.
///
/// TODO: You can freely add fields to this struct.
#[derive(Debug, Clone)]
pub struct NodeHandle;
/// Error type for graph operations.
#[derive(Debug)]
pub struct GraphError;
/// Subgraph
///
/// TODO: You can freely add fields to this struct.
#[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<bool, GraphError> {
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<bool, GraphError> {
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!()
}
}

View File

@@ -0,0 +1,63 @@
//! Test cases for assignment11/graph.rs
#[cfg(test)]
mod test_graph {
use crate::assignments::assignment11::graph::*;
#[test]
fn test_graph() {
let mut nodes = (0..6).map(NodeHandle::new).collect::<Vec<_>>();
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();
(0..6).for_each(|n| {
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();
}
}
}

View File

@@ -59,4 +59,82 @@ impl<T: Debug> SinglyLinkedList<T> {
pub fn pop_back(&mut self) -> Option<T> { pub fn pop_back(&mut self) -> Option<T> {
todo!() todo!()
} }
/// Create a new list from the given vector `vec`.
pub fn from_vec(vec: Vec<T>) -> Self {
todo!()
}
/// Convert the current list into a vector.
pub fn as_vec(&self) -> Vec<T> {
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<F: Fn(T) -> 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<F: Fn(T, T) -> T>(&mut self, f: F) {
todo!()
}
}
// A list of lists.
impl<T: Debug> SinglyLinkedList<SinglyLinkedList<T>> {
/// 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<T> {
todo!()
}
} }

View File

@@ -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::<i32>::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::<i32>::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]
);
}
}

View File

@@ -1,6 +1,8 @@
//! Mock storage. //! Mock storage.
//! //!
//! Consult <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects>. //! Hint: Consult <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects>.
//!
//! Refer `mock_storage_grade.rs` for test cases.
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;

View File

@@ -0,0 +1,31 @@
//! Test cases for assignment11/mock_storage.rs
#[cfg(test)]
mod test_mock_storage {
use crate::assignments::assignment11::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());
}
}

View File

@@ -1,9 +1,15 @@
//! Assignment 11: Familiarizing with smart pointers. //! Assignment 11: Familiarizing with smart pointers.
//! //!
//! You should fill out `todo!()` placeholders in such a way that `/scripts/grade-11.sh` works fine. //! 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 <https://gg.kaist.ac.kr>. //! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to <https://gg.kaist.ac.kr>.
pub mod graph;
pub mod linked_list; pub mod linked_list;
pub mod mock_storage; pub mod mock_storage;
pub mod tv_room; pub mod tv_room;
mod graph_grade;
mod linked_list_grade;
mod mock_storage_grade;
mod tv_room_grade;

View File

@@ -15,6 +15,8 @@
//! Consult the following documentations: //! Consult the following documentations:
//! - <https://doc.rust-lang.org/book/ch15-04-rc.html#rct-the-reference-counted-smart-pointer> //! - <https://doc.rust-lang.org/book/ch15-04-rc.html#rct-the-reference-counted-smart-pointer>
//! - <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#having-multiple-owners-of-mutable-data-by-combining-rct-and-refcellt> //! - <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#having-multiple-owners-of-mutable-data-by-combining-rct-and-refcellt>
//!
//! Refer `tv_room_grade.rs` for test cases.
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};

View File

@@ -0,0 +1,32 @@
//! Test cases for assignment11/tv_room.rs
#[cfg(test)]
mod test_tv_room {
use crate::assignments::assignment11::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());
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,52 @@
//! Flipping card game.
//!
//! 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.
//! 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<isize, isize>,
}
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!()
}
}

View File

@@ -0,0 +1,142 @@
//! Test cases for assignment12/card.rs
#[cfg(test)]
mod test_card {
use crate::assignments::assignment12::card::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex};
use std::thread;
use std::time::Duration;
const NUM_CARDS: usize = 10_000;
const DURATION: u64 = 1;
const NUM_ENEMIES: usize = 100;
#[derive(Clone, Debug)]
struct Card {
color: Arc<Mutex<Color>>,
}
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<Card>,
}
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...",);
}
}

View File

@@ -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 <https://www.electronics-tutorials.ws/combination/comb_3.html>
//!
//! 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<T, F: Fn(&T) -> bool> {
tx_true: Sender<T>,
tx_false: Sender<T>,
f: F,
}
impl<T, F: Fn(&T) -> bool> DemuxSender<T, F> {
/// 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<T>> {
todo!()
}
}
/// Demux.
pub fn demux<T, F: Fn(&T) -> bool>(f: F) -> (DemuxSender<T, F>, Receiver<T>, Receiver<T>) {
todo!()
}

View File

@@ -0,0 +1,36 @@
//! Test cases for assignment12/demux.rs
#[cfg(test)]
mod test_demux {
use crate::assignments::assignment12::demux::*;
use ntest::timeout;
use std::sync::mpsc::channel;
use std::thread;
#[test]
#[timeout(5000)]
fn test_demux() {
let (tx, rx1, rx2) = demux::<u32, _>(|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();
}
}

View File

@@ -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<T, F>(rxs: Vec<Receiver<T>>, tx: Sender<T>, f: F) -> JoinHandle<()>
where
T: Send + 'static,
F: Send + Sync + Fn(&T) -> bool + 'static,
{
todo!()
}

View File

@@ -0,0 +1,33 @@
//! Test cases for assignment12/funnel.rs
#[cfg(test)]
mod test_funnel {
use crate::assignments::assignment12::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::<u32>()).unzip();
let (tx, rx) = channel::<u32>();
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();
}
}

View File

@@ -0,0 +1,16 @@
//! 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 demux;
pub mod funnel;
pub mod small_exercises;
mod card_grade;
mod demux_grade;
mod funnel_grade;
mod small_exercises_grade;

View File

@@ -1,23 +1,25 @@
#![allow(single_use_lifetimes)] #![allow(single_use_lifetimes)]
//! Assignment 12: Concurrency. //! Small exercises
//! //!
//! The primary goal of this assignment is to get used to concurrency. //! Refer `small_exercises_grade.rs` for test cases
//!
//! 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.
use std::sync::mpsc::{Receiver, RecvError, Sender}; use std::sync::mpsc::{Receiver, RecvError, Sender};
use std::thread; use std::thread;
use etrace::*; 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<u32>, tx2: &mut Sender<u32>) -> bool { pub fn pong(rx1: &mut Receiver<u32>, tx2: &mut Sender<u32>) -> bool {
todo!() todo!()
} }
/// Executes the given functions (f1, f2) in concurrent and returns the results. /// Executes the given functions (f1, f2) in concurrent and returns the results.
///
/// Read the `test_scoped_thread` function in `small_exercises_grade.rs` to figure out what it should do.
pub fn use_scoped_thread<'scope, 'env, T1, T2, F1, F2>( pub fn use_scoped_thread<'scope, 'env, T1, T2, F1, F2>(
s: &'scope thread::Scope<'scope, 'env>, s: &'scope thread::Scope<'scope, 'env>,
f1: F1, f1: F1,

View File

@@ -1,6 +1,8 @@
//! Test cases for assignment12/small_exercises_grade.rs
#[cfg(test)] #[cfg(test)]
mod test { mod test_pingpong {
use super::super::assignment12::*; use crate::assignments::assignment12::small_exercises::*;
use ntest::timeout; use ntest::timeout;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;

View File

@@ -1,48 +0,0 @@
//! 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.
use rayon::prelude::*;
/// Returns the sum of `f(v)` for all element `v` the given array.
///
/// # Exmaple
///
/// ```
/// use cs220::assignments::assignment13::sigma;
/// use rayon::iter::IntoParallelIterator;
///
/// assert_eq!(sigma([1, 2].into_par_iter(), |x| x + 2), 7);
/// assert_eq!(sigma([1, 2].into_par_iter(), |x| x * 4), 12);
/// ```
pub fn sigma<T, F: Fn(T) -> i64 + Sync + Send>(
inner: impl ParallelIterator<Item = T>,
f: F,
) -> i64 {
todo!()
}
/// Alternate elements from three iterators until they have run out.
///
/// # Example
///
/// ```
/// use cs220::assignments::assignment13::interleave3;
/// use rayon::iter::IntoParallelIterator;
///
/// assert_eq!(
/// interleave3([1, 2].into_par_iter(), [3, 4].into_par_iter(), [5, 6].into_par_iter()),
/// vec![1, 3, 5, 2, 4, 6]
/// );
/// ```
pub fn interleave3<T: Send>(
list1: impl IndexedParallelIterator<Item = T>,
list2: impl IndexedParallelIterator<Item = T>,
list3: impl IndexedParallelIterator<Item = T>,
) -> Vec<T> {
todo!()
}

View File

@@ -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/small_exercises_grade.rs` and `/scripts/grade-13.sh` for the test script.
pub mod small_exercises;
mod small_exercises_grade;

Some files were not shown because too many files have changed in this diff Show More