How do I create a struct containing a nalgebra matrix with higher dimensions?

Viewed 483

I want to create a struct that contains a nalgebra::MatrixN that is U1 larger:

extern crate nalgebra as na;

use na::{DimName, DimNameAdd, DimNameSum, MatrixN, U1};

pub struct Homogenous<D: DimName>
where
    D: DimNameAdd<U1>,
{
    mat: na::MatrixN<f32, DimNameSum<D, U1>>,
}

I get the following error:

error[E0277]: cannot multiply `<<D as na::DimNameAdd<na::U1>>::Output as na::DimName>::Value` to `<<D as na::DimNameAdd<na::U1>>::Output as na::DimName>::Value`
 --> src/main.rs:9:5
  |
9 |     mat: na::MatrixN<f32, DimNameSum<D, U1>>,
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `<<D as na::DimNameAdd<na::U1>>::Output as na::DimName>::Value * <<D as na::DimNameAdd<na::U1>>::Output as na::DimName>::Value`
  |
  = help: the trait `std::ops::Mul` is not implemented for `<<D as na::DimNameAdd<na::U1>>::Output as na::DimName>::Value`
  = help: consider adding a `where <<D as na::DimNameAdd<na::U1>>::Output as na::DimName>::Value: std::ops::Mul` bound
  = note: required because of the requirements on the impl of `na::allocator::Allocator<f32, <D as na::DimNameAdd<na::U1>>::Output, <D as na::DimNameAdd<na::U1>>::Output>` for `na::DefaultAllocator`

Trying to follow the error message leads down a rabbit hole with the next trait error message. I have looked at the API of nalgebra, which does not contain such complicated trait chains. For example the to_homogenous method. I am not sure if my approach is even the right way.

There is also the trait Dim with corresponding DimAdd and DimSum, however since that part of nalgebra is not really documented,

I don't know if I am on the right path - or if what I want to do is even possible.

1 Answers

This post pointed me in the right direction. The way to do this is in nalgebra is a little bit convoluted:

extern crate nalgebra as na;

use crate::na::{Dim, DimName, DimNameAdd, DimNameSum, MatrixN, U1, DefaultAllocator};
use crate::na::allocator::Allocator;

pub struct Homogenous<D: Dim + DimName>
where
    D: DimNameAdd<U1>,
    DefaultAllocator: Allocator<f32, DimNameSum<D, U1>, DimNameSum<D, U1>>,
{
    mat: MatrixN<f32, DimNameSum<D, U1>>,
}

Hopefully, these type of generic manipulations become more ergonomic in future versions of Rust and nalgebra, since these rather cumbersome type annotations need to be repeated quite often.

By the way, just storing these generic types in a struct still requires the DefaultAllocator:

extern crate nalgebra as na;

use crate::na::{Dim, DimName, MatrixN, DefaultAllocator};
use crate::na::allocator::Allocator;

pub struct Homogenous<D: Dim + DimName>
where
    DefaultAllocator: Allocator<f32, D, D>,
{
    mat: MatrixN<f32, D>,
}
Related