2012-08-22 18 views
5

Tengo un MatrixXd triangular inferior y quiero copiar sus valores inferiores a la parte superior, ya que se convertirá en una matriz simétrica. ¿Cómo puedo hacerlo?Copiando MatrixXd superior para bajar MatrixXd (Eigen3) Biblioteca C++

Hasta ahora me he hecho:

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); 

      } 
     } 

¿Hay una manera más rápida de hacerlo? Estaba pensando en algún método interno que sea capaz de "copiar" la matriz triangular inferior a la superior. Di Tengo esta matriz, que llamamos m:

1 2 3 
4 5 6 
7 8 9 

lo que necesito para obtener en m es:

1 4 7 
4 5 8 
7 8 9 

Sé también se puede obtener la parte superior o la parte inferior de la matriz para hacer algo:

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

1 2 3 
0 5 6 
0 0 9 

Pero todavía no puede conseguir lo que quiero ...

+0

WHT es el tamaño de su matriz? – Heisenbug

+0

@ Heisenbug La dimensión es n (de 9000 a 32000) – Manolete

+0

Un poco fuera de tema: ¿es esta C? ¿No debería ser 'm [j] [i] = m [i] [j]'? –

Respuesta

4

Supongo aquí que se refiere a trabajar con la biblioteca Eigen3 C++. Esto no está claro en tu pregunta. si no, deberías considerarlo. En cualquier caso, dentro de Eigen, no hay necesidad de copiar la parte triangular, para obtener una matriz autoadjuntada. Eigen tiene el concepto de vistas, y puede usar un self adjoint view para realizar una operación como p. Ej.

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

aquí es un pequeño ejemplo para ilustrar el uso de matrices de tamaño fijo:

#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; 
} 

la salida será [1, 2, 2, 1]. ahora, el resultado en r es el mismo que si hubiera usado c * x en su lugar. Solo que no hay necesidad de copiar los valores en la matriz original para hacerlo autoadjunto.

+0

Gracias por aclarar. Sí, quise decir la biblioteca Eigen3 C++. Sin embargo, no puedo hacer lo que dices. Primero tengo 'clase Eigen :: MatrixXd 'no tiene ningún miembro llamado' selfAdjointView' del compilador. Por otro lado, lo que necesito es tener los mismos elementos en el lado superior e inferior de la matriz. Por lo tanto, necesito de alguna manera "copiar" los elementos de un lado a otro dentro del mismo MatrixXd. – Manolete

+0

No compilé el código, y había un error tipográfico en selfadjointView. Se corrigió el código y se agregaron algunas aclaraciones. – Jakob

+0

¡Bien! Eso funciona. Necesito tener todos los valores en la matriz original, 'm' siguiendo tu ejemplo. Entonces lo que he hecho es 'm = m.selfadjointView ();'. Sin embargo, es más lento que copiarlo con OpenMP. Así que prefiero seguir con mi implementación. ¡Gracias de cualquier manera! – Manolete

0

Esto funciona, puede cortar algo pero necesita al menos n * m/2 (menos), por lo que solo 2x

editar: Veo que usa este objeto matrixd ... la sintaxis es diferente , pero el algoritmo es esto, de todos modos

#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); 
} 
+0

OP está utilizando [Eigen] (http://eigen.tuxfamily.org/index.php?title=Main_Page), no es simple C. – kennytm

+0

@mauropellizzer Gracias por su ayuda, pero es no ese caso Como mencioné antes, esta no es una matriz simple en C. MatrixXd es un objeto de la biblioteca Eigen. – Manolete

+0

Sí, pero esto no cambia mucho: para (j = 1; j mauropellizzer

1

Creo que lo estás haciendo bien. Si conocía algunos detalles sobre el diseño de la memoria de los datos en la matriz, podría usar algunas optimizaciones de bajo nivel. Una de las técnicas es loop tiling.

+0

Ya estoy usando OpenMP, pero estaba pensando en algún método interno de matriz Eigen que pudiera acelerar mi código. – Manolete

+0

He visto algunas presentaciones de Intel donde dicen que usan mosaico y OpenMP al mismo tiempo. –

1

Si la velocidad es un gran problema, no copiaría nada simplemente decorar/envolver el objeto de la matriz con un objeto de inversión de coordenadas que volteará el (x, y) a (y, x). si convierte al operador() en una función en línea, no tendrá un costo significativo cuando lo utilice.

3

En caso de que el selfadjointView no es una opción para usted, la solución es utilizar triangularView en la matriz de destino:

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

2

La forma más simple que puedo pensar es copiando la parte superior de m matriz trasposed en la parte superior:

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

Por ejemplo, el siguiente código:

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

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

proporciona la salida que solicitó:

1 4 7 
4 5 8 
7 8 9 

Saludos.

1

Simplemente:

m = m.selfadjointView<Upper>();