Pergunta

I've got a lower triangular MatrixXd and I want to copy its lower values to the upper side as it'll become a symmetric matrix. How can I do it?

So far I've done:

 MatrixXd m(n,n); 
 .....
 //do something with m
 for(j=0; j < n; j++)
       {
         for(i=0; i<j; i++)
           {
             m(i,j) = m(j,i);

           }
       }

Is there a fastest way to do it? I was thinking of some internal method that is able to "copy" the lower triangular matrix to the upper. Say I've got this matrix, we call m:

1 2 3
4 5 6
7 8 9

what I need to obtain in m is :

1 4 7
4 5 8
7 8 9

I also know you can get the upper or the lower part of the matrix to do something:

MatrixXd m1(n,n);
 m1 = m.triangularView<Eigen::Upper>();
cout << m1 <<endl;

1 2 3
0 5 6
0 0 9

But I can't yet get what I want...

Foi útil?

Solução

I assume here that you are referring to working with the Eigen3 c++ library. This is not clear from your question. if not, you should consider it. In any case, within Eigen, there is no need to actually copy the triangular part, to get a selfadjoint matrix. Eigen has the concept of views, and you can use a self adjoint view in order to perform an operation like e.g.

using namespace Eigen;
MatrixXd m(m,n);
...
(generate uppper triangular entries in m)
...
VectorXd r(n), p(n);
r = m.selfadjointView<Upper>() * p;

here is a small example to illustrate using fixed size matrices:

#include <Eigen/Core>

using namespace std;
using namespace Eigen;

int main()
{
    Matrix2d m,c;
    m << 1, 2,
         0, 1;

    Vector2d x(0,2), r;

    // perform copy operation 
    c = m.selfadjointView<Upper>(); 
    cout << c << endl;

    // directly apply selfadjoint view in matrix operation
    // (no entries are copied)
    r = m.selfadjointView<Upper>() * x;
} 

the output will be [1, 2, 2, 1]. now, the result in r is the same as if you had used c * x instead. Just that there is no need for copying the values in the original matrix to make it selfadjoint.

Outras dicas

In case the selfadjointView is not an option for you, the solution is to use triangularView on the destination matrix:

m.triangularView<Lower>() = m.transpose();

The simplest way I can think of is by copying the upper part of m matrix trasposed on the upper part:

    m.triangularView<Upper>() = m.transpose();

For example, the following code:

    MatrixXd m(3,3);
    m << 1, 2, 3, 4, 5, 6, 7, 8, 9;

    m.triangularView<Upper>() = m.transpose();
    std::cout << m << std::endl;

Gives the output you asked for:

1 4 7
4 5 8
7 8 9

Regards.

Simply:

m = m.selfadjointView<Upper>();

I think you are doing it the right way. If you knew some details about the memory layout of data in the matrix you could use some low-level optimizations. One of the techniques is loop tiling.

If speed is a big issue, I would not copy anything just decorate/wrap the matrix object with a coordinate inverting object that would flip the (x,y) to (y,x). if you make the () operator an an inline function it will not incur any significant cost when you use it.

This works, you can cut something but you need at least n*m/2 (less something), so only of a 2x

edit: I see that you use this matrixd object... the syntax is different, but the algorithm is this, anyway

#include <stdio.h>


int main ( )
{
    int mat [ 4 ] [ 4 ];
    int i, j;

    mat [ 0 ] [ 0 ] = 0;
    mat [ 0 ] [ 1 ] = 1;
    mat [ 0 ] [ 2 ] = 2;
    mat [ 0 ] [ 3 ] = 3;
    mat [ 1 ] [ 0 ] = 4;
    mat [ 1 ] [ 1 ] = 5;
    mat [ 1 ] [ 2 ] = 6;
    mat [ 1 ] [ 3 ] = 7;
    mat [ 2 ] [ 0 ] = 8;
    mat [ 2 ] [ 1 ] = 9;
    mat [ 2 ] [ 2 ] = 10;
    mat [ 2 ] [ 3 ] = 11;
    mat [ 3 ] [ 0 ] = 12;
    mat [ 3 ] [ 1 ] = 13;
    mat [ 3 ] [ 2 ] = 14;
    mat [ 3 ] [ 3 ] = 15;

    for ( i = 0; i < 4; i++ )
    {
        for ( j = 0; j < 4; j++ )
            printf ( "%02d", mat [ i ] [ j ] );
        printf ( "\n" );
    }
    printf ( "\n" );

    for ( i = 1; i < 4; i++ )
    {
        for ( j = 0; j < i; j++ )
            mat [ j ] [ i ] = mat [ i ] [ j ];
    }

    for ( i = 0; i < 4; i++ )
    {
        for ( j = 0; j < 4; j++ )
            printf ( "%02d ", mat [ i ] [ j ] );
        printf ( "\n" );
    }
    printf ( "\n" );

    scanf ( "%d", &i );
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top