Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 600
borgmater Avatar asked Nov 15 '16 13:11

borgmater


People also ask

How to calculate eigenvalues and eigenvectors in Python?

Though the methods we introduced so far look complicated, the actually calculation of the eigenvalues and eigenvectors in Python is fairly easy. The main built-in function in Python to solve the eigenvalue/eigenvector problem for a square array is the eig function in numpy.linalg.

What is the eigenvalue of 2 in this matrix?

One of the two eigenvectors of this matrix (I call it Eigenvector 1, but this is arbitrary) is scaled by a factor of 1.4. Eigenvector 2 get’s also scaled by a factor of 1.4 but it’s direction get’s inverted. Therefore, eigenvalue 2 is -1.4. Using eigenvalues and eigenvectors, we can find the main axes of our data.

How to calculate the eigenvalues and eigenvectors of a Hermitian matrix?

Calculate the eigenvalues and eigenvectors using Numpy linalg.eig method. This method is designed to operate on both symmetric and non-symmetric square matrices. There is another method such as linalg.eigh which is used to decompose Hermitian matrices which is nothing but a complex square matrix that is equal to its own conjugate transpose.

Do data points on eigenvectors get rotated in PCA?

Data points lying directly on the eigenvectors do not get rotated. Principal component analysis uses the power of eigenvectors and eigenvalues to reduce the number of features in our data, while keeping most of the variance (and therefore most of the information). In PCA we specify the number of components we want to keep beforehand.


2 Answers

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]
 [      0    +     1*i]           [      0    -     1*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        ]])
like image 72
Warren Weckesser Avatar answered Oct 23 '22 15:10

Warren Weckesser


I don't think you'll be able to make it work. Here is why:

  • the test suite only tests real eigenvalues
  • mapMultiplyToSelf does not support complex arguments (so no multiplications by complex numbers including eigenvalues)

As of 2.0, this class supports only symmetric matrices, and hence computes only real realEigenvalues. This implies the D matrix returned by getD() is always diagonal and the imaginary values returned getImagEigenvalue(int) and getImagEigenvalues() are always null. (c) EigenDecomposition JavaDoc

like image 33
Ivan Avatar answered Oct 23 '22 15:10

Ivan