borgmater - 14 days ago 5
Python Question

Difference in calculating eigenvectors wih Java and Python

As a current task, I need to calculate eigenvalues and eigenvectors for a 120*120 matrix. For start, I tested those calculations on a simple 2 by 2 matrix in both Java (Apache Commons Math library) and Python 2.7 (Numpy library). I have a problem with eigenvector values not matching, as show below :

``````//Java
import org.apache.commons.math3.linear.EigenDecomposition;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;

public class TemporaryTest {

public static void main(String[] args) {

double[][] testArray = {{2, -1}, {1, 1}};
RealMatrix testMatrix = MatrixUtils.createRealMatrix(testArray);
EigenDecomposition decomposition = new EigenDecomposition (testMatrix);
System.out.println("eigenvector[0] = " + decomposition.getEigenvector(0));
System.out.println("eigenvector[1] = " + decomposition.getEigenvector(1));
}
``````

Output of eigenvectors are shown as {real_value + imaginary_value; real_value + imaginary_value}:

``````//Java output
eigenvector[0] = {-0.8660254038; 0}
eigenvector[1] = {0.5; 1}
``````

Same code in Python, but using Numpy library:

``````# Python
import numpy as np
from numpy import linalg as LA

w, v = LA.eig(np.array([[2, -1], [1, 1]]))
print (v[:, 0])
print (v[:, 1])
``````

Output of eigenvectors in Python are shown similarly, [real+imag real+imag]:

``````[ 0.35355339+0.61237244j  0.70710678+0.j        ]
[ 0.35355339-0.61237244j  0.70710678-0.j        ]
``````

My concern is, why are those vectors different ? Is there something that I am missing ? Ty for any kind of help or advice

In Apache Commons Math 3, `EigenDecomposition` accepts nonsymmetric matrices, but it returns results using the classes `RealVector` and `RealMatrix`. To get the actual complex results, you have to combine the appropriate real results into complex conjugate pairs.

In the case of the eigenvectors, you got:

``````eigenvector[0] = {-0.8660254038; 0}
eigenvector[1] = {0.5; 1}
``````

Both those vectors are associated with the complex conjugate pair of eigenvalues `getRealEigenvalue(0) + getImagEigenvalue(0)*i` and `getRealEigenvalue(1) + getImagEigenvalue(1)*i`, but those vectors are not the actual eigenvectors. The actual eigenvectors are the complex conjugate pairs `eigenvector[0] + eigenvector[1]*i` and `eigenvector[0] - eigenvector[1]*i`.

Those vectors still don't "match" the results returned by numpy, but that is because the two libraries have not used the same normalization. Eigenvectors are not unique; an eigenvector multiplied by any nonzero scalar (including a complex scalar) is still an eigenvector. The only difference between the Java result and the numpy result is a scalar multiplier.

For convenience, I'll convert the floating point values to their exact values. That is, `-0.8660254038` is the floating point approximation of `-sqrt(3)/2`. The Java math library is giving the following eigenvectors:

`````` [-sqrt(3)/2 + (1/2)*i]    and    [-sqrt(3)/2 - (1/2)*i]
[       i            ]           [        -i          ]
``````

If you multiply the first eigenvector by -(sqrt(2)/2)*i and the second by (sqrt(2)/2)*i, you'll get the eigenvectors that were return by numpy.

Here's an ipython session with that calculation. `v1` and `v2` are the vectors shown above.

``````In [20]: v1 = np.array([-np.sqrt(3)/2 + 0.5j, 1j])

In [21]: v1
Out[21]: array([-0.8660254+0.5j,  0.0000000+1.j ])

In [22]: v2 = np.array([-np.sqrt(3)/2 - 0.5j, -1j])

In [23]: v2
Out[23]: array([-0.8660254-0.5j,  0.0000000-1.j ])
``````

Multiply `v1` by -(sqrt(2)/2)*i to get the first eigenvector returned by `numpy.linalg.eig`:

``````In [24]: v1*(-np.sqrt(2)/2*1j)
Out[24]: array([ 0.35355339+0.61237244j,  0.70710678-0.j        ])
``````

Multiply `v2` by (sqrt(2)/2)*i to get the second eigenvector returned by `numpy.linalg.eig`:

``````In [25]: v2*(np.sqrt(2)/2*1j)
Out[25]: array([ 0.35355339-0.61237244j,  0.70710678+0.j        ])
``````

For convenience, here's a repeat of the numpy calculation. The columns of `evecs` are the eigenvectors.

``````In [28]: evals, evecs = np.linalg.eig(a)

In [29]: evecs
Out[29]:
array([[ 0.35355339+0.61237244j,  0.35355339-0.61237244j],
[ 0.70710678+0.j        ,  0.70710678-0.j        ]])
``````