From 8fc03190081ec5adf0ed77a51cdad422b9c2f64a Mon Sep 17 00:00:00 2001 From: Andreas Grois Date: Sun, 12 Dec 2021 17:13:13 +0100 Subject: Make matrix multiplication use unsafe MaybeUninit. This improves performance significantly. --- src/day6.rs | 41 ++++++++++++++++++----------------------- 1 file 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 IndexMut for Matrix(l : Matrix, r : Matrix) -> Matrix where T : Copy+Add+Mul+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 { + maybeinit: ManuallyDrop<[[MaybeUninit; 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; 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 Mul> for Matrix @@ -385,22 +396,6 @@ fn get_progress_matrix_inverse_eigenvectors() -> Matrix { ]}} } -#[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, -- cgit v1.2.3