Fri, 06 Dec 2024 16:14:41 -0500
Add "nightly" feature and provide alternative low-performance implementations of several things when not available.
Cargo.toml | file | annotate | diff | comparison | revisions | |
rust-toolchain.toml | file | annotate | diff | comparison | revisions | |
src/bisection_tree/refine.rs | file | annotate | diff | comparison | revisions | |
src/lib.rs | file | annotate | diff | comparison | revisions | |
src/linsolve.rs | file | annotate | diff | comparison | revisions | |
src/maputil.rs | file | annotate | diff | comparison | revisions | |
src/sets/cube.rs | file | annotate | diff | comparison | revisions |
--- a/Cargo.toml Fri Dec 06 15:30:23 2024 -0500 +++ b/Cargo.toml Fri Dec 06 16:14:41 2024 -0500 @@ -35,3 +35,5 @@ [features] default = [] use_custom_thread_pool = [] +nightly = [] # enable for higher-performance implementations of some things +
--- a/rust-toolchain.toml Fri Dec 06 15:30:23 2024 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly"
--- a/src/bisection_tree/refine.rs Fri Dec 06 15:30:23 2024 -0500 +++ b/src/bisection_tree/refine.rs Fri Dec 06 16:14:41 2024 -0500 @@ -364,8 +364,13 @@ let mut container = container_arc.lock().unwrap(); // Safe: we just created arg_b and have a mutable exclusive // reference to self containing it. + #[cfg(feature = "nightly")] unsafe { Arc::get_mut_unchecked(arc_b) } .stage_refine(domain, &mut *container); + #[cfg(not(feature = "nightly"))] + Arc::get_mut(arc_b).unwrap() + .stage_refine(domain, &mut *container); + return Err(container) }, _ => unreachable!("This cannot happen"),
--- a/src/lib.rs Fri Dec 06 15:30:23 2024 -0500 +++ b/src/lib.rs Fri Dec 06 16:14:41 2024 -0500 @@ -7,9 +7,11 @@ #![allow(mixed_script_confusables)] #![allow(confusable_idents)] -#![feature(maybe_uninit_uninit_array,maybe_uninit_array_assume_init,maybe_uninit_slice)] -#![feature(float_minimum_maximum)] -#![feature(get_mut_unchecked)] +#![cfg_attr(feature = "nightly", + feature(maybe_uninit_uninit_array,maybe_uninit_array_assume_init,maybe_uninit_slice), + feature(float_minimum_maximum), + feature(get_mut_unchecked), +)] // They don't work: //#![feature(negative_impls)]
--- a/src/linsolve.rs Fri Dec 06 15:30:23 2024 -0500 +++ b/src/linsolve.rs Fri Dec 06 16:14:41 2024 -0500 @@ -3,6 +3,7 @@ */ use crate::types::Float; +#[cfg(feature = "nightly")] use std::mem::MaybeUninit; /// Gaussian elimination for $AX=B$, where $A$ and $B$ are both stored in `ab`, @@ -45,27 +46,44 @@ // Solve UAX=UB for X where UA with U presenting the transformations above an // upper triangular matrix. + // + // If the "nightly" feature is enabled, we will use an uninitialised array for a + // little bit of efficiency. // This use of MaybeUninit assumes F : Copy. Otherwise undefined behaviour may occur. - let mut x : [[MaybeUninit<F>; K]; M] = core::array::from_fn(|_| MaybeUninit::uninit_array::<K>() ); - //unsafe { std::mem::MaybeUninit::uninit().assume_init() }; - for i in (0..M).rev() { - for 𝓁 in 0..K { - let mut tmp = ab[i][M+𝓁]; - for j in (i+1)..M { - tmp -= ab[i][j] * unsafe { *(x[j][𝓁].assume_init_ref()) }; + #[cfg(feature = "nightly")] + { + let mut x : [[MaybeUninit<F>; K]; M] = core::array::from_fn(|_| MaybeUninit::uninit_array::<K>() ); + //unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + for i in (0..M).rev() { + for 𝓁 in 0..K { + let mut tmp = ab[i][M+𝓁]; + for j in (i+1)..M { + tmp -= ab[i][j] * unsafe { *(x[j][𝓁].assume_init_ref()) }; + } + tmp /= ab[i][i]; + x[i][𝓁].write(tmp); } - tmp /= ab[i][i]; - x[i][𝓁].write(tmp); + } + unsafe { + //core::intrinsics::assert_inhabited::<[[F; K]; M]>(); + (&x as *const _ as *const [[F; K]; M]).read() } } - //unsafe { MaybeUninit::array_assume_init(x) }; - let xinit = unsafe { - //core::intrinsics::assert_inhabited::<[[F; K]; M]>(); - (&x as *const _ as *const [[F; K]; M]).read() - }; - - //std::mem::forget(x); - xinit + #[cfg(not(feature = "nightly"))] + { + let mut x : [[F; K]; M] = [[F::ZERO; K]; M]; + for i in (0..M).rev() { + for 𝓁 in 0..K { + let mut tmp = ab[i][M+𝓁]; + for j in (i+1)..M { + tmp -= ab[i][j] * x[j][𝓁]; + } + tmp /= ab[i][i]; + x[i][𝓁] = tmp; + } + } + x + } } /// Gaussian elimination for $Ax=b$, where $A$ and $b$ are both stored in `ab`,
--- a/src/maputil.rs Fri Dec 06 15:30:23 2024 -0500 +++ b/src/maputil.rs Fri Dec 06 16:14:41 2024 -0500 @@ -2,6 +2,7 @@ Utilities for mapping over various container types. */ +#[cfg(feature = "nightly")] use std::mem::MaybeUninit; use itertools::izip; @@ -322,8 +323,13 @@ /// /// If `iter.next()` panicks, all items already yielded by the iterator are /// dropped. +#[cfg(feature = "nightly")] #[inline] -pub(crate) fn collect_into_array_unchecked<T, I : Iterator<Item=T>, const N: usize>(mut iter: I) -> [T; N] +pub(crate) fn collect_into_array_unchecked< + T, + I : Iterator<Item=T>, + const N: usize +>(mut iter: I) -> [T; N] { if N == 0 { // SAFETY: An empty array is always inhabited and has no validity invariants. @@ -375,6 +381,19 @@ unreachable!("Something went wrong with iterator length") } +#[cfg(not(feature = "nightly"))] +#[inline] +pub(crate) fn collect_into_array_unchecked< + T, + I : Iterator<Item=T>, + const N: usize +>(iter: I) -> [T; N] +{ + match iter.collect::<Vec<T>>().try_into() { + Ok(a) => a, + Err(_) => panic!("collect_into_array failure: should not happen"), + } +} #[cfg(test)] mod tests {
--- a/src/sets/cube.rs Fri Dec 06 15:30:23 2024 -0500 +++ b/src/sets/cube.rs Fri Dec 06 16:14:41 2024 -0500 @@ -333,7 +333,9 @@ impl_common!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize, min, max); + // Any NaN yields NaN +#[cfg(feature = "nightly")] impl_common!(f32 f64, minimum, maximum); impl<U : Num, const N : usize> std::ops::Index<usize> for Cube<U, N> {