Skip to content

[Use Case]: Recursively calculating determinant of Matrix<M, M> #49

Open
@jamesthurley

Description

@jamesthurley

Code description

I've been enjoying using const generics to implement a simple struct Matrix<const M: usize, const N: usize>.

I successfully implemented a fn submatrix(&self, row: usize, column: usize) -> Matrix<{ M - 1 }, { N - 1 }> using feature(generic_const_exprs).

Next, I wanted to calculate the determinant using recursion. For the determinant of a generic square Matrix<M, M> it needs to calculate the cofactors of the matrix, and they require calculating the determinants of submatrices Matrix<M - 1, M - 1>. This happens recursively until you have a 2x2 matrix, at which point you can calculate the determinant of that directly and the recursion can unwind.

What worked well

I was able to successfully implement most of the supporting functions for calculating the determinant.

What worked less well

Once the recursive aspect was in place, I received a compiler error:

error: unconstrained generic constant
  --> src/lib.rs:64:19
   |
64 |         submatrix.determinant()
   |                   ^^^^^^^^^^^
   |
   = help: try adding a `where` bound using this expression: `where [(); M - 1]:`
note: required by a bound in `Matrix::<M, M>::determinant`
  --> src/lib.rs:45:14
   |
43 |     pub fn determinant(&self) -> f32
   |            ----------- required by a bound in this
44 |     where
45 |         [(); M - 1]:,
   |              ^^^^^ required by this bound in `Matrix::<M, M>::determinant`

However the suggested where bound already exists on the function.

I have one code sample showing the specific matrix case:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=143d8b7005a53b59d8a91953e41e1121

I have another simplified example showing the same error with less code:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=2151c05d5e451fd14929fb16792520ff

Here the problematic function is get_one(). The idea is that when you call get_one() on an A<S> it will use recursion to return you an A<1>. This is dumb, but it shows the issue.

There has been some discussion on Zulip:

https://rust-lang.zulipchat.com/#narrow/stream/260443-project-const-generics/topic/Recursive.20method.20calls.20with.20generic_const_exprs

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-generic-exprsGeneric const expressionsC-use-caseCategory: This is a use case for a feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions