Statically typed matrices whose size is a multiple or another one?

Hi there,

I’ve got a matrix of size SS and another matrix of size MS. Both are allocated as MatrixMNs.

I need to stack both matrices as

[ [S*S] ]
[ [M*S] ]

How can I initialize a MatrixMN that way? I need keep the generics in the structure which stores these matrices (I use those generics a lot). For the first implementation, I’ll be using a DMatrix.

Thanks

Hi!

So if I understand correctly, you want your final matrix of size (S + M) × S to be a DMatrix?
It would be interesting to add to nalgebra methods to stack matrices that way.

Anyway, to get this DMatrix, you can do something like (assuming S and M are the type-level dimension numbers while s and m are their usize values):

let mut stacked = DMatrix::zeros(s + m, s);
stacked.fixed_slice_mut::<S, S>(0, 0).copy_from(&matrix_ss);
stacked.fixed_slice_mut::<M, S>(s, 0).copy_from(&matrix_ms);

If you want a statically-sized matrix instead of DMatrix, you can do:

use nalgebra::dimension::DimNameSum;

let mut stacked = MatrixMN::<N, DimNameSum<S, M>, S>::zeros(s + m, s);
stacked.fixed_slice_mut::<S, S>(0, 0).copy_from(&matrix_ss);
stacked.fixed_slice_mut::<M, S>(s, 0).copy_from(&matrix_ms);
1 Like

Excellent thanks. I was looking for the second example.

And just to make sure I understand, MatrixNM is statically allocated too, because it’s statically sized, right? And DMatrix is dynamically allocated, is that correct ?

Yes, as long as the dimensions given to MatrixMN are not Dynamic, it will be statically allocated. The DMatrix can be seen as an alias for MatrixMN<Scalar, Dynamic, Dynamic> so it is always dynamically allocated.

1 Like

Sorry, I’m going getting around to implementing this now. I’ve got some compilation error I haven’t yet figured out, and was wondering if you could help.

Error

error[E0034]: multiple applicable items in scope
   --> src/od/srif.rs:205:27
    |
205 |         let mut stacked = MatrixMN::<f64, DimNameSum<S, M>, S>::zeros();
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `zeros` found
    |
    = note: candidate #1 is defined in an impl for the type `dynamics::na::Matrix<_, _, _, _>`
    = note: candidate #2 is defined in an impl for the type `dynamics::na::Matrix<_, _, dynamics::na::Dynamic, _>`
    = note: candidate #3 is defined in an impl for the type `dynamics::na::Matrix<_, dynamics::na::Dynamic, _, dynamics::na::VecStorage<_, dynamics::na::Dynamic, _>>`
    = note: candidate #4 is defined in an impl for the type `dynamics::na::Matrix<_, dynamics::na::Dynamic, dynamics::na::Dynamic, dynamics::na::VecStorage<_, dynamics::na::Dynamic, _>>`

error[E0277]: cannot add `<M as dynamics::na::DimName>::Value` to `<S as dynamics::na::DimName>::Value`
   --> src/od/srif.rs:205:43
    |
