Difference in calculating eigenvectors wih Java and Python
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 pairseigenvector[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]: v1Out[21]: array([-0.8660254+0.5j, 0.0000000+1.j ])In [22]: v2 = np.array([-np.sqrt(3)/2 - 0.5j, -1j])In [23]: v2Out[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]: evecsOut[29]: array([[ 0.35355339+0.61237244j, 0.35355339-0.61237244j], [ 0.70710678+0.j , 0.70710678-0.j ]])
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