Merge branch 'woojin' into 'main'

apply comments

See merge request kaist-cp-class/cs220-private!19
This commit is contained in:
Woojin Lee
2023-08-21 10:44:10 +00:00
43 changed files with 77 additions and 1122 deletions

View File

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

View File

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

View File

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

View File

@@ -4,16 +4,9 @@
//! Please make sure you're comfortable with developing Rust programs before moving on to the next assignments.
//!
//! You should fill out `add()` and `sub()` function bodies in such a way that `/scripts/grade-01.sh` works fine.
//! See `assignment01_grade.rs` and `/scripts/grade-01.sh` for the test script.
//! See `small_problems_grade.rs` and `/scripts/grade-01.sh` for the test script.
//!
//! Hint: <https://doc.rust-lang.org/std/primitive.usize.html>
/// Adds two unsigned words. If overflow happens, just wrap around.
pub fn add(lhs: usize, rhs: usize) -> usize {
todo!()
}
/// Subtracts two unsigned words. If overflow happens, just wrap around.
pub fn sub(lhs: usize, rhs: usize) -> usize {
todo!()
}
pub mod small_problems;
mod small_problems_grade;

View File

@@ -0,0 +1,12 @@
//! Assignment 1: Preparing Rust Development Environment.
//! Welcome to the CS220 course!
/// Adds two unsigned words. If overflow happens, just wrap around.
pub fn add(lhs: usize, rhs: usize) -> usize {
todo!()
}
/// Subtracts two unsigned words. If overflow happens, just wrap around.
pub fn sub(lhs: usize, rhs: usize) -> usize {
todo!()
}

View File

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

View File

@@ -1,6 +1,6 @@
#[cfg(test)]
mod test {
use super::super::semiring::*;
use crate::assignments::assignment06::semiring::*;
use ntest::assert_about_eq;
fn test_from_str(s: &str, f: impl Fn(i64) -> i64) {

View File

@@ -1,6 +1,6 @@
#[cfg(test)]
mod test {
use super::super::square_matrix::*;
use crate::assignments::assignment06::square_matrix::*;
use ntest::assert_about_eq;
#[test]

View File

@@ -1,6 +1,6 @@
#[cfg(test)]
mod test {
use super::super::symbolic_differentiation::*;
use crate::assignments::assignment06::symbolic_differentiation::*;
use ntest::assert_about_eq;
// Constant rationals to use

View File

@@ -3,7 +3,7 @@ mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use super::super::generator::*;
use crate::assignments::assignment07::generator::*;
#[test]
fn test_generator() {

View File

@@ -3,7 +3,7 @@ mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use super::super::hubo::*;
use crate::assignments::assignment07::hubo::*;
#[test]
fn test_hubo_dir4_movement() {

View File

@@ -3,7 +3,7 @@ mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use super::super::my_itertools::*;
use crate::assignments::assignment07::my_itertools::*;
#[test]
fn test_itertools() {

View File

@@ -3,7 +3,7 @@ mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use super::super::small_exercises::*;
use crate::assignments::assignment07::small_exercises::*;
#[test]
fn test_find() {

View File

@@ -3,7 +3,7 @@ mod test {
use itertools::Itertools;
use ntest::assert_about_eq;
use super::super::transform::*;
use crate::assignments::assignment07::transform::*;
#[test]
fn test_transform_identity() {

View File

@@ -0,0 +1,9 @@
//! Assignment 8: First-class functions.
//!
//! The primary goal of this assignment is to get used to first-class functions.
//!
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine.
//! See `small_problems_grade.rs` and `/scripts/grade-08.sh` for the test script.
pub mod small_problems;
mod small_problems_grade;

View File

@@ -1,9 +1,4 @@
//! Assignment 8: First-class functions.
//!
//! The primary goal of this assignment is to get used to first-class functions.
//!
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine.
//! See `assignment08_grade.rs` and `/scripts/grade-08.sh` for the test script.
//! Assignment 08: First-class functions.
/// Repeat
///

View File

@@ -1,6 +1,6 @@
#[cfg(test)]
mod test {
use super::super::assignment08::*;
use crate::assignments::assignment08::small_problems::*;
#[test]
fn test_repeat() {

View File

@@ -3,7 +3,7 @@ mod test {
use ntest::{assert_false, assert_true};
use super::super::bigint::*;
use crate::assignments::assignment09::bigint::*;
#[test]
fn test_inf_prec_simple() {

View File

@@ -20,6 +20,9 @@ pub fn vec_add(lhs: &[f64], rhs: &[f64]) -> Vec<f64> {
/// dot product of two arrays
///
/// You don't know how to calculate dot product?
/// See <https://mathinsight.org/dot_product_examples>
///
/// # Exmaple
///
/// ```
@@ -37,6 +40,9 @@ pub fn dot_product(lhs: &[f64], rhs: &[f64]) -> f64 {
/// Matrix multiplication
///
/// You don't know how to multiply matrix?
/// Quite simple! See <https://www.mathsisfun.com/algebra/matrix-multiplying.html>
///
/// Assume rhs is transposed
/// - lhs: (m, n)
/// - rhs: (p, n)

View File

@@ -3,7 +3,7 @@ mod test {
use ntest::{assert_false, assert_true};
use super::super::small_exercises::*;
use crate::assignments::assignment09::small_exercises::*;
#[test]
fn test_is_fibonacci() {

View File

@@ -3,7 +3,7 @@ mod test {
use rand::seq::SliceRandom;
use rand::thread_rng;
use super::super::labyrinth::*;
use crate::assignments::assignment10::labyrinth::*;
type Wife = usize;
type Rooms = Vec<Wife>;

View File

@@ -2,7 +2,7 @@
mod test {
use std::collections::HashSet;
use super::super::small_exercises::*;
use crate::assignments::assignment10::small_exercises::*;
#[test]
fn test_inversion() {

View File

@@ -1,202 +0,0 @@
//! Binary Search Tree
//!
//! Refer `bst_grade.rs` for test cases.
use std::cell::RefCell;
use std::cmp::Ordering;
use std::fmt::Debug;
use std::ops::Deref;
use std::rc::{Rc, Weak};
/// Node struct of tree
#[derive(Debug, Clone)]
struct Node<T>
where
T: Ord,
{
value: T,
parent: Option<Weak<RefCell<Node<T>>>>,
left: Option<Rc<RefCell<Node<T>>>>,
right: Option<Rc<RefCell<Node<T>>>>,
}
impl<T> Node<T>
where
T: Ord,
{
fn new(value: T) -> Rc<RefCell<Node<T>>> {
Rc::new(RefCell::new(Node {
value,
parent: None,
left: None,
right: None,
}))
}
fn with_parent(value: T, parent: Weak<RefCell<Node<T>>>) -> Rc<RefCell<Node<T>>> {
Rc::new(RefCell::new(Node {
value,
parent: Some(parent),
left: None,
right: None,
}))
}
/// Minimum node starting from cursor
fn min_node(mut cursor: Rc<RefCell<Node<T>>>) -> Rc<RefCell<Node<T>>> {
todo!();
}
/// Upgraded parent node.
/// `None` if the node has no parent.
fn parent(&self) -> Option<Rc<RefCell<Node<T>>>> {
self.parent.as_ref().and_then(|p| p.upgrade())
}
}
/// Binary Search Tree
#[derive(Debug)]
pub struct Tree<T>
where
T: Ord,
{
root: Option<Rc<RefCell<Node<T>>>>,
len: usize,
}
impl<T: Ord> Default for Tree<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Tree<T>
where
T: Ord,
{
/// New tree
pub fn new() -> Tree<T> {
Tree { root: None, len: 0 }
}
/// Length of the tree
pub fn len(&self) -> usize {
self.len
}
/// Check if the tree is empty.
pub fn is_empty(&self) -> bool {
self.len == 0
}
/// Check if the tree contains the value.
pub fn contains(&self, value: &T) -> bool {
if let Some(mut cursor) = self.root.clone() {
todo!();
} else {
false
}
}
/// Insert the value into the tree.
/// If there was no equal value in the tree, it returns `true`.
/// Otherwise, it returns `false`.
pub fn insert(&mut self, value: T) -> bool {
self.len += 1;
if let Some(mut cursor) = self.root.clone() {
todo!();
} else {
self.root = Some(Node::new(value));
true
}
}
/// Remove the node from the tree.
/// Returns the value of the removed node.
fn remove_node(&mut self, mut node: Rc<RefCell<Node<T>>>) -> T {
todo!();
}
/// Remove the value from the tree.
/// If there is an equal value in the tree, it returns `true`.
/// Otherwise, it returns `false`.
pub fn remove(&mut self, value: &T) -> Option<T> {
let res = if let Some(root) = self.root.clone() {
let mut cursor = root;
loop {
let mut cursor_ref = cursor.deref().borrow_mut();
let child = match value.cmp(&cursor_ref.value) {
Ordering::Less => cursor_ref.left.clone(),
Ordering::Greater => cursor_ref.right.clone(),
Ordering::Equal => {
drop(cursor_ref);
break Some(self.remove_node(cursor));
}
};
if let Some(child) = child {
drop(cursor_ref);
cursor = child;
} else {
break None;
}
}
} else {
None
};
self.len -= res.is_some() as usize;
res
}
}
impl<T> Clone for Tree<T>
where
T: Ord + Clone,
{
fn clone(&self) -> Self {
Tree {
root: self.root.clone(),
len: self.len,
}
}
}
/// IntoIterator for Tree
#[derive(Debug)]
pub struct IntoIter<T>
where
T: Ord,
{
tree: Tree<T>,
len: usize,
}
impl<T> IntoIterator for Tree<T>
where
T: Ord,
{
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
let len = self.len;
IntoIter { tree: self, len }
}
}
impl<T> Iterator for IntoIter<T>
where
T: Ord,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
todo!();
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}

View File

@@ -1,53 +0,0 @@
//! Test cases for assignment11/bst.rs
#[cfg(test)]
mod test_bst {
use super::super::bst::*;
#[test]
fn bst_insert_test() {
let mut tree = Tree::new();
let _ = tree.insert(1);
let _ = tree.insert(5);
let _ = tree.insert(3);
let _ = tree.insert(7);
assert_eq!(tree.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
}
#[test]
fn bst_remove_test() {
let mut tree = Tree::new();
let _ = tree.insert(1);
let _ = tree.insert(5);
let _ = tree.insert(3);
let _ = tree.insert(7);
let _ = tree.remove(&7);
assert_eq!(tree.into_iter().collect::<Vec<_>>(), vec![1, 3, 5]);
}
#[test]
fn bst_complex_test() {
let mut tree = Tree::new();
let _ = tree.insert(1);
let _ = tree.insert(5);
let _ = tree.insert(3);
let _ = tree.insert(7);
let _ = tree.remove(&7);
let _ = tree.insert(7);
let _ = tree.insert(6);
let _ = tree.insert(8);
let _ = tree.remove(&5);
let _ = tree.remove(&1);
let _ = tree.remove(&3);
let _ = tree.remove(&7);
let _ = tree.remove(&6);
let _ = tree.remove(&8);
assert_eq!(tree.into_iter().collect::<Vec<_>>(), vec![]);
}
}

View File

@@ -2,7 +2,7 @@
#[cfg(test)]
mod test_doubly_linked_list {
use super::super::doubly_linked_list::*;
use crate::assignments::assignment11::doubly_linked_list::*;
#[test]
fn test_works() {

View File

@@ -2,7 +2,7 @@
#[cfg(test)]
mod test_graph {
use super::super::graph::*;
use crate::assignments::assignment11::graph::*;
#[test]
fn test_graph() {

View File

@@ -1,140 +0,0 @@
//! Singly linked list.
//!
//! Consult <https://doc.rust-lang.org/book/ch15-01-box.html>.
use std::fmt::Debug;
/// Node of the list.
#[derive(Debug)]
pub struct Node<T: Debug> {
/// Value of current node.
pub value: T,
/// Pointer to the next node. If it is `None`, there is no next node.
pub next: Option<Box<Node<T>>>,
}
impl<T: Debug> Node<T> {
/// Creates a new node.
pub fn new(value: T) -> Self {
Self { value, next: None }
}
}
/// A singly-linked list.
#[derive(Debug)]
pub struct SinglyLinkedList<T: Debug> {
/// Head node of the list. If it is `None`, the list is empty.
head: Option<Node<T>>,
}
impl<T: Debug> Default for SinglyLinkedList<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Debug> SinglyLinkedList<T> {
/// Creates a new list.
pub fn new() -> Self {
Self { head: None }
}
/// Adds the given node to the front of the list.
pub fn push_front(&mut self, value: T) {
todo!()
}
/// Adds the given node to the back of the list.
pub fn push_back(&mut self, value: T) {
todo!()
}
/// Removes and returns the node at the front of the list.
pub fn pop_front(&mut self) -> Option<T> {
todo!()
}
/// Removes and returns the node at the back of the list.
pub fn pop_back(&mut self) -> Option<T> {
todo!()
}
/// Create a new list from the given vector `vec`.
pub fn from_vec(vec: Vec<T>) -> Self {
todo!()
}
/// Convert the current list into a vector.
pub fn as_vec(&self) -> Vec<T> {
todo!()
}
/// Return the length (i.e., number of nodes) of the list.
pub fn length(&self) -> usize {
todo!()
}
/// Apply function `f` on every element of the list.
///
/// # Examples
///
/// `self`: `[1, 2]`, `f`: `|x| x + 1` ==> `[2, 3]`
pub fn map<F: Fn(T) -> T>(&mut self, f: F) {
todo!()
}
/// Insert given list `another` at the specified index `idx`.
/// If `idx` is out-of-bound of `self`, append `another` at the end of `self`.
///
/// # Examples
///
/// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `1` ==> `[1, 3, 4, 2]`
/// `self`: `[1, 2]`, `another`: `[3, 4]`, `idx`: `5` ==> `[1, 2, 3, 4]`
pub fn insert(&mut self, another: &Self, idx: usize) {
todo!()
}
/// Reverse the list in a chunk of size `n`.
/// If `n == 0`, do nothing.
///
/// # Examples
///
/// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `3`
/// // each chunk of size `3`: `[1, 2, 3]`, `[4, 5, 6]`, `[7, 8, 9]`
/// // reversed sequence of chunks: `[7, 8, 9]`, `[4, 5, 6]`, `[1, 2, 3]`
/// ==> `[7, 8, 9, 4, 5, 6, 1, 2, 3]`,
///
/// `self`: `[1, 2, 3, 4, 5, 6, 7, 8, 9]`, `n`: `4`
/// // each chunk of size `4`: `[1, 2, 3, 4]`, `[5, 6, 7, 8]`, `[9]`
/// // reversed sequence of chunks: `[9]`, `[5, 6, 7, 8]`, `[1, 2, 3, 4]`
/// ==> `[9, 5, 6, 7, 8, 1, 2, 3, 4]`
pub fn chunk_reverse(&mut self, n: usize) {
todo!()
}
/// Apply given function `f` for each adjacent pair of elements in the list.
/// If `self.length() < 2`, do nothing.
///
/// # Examples
///
/// `self`: `[1, 2, 3, 4]`, `f`: `|x, y| x + y`
/// // each adjacent pair of elements: `(1, 2)`, `(2, 3)`, `(3, 4)`
/// // apply `f` to each pair: `f(1, 2) == 3`, `f(2, 3) == 5`, `f(3, 4) == 7`
/// ==> `[3, 5, 7]`
pub fn pair_map<F: Fn(T, T) -> T>(&mut self, f: F) {
todo!()
}
}
// A list of lists.
impl<T: Debug> SinglyLinkedList<SinglyLinkedList<T>> {
/// Flatten the list of lists into a single list.
///
/// # Examples
/// `self`: `[[1, 2, 3], [4, 5, 6], [7, 8]]`
/// ==> `[1, 2, 3, 4, 5, 6, 7, 8]`
pub fn flatten(self) -> SinglyLinkedList<T> {
todo!()
}
}

View File

@@ -1,122 +0,0 @@
#[cfg(test)]
mod test_linked_list {
use crate::assignments::assignment11::linked_list::*;
#[derive(Debug, PartialEq, Eq)]
struct V(usize);
#[test]
fn test_push_pop() {
let mut list = SinglyLinkedList::new();
list.push_back(V(3));
list.push_front(V(2));
list.push_back(V(4));
list.push_front(V(1));
list.push_back(V(5));
assert_eq!(list.pop_front(), Some(V(1)));
assert_eq!(list.pop_back(), Some(V(5)));
assert_eq!(list.pop_front(), Some(V(2)));
assert_eq!(list.pop_back(), Some(V(4)));
assert_eq!(list.pop_front(), Some(V(3)));
assert_eq!(list.pop_back(), None);
assert_eq!(list.pop_front(), None);
}
#[test]
fn test_from_as_vec() {
assert_eq!(SinglyLinkedList::<i32>::new().as_vec(), vec![]);
assert_eq!(
SinglyLinkedList::from_vec(vec![1, 2, 3]).as_vec(),
vec![1, 2, 3]
);
}
#[test]
fn test_length() {
let list = SinglyLinkedList::from_vec(vec![1, 2, 3]);
assert_eq!(list.length(), 3);
}
#[test]
fn test_map() {
let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3]);
let incr = |x: i32| x + 1;
list.map(incr);
assert_eq!(list.as_vec(), vec![2, 3, 4]);
}
#[test]
fn test_insert() {
let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3]);
let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3]);
let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]);
let list4 = SinglyLinkedList::from_vec(vec![4, 5, 6]);
list1.insert(&list4, 0);
assert_eq!(list1.as_vec(), vec![4, 5, 6, 1, 2, 3]);
list2.insert(&list4, 1);
assert_eq!(list2.as_vec(), vec![1, 4, 5, 6, 2, 3]);
list3.insert(&list4, 4);
assert_eq!(list3.as_vec(), vec![1, 2, 3, 4, 5, 6]);
}
#[test]
fn test_chunk_reverse() {
let mut list1 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
list1.chunk_reverse(3);
assert_eq!(list1.as_vec(), vec![7, 8, 9, 3, 4, 5, 1, 2, 3]);
let mut list2 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8]);
list2.chunk_reverse(3);
assert_eq!(list2.as_vec(), vec![7, 8, 4, 5, 6, 1, 2, 3]);
let mut list3 = SinglyLinkedList::from_vec(vec![1, 2, 3]);
list3.chunk_reverse(4);
assert_eq!(list3.as_vec(), vec![1, 2, 3]);
let mut list4 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]);
list4.chunk_reverse(1);
assert_eq!(list4.as_vec(), vec![4, 3, 2, 1]);
let mut list5 = SinglyLinkedList::from_vec(vec![1, 2, 3, 4]);
list4.chunk_reverse(0);
assert_eq!(list4.as_vec(), vec![1, 2, 3, 4]);
}
#[test]
fn test_pair_map() {
let mut list = SinglyLinkedList::from_vec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
let add = |x: i32, y: i32| x + y;
list.pair_map(add);
assert_eq!(list.as_vec(), vec![3, 5, 7, 9, 11, 13, 15, 17]);
list.pair_map(add);
assert_eq!(list.as_vec(), vec![8, 12, 16, 20, 24, 28, 32]);
list.pair_map(add);
assert_eq!(list.as_vec(), vec![20, 28, 36, 44, 52, 60]);
list.pair_map(add);
assert_eq!(list.as_vec(), vec![48, 64, 80, 96, 112]);
}
#[test]
fn test_flatten() {
let list1 = SinglyLinkedList::from_vec(vec![1, 2]);
let list2 = SinglyLinkedList::from_vec(vec![3]);
let list3 = SinglyLinkedList::from_vec(vec![4, 5, 6, 7]);
let list4 = SinglyLinkedList::<i32>::new();
let list5 = SinglyLinkedList::from_vec(vec![8, 9, 10]);
let list_list = SinglyLinkedList::from_vec(vec![list1, list2, list3, list4, list5]);
assert_eq!(
list_list.flatten().as_vec(),
vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
);
}
}

View File

@@ -2,7 +2,7 @@
#[cfg(test)]
mod test_mock_storage {
use super::super::mock_storage::*;
use crate::assignments::assignment11::mock_storage::*;
#[test]
fn test_mock_storage() {

View File

@@ -4,15 +4,6 @@
//! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script.
//! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to <https://gg.kaist.ac.kr>.
pub mod linked_list;
mod linked_list_grade;
pub mod peano_nat;
mod peano_nat_grade;
pub mod bst;
mod bst_grade;
pub mod doubly_linked_list;
mod doubly_linked_list_grade;
@@ -24,6 +15,3 @@ pub mod mock_storage_grade;
pub mod tv_room;
pub mod tv_room_grade;
pub mod turing_machine;
pub mod turing_machine_grade;

View File

@@ -1,56 +0,0 @@
//! Peano natural number.
/// We can represent any natural number using only two symbols: 0 and S.
///
/// E.g.
/// O == 0
/// S(O) == 1
/// S(S(O)) == 2
/// ... so on.
#[derive(Debug, Clone, PartialEq)]
pub enum Nat {
/// Zero
O,
/// Plus one
S(Box<Nat>),
}
impl Nat {
/// Create `Nat` from `usize`
pub fn from_usize(n: usize) -> Nat {
todo!()
}
/// Convert `Nat` into nonnegative integer
pub fn as_usize(&self) -> usize {
todo!()
}
}
// Implement `Add` operator (i.e. `+`) for `Nat`.
impl std::ops::Add for Nat {
type Output = Nat;
fn add(self, rhs: Self) -> Self::Output {
todo!()
}
}
// Implement `Sub` operator (i.e. `-`) for `Nat`.
// If the result is negative, return `Nat::O`.
impl std::ops::Sub for Nat {
type Output = Nat;
fn sub(self, rhs: Self) -> Self::Output {
todo!()
}
}
// Implement `Mul` operator (i.e. `*`) for `Nat`.
impl std::ops::Mul for Nat {
type Output = Nat;
fn mul(self, rhs: Self) -> Self::Output {
todo!()
}
}

View File

@@ -1,38 +0,0 @@
#[cfg(test)]
mod test_peano_nat {
use crate::assignments::assignment11::peano_nat::*;
#[test]
fn test_from_as_usize() {
assert_eq!(Nat::from_usize(0), Nat::O);
assert_eq!(
Nat::from_usize(2),
Nat::S(Box::new(Nat::S(Box::new(Nat::O))))
);
for n in 0..100 {
assert_eq!(Nat::from_usize(n).as_usize(), n);
}
}
fn safe_sub(i: usize, j: usize) -> usize {
if i > j {
i - j
} else {
0
}
}
#[test]
fn test_add_sub_mul() {
for i in 0..30 {
let n = Nat::from_usize(i);
for j in 0..30 {
let m = Nat::from_usize(j);
assert_eq!((n.clone() + m.clone()).as_usize(), i + j);
assert_eq!((n.clone() - m.clone()).as_usize(), safe_sub(i, j));
assert_eq!((n.clone() * m.clone()).as_usize(), i * j);
}
}
}
}

View File

@@ -1,139 +0,0 @@
//! Simple Turing machien emulator
//!
//! Simple One-head, One-tape turing machine
//! See <https://en.wikipedia.org/wiki/Turing_machine> that describes what turing machine is.
//! See `test_turing_machine` module in `assignment11_grade.rs` for examples.
//!
//! Goal: To be accustomed with `RefCell`, `HashMap`
//!
//! Refer `turing_machine.rs` for test cases.
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Formatter};
use thiserror::Error;
/// Error type for Turing machine
/// <https://google.github.io/comprehensive-rust/error-handling/deriving-error-enums.html>
#[derive(Debug, Error, PartialEq, Eq)]
pub enum TuringMachineError {
/// Invalid movement
/// You can't move left from the leftmost location
/// or move right from the rightmost location.
#[error("Invalid movement")]
InvalidMovement,
/// Exceeded maximum steps
#[error("Exceeded maximum steps")]
ExceedMaxSteps,
/// Invalid state or value
/// Occurs when you cannot find instruction for the current state and value
#[error("Invalid state or value")]
InvalidStateOrValue,
}
/// Turing Machine implementation
#[derive(Debug)]
pub struct TuringMachine<TMState, TMValue>
where
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
{
/// Number of steps taken by the Turing machine
pub steps: RefCell<usize>,
/// Table of instructions for the Turing machine
pub table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>,
/// Tape of the Turing machine. Finite length
pub tape: Vec<RefCell<TMValue>>,
}
/// Implementation of the movement instructions of the head of the tape.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Move {
/// Move Left
L,
/// Move Right
R,
/// Don't move
N,
}
/// Cursor for Turing machine
#[derive(Debug)]
pub struct Cursor<'a, TMState, TMValue>
where
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
{
// Turing mahcine
tm: &'a TuringMachine<TMState, TMValue>,
// Index of the tape
index: usize,
// Current state of the Turing machine
state: TMState,
}
impl<'a, TMState, TMValue> Cursor<'a, TMState, TMValue>
where
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
{
/// Generate new cursor
pub fn new(tm: &'a TuringMachine<TMState, TMValue>, state: TMState, index: usize) -> Self {
Cursor { tm, index, state }
}
/// Run the Turing machine until it halts (if it halts). Print every step of that.
pub fn run(&mut self, max_step: usize) -> Result<(TMValue, usize), TuringMachineError> {
let mut steps = self.tm.steps.borrow_mut();
while self.state != TMState::default() {
*steps += 1;
if *steps > max_step {
return Err(TuringMachineError::ExceedMaxSteps);
}
self.step()?;
// println!("{}", self);
}
Ok((self.get(), *steps))
}
/// Set tape value at the current index with `value`
/// You may need this function for `mov` function
fn set(&mut self, value: TMValue) -> TMValue {
todo!();
}
/// Step the Turing machine
/// Look at the `run` function to see how this function is used.
fn step(&mut self) -> Result<(), TuringMachineError> {
todo!();
}
/// Move the cursor while setting the value of the current index
fn mov(&mut self, new_value: TMValue, movement: &Move) -> Result<(), TuringMachineError> {
todo!();
}
/// Get the value of the current index
/// Look at the `run` function to see how this function is used.
fn get(&self) -> TMValue {
todo!();
}
}
impl<TMState, TMValue> TuringMachine<TMState, TMValue>
where
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
{
/// Generate new Turing machine
pub fn new(
table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>,
tape: Vec<RefCell<TMValue>>,
) -> Self {
todo!()
}
}

View File

@@ -1,309 +0,0 @@
//! Test cases for assignment11/turing_machine.rs
#[cfg(test)]
mod test_turing_machine {
use super::super::turing_machine::*;
use std::cell::RefCell;
use std::collections::HashMap;
#[test]
fn test_invalid_movement() {
/// Cell value of the tape
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
enum TMValue {
/// Zero
Zero,
/// One
One,
}
/// State for Turing machine
/// TODO: Modify this so that users can implement their own state
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
enum TMState {
/// Halt
#[default]
Halt,
/// A
A,
/// B
B,
}
let tape: Vec<RefCell<TMValue>> = vec![
TMValue::One,
TMValue::Zero,
TMValue::One,
TMValue::One,
TMValue::One,
TMValue::Zero,
TMValue::One,
]
.into_iter()
.map(|x| RefCell::new(x))
.collect();
let instr = HashMap::from([
(
(TMState::A, TMValue::Zero),
(TMState::B, Move::R, TMValue::One),
),
(
(TMState::A, TMValue::One),
(TMState::B, Move::L, TMValue::Zero),
),
(
(TMState::B, TMValue::Zero),
(TMState::A, Move::L, TMValue::One),
),
(
(TMState::B, TMValue::One),
(TMState::A, Move::R, TMValue::Zero),
),
]);
let mut tm = TuringMachine::new(instr, tape);
let mut cursor = Cursor::new(&tm, TMState::A, 0);
let result = cursor.run(1000);
assert_eq!(result, Err(TuringMachineError::InvalidMovement));
}
#[test]
fn test_write_15_fail_move() {
/// Cell value of the tape
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
enum TMValue {
/// Zero
Zero,
/// One
One,
}
/// State for Turing machine
/// TODO: Modify this so that users can implement their own state
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
enum TMState {
/// Halt
#[default]
Halt,
/// A
A,
/// B
B,
}
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Zero; 10]
.into_iter()
.map(|x| RefCell::new(x))
.collect();
let instr = HashMap::from([
(
(TMState::A, TMValue::Zero),
(TMState::B, Move::R, TMValue::One),
),
(
(TMState::A, TMValue::One),
(TMState::B, Move::L, TMValue::One),
),
(
(TMState::B, TMValue::Zero),
(TMState::A, Move::L, TMValue::One),
),
(
(TMState::B, TMValue::One),
(TMState::Halt, Move::R, TMValue::One),
),
]);
let mut tm = TuringMachine::new(instr, tape);
let mut cursor = Cursor::new(&tm, TMState::A, 0);
let result = cursor.run(1000);
assert_eq!(result, Err(TuringMachineError::InvalidMovement));
}
#[test]
fn test_write_15_pass() {
/// Cell value of the tape
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
enum TMValue {
/// Zero
Zero,
/// One
One,
}
/// State for Turing machine
/// TODO: Modify this so that users can implement their own state
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
enum TMState {
/// Halt
#[default]
Halt,
/// A
A,
/// B
B,
}
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Zero; 10]
.into_iter()
.map(|x| RefCell::new(x))
.collect();
let instr = HashMap::from([
(
(TMState::A, TMValue::Zero),
(TMState::B, Move::R, TMValue::One),
),
(
(TMState::A, TMValue::One),
(TMState::B, Move::L, TMValue::One),
),
(
(TMState::B, TMValue::Zero),
(TMState::A, Move::L, TMValue::One),
),
(
(TMState::B, TMValue::One),
(TMState::Halt, Move::R, TMValue::One),
),
]);
let mut tm = TuringMachine::new(instr, tape);
let mut cursor = Cursor::new(&tm, TMState::A, 2);
let result = cursor.run(1000);
for (idx, val) in tm.tape.iter().enumerate() {
if idx < 4 {
assert_eq!(*val.borrow(), TMValue::One);
} else {
assert_eq!(*val.borrow(), TMValue::Zero);
}
}
}
#[test]
fn test_write_zero_ones_fail_step() {
/// Cell value of the tape
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
enum TMValue {
/// Empty
Empty,
/// Zero
Zero,
/// One
One,
}
/// State for Turing machine
/// TODO: Modify this so that users can implement their own state
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
enum TMState {
/// Halt
#[default]
Halt,
/// A
A,
/// B
B,
}
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Empty; 100]
.into_iter()
.map(|x| RefCell::new(x))
.collect();
let instr = HashMap::from([
(
(TMState::A, TMValue::Empty),
(TMState::B, Move::R, TMValue::Zero),
),
(
(TMState::B, TMValue::Empty),
(TMState::A, Move::R, TMValue::One),
),
]);
let mut tm = TuringMachine::new(instr, tape);
let mut cursor = Cursor::new(&tm, TMState::A, 0);
let result = cursor.run(10);
assert_eq!(result, Err(TuringMachineError::ExceedMaxSteps));
}
#[test]
fn test_write_zero_ones() {
/// Cell value of the tape
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
enum TMValue {
/// Empty
Empty,
/// Zero
Zero,
/// One
One,
}
/// State for Turing machine
/// TODO: Modify this so that users can implement their own state
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
enum TMState {
/// Halt
#[default]
Halt,
/// A
A,
/// B
B,
}
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Empty; 100]
.into_iter()
.map(|x| RefCell::new(x))
.collect();
let instr = HashMap::from([
(
(TMState::A, TMValue::Empty),
(TMState::B, Move::R, TMValue::Zero),
),
(
(TMState::B, TMValue::Empty),
(TMState::A, Move::R, TMValue::One),
),
]);
let mut tm = TuringMachine::new(instr, tape);
let mut cursor = Cursor::new(&tm, TMState::A, 0);
let result = cursor.run(1000);
assert_eq!(result, Err(TuringMachineError::InvalidMovement));
for (idx, val) in tm.tape.iter().enumerate() {
if idx % 2 == 0 {
assert_eq!(*val.borrow(), TMValue::Zero);
} else {
assert_eq!(*val.borrow(), TMValue::One);
}
}
}
}

View File

@@ -2,7 +2,7 @@
#[cfg(test)]
mod test_tv_room {
use super::super::tv_room::*;
use crate::assignments::assignment11::tv_room::*;
#[test]
fn test_tv_room() {

View File

@@ -2,7 +2,8 @@
#[cfg(test)]
mod test_card {
use super::super::card::*;
use crate::assignments::assignment12::card::*;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier, Mutex};
use std::thread;

View File

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

View File

@@ -2,7 +2,7 @@
#[cfg(test)]
mod test_funnel {
use super::super::funnel::*;
use crate::assignments::assignment12::funnel::*;
use ntest::timeout;
use std::sync::mpsc::channel;

View File

@@ -2,7 +2,7 @@
#[cfg(test)]
mod test_pingpong {
use super::super::small_exercises::*;
use crate::assignments::assignment12::small_exercises::*;
use ntest::timeout;
use std::sync::mpsc::channel;

View File

@@ -0,0 +1,10 @@
//! Assignment 13: Parallelism.
//!
//! The primary goal of this assignment is to get used to data parallelism.
//!
//! Refer to your solution for assignment 09. You will implement the parallelized version of assignment 09.
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-13.sh` works fine.
//! See `assignment13_grade.rs` and `/scripts/grade-13.sh` for the test script.
pub mod small_problems;
mod small_problems_grade;

View File

@@ -1,10 +1,7 @@
//! Assignment 13: Parallelism.
//!
//! The primary goal of this assignment is to get used to data parallelism.
//!
//! Refer to your solution for assignment 09. You will implement the parallelized version of assignment 09.
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-13.sh` works fine.
//! See `assignment13_grade.rs` and `/scripts/grade-13.sh` for the test script.
//! If you did well on assignment 09, you will do well on this assignment.
//! Take it easy!
use rayon::prelude::*;
@@ -65,6 +62,9 @@ pub fn vec_add_par(lhs: &[f64], rhs: &[f64]) -> Vec<f64> {
/// Parallel dot product of two arrays
///
/// You don't know how to calculate dot product?
/// See <https://mathinsight.org/dot_product_examples>
///
/// # Exmaple
///
/// ```
@@ -82,6 +82,9 @@ pub fn dot_product_par(lhs: &[f64], rhs: &[f64]) -> f64 {
/// Parallel Matrix multiplication
///
/// You don't know how to multiply matrix?
/// Quite simple! See <https://www.mathsisfun.com/algebra/matrix-multiplying.html>
///
/// Assume rhs is transposed
/// - lhs: (m, n)
/// - rhs: (p, n)

View File

@@ -1,7 +1,7 @@
#[cfg(test)]
mod test {
use super::super::assignment09::matmul::*;
use super::super::assignment13::*;
use crate::assignments::assignment09::matmul::*;
use crate::assignments::assignment13::small_problems::*;
use approx::*;
use itertools::Itertools;
use ndarray::prelude::*;

View File

@@ -7,17 +7,14 @@
#![allow(unreachable_code)]
pub mod assignment01;
mod assignment01_grade;
pub mod assignment02;
pub mod assignment03;
pub mod assignment04;
pub mod assignment06;
pub mod assignment07;
pub mod assignment08;
mod assignment08_grade;
pub mod assignment09;
pub mod assignment10;
pub mod assignment11;
pub mod assignment12;
pub mod assignment13;
mod assignment13_grade;