Search code examples
pythonc++rarmadilloeigenvector

Why some eigen vector signs from C++ Armadillo are different from Python and R


I was wondering why the sign of the elements in the eigen vectors from Armadillo is the opposite from other languages like Python (i.e. numpy) and R.

For example:

C++

using namespace arma;

vec eigval;
mat eigvec;

// C++11 initialization
mat A = { 1, -1, 0, -1, 2, -1, 0, -1, 1};

eig_sym(eigval, eigvec, A);
eigvec.print("Eigen Vectors");

Output

Eigen Vectors
-5.7735e-01  -7.071068e-01  0.4082483
-5.7735e-01  9.714451e-e17  -0.8164966
-5.7735e-01  7.017068e-01   0.4082483

Python

import numpy as np
w,v = np.linalg.eig(np.array([[1,-1,0],[-1,2,-1],[0,-1,1]]))
v 

Output

array([[ -4.08248290e-01,  -7.07106781e-01,   5.77350269e-01],
       [  8.16496581e-01,   2.61214948e-16,   5.77350269e-01],
       [ -4.08248290e-01,   7.07106781e-01,   5.77350269e-01]])

R

eigen(matrix(c(1,-1,0,-1,2,-1,0,-1,1), 3, byrow=TRUE)$vectors

Output

-4.082483e-01  -7.071068e-01   5.773503e-01
 8.164966e-01   9.420555e-16   5.773503e-01
-4.082483e-01   7.071068e-01   5.773503e-01

You can see that Python and R provide the same eigen vectors (excluding rounding errors). The armadillo result does provide the same numbers (the order is a simple fix) but the sign on the first and third columns are opposite from the corresponding columns in Python and R. Am I overlooking something here?


Solution

  • That is answered by help(eigen) in R:

    Value:
    
         The spectral decomposition of ‘x’ is returned as components of a
         list with components
    
      values: a vector containing the p eigenvalues of ‘x’, sorted in
              _decreasing_ order, according to ‘Mod(values)’ in the
              asymmetric case when they might be complex (even for real
              matrices).  For real asymmetric matrices the vector will be
              complex only if complex conjugate pairs of eigenvalues are
              detected.
    
     vectors: either a p * p matrix whose columns contain the eigenvectors
              of ‘x’, or ‘NULL’ if ‘only.values’ is ‘TRUE’.  The vectors
              are normalized to unit length.
    
              Recall that the eigenvectors are only defined up to a
              constant: even when the length is specified they are still
              only defined up to a scalar of modulus one (the sign for real
              matrices).
    

    So the sign is a 'free' parameter, and the result is truly equivalent. If it were me, I'd follow R and Python but Conrad generally knows what he is doing.