/// <summary> /// Computes the eigenvalues and eigenvectors of the matrix. /// </summary> /// <returns>A representation of the eigenvalues and eigenvectors of the matrix.</returns> /// <remarks> /// <para>For a generic vector v and matrix M, Mv = u will point in some direction with no particular relationship to v. /// The eigenvectors of a matrix M are vectors z that satisfy Mz = λz, i.e. multiplying an eigenvector by a /// matrix reproduces the same vector, up to a prortionality constant λ called the eigenvalue.</para> /// <para>For v to be an eigenvector of M with eigenvalue λ, (M - λI)z = 0. But for a matrix to /// anihilate any non-zero vector, that matrix must have determinant, so det(M - λI)=0. For a matrix of /// order N, this is an equation for the roots of a polynomial of order N. Since an order-N polynomial always has exactly /// N roots, an order-N matrix always has exactly N eigenvalues.</para> /// <para>Since a polynomial with real coefficients can still have complex roots, a real square matrix can nonetheless /// have complex eigenvalues (and correspondly complex eigenvectors). However, again like the complex roots of a real /// polynomial, such eigenvalues will always occurs in complex-conjugate pairs.</para> /// <para>Although the eigenvalue polynomial ensures that an order-N matrix has N eigenvalues, it can occur that there /// are not N corresponding independent eigenvectors. A matrix with fewer eigenvectors than eigenvalues is called /// defective. Like singularity, defectiveness represents a delecate balance between the elements of a matrix that can /// typically be disturbed by just an infinitesimal perturbation of elements. Because of round-off-error, then, floating-point /// algorithms cannot reliably identify defective matrices. Instead, this method will return a full set of eigenvectors, /// but some eigenvectors, corresponding to very nearly equal eigenvalues, will be very nearly parallel.</para> /// <para>While a generic square matrix can be defective, many subspecies of square matrices are guaranteed not to be. /// This includes Markov matrices, orthogonal matrices, and symmetric matrices.</para> /// <para>Determining the eigenvalues and eigenvectors of a matrix is an O(N<sup>3</sup>) operation. If you need only the /// eigenvalues of a matrix, the <see cref="Eigenvalues"/> method is more efficient.</para> /// </remarks> public ComplexEigensystem Eigensystem() { double[] aStore = MatrixAlgorithms.Copy(store, dimension, dimension); int[] perm = new int[dimension]; for (int i = 0; i < perm.Length; i++) { perm[i] = i; } SquareMatrixAlgorithms.IsolateCheapEigenvalues(aStore, perm, dimension); double[] qStore = MatrixAlgorithms.AllocateStorage(dimension, dimension); for (int i = 0; i < perm.Length; i++) { MatrixAlgorithms.SetEntry(qStore, dimension, dimension, perm[i], i, 1.0); } //double[] qStore = SquareMatrixAlgorithms.CreateUnitMatrix(dimension); // Reduce the original matrix to Hessenberg form SquareMatrixAlgorithms.ReduceToHessenberg(aStore, qStore, dimension); // Reduce the Hessenberg matrix to real Schur form SquareMatrixAlgorithms.ReduceToRealSchurForm(aStore, qStore, dimension); //MatrixAlgorithms.PrintMatrix(aStore, dimension, dimension); //SquareMatrix A = new SquareMatrix(aStore, dimension); SquareMatrix Q = new SquareMatrix(qStore, dimension); Complex[] eigenvalues; Complex[][] eigenvectors; // Extract the eigenvalues and eigenvectors of the Schur form matrix SquareMatrixAlgorithms.SchurEigensystem(aStore, dimension, out eigenvalues, out eigenvectors); // transform eigenvectors of schur form into eigenvectors of original matrix // while we are at it, normalize so largest component has value 1 for (int i = 0; i < dimension; i++) { Complex[] v = new Complex[dimension]; double norm = 0.0; for (int j = 0; j < dimension; j++) { for (int k = 0; k < dimension; k++) { v[j] += Q[j, k] * eigenvectors[i][k]; } norm = Math.Max(norm, Math.Max(Math.Abs(v[j].Re), Math.Abs(v[j].Im))); } for (int j = 0; j < dimension; j++) { v[j] = v[j] / norm; } eigenvectors[i] = v; } ComplexEigensystem eigensystem = new ComplexEigensystem(dimension, eigenvalues, eigenvectors); return(eigensystem); }
/// <summary> /// Initializes a new square matrix. /// </summary> /// <param name="dimension">The dimension of the matrix, which must be positive.</param> /// <exception cref="ArgumentOutOfRangeException"><paramref name="dimension"/> < 1.</exception> public SquareMatrix(int dimension) { if (dimension < 1) { throw new ArgumentOutOfRangeException(nameof(dimension)); } this.dimension = dimension; this.store = MatrixAlgorithms.AllocateStorage(dimension, dimension, ref offset, ref rowStride, ref colStride); }
/// <summary> /// Initializes a new square matrix. /// </summary> /// <param name="dimension">The dimension of the matrix, which must be positive.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="dimension"/> < 1.</exception> public SquareMatrix(int dimension) { if (dimension < 1) { throw new ArgumentOutOfRangeException("dimension"); } this.dimension = dimension; this.store = MatrixAlgorithms.AllocateStorage(dimension, dimension); }
public static double[] CreateUnitMatrix(int dimension) { double[] store = MatrixAlgorithms.AllocateStorage(dimension, dimension); for (int i = 0; i < dimension; i++) { store[dimension * i + i] = 1.0; } return(store); }
// initialization and storage /// <summary> /// Initializes a rectangular matrix with the given dimensions. /// </summary> /// <param name="rowCount">The number of rows.</param> /// <param name="columnCount">The number of columns.</param> /// <exception cref="ArgumentOutOfRangeException"><paramref name="rowCount"/> or <paramref name="columnCount"/> /// is less than one.</exception> public RectangularMatrix(int rowCount, int columnCount) { if (rowCount < 1) { throw new ArgumentOutOfRangeException(nameof(rowCount)); } if (columnCount < 1) { throw new ArgumentOutOfRangeException(nameof(columnCount)); } rows = rowCount; cols = columnCount; store = MatrixAlgorithms.AllocateStorage(rows, cols, ref offset, ref rowStride, ref colStride); }
/// <summary> /// Initializes a rectangular matrix from the given 2D array. /// </summary> /// <param name="source">The source 2D array.</param> public RectangularMatrix(double[,] source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } rows = source.GetLength(0); cols = source.GetLength(1); store = MatrixAlgorithms.AllocateStorage(rows, cols, ref offset, ref rowStride, ref colStride); for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { store[MatrixAlgorithms.GetIndex(rows, cols, r, c)] = source[r, c]; } } }
// initialization and storage /// <summary> /// Initializes a rectangular matrix with the given dimensions. /// </summary> /// <param name="rowCount">The number of rows.</param> /// <param name="columnCount">The number of columns.</param> /// <exception cref="ArgumentOutOfRangeException"><paramref name="rowCount"/> or <paramref name="columnCount"/> /// is less than one.</exception> public RectangularMatrix(int rowCount, int columnCount) { if (rowCount < 1) { throw new ArgumentOutOfRangeException("rowCount"); } if (columnCount < 1) { throw new ArgumentOutOfRangeException("columnCount"); } rows = rowCount; cols = columnCount; store = MatrixAlgorithms.AllocateStorage(rows, cols); offset = 0; rowStride = 1; colStride = rows; }
/// <summary> /// Initializes a new square matrix from the given 2D array. /// </summary> /// <param name="entries">The source 2D array.</param> /// <remarks><para>The entries are copied, so changes to <paramref name="entries"/> after the matrix is initialized do not affect matrix entries.</para></remarks> /// <exception cref="ArgumentNullException"><paramref name="entries"/> is <see langword="null"/>.</exception> /// <exception cref="DimensionMismatchException">The two dimensions of <paramref name="entries"/> are not equal.</exception> public SquareMatrix(double[,] entries) { if (entries == null) { throw new ArgumentNullException(nameof(entries)); } if (entries.GetLength(0) != entries.GetLength(1)) { throw new DimensionMismatchException(); } this.dimension = entries.GetLength(0); this.store = MatrixAlgorithms.AllocateStorage(dimension, dimension, ref offset, ref rowStride, ref colStride); for (int r = 0; r < dimension; r++) { for (int c = 0; c < dimension; c++) { this[r, c] = entries[r, c]; } } }