# HG changeset patch # User Tuomo Valkonen # Date 1736213365 18000 # Node ID d5b0e496b72f0b65df2ac7f7fc513798cbbc1d48 # Parent 99ad55974e6201c1cd913dfe651a7fbf7848b2b1 More Serialize / Deserialize / Debug derives diff -r 99ad55974e62 -r d5b0e496b72f Cargo.toml --- a/Cargo.toml Mon Dec 30 15:46:28 2024 -0500 +++ b/Cargo.toml Mon Jan 06 20:29:25 2025 -0500 @@ -12,7 +12,7 @@ categories = ["mathematics", "data-structures"] [dependencies] -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "rc"] } csv = "~1.3.1" nalgebra = "~0.33.0" num-traits = { version = "~0.2.14", features = ["std"] } diff -r 99ad55974e62 -r d5b0e496b72f src/bisection_tree/aggregator.rs --- a/src/bisection_tree/aggregator.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/bisection_tree/aggregator.rs Mon Jan 06 20:29:25 2025 -0500 @@ -2,6 +2,7 @@ Aggregation / summarisation of information in branches of bisection trees. */ +use serde::{Serialize, Deserialize}; use crate::types::*; use crate::sets::Set; use crate::instance::Instance; @@ -33,7 +34,7 @@ } /// An [`Aggregator`] that doesn't aggregate anything. -#[derive(Clone,Debug)] +#[derive(Clone,Debug,Serialize,Deserialize)] pub struct NullAggregator; impl Aggregator for NullAggregator { @@ -47,7 +48,7 @@ } /// Upper and lower bounds on an `F`-valued function. -#[derive(Copy,Clone,Debug)] +#[derive(Copy,Clone,Debug,Serialize,Deserialize)] pub struct Bounds( /// Lower bound pub F, diff -r 99ad55974e62 -r d5b0e496b72f src/bisection_tree/bt.rs --- a/src/bisection_tree/bt.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/bisection_tree/bt.rs Mon Jan 06 20:29:25 2025 -0500 @@ -43,7 +43,13 @@ /// Node of a [`BT`] bisection tree. /// /// For the type and const parameteres, see the [module level documentation][super]. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound( + serialize = "NodeOption : Serialize, + A : Serialize,", + deserialize = "NodeOption : for<'a> Deserialize<'a>, + A : for<'a> Deserialize<'a>," +))] pub struct Node { /// The data or branches under the node. pub(super) data : NodeOption, @@ -54,7 +60,13 @@ /// Branching information of a [`Node`] of a [`BT`] bisection tree into `P` subnodes. /// /// For the type and const parameters, see the [module level documentation][super]. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound( + serialize = "[Node; P] : Serialize, + Loc : Serialize,", + deserialize = "[Node; P] : for<'a> Deserialize<'a>, + Loc : for<'a> Deserialize<'a>," +))] pub(super) struct Branches { /// Point for subdivision of the (unstored) [`Cube`] corresponding to the node. pub(super) branch_at : Loc, @@ -198,6 +210,7 @@ } /// An iterator over the $P=2^N$ subcubes of a [`Cube`] subdivided at a point `d`. +#[derive(Debug, Clone)] pub(super) struct SubcubeIter<'b, F : Float, const N : usize, const P : usize> { domain : &'b Cube, branch_at : Loc, @@ -637,7 +650,15 @@ /// It should be accessed via the [`BTImpl`] trait to hide the `const P : usize` parameter until /// const generics are flexible enough to fix `P=pow(2, N)` and thus also get rid of /// the `BTNodeLookup : BTNode` trait bound. -#[derive(Clone,Debug)] +#[derive(Clone,Debug,Serialize,Deserialize)] +#[serde(bound( + serialize = "Cube : Serialize, + M : Serialize, + >::Node : Serialize,", + deserialize = "Cube : for<'a> Deserialize<'a>, + M : for<'a> Deserialize<'a>, + >::Node : for<'a> Deserialize<'a>," +))] pub struct BT< M : Depth, F : Float, diff -r 99ad55974e62 -r d5b0e496b72f src/bisection_tree/btfn.rs --- a/src/bisection_tree/btfn.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/bisection_tree/btfn.rs Mon Jan 06 20:29:25 2025 -0500 @@ -1,5 +1,6 @@ use numeric_literals::replace_float_literals; +use serde::{Serialize, Deserialize}; use std::iter::Sum; use std::marker::PhantomData; use std::sync::Arc; @@ -30,7 +31,7 @@ /// Identifiers of the components ([`SupportGenerator::Id`], usually `usize`) are stored stored /// in a [bisection tree][BTImpl], when one is provided as `bt`. However `bt` may also be `()` /// for a [`PreBTFN`] that is only useful for vector space operations with a full [`BTFN`]. -#[derive(Clone,Debug)] +#[derive(Clone,Debug,Serialize,Deserialize)] pub struct BTFN< F : Float, G : SupportGenerator, @@ -39,6 +40,7 @@ > /*where G::SupportType : LocalAnalysis*/ { bt : BT, generator : Arc, + #[serde(skip)] _phantoms : PhantomData, } @@ -587,14 +589,17 @@ } /// Helper type to use [`P2Refiner`] for maximisation. +#[derive(Debug, Clone, Serialize, Deserialize)] struct RefineMax; /// Helper type to use [`P2Refiner`] for minimisation. +#[derive(Debug, Clone, Serialize, Deserialize)] struct RefineMin; /// A bisection tree [`Refiner`] for maximising or minimising a [`BTFN`]. /// /// The type parameter `T` should be either [`RefineMax`] or [`RefineMin`]. +#[derive(Debug, Clone, Serialize, Deserialize)] struct P2Refiner { /// The maximum / minimum should be above / below this threshold. /// If the threshold cannot be satisfied, the refiner will return `None`. @@ -733,6 +738,7 @@ /// The type parameter `T` should be either [`RefineMax`] for upper bound or [`RefineMin`] /// for lower bound. +#[derive(Debug, Clone, Serialize, Deserialize)] struct BoundRefiner { /// The upper/lower bound to check for bound : F, diff -r 99ad55974e62 -r d5b0e496b72f src/bisection_tree/either.rs --- a/src/bisection_tree/either.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/bisection_tree/either.rs Mon Jan 06 20:29:25 2025 -0500 @@ -1,6 +1,7 @@ use std::iter::Chain; use std::sync::Arc; +use serde::{Serialize, Deserialize}; use crate::types::*; use crate::mapping::{ @@ -20,7 +21,7 @@ /// A structure for storing two [`SupportGenerator`]s summed/chain together. /// /// This is needed to work with sums of different types of [`Support`]s. -#[derive(Debug,Clone)] +#[derive(Debug,Clone,Serialize,Deserialize)] pub struct BothGenerators( pub(super) Arc, pub(super) Arc, @@ -29,7 +30,7 @@ /// A structure for a [`Support`] that can be either `A` or `B`. /// /// This is needed to work with sums of different types of [`Support`]s. -#[derive(Debug,Clone)] +#[derive(Debug,Clone,Serialize,Deserialize)] pub enum EitherSupport { Left(A), Right(B), diff -r 99ad55974e62 -r d5b0e496b72f src/bisection_tree/refine.rs --- a/src/bisection_tree/refine.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/bisection_tree/refine.rs Mon Jan 06 20:29:25 2025 -0500 @@ -3,6 +3,7 @@ use std::cmp::{PartialOrd, Ord, Ordering, Ordering::*, max}; use std::marker::PhantomData; use std::sync::{Arc, Mutex, MutexGuard, Condvar}; +use serde::{Serialize, Deserialize}; use crate::types::*; use crate::nanleast::NaNLeast; use crate::sets::Cube; @@ -35,12 +36,20 @@ /// An [`AggregatorSorting`] for [`Bounds`], using the upper/lower bound as the upper/lower key. /// /// See [`LowerBoundSorting`] for the opposite ordering. -pub struct UpperBoundSorting(PhantomData); +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct UpperBoundSorting( + #[serde(skip)] + PhantomData +); /// An [`AggregatorSorting`] for [`Bounds`], using the upper/lower bound as the lower/upper key. /// /// See [`UpperBoundSorting`] for the opposite ordering. -pub struct LowerBoundSorting(PhantomData); +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LowerBoundSorting( + #[serde(skip)] + PhantomData +); impl AggregatorSorting for UpperBoundSorting { type Agg = Bounds; @@ -136,6 +145,7 @@ } /// Structure for tracking the refinement process in a [`BinaryHeap`]. +#[derive(Debug)] struct RefinementInfo<'a, F, D, A, S, RResult, const N : usize, const P : usize> where F : Float, D : 'static, @@ -228,6 +238,7 @@ /// This is a container for a [`BinaryHeap`] of [`RefinementInfo`]s together with tracking of /// the greatest lower bound of the [`Aggregator`]s of the [`Node`]s therein accroding to /// chosen [`AggregatorSorting`]. +#[derive(Debug)] struct HeapContainer<'a, F, D, A, S, RResult, const N : usize, const P : usize> where F : Float, D : 'static + Copy, diff -r 99ad55974e62 -r d5b0e496b72f src/bisection_tree/support.rs --- a/src/bisection_tree/support.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/bisection_tree/support.rs Mon Jan 06 20:29:25 2025 -0500 @@ -2,7 +2,7 @@ /*! Traits for representing the support of a [`Mapping`], and analysing the mapping on a [`Cube`]. */ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use std::ops::{MulAssign,DivAssign,Neg}; use crate::types::{Float, Num}; use crate::maputil::map2; @@ -103,7 +103,13 @@ impl>> Bounded for T { } /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`]. -#[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. +#[derive(Copy,Clone,Debug,Serialize,Deserialize)] +#[serde(bound( + serialize = "Loc : Serialize, + T : Serialize,", + deserialize = "Loc : for<'a> Deserialize<'a>, + T : for<'a> Deserialize<'a>", +))] pub struct Shift { shift : Loc, base_fn : T, diff -r 99ad55974e62 -r d5b0e496b72f src/convex.rs --- a/src/convex.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/convex.rs Mon Jan 06 20:29:25 2025 -0500 @@ -3,6 +3,7 @@ */ use std::marker::PhantomData; +use serde::{Serialize, Deserialize}; use crate::types::*; use crate::mapping::{Mapping, Space}; use crate::linops::IdOp; @@ -68,6 +69,7 @@ } +#[derive(Serialize,Deserialize,Debug,Clone)] pub struct NormConstraint { radius : F, norm : NormMapping, @@ -160,6 +162,7 @@ } } +#[derive(Serialize,Deserialize,Debug,Clone)] pub struct NormProjection { radius : F, exponent : E, @@ -194,7 +197,11 @@ /// The zero mapping -pub struct Zero(PhantomData<(Domain, F)>); +#[derive(Serialize,Deserialize,Debug,Clone)] +pub struct Zero( + #[serde(skip)] + PhantomData<(Domain, F)> +); impl Zero { pub fn new() -> Self { @@ -247,7 +254,11 @@ /// The zero indicator -pub struct ZeroIndicator(PhantomData<(Domain, F)>); +#[derive(Serialize,Deserialize,Debug,Clone)] +pub struct ZeroIndicator( + #[serde(skip)] + PhantomData<(Domain, F)> +); impl ZeroIndicator { pub fn new() -> Self { diff -r 99ad55974e62 -r d5b0e496b72f src/discrete_gradient.rs --- a/src/discrete_gradient.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/discrete_gradient.rs Mon Jan 06 20:29:25 2025 -0500 @@ -2,6 +2,7 @@ Simple disrete gradient operators */ use numeric_literals::replace_float_literals; +use serde::{Serialize, Deserialize}; use nalgebra::{ DVector, Matrix, U1, Storage, StorageMut, Dyn }; @@ -10,23 +11,32 @@ use crate::linops::{Mapping, Linear, BoundedLinear, Adjointable, GEMV}; use crate::norms::{Norm, L2}; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] /// Forward differences with Neumann boundary conditions pub struct ForwardNeumann; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] /// Forward differences with Dirichlet boundary conditions pub struct ForwardDirichlet; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] /// Backward differences with Dirichlet boundary conditions pub struct BackwardDirichlet; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] /// Backward differences with Neumann boundary conditions pub struct BackwardNeumann; /// Finite differences gradient +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound( + serialize = "[usize; N] : Serialize, + B : Serialize, + F : Serialize,", + deserialize = "[usize; N] : for<'a> Deserialize<'a>, + B : for<'a> Deserialize<'a>, + F : for<'a> Deserialize<'a>," +))] pub struct Grad< F : Float + nalgebra::RealField, B : Discretisation, diff -r 99ad55974e62 -r d5b0e496b72f src/fe_model/p2_local_model.rs --- a/src/fe_model/p2_local_model.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/fe_model/p2_local_model.rs Mon Jan 06 20:29:25 2025 -0500 @@ -2,6 +2,7 @@ Second order polynomical (P2) models on real intervals and planar 2D simplices. */ +use serde::{Serialize, Deserialize}; use crate::types::*; use crate::loc::Loc; use crate::sets::{Set,NPolygon,SpannedHalfspace}; @@ -16,6 +17,11 @@ /// /// The type parameter `D` indicates the number of nodes. (Rust's const generics do not currently /// allow its automatic calculation from `N`.) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(bound( + serialize = "[Loc; D] : Serialize", + deserialize = "[Loc; D] : for<'a> Deserialize<'a>", +))] pub struct Simplex(pub [Loc; D]); /// A two-dimensional planar simplex pub type PlanarSimplex = Simplex; @@ -119,6 +125,15 @@ } /// A local second order polynomical model of dimension `N` with `E` edges +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(bound( + serialize = "F : Serialize, + Loc : Serialize, + Loc : Serialize", + deserialize = "F : for<'a> Deserialize<'a>, + Loc : for<'a> Deserialize<'a>, + Loc : for<'a> Deserialize<'a>", +))] pub struct P2LocalModel { a0 : F, a1 : Loc, diff -r 99ad55974e62 -r d5b0e496b72f src/loc.rs --- a/src/loc.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/loc.rs Mon Jan 06 20:29:25 2025 -0500 @@ -13,14 +13,18 @@ use crate::linops::{AXPY, Mapping, Linear}; use crate::instance::{Instance, BasicDecomposition}; use crate::mapping::Space; -use serde::ser::{Serialize, Serializer, SerializeSeq}; +use serde::{Serialize, Deserialize}; /// A container type for (short) `N`-dimensional vectors of element type `F`. /// /// Supports basic operations of an [`Euclidean`] space, several [`Norm`]s, and /// fused [`AXPY`] operations, among others. -#[derive(Copy,Clone,Debug,PartialEq,Eq)] +#[derive(Copy,Clone,Debug,PartialEq,Eq,Serialize,Deserialize)] +#[serde(bound( + serialize = "[F; N] : Serialize", + deserialize = "[F; N] : for<'a> Deserialize<'a>" +))] pub struct Loc( /// An array of the elements of the vector pub [F; N] @@ -39,23 +43,6 @@ } } -// Need to manually implement as [F; N] serialisation is provided only for some N. -impl Serialize for Loc -where - F: Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(Some(N))?; - for e in self.iter() { - seq.serialize_element(e)?; - } - seq.end() - } -} - impl Loc { /// Creates a new `Loc` vector from an array. #[inline] diff -r 99ad55974e62 -r d5b0e496b72f src/norms.rs --- a/src/norms.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/norms.rs Mon Jan 06 20:29:25 2025 -0500 @@ -2,7 +2,7 @@ Norms, projections, etc. */ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use std::marker::PhantomData; use crate::types::*; use crate::euclidean::*; @@ -12,10 +12,11 @@ // Abstract norms // -#[derive(Copy,Clone,Debug)] +#[derive(Copy,Clone,Debug, Serialize, Deserialize)] /// Helper structure to convert a [`NormExponent`] into a [`Mapping`] pub struct NormMapping{ pub(crate) exponent : E, + #[serde(skip)] _phantoms : PhantomData } @@ -30,29 +31,29 @@ } /// Exponent type for the 1-[`Norm`]. -#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +#[derive(Copy,Debug,Clone,Serialize,Deserialize,Eq,PartialEq)] pub struct L1; impl NormExponent for L1 {} /// Exponent type for the 2-[`Norm`]. -#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +#[derive(Copy,Debug,Clone,Serialize,Deserialize,Eq,PartialEq)] pub struct L2; impl NormExponent for L2 {} /// Exponent type for the ∞-[`Norm`]. -#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +#[derive(Copy,Debug,Clone,Serialize,Deserialize,Eq,PartialEq)] pub struct Linfinity; impl NormExponent for Linfinity {} /// Exponent type for 2,1-[`Norm`]. /// (1-norm over a domain Ω, 2-norm of a vector at each point of the domain.) -#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +#[derive(Copy,Debug,Clone,Serialize,Deserialize,Eq,PartialEq)] pub struct L21; impl NormExponent for L21 {} /// Norms for pairs (a, b). ‖(a,b)‖ = ‖(‖a‖_A, ‖b‖_B)‖_J /// For use with [`crate::direct_product::Pair`] -#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +#[derive(Copy,Debug,Clone,Serialize,Deserialize,Eq,PartialEq)] pub struct PairNorm(pub A, pub B, pub J); impl NormExponent for PairNorm @@ -63,7 +64,7 @@ /// /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher /// values more smoothing. Behaviour with γ < 0 is undefined. -#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +#[derive(Copy,Debug,Clone,Serialize,Deserialize,Eq,PartialEq)] pub struct HuberL1(pub F); impl NormExponent for HuberL1 {} @@ -71,7 +72,7 @@ /// /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher /// values more smoothing. Behaviour with γ < 0 is undefined. -#[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] +#[derive(Copy,Debug,Clone,Serialize,Deserialize,Eq,PartialEq)] pub struct HuberL21(pub F); impl NormExponent for HuberL21 {} diff -r 99ad55974e62 -r d5b0e496b72f src/operator_arithmetic.rs --- a/src/operator_arithmetic.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/operator_arithmetic.rs Mon Jan 06 20:29:25 2025 -0500 @@ -2,7 +2,7 @@ Arithmetic of [`Mapping`]s. */ -use serde::Serialize; +use serde::{Serialize, Deserialize}; use crate::types::*; use crate::instance::{Space, Instance}; use crate::mapping::{Mapping, DifferentiableImpl, DifferentiableMapping}; @@ -22,7 +22,7 @@ } /// Weighting of a [`Mapping`] by scalar multiplication. -#[derive(Copy,Clone,Debug,Serialize)] +#[derive(Copy,Clone,Debug,Serialize,Deserialize)] pub struct Weighted { /// The weight pub weight : C, @@ -73,7 +73,7 @@ } /// A sum of [`Mapping`]s. -#[derive(Serialize, Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct MappingSum(Vec); impl< M> MappingSum { diff -r 99ad55974e62 -r d5b0e496b72f src/sets.rs --- a/src/sets.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/sets.rs Mon Jan 06 20:29:25 2025 -0500 @@ -7,7 +7,7 @@ use crate::loc::Loc; use crate::euclidean::Euclidean; use crate::instance::{Space, Instance}; -use serde::Serialize; +use serde::{Serialize, Deserialize}; pub mod cube; pub use cube::Cube; @@ -62,7 +62,7 @@ /// /// The halfspace is $H = \\{ t v + a \mid a^⊤ v = 0 \\}$, where $v$ is the orthogonal /// vector and $t$ the offset. -#[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] +#[derive(Clone,Copy,Debug,Serialize,Deserialize,Eq,PartialEq)] pub struct Halfspace where A : Euclidean, F : Float { pub orthogonal : A, pub offset : F, @@ -116,7 +116,11 @@ } /// Polygons defined by `N` `Halfspace`s. -#[derive(Clone,Copy,Debug,Eq,PartialEq)] +#[derive(Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize)] +#[serde(bound( + serialize = "[Halfspace; N] : Serialize", + deserialize = "[Halfspace; N] : for<'a> Deserialize<'a>" +))] pub struct NPolygon(pub [Halfspace; N]) where A : Euclidean, F : Float; diff -r 99ad55974e62 -r d5b0e496b72f src/sets/cube.rs --- a/src/sets/cube.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/sets/cube.rs Mon Jan 06 20:29:25 2025 -0500 @@ -16,7 +16,7 @@ ``` */ -use serde::ser::{Serialize, Serializer, SerializeTupleStruct}; +use serde::{Serialize, Deserialize}; use crate::types::*; use crate::loc::Loc; use crate::sets::SetOrd; @@ -30,25 +30,14 @@ /// A multi-dimensional cube $∏_{i=1}^N [a_i, b_i)$ with the starting and ending points /// along $a_i$ and $b_i$ along each dimension of type `U`. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Cube(pub(super) [[U; 2]; N]); - -// Need to manually implement as [F; N] serialisation is provided only for some N. -impl Serialize for Cube -where - F: Serialize, -{ - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut ts = serializer.serialize_tuple_struct("Cube", N)?; - for e in self.0.iter() { - ts.serialize_field(e)?; - } - ts.end() - } -} +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[serde(bound( + serialize = "[[U; 2]; N] : Serialize", + deserialize = "[[U; 2]; N] : for<'a> Deserialize<'a>", +))] +pub struct Cube( + pub(super) [[U; 2]; N] +); impl FixedLength for Cube { type Iter = std::array::IntoIter<[A; 2], N>; diff -r 99ad55974e62 -r d5b0e496b72f src/types.rs --- a/src/types.rs Mon Dec 30 15:46:28 2024 -0500 +++ b/src/types.rs Mon Jan 06 20:29:25 2025 -0500 @@ -60,7 +60,8 @@ /// Trait for general numeric types pub trait Num : 'static + Copy + Sync + Send + num::Num + num_traits::NumAssign + std::iter::Sum + std::iter::Product - + std::fmt::Debug + std::fmt::Display + serde::Serialize + + std::fmt::Debug + std::fmt::Display + + serde::Serialize + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom