Start work on 0.4.0(-dev). dev

Sun, 27 Apr 2025 14:48:13 -0500

author
Tuomo Valkonen <tuomov@iki.fi>
date
Sun, 27 Apr 2025 14:48:13 -0500
branch
dev
changeset 95
9cb8225a3a41
parent 89
8513a10c5dd9 (current diff)
parent 93
123f7f38e161 (diff)
child 96
962c8e346ab9

Start work on 0.4.0(-dev).

Cargo.toml file | annotate | diff | comparison | revisions
--- a/Cargo.lock	Thu Jan 23 23:38:40 2025 +0100
+++ b/Cargo.lock	Sun Apr 27 14:48:13 2025 -0500
@@ -4,7 +4,7 @@
 
 [[package]]
 name = "alg_tools"
-version = "0.3.0"
+version = "0.3.1"
 dependencies = [
  "anyhow",
  "colored",
--- a/Cargo.toml	Thu Jan 23 23:38:40 2025 +0100
+++ b/Cargo.toml	Sun Apr 27 14:48:13 2025 -0500
@@ -1,6 +1,6 @@
 [package]
 name = "alg_tools"
-version = "0.3.0"
+version = "0.4.0-dev"
 edition = "2021"
 rust-version = "1.85"
 authors = ["Tuomo Valkonen <tuomov@iki.fi>"]
@@ -8,7 +8,13 @@
 homepage = "https://tuomov.iki.fi/software/alg_tools/"
 repository = "https://tuomov.iki.fi/repos/alg_tools/"
 license-file = "LICENSE"
-keywords = ["iterative", "optimization", "bisection", "branch-and-bound", "numerical"]
+keywords = [
+    "iterative",
+    "optimization",
+    "bisection",
+    "branch-and-bound",
+    "numerical",
+]
 categories = ["mathematics", "data-structures"]
 
 [dependencies]
@@ -27,7 +33,7 @@
 anyhow = "1.0.95"
 
 [package.metadata.docs.rs]
-rustdoc-args = [ "--html-in-header", "katex-header.html" ]
+rustdoc-args = ["--html-in-header", "katex-header.html"]
 
 
 [profile.release]
@@ -36,5 +42,4 @@
 [features]
 default = ["nightly"]
 use_custom_thread_pool = []
-nightly = [] # enable for higher-performance implementations of some things
-
+nightly = []                # enable for higher-performance implementations of some things
--- a/src/lib.rs	Thu Jan 23 23:38:40 2025 +0100
+++ b/src/lib.rs	Sun Apr 27 14:48:13 2025 -0500
@@ -8,7 +8,7 @@
 #![allow(confusable_idents)]
 
 #![cfg_attr(feature = "nightly",
-    feature(maybe_uninit_uninit_array,maybe_uninit_array_assume_init,maybe_uninit_slice),
+    feature(maybe_uninit_array_assume_init,maybe_uninit_slice),
     feature(float_minimum_maximum),
     feature(get_mut_unchecked),
     feature(cow_is_borrowed),
--- a/src/linsolve.rs	Thu Jan 23 23:38:40 2025 +0100
+++ b/src/linsolve.rs	Sun Apr 27 14:48:13 2025 -0500
@@ -8,33 +8,33 @@
 
 /// Gaussian elimination for $AX=B$, where $A$ and $B$ are both stored in `ab`,
 /// $A \in \mathbb{R}^{M \times M}$ and $X, B \in \mathbb{R}^{M \times K}$.
-pub fn linsolve0<F : Float, const M : usize, const N : usize, const K : usize>(
-    mut ab : [[F; N]; M]
+pub fn linsolve0<F: Float, const M: usize, const N: usize, const K: usize>(
+    mut ab: [[F; N]; M],
 ) -> [[F; K]; M] {
-    assert_eq!(M + K , N);
+    assert_eq!(M + K, N);
 
     let mut k = 0;
 
     // Convert to row-echelon form
-    for h in 0..(M-1) {
+    for h in 0..(M - 1) {
         // Find pivotable column (has some non-zero entries in rows ≥ h)
         'find_pivot: while k < N {
             let (mut î, mut v) = (h, ab[h][k].abs());
             // Find row ≥ h of maximum absolute value in this column
-            for i in (h+1)..M {
+            for i in (h + 1)..M {
                 let ṽ = ab[i][k].abs();
-                if ṽ > v  {
+                if ṽ > v {
                     î = i;
                     v = ṽ;
                 }
             }
             if v > F::ZERO {
                 ab.swap(h, î);
-                for i in (h+1)..M {
+                for i in (h + 1)..M {
                     let f = ab[i][k] / ab[h][k];
                     ab[i][k] = F::ZERO;
-                    for j in (k+1)..N {
-                        ab[i][j] -= ab[h][j]*f;
+                    for j in (k + 1)..N {
+                        ab[i][j] -= ab[h][j] * f;
                     }
                 }
                 k += 1;
@@ -52,12 +52,12 @@
     // This use of MaybeUninit assumes F : Copy. Otherwise undefined behaviour may occur.
     #[cfg(feature = "nightly")]
     {
-        let mut x : [[MaybeUninit<F>; K]; M] = core::array::from_fn(|_| MaybeUninit::uninit_array::<K>() );
+        let mut x: [[MaybeUninit<F>; K]; M] = [[const { MaybeUninit::uninit() }; K]; M];
         //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 {
+                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];
@@ -71,11 +71,11 @@
     }
     #[cfg(not(feature = "nightly"))]
     {
-        let mut x : [[F; K]; M] = [[F::ZERO; K]; M];
+        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 {
+                let mut tmp = ab[i][M + 𝓁];
+                for j in (i + 1)..M {
                     tmp -= ab[i][j] * x[j][𝓁];
                 }
                 tmp /= ab[i][i];
@@ -89,12 +89,11 @@
 /// Gaussian elimination for $Ax=b$, where $A$ and $b$ are both stored in `ab`,
 /// $A \in \mathbb{R}^{M \times M}$ and $x, b \in \mathbb{R}^M$.
 #[inline]
-pub fn linsolve<F : Float, const M : usize, const N : usize>(ab : [[F; N]; M]) -> [F; M] {
-    let x : [[F; 1]; M] = linsolve0(ab);
-    unsafe { *((&x as *const [F; 1]) as *const [F; M] ) }
+pub fn linsolve<F: Float, const M: usize, const N: usize>(ab: [[F; N]; M]) -> [F; M] {
+    let x: [[F; 1]; M] = linsolve0(ab);
+    unsafe { *((&x as *const [F; 1]) as *const [F; M]) }
 }
 
-
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -103,8 +102,11 @@
     fn linsolve_test() {
         let ab1 = [[1.0, 2.0, 3.0], [2.0, 1.0, 6.0]];
         assert_eq!(linsolve(ab1), [3.0, 0.0]);
-        let ab2 = [[1.0, 2.0, 0.0, 1.0], [4.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0]];
+        let ab2 = [
+            [1.0, 2.0, 0.0, 1.0],
+            [4.0, 0.0, 0.0, 0.0],
+            [0.0, 0.0, 1.0, 0.0],
+        ];
         assert_eq!(linsolve(ab2), [0.0, 0.5, 0.0]);
     }
 }
-
--- a/src/maputil.rs	Thu Jan 23 23:38:40 2025 +0100
+++ b/src/maputil.rs	Sun Apr 27 14:48:13 2025 -0500
@@ -2,34 +2,36 @@
 Utilities for mapping over various container types.
 */
 
+use itertools::izip;
 #[cfg(feature = "nightly")]
 use std::mem::MaybeUninit;
-use itertools::izip;
 
 /// Trait for a fixed-length container type.
-/// 
+///
 /// Implemented by [`Loc`][crate::loc::Loc] vectors, [`Cube`][crate::sets::Cube]s,
 /// and basic arrays.
-pub trait FixedLength<const N : usize> {
+pub trait FixedLength<const N: usize> {
     /// Type of elements of the container.
     type Elem;
     /// Type of iterators over the elements of the container.
-    type Iter : Iterator<Item = Self::Elem>;
+    type Iter: Iterator<Item = Self::Elem>;
 
     /// Returns an iteartor over the elements of the container.
     fn fl_iter(self) -> Self::Iter;
 }
 
 /// Trait for a mutable fixed-length container type.
-pub trait FixedLengthMut<const N : usize> : FixedLength<N> {
+pub trait FixedLengthMut<const N: usize>: FixedLength<N> {
     /// Type of iterators over references to mutable elements of the container.
-    type IterMut<'a> : Iterator<Item=&'a mut Self::Elem> where Self : 'a;
+    type IterMut<'a>: Iterator<Item = &'a mut Self::Elem>
+    where
+        Self: 'a;
 
     /// Returns an iterator over mutable references to elements of the container.
     fn fl_iter_mut(&mut self) -> Self::IterMut<'_>;
 }
 
-impl<A, const N : usize> FixedLength<N> for [A; N] {
+impl<A, const N: usize> FixedLength<N> for [A; N] {
     type Elem = A;
     type Iter = std::array::IntoIter<A, N>;
     #[inline]
@@ -38,15 +40,18 @@
     }
 }
 
-impl<A, const N : usize> FixedLengthMut<N> for [A; N] {
-    type IterMut<'a> = std::slice::IterMut<'a, A> where A : 'a;
+impl<A, const N: usize> FixedLengthMut<N> for [A; N] {
+    type IterMut<'a>
+        = std::slice::IterMut<'a, A>
+    where
+        A: 'a;
     #[inline]
     fn fl_iter_mut(&mut self) -> Self::IterMut<'_> {
         self.iter_mut()
     }
 }
 
-impl<'a, A, const N : usize> FixedLength<N> for &'a [A; N] {
+impl<'a, A, const N: usize> FixedLength<N> for &'a [A; N] {
     type Elem = &'a A;
     type Iter = std::slice::Iter<'a, A>;
     #[inline]
@@ -157,10 +162,9 @@
 make_mapmany_mut!(map5_mut, map5_indexed_mut, a b c d e;   A B C D E,   CA CB CC CD CE);
 make_mapmany_mut!(map6_mut, map6_indexed_mut, a b c d e f; A B C D E F, CA CB CC CD CE CF);
 
-
 /// Initialise an array of length `N` by calling `f` multiple times.
 #[inline]
-pub fn array_init<A, F :  Fn() -> A, const N : usize>(f : F) -> [A; N] {
+pub fn array_init<A, F: Fn() -> A, const N: usize>(f: F) -> [A; N] {
     //[(); N].map(|_| f())
     core::array::from_fn(|_| f())
 }
@@ -172,17 +176,17 @@
 //     core::array::from_fn(f)
 // }
 
-
-
 /// Iterator returned by [`foldmap`][FoldMappable::foldmap] applied to an iterator.
 
-pub struct FoldMap<I : Iterator<Item=A>, A, B, J : Copy, F : Fn(J, A) -> (J, B)> {
-    iter : I,
-    f : F,
-    j : J,
+pub struct FoldMap<I: Iterator<Item = A>, A, B, J: Copy, F: Fn(J, A) -> (J, B)> {
+    iter: I,
+    f: F,
+    j: J,
 }
 
-impl<A, B, I : Iterator<Item=A>, J : Copy, F : Fn(J, A) -> (J, B)> Iterator for FoldMap<I, A, B, J, F> {
+impl<A, B, I: Iterator<Item = A>, J: Copy, F: Fn(J, A) -> (J, B)> Iterator
+    for FoldMap<I, A, B, J, F>
+{
     type Item = B;
     #[inline]
     fn next(&mut self) -> Option<B> {
@@ -195,19 +199,19 @@
 }
 
 /// Iterator returned by [`indexmap`][IndexMappable::indexmap] applied to an iterator.
-pub struct IndexMap<I : Iterator<Item=A>, A, B, F : Fn(usize, A) -> B> {
-    iter : I,
-    f : F,
-    j : usize,
+pub struct IndexMap<I: Iterator<Item = A>, A, B, F: Fn(usize, A) -> B> {
+    iter: I,
+    f: F,
+    j: usize,
 }
 
-impl<A, B, I : Iterator<Item=A>, F : Fn(usize, A) -> B> Iterator for IndexMap<I, A, B, F> {
+impl<A, B, I: Iterator<Item = A>, F: Fn(usize, A) -> B> Iterator for IndexMap<I, A, B, F> {
     type Item = B;
     #[inline]
     fn next(&mut self) -> Option<B> {
         self.iter.next().map(|a| {
             let b = (self.f)(self.j, a);
-            self.j = self.j+1;
+            self.j = self.j + 1;
             b
         })
     }
@@ -216,68 +220,90 @@
 /// Trait for things that can be foldmapped.
 ///
 /// `A` is the type of elements of `Self`, and `J` the accumulator type for the folding.
-pub trait FoldMappable<A, J> : Sized {
-    type Output<B, F> where F : Fn(J, A) -> (J, B);
+pub trait FoldMappable<A, J>: Sized {
+    type Output<B, F>
+    where
+        F: Fn(J, A) -> (J, B);
     /// Fold and map over `self` with `f`. `j` is the initial accumulator for folding.
     ///
     /// The output type depends on the implementation, but will generally have elements of
     /// type `B`.
-    fn foldmap<B, F : Fn(J, A) -> (J, B)>(self, j : J, f : F) -> Self::Output<B, F>;
+    fn foldmap<B, F: Fn(J, A) -> (J, B)>(self, j: J, f: F) -> Self::Output<B, F>;
 }
 
 /// Trait for things that can be indexmapped.
 ///
 /// `A` is the type of elements of `Self`.
-pub trait IndexMappable<A> : Sized {
-    type Output<B, F> where F : Fn(usize, A) -> B;
+pub trait IndexMappable<A>: Sized {
+    type Output<B, F>
+    where
+        F: Fn(usize, A) -> B;
     /// Map over element indices and elements of `self`.
     ///
     /// The output type depends on the implementation, but will generally have elements of
     /// type `B`.
-    fn indexmap<B, F : Fn(usize, A) -> B>(self, f : F) -> Self::Output<B, F>;
+    fn indexmap<B, F: Fn(usize, A) -> B>(self, f: F) -> Self::Output<B, F>;
 }
 
-impl<'a, A, J : Copy> FoldMappable<&'a A, J>
-for std::slice::Iter<'a, A> {
-    type Output<B, F> = FoldMap<Self, &'a A, B, J, F> where F : Fn(J, &'a A) -> (J, B);
+impl<'a, A, J: Copy> FoldMappable<&'a A, J> for std::slice::Iter<'a, A> {
+    type Output<B, F>
+        = FoldMap<Self, &'a A, B, J, F>
+    where
+        F: Fn(J, &'a A) -> (J, B);
     #[inline]
-    fn foldmap<B, F : Fn(J, &'a A) -> (J, B)>(self, j : J, f : F) -> Self::Output<B, F> {
-        FoldMap { iter : self, j, f }
+    fn foldmap<B, F: Fn(J, &'a A) -> (J, B)>(self, j: J, f: F) -> Self::Output<B, F> {
+        FoldMap { iter: self, j, f }
     }
 }
 
-impl<'a, A> IndexMappable<&'a A>
-for std::slice::Iter<'a, A> {
-    type Output<B, F> = IndexMap<Self, &'a A, B, F> where F : Fn(usize, &'a A) -> B;
+impl<'a, A> IndexMappable<&'a A> for std::slice::Iter<'a, A> {
+    type Output<B, F>
+        = IndexMap<Self, &'a A, B, F>
+    where
+        F: Fn(usize, &'a A) -> B;
     #[inline]
-    fn indexmap<B, F : Fn(usize, &'a A) -> B>(self, f : F) -> Self::Output<B, F> {
-        IndexMap { iter : self, j : 0, f }
+    fn indexmap<B, F: Fn(usize, &'a A) -> B>(self, f: F) -> Self::Output<B, F> {
+        IndexMap {
+            iter: self,
+            j: 0,
+            f,
+        }
     }
 }
 
-
-impl<A, J : Copy, const N : usize> FoldMappable<A, J>
-for std::array::IntoIter<A, N> {
-    type Output<B, F> = FoldMap<Self, A, B, J, F> where F : Fn(J, A) -> (J, B);
+impl<A, J: Copy, const N: usize> FoldMappable<A, J> for std::array::IntoIter<A, N> {
+    type Output<B, F>
+        = FoldMap<Self, A, B, J, F>
+    where
+        F: Fn(J, A) -> (J, B);
     #[inline]
-    fn foldmap<B, F : Fn(J, A) -> (J, B)>(self, j : J, f : F) -> Self::Output<B, F> {
-        FoldMap { iter : self, j, f }
+    fn foldmap<B, F: Fn(J, A) -> (J, B)>(self, j: J, f: F) -> Self::Output<B, F> {
+        FoldMap { iter: self, j, f }
     }
 }
 
-impl<'a, A, const N : usize> IndexMappable<A>
-for std::array::IntoIter<A, N> {
-    type Output<B, F> = IndexMap<Self, A, B, F> where F : Fn(usize, A) -> B;
+impl<'a, A, const N: usize> IndexMappable<A> for std::array::IntoIter<A, N> {
+    type Output<B, F>
+        = IndexMap<Self, A, B, F>
+    where
+        F: Fn(usize, A) -> B;
     #[inline]
-    fn indexmap<B, F : Fn(usize, A) -> B>(self, f : F) -> Self::Output<B, F> {
-        IndexMap { iter : self, j : 0, f }
+    fn indexmap<B, F: Fn(usize, A) -> B>(self, f: F) -> Self::Output<B, F> {
+        IndexMap {
+            iter: self,
+            j: 0,
+            f,
+        }
     }
 }
 
-impl<A, J : Copy, const N : usize> FoldMappable<A, J> for [A; N] {
-    type Output<B, F> = [B; N] where F : Fn(J, A) -> (J, B);
+impl<A, J: Copy, const N: usize> FoldMappable<A, J> for [A; N] {
+    type Output<B, F>
+        = [B; N]
+    where
+        F: Fn(J, A) -> (J, B);
     #[inline]
-    fn foldmap<B, F : Fn(J, A) -> (J, B)>(self, j : J, f : F) -> [B; N] {
+    fn foldmap<B, F: Fn(J, A) -> (J, B)>(self, j: J, f: F) -> [B; N] {
         // //let mut res : [MaybeUninit<B>; N] = unsafe { MaybeUninit::uninit().assume_init() };
         // let mut res = MaybeUninit::uninit_array::<N>();
         // for (a, i) in self.into_iter().zip(0..N) {
@@ -292,10 +318,13 @@
     }
 }
 
-impl<A, const N : usize> IndexMappable<A> for [A; N] {
-    type Output<B, F> = [B; N] where F : Fn(usize, A) -> B;
+impl<A, const N: usize> IndexMappable<A> for [A; N] {
+    type Output<B, F>
+        = [B; N]
+    where
+        F: Fn(usize, A) -> B;
     #[inline]
-    fn indexmap<B, F : Fn(usize, A) -> B>(self, f : F) -> [B; N] {
+    fn indexmap<B, F: Fn(usize, A) -> B>(self, f: F) -> [B; N] {
         // //let mut res : [MaybeUninit<B>; N] = unsafe { MaybeUninit::uninit().assume_init() };
         // let mut res = MaybeUninit::uninit_array::<N>();
         // for (a, i) in self.into_iter().zip(0..N) {
@@ -325,12 +354,9 @@
 /// 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.
         return unsafe { core::mem::zeroed() };
@@ -348,22 +374,28 @@
 
             // SAFETY: this slice will contain only initialized objects.
             unsafe {
-                core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
-                    &mut self.array_mut.get_unchecked_mut(..self.initialized),
-                ));
+                for elem in self.array_mut.get_unchecked_mut(..self.initialized) {
+                    elem.assume_init_drop();
+                }
             }
         }
     }
 
-    let mut array = MaybeUninit::uninit_array::<N>();
-    let mut guard = Guard { array_mut: &mut array, initialized: 0 };
+    let mut array = [const { MaybeUninit::uninit() }; N];
+    let mut guard = Guard {
+        array_mut: &mut array,
+        initialized: 0,
+    };
 
     while let Some(item) = iter.next() {
         // SAFETY: `guard.initialized` starts at 0, is increased by one in the
         // loop and the loop is aborted once it reaches N (which is
         // `array.len()`).
         unsafe {
-            guard.array_mut.get_unchecked_mut(guard.initialized).write(item);
+            guard
+                .array_mut
+                .get_unchecked_mut(guard.initialized)
+                .write(item);
         }
         guard.initialized += 1;
 
@@ -383,12 +415,9 @@
 
 #[cfg(not(feature = "nightly"))]
 #[inline]
-pub(crate) fn collect_into_array_unchecked<
-    T,
-    I : Iterator<Item=T>,
-    const N: usize
->(iter: I) -> [T; N]
-{
+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"),
@@ -401,12 +430,12 @@
 
     #[test]
     fn mapx_test() {
-        let a = [0,1,2];
-        let mut b = [2,1,0];
-        assert_eq!(map1(a, |x| x+1), [1,2,3]);
-        assert_eq!(map2(a, b, |x, y| x+y), [2,2,2]);
-        assert_eq!(map1_indexed(a, |i, y| y-i), [0,0,0]);
-        map1_indexed_mut(&mut b, |i, y| *y=i);
+        let a = [0, 1, 2];
+        let mut b = [2, 1, 0];
+        assert_eq!(map1(a, |x| x + 1), [1, 2, 3]);
+        assert_eq!(map2(a, b, |x, y| x + y), [2, 2, 2]);
+        assert_eq!(map1_indexed(a, |i, y| y - i), [0, 0, 0]);
+        map1_indexed_mut(&mut b, |i, y| *y = i);
         assert_eq!(b, a);
     }
 }

mercurial