Add "nightly" feature and provide alternative low-performance implementations of several things when not available. dev

Fri, 06 Dec 2024 16:14:41 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Fri, 06 Dec 2024 16:14:41 -0500
branch
dev
changeset 55
7b2ee3e84c5f
parent 54
c0301da04883
child 56
5e3c1874797d

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> {

mercurial