Skip to content

`diagmat()`, `diagvec()`, and `.diag()` support

Ryan Curtin requested to merge rcurtin/bandicoot-code:diag into unstable

This MR implements support for diagonal matrices and diagonals. Unlike CPU-based Armadillo, the implementation is not based on the idea of a "Proxy" that can be used as an iterator, but instead uses handcrafted kernels to extract or manipulate diagonals. The diagview class is adapted from Armadillo, building on @zoq's preliminary adaptation.

Functionality overview:

  • .diag() operators added to Mat and subview; these return diagviews.
  • Support added to Mat to handle diagviews; these typically extract the diagonal from the argument with the extract_diag kernel, and then perform the requested operation.
  • Handling added for all diagview operations (element access, inplace operations, fill(), clamp(), zeros(), ones(), randu(), randn()). When possible custom kernels are used, but sometimes the convenient implementation for now is to extract the diagonal, perform the operation, and set the diagonal.
  • Added diagmat() and diagvec() functions that match Armadillo's API.
  • When diagmat(A) * B (or similar) is detected, special matrix multiplication handling via the mul_colwise, mul_rowwise, mul_colwise_trans, and mul_rowwise_trans kernels is used. I think this actually might detect more complicated expressions than Armadillo, like trans(diagmat(3 * A)) * 4 * trans(B) or similar, but I have not checked for sure---I just glanced through the Armadillo code.
  • Tests for everything I could think of were added in diag.cpp.

Like so many things, it ended up being more code than I originally anticipated... 😄

I'll let the MR sit for a couple days in case anyone has any comments and to give myself a chance to review it.

Merge request reports