aboutsummaryrefslogtreecommitdiff
path: root/src/day6.rs
diff options
context:
space:
mode:
authorAndreas Grois <andi@grois.info>2021-12-12 17:13:13 +0100
committerAndreas Grois <andi@grois.info>2021-12-12 17:13:13 +0100
commit8fc03190081ec5adf0ed77a51cdad422b9c2f64a (patch)
treed9199698acf1be48cbd5fd5d235af88aee47c282 /src/day6.rs
parent258994f017996e5a48a1a4b8decc181438c54c72 (diff)
Make matrix multiplication use unsafe MaybeUninit.
This improves performance significantly.
Diffstat (limited to 'src/day6.rs')
-rw-r--r--src/day6.rs41
1 files changed, 18 insertions, 23 deletions
diff --git a/src/day6.rs b/src/day6.rs
index 4404ec6..89b55d7 100644
--- a/src/day6.rs
+++ b/src/day6.rs
@@ -112,13 +112,24 @@ impl<T, const COLUMNS : usize, const ROWS : usize> IndexMut<usize> for Matrix<T,
fn dot<T, const R1 : usize, const C1R2 : usize, const C2 : usize>(l : Matrix<T, C1R2, R1>, r : Matrix<T, C2, C1R2>) -> Matrix<T, C2, R1>
where T : Copy+Add<Output=T>+Mul<Output=T>+Default+std::iter::Sum
{
- //the Matrix::default() call is ugly and wastes cycles, but afaict the only currently sane way to pull this
- //off... There'd be the https://docs.rs/array-init/ crate, or I could write my own unsafe code,
- //or use non-inline storage, but that all sounds ugly.
- (0..R1).flat_map(|row| (0..C2).map(move |column| (row, column))).fold(Matrix::default(), |mut result, (row, column)| {
- result[row][column] = l[row].iter().zip(0..C1R2).map(|(rv, cindex)| (rv, r[cindex][column])).map(|(&a,b)| a*b).sum();
- result
- })
+ use std::mem::{MaybeUninit, ManuallyDrop};
+ union ArrayInit<T, const COLUMNS :usize, const ROWS : usize> {
+ maybeinit: ManuallyDrop<[[MaybeUninit<T>; COLUMNS]; ROWS]>,
+ init: ManuallyDrop<[[T; COLUMNS];ROWS]>,
+ }
+ let storage_maybe_uninit = (0..R1).flat_map(|row| (0..C2).map(move |column| (row, column))).fold(
+ unsafe { MaybeUninit::uninit().assume_init() }, |mut result : [[MaybeUninit<T>; C2]; R1], (row, column)| {
+ result[row][column].write(l[row].iter().zip(0..C1R2).map(|(rv, cindex)| (rv, r[cindex][column])).map(|(&a,b)| a*b).sum());
+ unsafe { result[row][column].assume_init() };
+ result
+ }
+ );
+ let storage = unsafe {
+ ManuallyDrop::into_inner(ArrayInit {
+ maybeinit: ManuallyDrop::new(storage_maybe_uninit)
+ }.init)
+ };
+ Matrix { storage }
}
impl<T, const R1 : usize, const C1R2 : usize, const C2 : usize> Mul<Matrix<T, C2, C1R2>> for Matrix<T, C1R2, R1>
@@ -385,22 +396,6 @@ fn get_progress_matrix_inverse_eigenvectors() -> Matrix<Complex,9,9> {
]}}
}
-#[cfg(test)]
-mod eigenvector_tests{
- use super::*;
- #[test]
- fn test_inverse() {
- let a = get_progress_matrix_inverse_eigenvectors();
- let b = get_progress_matrix_eigenvectors();
- let should_be_unit = a*b;
- for (row, column) in (0..9).flat_map(|row| (0..9).map(move |column| (row, column))) {
- assert!(should_be_unit[row][column].imag.abs() < 1e-10);
- assert!((should_be_unit[row][column].real - if row == column {1.0} else { 0.0 }).abs() < 1e-10);
- }
- }
-}
-
-
#[derive(Default, Debug, PartialEq, Copy, Clone)]
struct Complex {
real : f64,