7

I have an Eigen::MatrixXd and I need to modify the value of the elements in its diagonal. In particular I have another Eigen::MatrixXd with one single column and the same number of rows of the first matrix.

I need to subtract to the diagonal of the first matrix the value of the elements of the second matrix.

Example:

A
 1 2 3
 4 5 6
 7 8 9

B
 1
 1
 1


A'
 0 2 3
 4 4 6
 7 8 8

How can I do?

Nick
  • 10,309
  • 21
  • 97
  • 201
  • Subtract some arbitrary diagonal? Or is it always 1's (in other words are you always subtracting the [identity matrix](http://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#a0650b65c6ae6c3d19a138b72a6d68568)) – Cory Kramer Nov 20 '15 at 19:50
  • @CoryKramer arbitrary diagonal – Nick Nov 20 '15 at 23:57

4 Answers4

8

The simplest and fastest way to do achieve this is:

Eigen::MatrixXd A1(3,3), B(3,1), A2;
...
A2 = A1;
A2.diagonal() -= B;

of course, better use the VectorXd type for vectors (here for B), and finally if B is constant, then you can use array facilities:

A2.diagonal().array() -= 1;
ggael
  • 28,425
  • 2
  • 65
  • 71
  • 3
    How is this simpler and faster than `A - B.asDiagonal()`? – Timothy Shields Nov 24 '15 at 20:29
  • Perhaps because it avoids creating B as a diagonal matrix and only has to do A2.rows() calculations rather than A2.size? Although I suppose Eigen is smart enough when it knows B.asDiagonal() is diagonal. – luke.sonnet Dec 12 '17 at 00:52
7

This works for me:

A_2=A-B.asDiagonal();
Ash
  • 4,611
  • 6
  • 27
  • 41
0
for(int i = 0; i < matrix1.rows(); ++i)
    matrix1(i, i) -= matrix2(i, 0);

This code iterates over each row of the matrix (matrix1.rows()) and subtracts the corresponding value of matrix2 (matrix2(i, 0)) from the diagonals in matrix1 (matrix1(i, i)).

otah007
  • 505
  • 1
  • 4
  • 17
  • While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – Bono Nov 20 '15 at 21:52
0

Matrix manipulation in Eigen works very similar to that of arrays. The indexing starts from zero and it is row major. The documentation (Eigen: The Matrix Class is well written and may help you to solve future problems.

For your stated problem the solution is given below.

#include <iostream>
#include <eigen3/Eigen/Dense>
using Eigen::MatrixXd;
int main()
{
  MatrixXd matA(3,3), matB(3,1);
  matA<<1,2,3,
    4,5,6,
    7,8,9;
  matB<<1,1,1;
  for(int i=0; i<3;i++)
    matA(i,i) -= matB(i);
  std::cout<<matA<<std::endl;
  return 0;
}

However, I would use Matrix3d and Vector3d for the first and second matrix, respectively.

Marvin
  • 285
  • 2
  • 16
  • It's probably better to use `matB.rows()` instead of hard-coded number `3`, as done in the answer by @otah007 – Marvin Nov 20 '15 at 20:10