173 |     ) -> Result<(Self::Estimate, Residual<M>), FilterError> {
    |                                                            - help: consider further restricting the associated type: `where <S as dynamics::na::DimName>::Value: std::ops::Add<<M as dynamics::na::DimName>::Value>`
...
205 |         let mut stacked = MatrixMN::<f64, DimNameSum<S, M>, S>::zeros();
    |                                           ^^^^^^^^^^^^^^^^ no implementation for `<S as dynamics::na::DimName>::Value + <M as dynamics::na::DimName>::Value`
    |
    = help: the trait `std::ops::Add<<M as dynamics::na::DimName>::Value>` is not implemented for `<S as dynamics::na::DimName>::Value`
    = note: required because of the requirements on the impl of `dynamics::na::DimNameAdd<M>` for `S`

error[E0277]: cannot add `<M as dynamics::na::DimName>::Value` to `<S as dynamics::na::DimName>::Value`
   --> src/od/srif.rs:205:43
    |
173 |     ) -> Result<(Self::Estimate, Residual<M>), FilterError> {
    |                                                            - help: consider further restricting the associated type: `where <S as dynamics::na::DimName>::Value: std::ops::Add<<M as dynamics::na::DimName>::Value>`
...
205 |         let mut stacked = MatrixMN::<f64, DimNameSum<S, M>, S>::zeros();
    |                                           ^^^^^^^^^^^^^^^^ no implementation for `<S as dynamics::na::DimName>::Value + <M as dynamics::na::DimName>::Value`
    |
    = help: the trait `std::ops::Add<<M as dynamics::na::DimName>::Value>` is not implemented for `<S as dynamics::na::DimName>::Value`
    = note: required because of the requirements on the impl of `dynamics::na::DimNameAdd<M>` for `S`

Relevant Code


impl<S, A, M> SRIF<S, A, M>
where
    S: DimName,
    A: DimName,
    M: DimName,
    DefaultAllocator: Allocator<f64, M>
        + Allocator<f64, S>
        + Allocator<f64, M, M>
        + Allocator<f64, M, S>
        + Allocator<f64, S, M>
        + Allocator<f64, S, S>
        + Allocator<f64, A, A>
        + Allocator<f64, S, A>
        + Allocator<f64, A, S>,
{
    /// Initializes this KF with an initial estimate and measurement noise.
    pub fn initialize(
        initial_estimate: IfEstimate<S>,
        process_noise: MatrixMN<f64, A, A>,
        measurement_noise: MatrixMN<f64, M, M>,
        process_noise_dt: Option<f64>,
    ) -> Self {
        let inv_measurement_noise = measurement_noise
            .try_inverse()
            .expect("measurement noise singular");

        Self {
            prev_estimate: initial_estimate,
            inv_measurement_noise,
            process_noise: Some(process_noise),
            process_noise_dt,
            ekf: false,
            h_tilde: MatrixMN::<f64, M, S>::zeros(),
            stm: MatrixMN::<f64, S, S>::identity(),
            stm_updated: false,
            h_tilde_updated: false,
            epoch_fmt: EpochFormat::MjdTai,
            covar_fmt: CovarFormat::Sqrt,
        }
    }
}

impl<S, A, M> Filter<S, A, M> for SRIF<S, A, M>
where
    S: DimName,
    A: DimName,
    M: DimName,
    DefaultAllocator: Allocator<f64, M>
        + Allocator<f64, S>
        + Allocator<f64, M, M>
        + Allocator<f64, M, S>
        + Allocator<f64, S, M>
        + Allocator<f64, S, S>
        + Allocator<f64, A, A>
        + Allocator<f64, S, A>
        + Allocator<f64, A, S>
        + Allocator<f64, S, U1>,
{
    type Estimate = IfEstimate<S>;
    /// ... some functions ...
    fn measurement_update(
        &mut self,
        dt: Epoch,
        real_obs: VectorN<f64, M>,
        computed_obs: VectorN<f64, M>,
    ) -> Result<(Self::Estimate, Residual<M>), FilterError> {
        /// ... some code
        /// Erroring line
        let mut stacked = MatrixMN::<f64, DimNameSum<S, M>, S>::zeros();

Nevermind, I simply had to add the allocator for + Allocator<f64, DimNameSum<S, M>, S>.

From the code above, I’m trying to called QR::new(...) to perform a QR decomposition using the Householder transformation.

I’m stuck where I’m missing some DimMinimum trait constraint which I can’t see to understand.

If I define the implementation:

impl<S, A, M> Filter<S, A, M> for SRIF<S, A, M>
where
    S: DimName + DimNameAdd<M> + DimNameAdd<S> + DimNameAdd<U1>,
    A: DimName,
    M: DimName + DimNameAdd<S> + DimNameAdd<M> + DimNameAdd<U1>,
    DefaultAllocator: Allocator<f64, M>
        + Allocator<f64, S>
        + Allocator<f64, M, M>
        + Allocator<f64, M, S>
        + Allocator<f64, DimNameSum<S, M>, DimNameSum<S, U1>>
        + Allocator<f64, DimMinimum<S, S>>
        + Allocator<f64, S, M>
        + Allocator<f64, S, S>
        + Allocator<f64, A, A>
        + Allocator<f64, S, A>
        + Allocator<f64, A, S>
        + Allocator<f64, S, U1>,
{
    type Estimate = IfEstimate<S>;

Then I get (this error is repeated for every function in my implementation).

error[E0277]: the trait bound `<S as dynamics::na::DimName>::Value: typenum::type_operators::Min` is not satisfied
   --> src/od/srif.rs:279:5
    |
279 |       fn set_extended(&mut self, status: bool) {
    |       ^                                       - help: consider further restricting the associated type: `where <S as dynamics::na::DimName>::Value: typenum::type_operators::Min`
    |  _____|
    | |
280 | |         self.ekf = status;
281 | |     }
    | |_____^ the trait `typenum::type_operators::Min` is not implemented for `<S as dynamics::na::DimName>::Value`
    |
    = note: required because of the requirements on the impl of `dynamics::na::DimMin<S>` for `S`

If instead, I remove the Allocator<f64, DimMinimum<S, S>> at the impl level, then I get the following (seemingly easier) errors:

error[E0277]: the trait bound `<<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value: typenum::type_operators::Min<<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output as dynamics::na::DimName>::Value>` is not satisfied
   --> src/od/srif.rs:225:18
    |
169 |     ) -> Result<(Self::Estimate, Residual<M>), FilterError> {
    |                                                            - help: consider further restricting the associated type: `where <<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value: typenum::type_operators::Min<<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output as dynamics::na::DimName>::Value>`
...
225 |         let qr = QR::new(stacked);
    |                  ^^^^^^^ the trait `typenum::type_operators::Min<<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output as dynamics::na::DimName>::Value>` is not implemented for `<<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value`
    |
    = note: required because of the requirements on the impl of `dynamics::na::DimMin<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output>` for `<S as dynamics::na::DimNameAdd<M>>::Output`

error[E0277]: cannot multiply `typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>` to `<<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value`
   --> src/od/srif.rs:225:18
    |
169 |     ) -> Result<(Self::Estimate, Residual<M>), FilterError> {
    |                                                            - help: consider further restricting the associated type: `where <<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value: std::ops::Mul<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>>`
...
225 |         let qr = QR::new(stacked);
    |                  ^^^^^^^ no implementation for `<<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value * typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>`
    |
    = help: the trait `std::ops::Mul<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>>` is not implemented for `<<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value`
    = note: required because of the requirements on the impl of `od::hyperdual::Allocator<f64, <S as dynamics::na::DimNameAdd<M>>::Output>` for `dynamics::na::DefaultAllocator`
    = note: required by `dynamics::na::QR::<N, R, C>::new`

error[E0277]: the trait bound `<<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value: typenum::type_operators::Min<<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output as dynamics::na::DimName>::Value>` is not satisfied
   --> src/od/srif.rs:225:18
    |
169 |     ) -> Result<(Self::Estimate, Residual<M>), FilterError> {
    |                                                            - help: consider further restricting the associated type: `where <<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value: typenum::type_operators::Min<<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output as dynamics::na::DimName>::Value>`
...
225 |         let qr = QR::new(stacked);
    |                  ^^^^^^^^^^^^^^^^ the trait `typenum::type_operators::Min<<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output as dynamics::na::DimName>::Value>` is not implemented for `<<S as dynamics::na::DimNameAdd<M>>::Output as dynamics::na::DimName>::Value`
    |
    = note: required because of the requirements on the impl of `dynamics::na::DimMin<<S as dynamics::na::DimNameAdd<dynamics::na::U1>>::Output>` for `<S as dynamics::na::DimNameAdd<M>>::Output`
    = note: required by `dynamics::na::QR`

I think these error are because I’m missing an Allocator. In fact, from the QR documentation I need the constraint DimMinimum. But as mentioned before, if I add this, then I get 14 errors about how my dimension does not implement Min.

How can I fix this? Thanks

Here is a short source for the problem I’m having:

extern crate nalgebra as na;

use na::allocator::Allocator;
use na::dimension::{Dim, DimMin, DimMinimum, DimNameMin};
use na::linalg::QR;
use na::{DefaultAllocator, DimName, Matrix2, MatrixMN, Vector1, VectorN, U1, U2, U3};

fn householder<R: Dim + DimName + DimMin<C> + DimNameMin<C>, C: Dim + DimName>(
    mat: MatrixMN<f64, R, C>,
) -> bool
where
    DefaultAllocator: Allocator<f64, R, C>
        + Allocator<f64, DimMinimum<R, C>>
        + Allocator<f64, R>
        + Allocator<f64, C>,
{
    let qr = QR::new(mat);
    qr.r();
    true
}

fn main() {
    let r_bar = Matrix2::<f64>::new(1.0, -1.0, 1.0, -1.0);
    let b_bar = VectorN::<f64, U2>::new(2.0, 2.0);
    let h_tilde = MatrixMN::<f64, U1, U2>::new(3.0, -3.0);
    let prefit = Vector1::new(4.0);

    let mut stacked = MatrixMN::<f64, U3, U3>::zeros();
    stacked.fixed_slice_mut::<U2, U2>(0, 0).copy_from(&r_bar);
    stacked
        .fixed_slice_mut::<U2, U1>(0, U2::dim())
        .copy_from(&b_bar);
    stacked
        .fixed_slice_mut::<U1, U2>(U2::dim(), 0)
        .copy_from(&h_tilde);
    stacked
        .fixed_slice_mut::<U1, U1>(U2::dim(), U2::dim())
        .copy_from(&prefit);

    println!("{}", &stacked);

    let qr = QR::new(stacked);

    println!("Q {} R {}", qr.q(), qr.r());

    householder(stacked);
}

Compilation error is the following:

error[E0277]: the trait bound `<R as na::DimMin<C>>::Output: na::DimName` is not satisfied
  --> src/main.rs:18:8
   |
15 |         + Allocator<f64, C>,
   |                             - help: consider further restricting the associated type: `, <R as na::DimMin<C>>::Output: na::DimName`
...
18 |     qr.r();
   |        ^ the trait `na::DimName` is not implemented for `<R as na::DimMin<C>>::Output`
   |
   = note: required because of the requirements on the impl of `na::allocator::Allocator<f64, <R as na::DimMin<C>>::Output, C>` for `na::DefaultAllocator`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.

I’m still trying to figure this out, so any help is appreciated.

Writing this KISS example helped a lot since I was able to fix my problem in minutes.

Solution:

extern crate nalgebra as na;

use na::allocator::Allocator;
use na::dimension::{Dim, DimMin, DimMinimum};
use na::linalg::QR;
use na::{DefaultAllocator, DimName, Matrix2, MatrixMN, Vector1, VectorN, U1, U2, U3};

fn householder<R: DimMin<C>, C: Dim>(mat: MatrixMN<f64, R, C>) -> MatrixMN<f64, DimMinimum<R, C>, C>
where
    DefaultAllocator: Allocator<f64, R, C>
        + Allocator<f64, DimMinimum<R, C>>
        + Allocator<f64, R>
        + Allocator<f64, DimMinimum<R, C>, C>,
{
    let qr = QR::new(mat);
    qr.r()
}

fn main() {
    let r_bar = Matrix2::<f64>::new(1.0, -1.0, 1.0, -1.0);
    let b_bar = VectorN::<f64, U2>::new(2.0, 2.0);
    let h_tilde = MatrixMN::<f64, U1, U2>::new(3.0, -3.0);
    let prefit = Vector1::new(4.0);

    let mut stacked = MatrixMN::<f64, U3, U3>::zeros();
    stacked.fixed_slice_mut::<U2, U2>(0, 0).copy_from(&r_bar);
    stacked
        .fixed_slice_mut::<U2, U1>(0, U2::dim())
        .copy_from(&b_bar);
    stacked
        .fixed_slice_mut::<U1, U2>(U2::dim(), 0)
        .copy_from(&h_tilde);
    stacked
        .fixed_slice_mut::<U1, U1>(U2::dim(), U2::dim())
        .copy_from(&prefit);

    println!("{}", &stacked);

    let qr = QR::new(stacked);

    println!("Q {} R {}", qr.q(), qr.r());

    let r = householder(stacked);

    println!("R {}", r);
}