mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-12 21:08:45 +00:00
Merge from cs220-private
This commit is contained in:
616
Cargo.lock
generated
616
Cargo.lock
generated
@@ -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",
|
||||||
|
]
|
||||||
|
|||||||
18
Cargo.toml
18
Cargo.toml
@@ -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"
|
||||||
|
|||||||
@@ -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/)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
29
assets/why3/assignment05/max.mlw
Normal file
29
assets/why3/assignment05/max.mlw
Normal 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
|
||||||
41
assets/why3/assignment05/pascal.mlw
Normal file
41
assets/why3/assignment05/pascal.mlw
Normal 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
|
||||||
@@ -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
|
|
||||||
29
assets/why3/exercises/ex1_eucl_div.mlw
Normal file
29
assets/why3/exercises/ex1_eucl_div.mlw
Normal 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
|
||||||
49
assets/why3/exercises/ex2_fact.mlw
Normal file
49
assets/why3/exercises/ex2_fact.mlw
Normal 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
|
||||||
51
assets/why3/exercises/ex3_two_way.mlw
Normal file
51
assets/why3/exercises/ex3_two_way.mlw
Normal 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
|
||||||
30
assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw
Normal file
30
assets/why3/exercises/solutions/ex1_eucl_div_sol.mlw
Normal 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
|
||||||
@@ -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
|
||||||
@@ -2,21 +2,11 @@
|
|||||||
|
|
||||||
The following program sorts an array of Boolean values, with False<True.
|
The following program sorts an array of Boolean values, with False<True.
|
||||||
|
|
||||||
Questions:
|
E.g.
|
||||||
|
two_way_sorted [True; False; False; True; False]
|
||||||
|
= [False; False; False; True; True]
|
||||||
|
|
||||||
1. Prove safety i.e. the absence of array access out of bounds.
|
- Strengthen the invariant to prove correctness.
|
||||||
|
|
||||||
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
|
||||||
@@ -1 +1 @@
|
|||||||
1.70.0
|
1.71.0
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
10
src/assignments/assignment01/mod.rs
Normal file
10
src/assignments/assignment01/mod.rs
Normal 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;
|
||||||
@@ -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>
|
||||||
|
|
||||||
@@ -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() {
|
||||||
@@ -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!()
|
|
||||||
}
|
|
||||||
13
src/assignments/assignment02/mod.rs
Normal file
13
src/assignments/assignment02/mod.rs
Normal 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;
|
||||||
46
src/assignments/assignment02/small_exercises.rs
Normal file
46
src/assignments/assignment02/small_exercises.rs
Normal 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!()
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
"#;
|
|
||||||
}
|
}
|
||||||
124
src/assignments/assignment02/vec_and_mat.rs
Normal file
124
src/assignments/assignment02/vec_and_mat.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/assignments/assignment02/vec_and_mat_grade.rs
Normal file
60
src/assignments/assignment02/vec_and_mat_grade.rs
Normal 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
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/assignments/assignment03/custom_operators.rs
Normal file
79
src/assignments/assignment03/custom_operators.rs
Normal 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!()
|
||||||
|
}
|
||||||
58
src/assignments/assignment03/custom_operators_grade.rs
Normal file
58
src/assignments/assignment03/custom_operators_grade.rs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/assignments/assignment03/mod.rs
Normal file
13
src/assignments/assignment03/mod.rs
Normal 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;
|
||||||
28
src/assignments/assignment03/parse_shell.rs
Normal file
28
src/assignments/assignment03/parse_shell.rs
Normal 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!()
|
||||||
|
}
|
||||||
38
src/assignments/assignment03/parse_shell_grade.rs
Normal file
38
src/assignments/assignment03/parse_shell_grade.rs
Normal 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(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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!()
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
]),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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() {
|
||||||
@@ -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;
|
||||||
|
|||||||
12
src/assignments/assignment06/mod.rs
Normal file
12
src/assignments/assignment06/mod.rs
Normal 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;
|
||||||
@@ -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!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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>();
|
||||||
365
src/assignments/assignment06/symbolic_differentiation.rs
Normal file
365
src/assignments/assignment06/symbolic_differentiation.rs
Normal 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})"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
216
src/assignments/assignment06/symbolic_differentiation_grade.rs
Normal file
216
src/assignments/assignment06/symbolic_differentiation_grade.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
43
src/assignments/assignment07/generator.rs
Normal file
43
src/assignments/assignment07/generator.rs
Normal 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!()
|
||||||
|
}
|
||||||
38
src/assignments/assignment07/generator_grade.rs
Normal file
38
src/assignments/assignment07/generator_grade.rs
Normal 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
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/assignments/assignment07/mod.rs
Normal file
16
src/assignments/assignment07/mod.rs
Normal 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;
|
||||||
117
src/assignments/assignment07/my_itertools.rs
Normal file
117
src/assignments/assignment07/my_itertools.rs
Normal 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 {}
|
||||||
65
src/assignments/assignment07/my_itertools_grade.rs
Normal file
65
src/assignments/assignment07/my_itertools_grade.rs
Normal 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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
119
src/assignments/assignment07/small_exercises.rs
Normal file
119
src/assignments/assignment07/small_exercises.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
189
src/assignments/assignment07/small_exercises_grade.rs
Normal file
189
src/assignments/assignment07/small_exercises_grade.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/assignments/assignment07/transform.rs
Normal file
95
src/assignments/assignment07/transform.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/assignments/assignment07/transform_grade.rs
Normal file
62
src/assignments/assignment07/transform_grade.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
71
src/assignments/assignment08/church.rs
Normal file
71
src/assignments/assignment08/church.rs
Normal 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!()
|
||||||
|
}
|
||||||
73
src/assignments/assignment08/church_grade.rs
Normal file
73
src/assignments/assignment08/church_grade.rs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/assignments/assignment08/mod.rs
Normal file
12
src/assignments/assignment08/mod.rs
Normal 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;
|
||||||
@@ -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,
|
||||||
47
src/assignments/assignment08/small_exercises_grade.rs
Normal file
47
src/assignments/assignment08/small_exercises_grade.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
91
src/assignments/assignment09/bigint.rs
Normal file
91
src/assignments/assignment09/bigint.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/assignments/assignment09/bigint_grade.rs
Normal file
104
src/assignments/assignment09/bigint_grade.rs
Normal 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.
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/assignments/assignment09/matmul.rs
Normal file
72
src/assignments/assignment09/matmul.rs
Normal 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!()
|
||||||
|
}
|
||||||
106
src/assignments/assignment09/matmul_grade.rs
Normal file
106
src/assignments/assignment09/matmul_grade.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/assignments/assignment09/mod.rs
Normal file
14
src/assignments/assignment09/mod.rs
Normal 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;
|
||||||
@@ -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!()
|
||||||
|
}
|
||||||
@@ -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()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
48
src/assignments/assignment10/labyrinth.rs
Normal file
48
src/assignments/assignment10/labyrinth.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/assignments/assignment10/labyrinth_grade.rs
Normal file
62
src/assignments/assignment10/labyrinth_grade.rs
Normal 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... 🪓*/)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/assignments/assignment10/mod.rs
Normal file
11
src/assignments/assignment10/mod.rs
Normal 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;
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
351
src/assignments/assignment10/small_exercises_grade.rs
Normal file
351
src/assignments/assignment10/small_exercises_grade.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
97
src/assignments/assignment11/graph.rs
Normal file
97
src/assignments/assignment11/graph.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/assignments/assignment11/graph_grade.rs
Normal file
63
src/assignments/assignment11/graph_grade.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
src/assignments/assignment11/linked_list_grade.rs
Normal file
122
src/assignments/assignment11/linked_list_grade.rs
Normal 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]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
31
src/assignments/assignment11/mock_storage_grade.rs
Normal file
31
src/assignments/assignment11/mock_storage_grade.rs
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|
||||||
|
|||||||
32
src/assignments/assignment11/tv_room_grade.rs
Normal file
32
src/assignments/assignment11/tv_room_grade.rs
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
52
src/assignments/assignment12/card.rs
Normal file
52
src/assignments/assignment12/card.rs
Normal 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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
142
src/assignments/assignment12/card_grade.rs
Normal file
142
src/assignments/assignment12/card_grade.rs
Normal 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...",);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/assignments/assignment12/demux.rs
Normal file
37
src/assignments/assignment12/demux.rs
Normal 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!()
|
||||||
|
}
|
||||||
36
src/assignments/assignment12/demux_grade.rs
Normal file
36
src/assignments/assignment12/demux_grade.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/assignments/assignment12/funnel.rs
Normal file
21
src/assignments/assignment12/funnel.rs
Normal 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!()
|
||||||
|
}
|
||||||
33
src/assignments/assignment12/funnel_grade.rs
Normal file
33
src/assignments/assignment12/funnel_grade.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/assignments/assignment12/mod.rs
Normal file
16
src/assignments/assignment12/mod.rs
Normal 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;
|
||||||
@@ -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,
|
||||||
@@ -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;
|
||||||
@@ -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!()
|
|
||||||
}
|
|
||||||
10
src/assignments/assignment13/mod.rs
Normal file
10
src/assignments/assignment13/mod.rs
Normal 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
Reference in New Issue
Block a user