/** * 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 ZMatrixRMaj householderVector(ZMatrixRMaj x) { ZMatrixRMaj u = (ZMatrixRMaj)x.copy(); double max = CommonOps_ZDRM.elementMaxAbs(u); CommonOps_ZDRM.elementDivide(u, max, 0, u); double nx = NormOps_ZDRM.normF(u); Complex_F64 c = new Complex_F64(); u.get(0, 0, c); double 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_ZDRM.elementDivide(u, u.getReal(0, 0), u.getImag(0, 0), u); return(u); }
public static void print(Stream output, ZMatrix mat, string format) { string type = "dense64"; Console.WriteLine("Type = " + type + " complex , numRows = " + mat.getNumRows() + " , numCols = " + mat.getNumCols()); format += " "; Complex_F64 c = new Complex_F64(); 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(); } }
/** * <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(ZMatrixRMaj Q, double tol) { if (Q.numCols != Q.numRows) { return(false); } Complex_F64 a = new Complex_F64(); Complex_F64 b = new Complex_F64(); 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> * 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(DMatrixRMaj A) { if (!isSquare(A)) { return(false); } EigenDecomposition_F64 <DMatrixRMaj> eig = DecompositionFactory_DDRM.eig(A.numCols, false); if (eig.inputModified()) { A = (DMatrixRMaj)A.copy(); } eig.decompose(A); for (int i = 0; i < A.numRows; i++) { Complex_F64 v = eig.getEigenvalue(i); if (v.getReal() < 0) { return(false); } } return(true); }
/** * <p> * Division: result = a / b * </p> * * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void divide(Complex_F64 a, Complex_F64 b, Complex_F64 result) { double norm = b.getMagnitude2(); result.real = (a.real * b.real + a.imaginary * b.imaginary) / norm; result.imaginary = (a.imaginary * b.real - a.real * b.imaginary) / norm; }
public static void main(string[] args) { Complex_F64 a = new Complex_F64(1, 2); Complex_F64 b = new Complex_F64(-1, -0.6); Complex_F64 c = new Complex_F64(); ComplexPolar_F64 polarC = new ComplexPolar_F64(); Console.WriteLine("a = " + a); Console.WriteLine("b = " + b); Console.WriteLine("------------------"); ComplexMath_F64.plus(a, b, c); Console.WriteLine("a + b = " + c); ComplexMath_F64.minus(a, b, c); Console.WriteLine("a - b = " + c); ComplexMath_F64.multiply(a, b, c); Console.WriteLine("a * b = " + c); ComplexMath_F64.divide(a, b, c); Console.WriteLine("a / b = " + c); Console.WriteLine("------------------"); ComplexPolar_F64 polarA = new ComplexPolar_F64(); ComplexMath_F64.convert(a, polarA); Console.WriteLine("polar notation of a = " + polarA); ComplexMath_F64.pow(polarA, 3, polarC); Console.WriteLine("a ** 3 = " + polarC); ComplexMath_F64.convert(polarC, c); Console.WriteLine("a ** 3 = " + c); }
/** * <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 DMatrixRMaj createMatrixV(EigenDecomposition_F64 <DMatrixRMaj> eig) { int N = eig.getNumberOfEigenvalues(); DMatrixRMaj V = new DMatrixRMaj(N, N); for (int i = 0; i < N; i++) { Complex_F64 c = eig.getEigenvalue(i); if (c.isReal()) { DMatrixRMaj v = eig.getEigenVector(i); if (v != null) { for (int j = 0; j < N; j++) { V.set(j, i, v.get(j, 0)); } } } } return(V); }
/** * <p> * Given a set of polynomial coefficients, compute the roots of the polynomial. Depending on * the polynomial being considered the roots may contain complex number. When complex numbers are * present they will come in pairs of complex conjugates. * </p> * * <p> * Coefficients are ordered from least to most significant, e.g: y = c[0] + x*c[1] + x*x*c[2]. * </p> * * @param coefficients Coefficients of the polynomial. * @return The roots of the polynomial */ public static Complex_F64[] findRoots(params double[] coefficients) { int N = coefficients.Length - 1; // Construct the companion matrix DMatrixRMaj c = new DMatrixRMaj(N, N); double a = coefficients[N]; for (int i = 0; i < N; i++) { c.set(i, N - 1, -coefficients[i] / a); } for (int i = 1; i < N; i++) { c.set(i, i - 1, 1); } // use generalized eigenvalue decomposition to find the roots EigenDecomposition_F64 <DMatrixRMaj> evd = DecompositionFactory_DDRM.eig(N, false); evd.decompose(c); Complex_F64[] roots = new Complex_F64[N]; for (int i = 0; i < N; i++) { roots[i] = evd.getEigenvalue(i); } return(roots); }
public static void assertEquals(ZMatrix A, ZMatrix B, double tol) { assertShape(A, B); Complex_F64 a = new Complex_F64(); Complex_F64 b = new Complex_F64(); 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(!double.IsNaN(a.real) && !double.IsNaN(b.real), "Real At (" + i + "," + j + ") A = " + a.real + " B = " + b.real); assertTrue(!double.IsInfinity(a.real) && !double.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(!double.IsNaN(a.imaginary) && !double.IsNaN(b.imaginary), "Img At (" + i + "," + j + ") A = " + a.imaginary + " B = " + b.imaginary); assertTrue(!double.IsInfinity(a.imaginary) && !double.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> * 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_F64 innerProdH(ZMatrixRMaj x, ZMatrixRMaj y, Complex_F64 output) { if (output == null) { output = new Complex_F64(); } else { output.real = output.imaginary = 0; } int m = x.getDataLength(); for (int i = 0; i < m; i += 2) { double realX = x.data[i]; double imagX = x.data[i + 1]; double realY = y.data[i]; double imagY = -y.data[i + 1]; output.real += realX * realY - imagX * imagY; output.imaginary += realX * imagY + imagX * realY; } return(output); }
/** * 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 double computeTauGammaAndDivide(int start, int stop, double[] x, double max, Complex_F64 tau) { int index = start * 2; double nx = 0; for (int i = start; i < stop; i++) { double realX = x[index++] /= max; double imagX = x[index++] /= max; nx += realX * realX + imagX * imagX; } nx = Math.Sqrt(nx); double real_x0 = x[2 * start]; double imag_x0 = x[2 * start + 1]; double mag_x0 = 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; } double top, bottom; // if there is a chance they can cancel swap the sign // TODO not sure if this is right... double m0 = mag(real_x0 + tau.real, imag_x0 + tau.imaginary); double 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.0 * nx * mag_x0 + nx * nx; } else { top = nx * nx + nx * mag_x0; bottom = mag_x0 * mag_x0 + 2.0 * nx * mag_x0 + nx * nx; } return(bottom / top); // gamma }
/** * Computes the N<sup>th</sup> root of a complex number. There are * N distinct N<sup>th</sup> roots. * * @param a Complex number * @param N The root's magnitude * @param k Specifies which root. 0 ≤ k < N * @param result Computed root */ public static void root(Complex_F64 a, int N, int k, Complex_F64 result) { double r = a.getMagnitude(); double theta = Math.Atan2(a.imaginary, a.real); r = Math.Pow(r, 1.0 / N); theta = (theta + 2.0 * k * UtilEjml.PI) / N; result.real = r * Math.Cos(theta); result.imaginary = r * Math.Sin(theta); }
/** * <p> * Returns an eigenvalue as a complex number. For symmetric matrices the returned eigenvalue will always be a real * number, which means the imaginary component will be equal to zero. * </p> * * <p> * NOTE: The order of the eigenvalues is dependent upon the decomposition algorithm used. This means that they may * or may not be ordered by magnitude. For example the QR algorithm will returns results that are partially * ordered by magnitude, but this behavior should not be relied upon. * </p> * * @param index Index of the eigenvalue eigenvector pair. * @return An eigenvalue. */ public Complex_F64 getEigenvalue(int index) { if (is64) { return(((EigenDecomposition_F64 <DMatrixRMaj>)eig).getEigenvalue(index)); } else { Complex_F64 c = ((EigenDecomposition_F64 <FMatrixRMaj>)eig).getEigenvalue(index); return(new Complex_F64(c.real, c.imaginary)); } }
/** * Computes the square root of the complex number. * * @param input Input complex number. * @param root Output. The square root of the input */ public static void sqrt(Complex_F64 input, Complex_F64 root) { double r = input.getMagnitude(); double a = input.real; root.real = Math.Sqrt((r + a) / 2.0); root.imaginary = Math.Sqrt((r - a) / 2.0); if (input.imaginary < 0) { root.imaginary = -root.imaginary; } }
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_F64 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_F64 a, Complex_F64 b, double tol) { assertTrue(!double.IsNaN(a.real) && !double.IsNaN(b.real), "real a = " + a.real + " b = " + b.real); assertTrue(!double.IsInfinity(a.real) && !double.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(!double.IsNaN(a.imaginary) && !double.IsNaN(b.imaginary), "imaginary a = " + a.imaginary + " b = " + b.imaginary); assertTrue(!double.IsInfinity(a.imaginary) && !double.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 DMatrixRMaj createMatrixD(EigenDecomposition_F64 <DMatrixRMaj> eig) { int N = eig.getNumberOfEigenvalues(); DMatrixRMaj D = new DMatrixRMaj(N, N); for (int i = 0; i < N; i++) { Complex_F64 c = eig.getEigenvalue(i); if (c.isReal()) { D.set(i, i, c.real); } } return(D); }
public void setup(DMatrixRMaj A) { if (A.numRows != A.numCols) { throw new InvalidOperationException("Must be square"); } if (N != A.numRows) { N = A.numRows; this.A = (DMatrixRMaj)A.copy(); u = new DMatrixRMaj(A.numRows, 1); _temp = new DMatrixRMaj(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_F64[A.numRows]; for (int i = 0; i < eigenvalues.Length; i++) { eigenvalues[i] = new Complex_F64(); } numEigen = 0; lastExceptional = 0; numExceptional = 0; steps = 0; }
private void solveEigenvectorDuplicateEigenvalue(double real, int first, bool isTriangle) { double 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_F64 c = _implicit.eigenvalues[N - i - 1]; if (c.isReal() && Math.Abs(c.real - real) / scale < 100.0 * UtilEjml.EPS) { eigenvectorTemp.data[i] = 1; DMatrixRMaj v = new DMatrixRMaj(N, 1); CommonOps_DDRM.multTransA(Q, eigenvectorTemp, v); eigenvectors[N - i - 1] = v; NormOps_DDRM.normalizeF(v); eigenvectorTemp.data[i] = 0; } } }
public bool extractVectors(DMatrixRMaj Q_h) { 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_F64 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) { DMatrixRMaj temp = new DMatrixRMaj(N, 1); for (int i = 0; i < N; i++) { DMatrixRMaj v = eigenvectors[i]; if (v != null) { CommonOps_DDRM.mult(Q_h, v, temp); eigenvectors[i] = temp; temp = v; } } } return(true); }
/** * <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(ZMatrixRMaj Q, double 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_F64 prod = new Complex_F64(); ZMatrixRMaj[] u = CommonOps_ZDRM.columnsToVector(Q, null); for (int i = 0; i < u.Length; i++) { ZMatrixRMaj a = u[i]; VectorVectorMult_ZDRM.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_ZDRM.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(ZMatrix mat, double tol) { // see if the result is an identity matrix Complex_F64 c = new Complex_F64(); 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); }
public void get(Matrix A, int row, int column, Complex_F64 value) { value.real = ((DMatrixRMaj)A).get(row, column); value.imaginary = 0; }
/** * <p> * Converts a complex number into polar notation. * </p> * * @param input Standard notation * @param output Polar notation */ public static void convert(Complex_F64 input, ComplexPolar_F64 output) { output.r = input.getMagnitude(); output.theta = Math.Atan2(input.imaginary, input.real); }
/** * <p> * Multiplication: result = a * b * </p> * * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void multiply(Complex_F64 a, Complex_F64 b, Complex_F64 result) { result.real = a.real * b.real - a.imaginary * b.imaginary; result.imaginary = a.real * b.imaginary + a.imaginary * b.real; }
/** * <p> * Subtraction: result = a - b * </p> * * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void minus(Complex_F64 a, Complex_F64 b, Complex_F64 result) { result.real = a.real - b.real; result.imaginary = a.imaginary - b.imaginary; }
/** * <p> * Addition: result = a + b * </p> * * @param a Complex number. Not modified. * @param b Complex number. Not modified. * @param result Storage for output */ public static void plus(Complex_F64 a, Complex_F64 b, Complex_F64 result) { result.real = a.real + b.real; result.imaginary = a.imaginary + b.imaginary; }
/** * Complex conjugate * @param input Input complex number * @param conj Complex conjugate of the input number */ public static void conj(Complex_F64 input, Complex_F64 conj) { conj.real = input.real; conj.imaginary = -input.imaginary; }
/** * <p> * Converts a complex number in polar notation into standard notation. * </p> * * @param input Standard notation * @param output Polar notation */ public static void convert(ComplexPolar_F64 input, Complex_F64 output) { output.real = input.r * Math.Cos(input.theta); output.imaginary = input.r * Math.Sin(input.theta); }