num_traits::float::TotalOrder to Float trait bounds. Remove NaNLeast.

Tue, 07 Jul 2026 11:53:22 +0300

author
Tuomo Valkonen <tuomov@iki.fi>
date
Tue, 07 Jul 2026 11:53:22 +0300
changeset 199
32f5062ee477
parent 198
3868555d135c
child 200
fbd4791f16bc

num_traits::float::TotalOrder to Float trait bounds. Remove NaNLeast.

Cargo.lock file | annotate | diff | comparison | revisions
Cargo.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/nanleast.rs file | annotate | diff | comparison | revisions
src/types.rs file | annotate | diff | comparison | revisions
--- a/Cargo.lock	Fri May 15 14:46:30 2026 -0500
+++ b/Cargo.lock	Tue Jul 07 11:53:22 2026 +0300
@@ -4,7 +4,7 @@
 
 [[package]]
 name = "alg_tools"
-version = "0.4.1-dev"
+version = "0.5.1-dev"
 dependencies = [
  "anyhow",
  "colored",
--- a/Cargo.toml	Fri May 15 14:46:30 2026 -0500
+++ b/Cargo.toml	Tue Jul 07 11:53:22 2026 +0300
@@ -1,6 +1,6 @@
 [package]
 name = "alg_tools"
-version = "0.4.1-dev"
+version = "0.5.1-dev"
 edition = "2021"
 rust-version = "1.85"
 authors = ["Tuomo Valkonen <tuomov@iki.fi>"]
--- a/src/bisection_tree/refine.rs	Fri May 15 14:46:30 2026 -0500
+++ b/src/bisection_tree/refine.rs	Tue Jul 07 11:53:22 2026 +0300
@@ -1,12 +1,12 @@
 use super::aggregator::*;
 use super::bt::*;
 use super::support::*;
-use crate::nanleast::NaNLeast;
 use crate::parallelism::TaskBudget;
 use crate::parallelism::{thread_pool, thread_pool_size};
 use crate::sets::Cube;
 use crate::types::*;
-use std::cmp::{max, Ord, Ordering, Ordering::*, PartialOrd};
+use num_traits::float::TotalOrder;
+use std::cmp::{Ord, Ordering, Ordering::*, PartialOrd};
 use std::collections::BinaryHeap;
 use std::marker::PhantomData;
 use std::sync::{Arc, Condvar, Mutex, MutexGuard};
@@ -19,7 +19,11 @@
 pub trait AggregatorSorting: Sync + Send + 'static {
     // Priority
     type Agg: Aggregator;
-    type Sort: Ord + Copy + std::fmt::Debug + Sync + Send;
+    /// This is temporarily a Float, after removal of NanLeast, to use [
+    /// `num_traits::float::TotalOrder`] and [`num_traits::float::Float::max`].
+    /// It should be generalised by introducing a general PseudoTotalOrder trait
+    /// (because Rust's standard one is not implemented for `Float`s)
+    type Sort: Float + Copy + std::fmt::Debug + Sync + Send;
 
     /// Returns lower sorting key
     fn sort_lower(aggregator: &Self::Agg) -> Self::Sort;
@@ -43,41 +47,41 @@
 
 impl<F: Float> AggregatorSorting for UpperBoundSorting<F> {
     type Agg = Bounds<F>;
-    type Sort = NaNLeast<F>;
+    type Sort = F;
 
     #[inline]
     fn sort_lower(aggregator: &Bounds<F>) -> Self::Sort {
-        NaNLeast(aggregator.lower())
+        aggregator.lower()
     }
 
     #[inline]
     fn sort_upper(aggregator: &Bounds<F>) -> Self::Sort {
-        NaNLeast(aggregator.upper())
+        aggregator.upper()
     }
 
     #[inline]
     fn bottom() -> Self::Sort {
-        NaNLeast(F::NEG_INFINITY)
+        F::NEG_INFINITY
     }
 }
 
 impl<F: Float> AggregatorSorting for LowerBoundSorting<F> {
     type Agg = Bounds<F>;
-    type Sort = NaNLeast<F>;
+    type Sort = F;
 
     #[inline]
     fn sort_upper(aggregator: &Bounds<F>) -> Self::Sort {
-        NaNLeast(-aggregator.lower())
+        -aggregator.lower()
     }
 
     #[inline]
     fn sort_lower(aggregator: &Bounds<F>) -> Self::Sort {
-        NaNLeast(-aggregator.upper())
+        -aggregator.upper()
     }
 
     #[inline]
     fn bottom() -> Self::Sort {
-        NaNLeast(F::NEG_INFINITY)
+        F::NEG_INFINITY
     }
 }
 
@@ -240,9 +244,11 @@
     #[inline]
     fn cmp(&self, other: &Self) -> Ordering {
         self.with_aggregator(|agg1| {
-            other.with_aggregator(|agg2| match S::sort_upper(agg1).cmp(&S::sort_upper(agg2)) {
-                Equal => S::sort_lower(agg1).cmp(&S::sort_lower(agg2)),
-                order => order,
+            other.with_aggregator(|agg2| {
+                match S::sort_upper(agg1).total_cmp(&S::sort_upper(agg2)) {
+                    Equal => S::sort_lower(agg1).total_cmp(&S::sort_lower(agg2)),
+                    order => order,
+                }
             })
         })
     }
@@ -318,12 +324,7 @@
     {
         // Insert all subnodes into the refinement heap.
         for (node, cube) in self.nodes_and_cubes_mut(&domain) {
-            container.push(RefinementInfo {
-                cube,
-                node,
-                refiner_info: None,
-                sorting: PhantomData,
-            });
+            container.push(RefinementInfo { cube, node, refiner_info: None, sorting: PhantomData });
         }
     }
 }
@@ -540,7 +541,12 @@
         // Do priority queue maintenance
         if container.insert_counter > container.heap_prune_threshold {
             // Make sure glb is good.
-            match container.heap.iter().map(|ri| ri.sort_lower()).reduce(max) {
+            match container
+                .heap
+                .iter()
+                .map(|ri| ri.sort_lower())
+                .reduce(num_traits::Float::max)
+            {
                 Some(glb) => {
                     container.glb = glb;
                     // Prune
--- a/src/lib.rs	Fri May 15 14:46:30 2026 -0500
+++ b/src/lib.rs	Tue Jul 07 11:53:22 2026 +0300
@@ -23,7 +23,6 @@
 pub mod euclidean;
 pub mod instance;
 pub mod maputil;
-pub mod nanleast;
 pub mod norms;
 pub mod parallelism;
 pub mod tuple;
--- a/src/nanleast.rs	Fri May 15 14:46:30 2026 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*!
-This module provides an artificial total order of floating point numbers.
-
-The [`NaNLeast`]`<F>` container for `F` a [`Float`] puts `F` in an [`Ord`] total order with
-`NaN` the least element. This allows the numbers to be sorted with `NaN` the “least important”
-element when looking for the maximum. Thus erroneous computations producing `NaN` can be ignored
-when there are good results.
-*/
-
-use crate::types::Float;
-use std::cmp::{PartialOrd,Ord,Ordering,Ordering::*};
-
-/// A container for floating point numbers. 
-///
-/// The implementation of [`Ord`] for this type type sorts `NaN` as the least element.
-#[derive(Debug, Clone, Copy)]
-pub struct NaNLeast<F : Float>(pub F);
-
-impl<F : Float> Ord for NaNLeast<F> {
-    #[inline]
-    fn cmp(&self, NaNLeast(b) : &Self) -> Ordering {
-        let NaNLeast(a) = self;
-        match a.partial_cmp(b) {
-            None => match (a.is_nan(), b.is_nan()) {
-                (true, false) => Less,
-                (false, true) => Greater,
-                _ => Equal // The case (true, true) should not occur!
-            }
-            Some(order) => order
-        }
-    }
-}
-
-impl<F : Float> PartialEq for NaNLeast<F> {
-    #[inline]
-    fn eq(&self, other : &Self) -> bool { self.cmp(other)==Equal }
-}
-
-impl<F : Float> Eq for NaNLeast<F> { }
-
-impl<F : Float> PartialOrd for NaNLeast<F> {
-    #[inline]
-    fn partial_cmp(&self, other : &Self) -> Option<Ordering> { Some(self.cmp(other)) }
-}
--- a/src/types.rs	Fri May 15 14:46:30 2026 -0500
+++ b/src/types.rs	Tue Jul 07 11:53:22 2026 +0300
@@ -11,6 +11,7 @@
 
 //use trait_set::trait_set;
 pub use num_traits::cast::AsPrimitive;
+pub use num_traits::float::TotalOrder;
 pub use num_traits::Float as NumTraitsFloat; // needed to re-export functions.
 
 pub use simba::scalar::{
@@ -97,7 +98,10 @@
 impl<U: Num + num::Signed + std::ops::Neg<Output = Self>> SignedNum for U {}
 
 /// Trait for floating point numbers
-pub trait Float: SignedNum + std::fmt::LowerExp + num::Float /*+ From<Self::CompatibleSize>*/ {
+pub trait Float:
+    SignedNum + std::fmt::LowerExp + num::Float + num_traits::float::TotalOrder
+/*+ From<Self::CompatibleSize>*/
+{
     // An unsigned integer that can be used for indexing operations and
     // converted to F without loss.
     //type CompatibleSize : CompatibleUnsigned<Self>;

mercurial