/** * <p> * Computes the inner product between a vector and the conjugate of another one. * <br> * <br> * ∑<sub>k=1:n</sub> x<sub>k</sub> * conj(y<sub>k</sub>)<br> * where x and y are vectors with n elements. * </p> * * <p> * These functions are often used inside of highly optimized code and therefor sanity checks are * kept to a minimum. It is not recommended that any of these functions be used directly. * </p> * * @param x A vector with n elements. Not modified. * @param y A vector with n elements. Not modified. * @return The inner product of the two vectors. */ public static Complex_F32 innerProdH(CMatrixRMaj x, CMatrixRMaj y, Complex_F32 output) { if (output == null) { output = new Complex_F32(); } else { output.real = output.imaginary = 0; } int m = x.getDataLength(); for (int i = 0; i < m; i += 2) { float realX = x.data[i]; float imagX = x.data[i + 1]; float realY = y.data[i]; float imagY = -y.data[i + 1]; output.real += realX * realY - imagX * imagY; output.imaginary += realX * imagY + imagX * realY; } return(output); }
/** * Computes the householder vector used in QR decomposition. * * u = x / max(x) * u(0) = u(0) + |u| * u = u / u(0) * * @param x Input vector. Unmodified. * @return The found householder reflector vector */ public static CMatrixRMaj householderVector(CMatrixRMaj x) { CMatrixRMaj u = (CMatrixRMaj)x.copy(); float max = CommonOps_CDRM.elementMaxAbs(u); CommonOps_CDRM.elementDivide(u, max, 0, u); float nx = NormOps_CDRM.normF(u); Complex_F32 c = new Complex_F32(); u.get(0, 0, c); float realTau, imagTau; if (c.getMagnitude() == 0) { realTau = nx; imagTau = 0; } else { realTau = c.real / c.getMagnitude() * nx; imagTau = c.imaginary / c.getMagnitude() * nx; } u.set(0, 0, c.real + realTau, c.imaginary + imagTau); CommonOps_CDRM.elementDivide(u, u.getReal(0, 0), u.getImag(0, 0), u); return(u); }
public static void assertEquals(CMatrix A, CMatrix B, float tol) { assertShape(A, B); Complex_F32 a = new Complex_F32(); Complex_F32 b = new Complex_F32(); for (int i = 0; i < A.getNumRows(); i++) { for (int j = 0; j < A.getNumCols(); j++) { A.get(i, j, a); B.get(i, j, b); assertTrue(!float.IsNaN(a.real) && !float.IsNaN(b.real), "Real At (" + i + "," + j + ") A = " + a.real + " B = " + b.real); assertTrue(!float.IsInfinity(a.real) && !float.IsInfinity(b.real), "Real At (" + i + "," + j + ") A = " + a.real + " B = " + b.real); assertTrue(Math.Abs(a.real - b.real) <= tol, "Real At (" + i + "," + j + ") A = " + a.real + " B = " + b.real); assertTrue(!float.IsNaN(a.imaginary) && !float.IsNaN(b.imaginary), "Img At (" + i + "," + j + ") A = " + a.imaginary + " B = " + b.imaginary); assertTrue(!float.IsInfinity(a.imaginary) && !float.IsInfinity(b.imaginary), "Img At (" + i + "," + j + ") A = " + a.imaginary + " B = " + b.imaginary); assertTrue(Math.Abs(a.imaginary - b.imaginary) <= tol, "Img At (" + i + "," + j + ") A = " + a.imaginary + " B = " + b.imaginary); } } }
/** * <p> * Checks to see if the matrix is positive semidefinite: * </p> * <p> * x<sup>T</sup> A x ≥ 0<br> * for all x where x is a non-zero vector and A is a symmetric matrix. * </p> * * @param A square symmetric matrix. Not modified. * * @return True if it is positive semidefinite and false if it is not. */ public static bool isPositiveSemidefinite(FMatrixRMaj A) { if (!isSquare(A)) { return(false); } EigenDecomposition_F32 <FMatrixRMaj> eig = DecompositionFactory_FDRM.eig(A.numCols, false); if (eig.inputModified()) { A = (FMatrixRMaj)A.copy(); } eig.decompose(A); for (int i = 0; i < A.numRows; i++) { Complex_F32 v = eig.getEigenvalue(i); if (v.getReal() < 0) { return(false); } } return(true); }
/** * <p>Hermitian matrix is a square matrix with complex entries that are equal to its own conjugate transpose.</p> * * <p>a[i,j] = conj(a[j,i])</p> * * @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static bool isHermitian(CMatrixRMaj Q, float tol) { if (Q.numCols != Q.numRows) { return(false); } Complex_F32 a = new Complex_F32(); Complex_F32 b = new Complex_F32(); for (int i = 0; i < Q.numCols; i++) { for (int j = i; j < Q.numCols; j++) { Q.get(i, j, a); Q.get(j, i, b); if (Math.Abs(a.real - b.real) > tol) { return(false); } if (Math.Abs(a.imaginary + b.imaginary) > tol) { return(false); } } } return(true); }
/** * <p> * Puts all the real eigenvectors into the columns of a matrix. If an eigenvalue is imaginary * then the corresponding eigenvector will have zeros in its column. * </p> * * @param eig An eigenvalue decomposition which has already decomposed a matrix. * @return An m by m matrix containing eigenvectors in its columns. */ public static FMatrixRMaj createMatrixV(EigenDecomposition_F32 <FMatrixRMaj> eig) { int N = eig.getNumberOfEigenvalues(); FMatrixRMaj V = new FMatrixRMaj(N, N); for (int i = 0; i < N; i++) { Complex_F32 c = eig.getEigenvalue(i); if (c.isReal()) { FMatrixRMaj v = eig.getEigenVector(i); if (v != null) { for (int j = 0; j < N; j++) { V.set(j, i, v.get(j, 0)); } } } } return(V); }
public static void print(Stream output, CMatrix mat, string format) { string type = "dense32"; Console.WriteLine("Type = " + type + " complex , numRows = " + mat.getNumRows() + " , numCols = " + mat.getNumCols()); format += " "; Complex_F32 c = new Complex_F32(); for (int y = 0; y < mat.getNumRows(); y++) { for (int x = 0; x < mat.getNumCols(); x++) { mat.get(y, x, c); Console.Write(format, c.real, c.imaginary); if (x < mat.getNumCols() - 1) { Console.Write(" , "); } } Console.WriteLine(); } }
/** * Performs the following operations: * <pre> * x = x / max * tau = x0*|x|/|xo| adjust sign to avoid cancellation * u = x; u0 = x0 + tau; u = u/u0 (x is not divided by x0) * gamma = 2/|u|^2 * </pre> * Note that u is not explicitly computed here. * * @param start Element in 'u' that it starts at. * @param stop Element in 'u' that it stops at. * @param x Array * @param max Max value in 'u' that is used to normalize it. * @param tau Storage for tau * @return Returns gamma */ public static float computeTauGammaAndDivide(int start, int stop, float[] x, float max, Complex_F32 tau) { int index = start * 2; float nx = 0; for (int i = start; i < stop; i++) { float realX = x[index++] /= max; float imagX = x[index++] /= max; nx += realX * realX + imagX * imagX; } nx = (float)Math.Sqrt(nx); float real_x0 = x[2 * start]; float imag_x0 = x[2 * start + 1]; float mag_x0 = (float)Math.Sqrt(real_x0 * real_x0 + imag_x0 * imag_x0); // TODO Could stability be improved by computing theta so that this // special case doesn't need to be handled? if (mag_x0 == 0) { tau.real = nx; tau.imaginary = 0; } else { tau.real = real_x0 / mag_x0 * nx; tau.imaginary = imag_x0 / mag_x0 * nx; } float top, bottom; // if there is a chance they can cancel swap the sign // TODO not sure if this is right... float m0 = mag(real_x0 + tau.real, imag_x0 + tau.imaginary); float m1 = mag(real_x0 - tau.real, imag_x0 - tau.imaginary); // if ( real_x0*tau.real<0) { // This is the previous rule until the m0 m1 code came into play if (m1 > m0) { tau.real = -tau.real; tau.imaginary = -tau.imaginary; top = nx * nx - nx * mag_x0; bottom = mag_x0 * mag_x0 - 2.0f * nx * mag_x0 + nx * nx; } else { top = nx * nx + nx * mag_x0; bottom = mag_x0 * mag_x0 + 2.0f * nx * mag_x0 + nx * nx; } return(bottom / top); // gamma }
private void checkSplitPerformImplicit() { // check for splits for (int i = x2; i > x1; i--) { if (_implicit.isZero(i, i - 1)) { x1 = i; splits[numSplits++] = i - 1; // reduce the scope of what it is looking at return; } } // first try using known eigenvalues in the same order they were originally found if (onscript) { if (_implicit.steps > _implicit.exceptionalThreshold / 2) { onscript = false; } else { Complex_F32 a = origEigenvalues[indexVal]; // if no splits are found perform an _implicit step if (a.isReal()) { _implicit.performImplicitSingleStep(x1, x2, a.getReal()); } else if (x2 - x1 >= 1 && x1 + 2 < N) { _implicit.performImplicitDoubleStep(x1, x2, a.real, a.imaginary); } else { onscript = false; } } } else { // that didn't work so try a modified order if (x2 - x1 >= 1 && x1 + 2 < N) { _implicit.implicitDoubleStep(x1, x2); } else { _implicit.performImplicitSingleStep(x1, x2, _implicit.A.get(x2, x2)); } } }
public static void assertEquals(Complex_F32 a, Complex_F32 b, float tol) { assertTrue(!float.IsNaN(a.real) && !float.IsNaN(b.real), "real a = " + a.real + " b = " + b.real); assertTrue(!float.IsInfinity(a.real) && !float.IsInfinity(b.real), "real a = " + a.real + " b = " + b.real); assertTrue(Math.Abs(a.real - b.real) <= tol, "real a = " + a.real + " b = " + b.real); assertTrue(!float.IsNaN(a.imaginary) && !float.IsNaN(b.imaginary), "imaginary a = " + a.imaginary + " b = " + b.imaginary); assertTrue(!float.IsInfinity(a.imaginary) && !float.IsInfinity(b.imaginary), "imaginary a = " + a.imaginary + " b = " + b.imaginary); assertTrue(Math.Abs(a.imaginary - b.imaginary) <= tol, "imaginary a = " + a.imaginary + " b = " + b.imaginary); }
/** * <p> * A diagonal matrix where real diagonal element contains a real eigenvalue. If an eigenvalue * is imaginary then zero is stored in its place. * </p> * * @param eig An eigenvalue decomposition which has already decomposed a matrix. * @return A diagonal matrix containing the eigenvalues. */ public static FMatrixRMaj createMatrixD(EigenDecomposition_F32 <FMatrixRMaj> eig) { int N = eig.getNumberOfEigenvalues(); FMatrixRMaj D = new FMatrixRMaj(N, N); for (int i = 0; i < N; i++) { Complex_F32 c = eig.getEigenvalue(i); if (c.isReal()) { D.set(i, i, c.real); } } return(D); }
public bool extractVectors(FMatrixRMaj Q_h) { //Arrays.fill(eigenvectorTemp.data, 0); Array.Clear(eigenvectorTemp.data, 0, eigenvectorTemp.data.Length); // extract eigenvectors from the shur matrix // start at the top left corner of the matrix bool triangular = true; for (int i = 0; i < N; i++) { Complex_F32 c = _implicit.eigenvalues[N - i - 1]; if (triangular && !c.isReal()) { triangular = false; } if (c.isReal() && eigenvectors[N - i - 1] == null) { solveEigenvectorDuplicateEigenvalue(c.real, i, triangular); } } // translate the eigenvectors into the frame of the original matrix if (Q_h != null) { FMatrixRMaj temp = new FMatrixRMaj(N, 1); for (int i = 0; i < N; i++) { FMatrixRMaj v = eigenvectors[i]; if (v != null) { CommonOps_FDRM.mult(Q_h, v, temp); eigenvectors[i] = temp; temp = v; } } } return(true); }
private void solveEigenvectorDuplicateEigenvalue(float real, int first, bool isTriangle) { float scale = Math.Abs(real); if (scale == 0) { scale = 1; } eigenvectorTemp.reshape(N, 1, false); eigenvectorTemp.zero(); if (first > 0) { if (isTriangle) { solveUsingTriangle(real, first, eigenvectorTemp); } else { solveWithLU(real, first, eigenvectorTemp); } } eigenvectorTemp.reshape(N, 1, false); for (int i = first; i < N; i++) { Complex_F32 c = _implicit.eigenvalues[N - i - 1]; if (c.isReal() && Math.Abs(c.real - real) / scale < 100.0f * UtilEjml.F_EPS) { eigenvectorTemp.data[i] = 1; FMatrixRMaj v = new FMatrixRMaj(N, 1); CommonOps_FDRM.multTransA(Q, eigenvectorTemp, v); eigenvectors[N - i - 1] = v; NormOps_FDRM.normalizeF(v); eigenvectorTemp.data[i] = 0; } } }
public void setup(FMatrixRMaj A) { if (A.numRows != A.numCols) { throw new InvalidOperationException("Must be square"); } if (N != A.numRows) { N = A.numRows; this.A = (FMatrixRMaj)A.copy(); u = new FMatrixRMaj(A.numRows, 1); _temp = new FMatrixRMaj(A.numRows, 1); numStepsFind = new int[A.numRows]; } else { this.A.set(A); UtilEjml.memset(numStepsFind, 0, numStepsFind.Length); } // zero all the off numbers that should be zero for a hessenberg matrix for (int i = 2; i < N; i++) { for (int j = 0; j < i - 1; j++) { this.A.set(i, j, 0); } } eigenvalues = new Complex_F32[A.numRows]; for (int i = 0; i < eigenvalues.Length; i++) { eigenvalues[i] = new Complex_F32(); } numEigen = 0; lastExceptional = 0; numExceptional = 0; steps = 0; }
/** * <p> * Unitary matrices have the following properties:<br><br> * Q*Q<sup>H</sup> = I * </p> * <p> * This is the complex equivalent of orthogonal matrix. * </p> * @param Q The matrix being tested. Not modified. * @param tol Tolerance. * @return True if it passes the test. */ public static bool isUnitary(CMatrixRMaj Q, float tol) { if (Q.numRows < Q.numCols) { throw new ArgumentException("The number of rows must be more than or equal to the number of columns"); } Complex_F32 prod = new Complex_F32(); CMatrixRMaj[] u = CommonOps_CDRM.columnsToVector(Q, null); for (int i = 0; i < u.Length; i++) { CMatrixRMaj a = u[i]; VectorVectorMult_CDRM.innerProdH(a, a, prod); if (Math.Abs(prod.real - 1) > tol) { return(false); } if (Math.Abs(prod.imaginary) > tol) { return(false); } for (int j = i + 1; j < u.Length; j++) { VectorVectorMult_CDRM.innerProdH(a, u[j], prod); if (!(prod.getMagnitude2() <= tol * tol)) { return(false); } } } return(true); }
/** * Checks to see if the provided matrix is within tolerance to an identity matrix. * * @param mat Matrix being examined. Not modified. * @param tol Tolerance. * @return True if it is within tolerance to an identify matrix. */ public static bool isIdentity(CMatrix mat, float tol) { // see if the result is an identity matrix Complex_F32 c = new Complex_F32(); for (int i = 0; i < mat.getNumRows(); i++) { for (int j = 0; j < mat.getNumCols(); j++) { mat.get(i, j, c); if (i == j) { if (!(Math.Abs(c.real - 1) <= tol)) { return(false); } if (!(Math.Abs(c.imaginary) <= tol)) { return(false); } } else { if (!(Math.Abs(c.real) <= tol)) { return(false); } if (!(Math.Abs(c.imaginary) <= tol)) { return(false); } } } } return(true); }
/** * Returns a list of all the eigenvalues */ public List <Complex_F64> getEigenvalues() { List <Complex_F64> ret = new List <Complex_F64>(); if (is64) { var d = (EigenDecomposition_F64 <DMatrixRMaj>)eig; for (int i = 0; i < eig.getNumberOfEigenvalues(); i++) { ret.Add(d.getEigenvalue(i)); } } else { var d = (EigenDecomposition_F32 <FMatrixRMaj>)eig; for (int i = 0; i < eig.getNumberOfEigenvalues(); i++) { Complex_F32 c = d.getEigenvalue(i); ret.Add(new Complex_F64(c.real, c.imaginary)); } } return(ret); }