Migrating generic programming to version 0.26+

Question

Hi there,

I heavily rely on nalgebra’s generic programming to simplify some relatively complex scientific code. Specifically, I define a State which has types for its state size as DimName (and other fields). This StateSize is then used in a Dynamics trait, which defines the equations of motion of a system. That same StateSize is also used in the Propagator.

It is my understanding that now, with generic programming, I’ll need to “propagate” the constants (cf. examples below).

For example, the following EventEvaluator trait, which is typed by a generic State, now needs to know the const _: usize of all its children. is that correct? Is there a cleaner and less verbose method?

Really, what I’d like to do is something similar to this, but it fails on the stable branch of Rust:

where
    Self: Sized,
{
    /// Size of the state and its STM
    const SIZE: usize;
    
    fn info(&self) -> [u8; Self::SIZE];
}

Any help is appreciated, thanks.

Prior implementation

pub trait EventEvaluator<S: State>: fmt::Display + Send + Sync
where
    DefaultAllocator: Allocator<f64, S::Size>,
{
/* ... */
}

New implementation

pub trait EventEvaluator<S: State<Z, T>, const Z: usize, const T: usize>:
    fmt::Display + Send + Sync { /* ... */ }

For reference

State (prior to 0.26)

pub trait State:
    TimeTagged + Copy + Clone + PartialEq + fmt::Display + fmt::LowerExp + Send + Sync
where
    Self: Sized,
    DefaultAllocator: Allocator<f64, Self::Size>,
{
    /// Size of the state and its STM
    type Size: DimName;
    type PropVecSize: DimName;
 /* ... */
}

State after update

pub trait State<const SIZE: usize, const VEC_LENGTH: usize>:
    TimeTagged + Copy + Clone + PartialEq + fmt::Display + fmt::LowerExp + Send + Sync
where
    Self: Sized,
{
/* ... */
}

Hi!

Yes, you will likely have to propagate const parameters the way you did because associated consts will be too limited for your use. However, if you are using matrices/vectors from nalgebra, you can still use your old system with the DimName bound, and usefor example Const<3> as the dimension type parameter.

1 Like

Hi!

Excellent, thank you for your quick response, this worked.

To clarify for others, I opted for using an OVector. The changes from VectorN are very minimal.

pub trait State:
    TimeTagged + Copy + Clone + PartialEq + fmt::Display + fmt::LowerExp + Send + Sync
where
    Self: Sized,
    DefaultAllocator: Allocator<f64, Self::Size>
        + Allocator<f64, Self::Size, Self::Size>
        + Allocator<f64, Self::VecLength>,
{
    /// Size of the state and its STM
    type Size: DimName;
    type VecLength: DimName;
    /// Initialize an empty state
    fn zeros() -> Self;

    /// Return this state as a vector for the propagation/estimation
    fn as_vector(&self) -> Result<OVector<f64, Self::VecLength>, NyxError>;
    /* ... */
}