mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-14 22:18:46 +00:00
Merge branch 'main' into 'main'
minor format & typo fixes See merge request kaist-cp-class/cs220-private!16
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
//! 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;
|
||||||
|
|||||||
66
src/assignments/assignment09/matmul.rs
Normal file
66
src/assignments/assignment09/matmul.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//! 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
|
||||||
|
///
|
||||||
|
/// # 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
|
||||||
|
///
|
||||||
|
/// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,9 @@
|
|||||||
//! See `assignment09_grade.rs` and `/scripts/grade-09.sh` for the test script.
|
//! See `assignment09_grade.rs` and `/scripts/grade-09.sh` for the test script.
|
||||||
|
|
||||||
pub mod bigint;
|
pub mod bigint;
|
||||||
|
pub mod matmul;
|
||||||
pub mod small_exercises;
|
pub mod small_exercises;
|
||||||
|
|
||||||
mod bigint_grade;
|
mod bigint_grade;
|
||||||
|
mod matmul_grade;
|
||||||
mod small_exercises_grade;
|
mod small_exercises_grade;
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,10 +6,10 @@
|
|||||||
//! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script.
|
//! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script.
|
||||||
|
|
||||||
pub mod card;
|
pub mod card;
|
||||||
pub mod card_grade;
|
mod card_grade;
|
||||||
pub mod demux;
|
pub mod demux;
|
||||||
pub mod demux_grade;
|
mod demux_grade;
|
||||||
pub mod funnel;
|
pub mod funnel;
|
||||||
pub mod funnel_grade;
|
mod funnel_grade;
|
||||||
pub mod small_exercises;
|
pub mod small_exercises;
|
||||||
pub mod small_exercises_grade;
|
mod small_exercises_grade;
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::super::assignment12::*;
|
|
||||||
use ntest::timeout;
|
|
||||||
|
|
||||||
use std::sync::mpsc::channel;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ping_pong() {
|
|
||||||
let (tx1, mut rx1) = channel();
|
|
||||||
let (mut tx2, rx2) = channel();
|
|
||||||
|
|
||||||
let thread_ping = thread::spawn(move || {
|
|
||||||
for i in 0..100 {
|
|
||||||
tx1.send(i).unwrap();
|
|
||||||
let x = rx2.recv().unwrap();
|
|
||||||
assert_eq!(x, i + 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let thread_pong = thread::spawn(move || while pong(&mut rx1, &mut tx2) {});
|
|
||||||
|
|
||||||
thread_ping.join().unwrap();
|
|
||||||
thread_pong.join().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scoped_thread() {
|
|
||||||
for i in 0..100 {
|
|
||||||
let v = (0..i).collect::<Vec<u32>>();
|
|
||||||
|
|
||||||
thread::scope(|s| {
|
|
||||||
let (r1, r2) = use_scoped_thread(
|
|
||||||
s,
|
|
||||||
|| v.iter().sum::<u32>(),
|
|
||||||
|| v.windows(2).map(|x| x[0] * x[1]).sum::<u32>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(r1, v.iter().sum());
|
|
||||||
assert_eq!(r2, v.windows(2).map(|x| x[0] * x[1]).sum());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[timeout(5000)]
|
|
||||||
fn test_scoped_thread_concurrent() {
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
let m = Mutex::new(0);
|
|
||||||
let (r1, r2) = thread::scope(|s| {
|
|
||||||
use_scoped_thread(
|
|
||||||
s,
|
|
||||||
|| {
|
|
||||||
for i in 0..100 {
|
|
||||||
loop {
|
|
||||||
let mut a = m.lock().unwrap();
|
|
||||||
if *a == 2 * i {
|
|
||||||
*a += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thread::current().id()
|
|
||||||
},
|
|
||||||
|| {
|
|
||||||
for i in 0..100 {
|
|
||||||
loop {
|
|
||||||
let mut a = m.lock().unwrap();
|
|
||||||
if *a == 2 * i + 1 {
|
|
||||||
*a += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thread::current().id()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
assert!(r1 != r2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,10 +16,10 @@ use rayon::prelude::*;
|
|||||||
/// use cs220::assignments::assignment13::sigma;
|
/// use cs220::assignments::assignment13::sigma;
|
||||||
/// use rayon::iter::IntoParallelIterator;
|
/// use rayon::iter::IntoParallelIterator;
|
||||||
///
|
///
|
||||||
/// assert_eq!(sigma([1, 2].into_par_iter(), |x| x + 2), 7);
|
/// assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x + 2), 7);
|
||||||
/// assert_eq!(sigma([1, 2].into_par_iter(), |x| x * 4), 12);
|
/// assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x * 4), 12);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn sigma<T, F: Fn(T) -> i64 + Sync + Send>(
|
pub fn sigma_par<T, F: Fn(T) -> i64 + Sync + Send>(
|
||||||
inner: impl ParallelIterator<Item = T>,
|
inner: impl ParallelIterator<Item = T>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> i64 {
|
) -> i64 {
|
||||||
@@ -35,14 +35,77 @@ pub fn sigma<T, F: Fn(T) -> i64 + Sync + Send>(
|
|||||||
/// use rayon::iter::IntoParallelIterator;
|
/// use rayon::iter::IntoParallelIterator;
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// interleave3([1, 2].into_par_iter(), [3, 4].into_par_iter(), [5, 6].into_par_iter()),
|
/// interleave3_par([1, 2].into_par_iter(), [3, 4].into_par_iter(), [5, 6].into_par_iter()),
|
||||||
/// vec![1, 3, 5, 2, 4, 6]
|
/// vec![1, 3, 5, 2, 4, 6]
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
pub fn interleave3<T: Send>(
|
pub fn interleave3_par<T: Send>(
|
||||||
list1: impl IndexedParallelIterator<Item = T>,
|
list1: impl IndexedParallelIterator<Item = T>,
|
||||||
list2: impl IndexedParallelIterator<Item = T>,
|
list2: impl IndexedParallelIterator<Item = T>,
|
||||||
list3: impl IndexedParallelIterator<Item = T>,
|
list3: impl IndexedParallelIterator<Item = T>,
|
||||||
) -> Vec<T> {
|
) -> Vec<T> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parallel vector addition
|
||||||
|
///
|
||||||
|
/// # Exmaple
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use cs220::assignments::assignment13::vec_add_par;
|
||||||
|
///
|
||||||
|
/// 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_par(&vec1, &vec2);
|
||||||
|
/// assert_eq!(res, vec![2.0, 4.0, 6.0, 8.0, 10.0]);
|
||||||
|
/// ```
|
||||||
|
pub fn vec_add_par(lhs: &[f64], rhs: &[f64]) -> Vec<f64> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parallel dot product of two arrays
|
||||||
|
///
|
||||||
|
/// # Exmaple
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use cs220::assignments::assignment13::dot_product_par;
|
||||||
|
///
|
||||||
|
/// 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_par(&vec1, &vec2);
|
||||||
|
///
|
||||||
|
/// assert_eq!(res, 55.0);
|
||||||
|
/// ```
|
||||||
|
pub fn dot_product_par(lhs: &[f64], rhs: &[f64]) -> f64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parallel Matrix multiplication
|
||||||
|
///
|
||||||
|
/// Assume rhs is transposed
|
||||||
|
/// - lhs: (m, n)
|
||||||
|
/// - rhs: (p, n)
|
||||||
|
/// - output: (m, p)
|
||||||
|
///
|
||||||
|
/// # Exmaple
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use cs220::assignments::assignment13::matmul_par;
|
||||||
|
///
|
||||||
|
/// 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_par(&mat1, &mat2);
|
||||||
|
/// assert_eq!(ans, res);
|
||||||
|
/// ```
|
||||||
|
pub fn matmul_par(lhs: &[Vec<f64>], rhs: &[Vec<f64>]) -> Vec<Vec<f64>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,42 +1,48 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::super::assignment09::matmul::*;
|
||||||
use super::super::assignment13::*;
|
use super::super::assignment13::*;
|
||||||
|
use approx::*;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use ndarray::prelude::*;
|
||||||
|
use ndarray_rand::{rand_distr::Uniform, RandomExt};
|
||||||
use rayon::prelude::IntoParallelIterator;
|
use rayon::prelude::IntoParallelIterator;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sigma() {
|
fn test_sigma_par() {
|
||||||
assert_eq!(sigma([].into_par_iter(), |x: i64| x * 2), 0);
|
assert_eq!(sigma_par([].into_par_iter(), |x: i64| x * 2), 0);
|
||||||
assert_eq!(sigma([1].into_par_iter(), |x| x * 3), 3);
|
assert_eq!(sigma_par([1].into_par_iter(), |x| x * 3), 3);
|
||||||
assert_eq!(sigma([1, 2].into_par_iter(), |x| x + 2), 7);
|
assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x + 2), 7);
|
||||||
assert_eq!(sigma([1, 2].into_par_iter(), |x| x * 4), 12);
|
assert_eq!(sigma_par([1, 2].into_par_iter(), |x| x * 4), 12);
|
||||||
assert_eq!(sigma([1, 2, 3].into_par_iter(), |x| x * 5), 30);
|
assert_eq!(sigma_par([1, 2, 3].into_par_iter(), |x| x * 5), 30);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sigma([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.floor()
|
sigma_par([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.floor()
|
||||||
as i64),
|
as i64),
|
||||||
10
|
10
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sigma([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.ceil()
|
sigma_par([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.ceil()
|
||||||
as i64),
|
as i64),
|
||||||
13
|
13
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sigma([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.round()
|
sigma_par([-1.2, 3.0, 4.2, 5.8].into_par_iter(), |x: f64| x.round()
|
||||||
as i64),
|
as i64),
|
||||||
12
|
12
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sigma(["Hello,", "World!"].into_par_iter(), |x| x.len() as i64),
|
sigma_par(["Hello,", "World!"].into_par_iter(), |x| x.len() as i64),
|
||||||
12
|
12
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_interleave3() {
|
fn test_interleave3_par() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interleave3(
|
interleave3_par(
|
||||||
[1, 2].into_par_iter(),
|
[1, 2].into_par_iter(),
|
||||||
[3, 4].into_par_iter(),
|
[3, 4].into_par_iter(),
|
||||||
[5, 6].into_par_iter()
|
[5, 6].into_par_iter()
|
||||||
@@ -45,7 +51,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interleave3(
|
interleave3_par(
|
||||||
[1, 2, 3].into_par_iter(),
|
[1, 2, 3].into_par_iter(),
|
||||||
[4, 5, 6].into_par_iter(),
|
[4, 5, 6].into_par_iter(),
|
||||||
[7, 8, 9].into_par_iter()
|
[7, 8, 9].into_par_iter()
|
||||||
@@ -54,7 +60,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interleave3(
|
interleave3_par(
|
||||||
["a", "b", "c"].into_par_iter(),
|
["a", "b", "c"].into_par_iter(),
|
||||||
["d", "e", "f"].into_par_iter(),
|
["d", "e", "f"].into_par_iter(),
|
||||||
["g", "h", "i"].into_par_iter()
|
["g", "h", "i"].into_par_iter()
|
||||||
@@ -64,4 +70,148 @@ mod test {
|
|||||||
"adgbehcfi"
|
"adgbehcfi"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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 now_seq = Instant::now();
|
||||||
|
let res_seq = vec_add(vec1.as_slice().unwrap(), vec2.as_slice().unwrap());
|
||||||
|
let elapsed_seq = now_seq.elapsed();
|
||||||
|
|
||||||
|
let now_par = Instant::now();
|
||||||
|
let res_par = vec_add_par(vec1.as_slice().unwrap(), vec2.as_slice().unwrap());
|
||||||
|
let elapsed_par = now_par.elapsed();
|
||||||
|
|
||||||
|
let ans = vec1 + vec2;
|
||||||
|
assert_eq!(Array::from_vec(res_seq), ans);
|
||||||
|
assert_eq!(Array::from_vec(res_par), ans);
|
||||||
|
assert!(elapsed_par < elapsed_seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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_seq = dot_product(&vec1, &vec2);
|
||||||
|
let res_par = dot_product_par(&vec1, &vec2);
|
||||||
|
assert_eq!(res_seq, 55.0);
|
||||||
|
assert_eq!(res_par, 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 now_seq = Instant::now();
|
||||||
|
let res_seq = dot_product(vec1.as_slice().unwrap(), vec2.as_slice().unwrap());
|
||||||
|
let elapsed_seq = now_seq.elapsed();
|
||||||
|
|
||||||
|
let now_par = Instant::now();
|
||||||
|
let res_par = dot_product_par(vec1.as_slice().unwrap(), vec2.as_slice().unwrap());
|
||||||
|
let elapsed_par = now_par.elapsed();
|
||||||
|
|
||||||
|
let _res = relative_eq!(res_seq, vec1.dot(&vec2), epsilon = f64::EPSILON);
|
||||||
|
let _res = relative_eq!(res_par, vec1.dot(&vec2), epsilon = f64::EPSILON);
|
||||||
|
assert!(elapsed_par < elapsed_seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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_seq = matmul(&mat1, &mat2);
|
||||||
|
let res_par = matmul_par(&mat1, &mat2);
|
||||||
|
assert_eq!(ans, res_seq);
|
||||||
|
assert_eq!(ans, res_par);
|
||||||
|
|
||||||
|
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 now_seq = Instant::now();
|
||||||
|
let res_seq = 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(),
|
||||||
|
);
|
||||||
|
let elapsed_seq = now_seq.elapsed();
|
||||||
|
|
||||||
|
// Run parallel matrix multiplication
|
||||||
|
let now_par = Instant::now();
|
||||||
|
let res_par = matmul_par(
|
||||||
|
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(),
|
||||||
|
);
|
||||||
|
let elapsed_par = now_par.elapsed();
|
||||||
|
|
||||||
|
// Check answer
|
||||||
|
for it in ans.iter().zip(vec_to_array(res_seq).iter()) {
|
||||||
|
let (ans, seq) = it;
|
||||||
|
let _res = relative_eq!(ans, seq);
|
||||||
|
}
|
||||||
|
for it in ans.iter().zip(vec_to_array(res_par).iter()) {
|
||||||
|
let (ans, par) = it;
|
||||||
|
let _res = relative_eq!(ans, par);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check time
|
||||||
|
// println!("Sequential: {:?}", elapsed_seq);
|
||||||
|
// println!("Parallel: {:?}", elapsed_par);
|
||||||
|
assert!(elapsed_par < elapsed_seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ mod assignment02_grade;
|
|||||||
pub mod assignment03;
|
pub mod assignment03;
|
||||||
mod assignment03_grade;
|
mod assignment03_grade;
|
||||||
pub mod assignment04;
|
pub mod assignment04;
|
||||||
mod assignment04_grade;
|
|
||||||
pub mod assignment06;
|
pub mod assignment06;
|
||||||
pub mod assignment07;
|
pub mod assignment07;
|
||||||
pub mod assignment08;
|
pub mod assignment08;
|
||||||
|
|||||||
Reference in New Issue
Block a user