/// <summary> /// Computes the eigenvalues for an N-by-N real nonsymmetric matrix A. /// </summary> /// <param name="A">N-by-N real nonsymmetric matrix A.</param> /// <returns>The eigenvalues.</returns> public ComplexMatrix GetEigenvalues(Matrix A) { if (this._dgeev == null) { this._dgeev = new DGEEV(); } this.CheckDimensions(A); Matrix ACopy = A.Clone(); double[] ACopyData = ACopy.Data; Matrix RealEVectors = new Matrix(1, 1); double[] EigenVectsData = RealEVectors.Data; ComplexMatrix EigenVals = new ComplexMatrix(A.RowCount, 1); double[] REigVal = new double[A.RowCount]; double[] IEigVal = new double[A.RowCount]; //double[] EigenValsData = EigenVals.Data; int Info = 0; double[] VL = new double[A.RowCount]; double[] Work = new double[1]; int LWork = -1; //Calculamos LWORK _dgeev.Run("N", "N", A.RowCount, ref ACopyData, 0, ACopy.RowCount, ref REigVal, 0, ref IEigVal, 0, ref VL, 0, 1, ref EigenVectsData, 0, A.RowCount, ref Work, 0, LWork, ref Info); LWork = Convert.ToInt32(Work[0]); if (LWork > 0) { Work = new double[LWork]; _dgeev.Run("N", "N", A.RowCount, ref ACopyData, 0, ACopy.RowCount, ref REigVal, 0, ref IEigVal, 0, ref VL, 0, 1, ref EigenVectsData, 0, A.RowCount, ref Work, 0, LWork, ref Info); } else { //Error } #region Error //= 0: successful exit //.LT. 0: if INFO = -i, the i-th argument had an illegal value. //.GT. 0: if INFO = i, the QR algorithm failed to compute all the // eigenvalues, and no eigenvectors have been computed; // elements i+1:N of WR and WI contain eigenvalues which // have converged. if (Info < 0) { string infoSTg = Math.Abs(Info).ToString(); throw new ArgumentException("the " + infoSTg + " -th argument had an illegal value"); } else if (Info > 0) { string infoSTg = Math.Abs(Info).ToString(); throw new Exception("The QR algorithm failed to compute all the eigenvalues."); } #endregion for (int i = 0; i < EigenVals.RowCount; i++) { EigenVals[i, 0] = new Complex(REigVal[i], IEigVal[i]); } return(EigenVals); }
/// <summary> ///Computes the singular value decomposition (SVD) of a real /// M-by-N matrix A. /// The SVD is written /// A = U * S * transpose(V) /// </summary> /// <param name="A">The A matrix.</param> /// <param name="S">The diagonal elements of S are the singular values of A.</param> /// <param name="U">The U matrix, U is an M-by-M orthogonal matrix</param> /// <param name="VT">the transpose(V), V is an N-by-N orthogonal matrix.</param> public void ComputeSVD(Matrix A, out Matrix S, out Matrix U, out Matrix VT) { if (this._dgesvd == null) { this._dgesvd = new DGESVD(); } Matrix ACopy = A.Clone(); double[] ACopyData = ACopy.Data; S = new Matrix(A.RowCount, A.ColumnCount); // A is MxN, S is MxN double[] SingularValuesData = new double[Math.Min(A.RowCount, A.ColumnCount)]; U = new Matrix(A.RowCount, A.RowCount); // A is MxN, U is MxM double[] UData = U.Data; VT = new Matrix(A.ColumnCount, A.ColumnCount); // A is MxN, V is NxN double[] VTData = VT.Data; double[] Work = new double[1]; int LWork = -1; int Info = 0; //Calculamos LWORK this._dgesvd.Run("A", "A", A.RowCount, A.ColumnCount, ref ACopyData, 0, A.RowCount, ref SingularValuesData, 0, ref UData, 0, U.RowCount, ref VTData, 0, VT.RowCount, ref Work, 0, LWork, ref Info); LWork = Convert.ToInt32(Work[0]); if (LWork > 0) { Work = new double[LWork]; _dgesvd.Run("A", "A", A.RowCount, A.ColumnCount, ref ACopyData, 0, A.RowCount, ref SingularValuesData, 0, ref UData, 0, U.RowCount, ref VTData, 0, VT.RowCount, ref Work, 0, LWork, ref Info); } else { //Error } #region Error // <param name="INFO"> // (output) INTEGER // = 0: successful exit. // .LT. 0: if INFO = -i, the i-th argument had an illegal value. // .GT. 0: if DBDSQR did not converge, INFO specifies how many // superdiagonals of an intermediate bidiagonal form B // did not converge to zero. See the description of WORK // above for details. if (Info < 0) { string infoSTg = Math.Abs(Info).ToString(); throw new ArgumentException("the " + infoSTg + " -th argument had an illegal value"); } else if (Info > 0) { string infoSTg = Math.Abs(Info).ToString(); throw new Exception("DBDSQR did not converge."); } #endregion for (int i = 0; i < SingularValuesData.Length; i++) { S[i, i] = SingularValuesData[i]; } }
/// <summary> /// Computes the minimum-norm solution to a real linear least squares problem: minimize 2-norm(|| A*X - B||) /// using the singular value decomposition (SVD) of A. /// The matrix A can be rank-deficient. /// </summary> /// <param name="A">The A matrix.</param> /// <param name="B">The matrix containing the right-hand side of the linear system.</param> /// <param name="rcond"> /// rcond is used to determine the effective rank of A. /// Singular values S(i) .LE. rcond*S(1) are treated as zero. /// </param> /// <returns>A matrix containing the solution.</returns> public Matrix SVDdcSolve(Matrix A, Matrix B, double rcond) { if (this._dgelsd == null) { this._dgelsd = new DGELSD(); } Matrix AClon = A.Clone(); double[] AClonData = AClon.Data; Matrix ClonB = new Matrix(Math.Max(A.RowCount, A.ColumnCount), B.ColumnCount); double[] ClonData = ClonB.Data; for (int j = 0; j < ClonB.ColumnCount; j++) { for (int i = 0; i < B.RowCount; i++) { ClonB[i, j] = B[i, j]; } } // (output) DOUBLE PRECISION array, dimension (min(M,N)) //The singular values of A in decreasing order. //The condition number of A in the 2-norm = S(1)/S(min(m,n)). double[] S = new double[Math.Min(A.RowCount, A.ColumnCount)]; //// (input) DOUBLE PRECISION //// RCOND is used to determine the effective rank of A. //// Singular values S(i) .LE. RCOND*S(1) are treated as zero. //// If RCOND .LT. 0, machine precision is used instead. //double RCond = -1.0; // (output) INTEGER // The effective rank of A, i.e., the number of singular values // which are greater than RCOND*S(1). int Rank = 0; int Info = 0; //int LWork double[] Work = new double[1]; int LWork = -1; int LIWork = this.CalculateLIWORK(A.RowCount, A.ColumnCount); int[] IWork = new int[LIWork]; //Calculamos LWORK ideal this._dgelsd.Run(A.RowCount, A.ColumnCount, B.ColumnCount, ref AClonData, 0, A.RowCount, ref ClonData, 0, ClonB.RowCount, ref S, 0, rcond, ref Rank, ref Work, 0, LWork, ref IWork, 0, ref Info); LWork = Convert.ToInt32(Work[0]); if (LWork > 0) { Work = new double[LWork]; this._dgelsd.Run(A.RowCount, A.ColumnCount, B.ColumnCount, ref AClonData, 0, A.RowCount, ref ClonData, 0, ClonB.RowCount, ref S, 0, rcond, ref Rank, ref Work, 0, LWork, ref IWork, 0, ref Info); } else { //Error } #region Error // = 0: successful exit // .LT. 0: if INFO = -i, the i-th argument had an illegal value. // .GT. 0: the algorithm for computing the SVD failed to converge; // if INFO = i, i off-diagonal elements of an intermediate // bidiagonal form did not converge to zero. if (Info < 0) { string infoSTg = Math.Abs(Info).ToString(); throw new ArgumentException("the " + infoSTg + " -th argument had an illegal value"); } else if (Info > 0) { string infoSTg = Math.Abs(Info).ToString(); throw new Exception("The algorithm for computing the SVD failed to converge."); } #endregion Matrix Solution = new Matrix(A.ColumnCount, B.ColumnCount); for (int j = 0; j < Solution.ColumnCount; j++) { for (int i = 0; i < Solution.RowCount; i++) { Solution[i, j] = ClonB[i, j]; } } return(Solution); }
//public Matrix Solve(Matrix A, Matrix B) //{ // return this.SVDdcSolve(A, B); //} //public Matrix Solve(Matrix A, Matrix B, LLSMethod method) //{ // switch (method) // { // case LLSMethod.QRorLQ: // return this.QRorLQSolve(A, B); // break; // case LLSMethod.COF: // return this.COFSolve(A, B); // break; // case LLSMethod.SVD: // return this.SVDdcSolve(A, B); // break; // } //} #endregion #region Private Metods #region QR or LQ factorization /// <summary> /// Solves overdetermined or underdetermined real linear systems /// involving an M-by-N matrix A, using a QR or LQ /// factorization of A. It is assumed that A has full rank. /// </summary> /// <param name="A">The A matrix.</param> /// <param name="B">The matrix containing the right-hand side of the linear system.</param> /// <returns>A matrix containing the solution.</returns> public Matrix QRorLQSolve(Matrix A, Matrix B) { if (this._dgels == null) { this._dgels = new DGELS(); } Matrix AClon = A.Clone(); double[] AClonData = AClon.Data; Matrix ClonB = new Matrix(Math.Max(A.RowCount, A.ColumnCount), B.ColumnCount); double[] ClonData = ClonB.Data; for (int j = 0; j < ClonB.ColumnCount; j++) { for (int i = 0; i < B.RowCount; i++) { ClonB[i, j] = B[i, j]; } } int Info = 0; //int LWork double[] Work = new double[1]; int LWork = -1; //Calculamos LWORK ideal _dgels.Run("N", A.RowCount, A.ColumnCount, B.ColumnCount, ref AClonData, 0, A.RowCount, ref ClonData, 0, ClonB.RowCount, ref Work, 0, LWork, ref Info); LWork = Convert.ToInt32(Work[0]); if (LWork > 0) { Work = new double[LWork]; _dgels.Run("N", A.RowCount, A.ColumnCount, B.ColumnCount, ref AClonData, 0, A.RowCount, ref ClonData, 0, ClonB.RowCount, ref Work, 0, LWork, ref Info); } else { //Error } #region Error // = 0: successful exit // .LT. 0: if INFO = -i, the i-th argument had an illegal value // .GT. 0: if INFO = i, the i-th diagonal element of the // triangular factor of A is zero, so that A does not have // full rank; the least squares solution could not be // computed. if (Info < 0) { string infoSTg = Math.Abs(Info).ToString(); throw new ArgumentException("the " + infoSTg + " -th argument had an illegal value"); } else if (Info > 0) { string infoSTg = Math.Abs(Info).ToString(); throw new Exception("The matrix A does not have full rank; the least squares solution could not be computed. You can use SVDSolve or SVDdcSolve"); } #endregion Matrix Solution = new Matrix(A.ColumnCount, B.ColumnCount); for (int j = 0; j < Solution.ColumnCount; j++) { for (int i = 0; i < Solution.RowCount; i++) { Solution[i, j] = ClonB[i, j]; } } return(Solution); }
/// <summary> /// Computes the minimum-norm solution to a real linear least squares problem: minimize 2-norm(|| A*X - B||) /// using a complete orthogonal factorization of A. /// The matrix A can be rank-deficient. /// </summary> /// <param name="A">The A matrix.</param> /// <param name="B">The matrix containing the right-hand side of the linear system.</param> /// <param name="rcond"> /// The parameter rcond is used to determine the effective rank of A, which /// is defined as the order of the largest leading triangular /// submatrix R11 in the QR factorization with pivoting of A, /// whose estimated condition number .LT. 1/rcond. /// </param> /// <returns>A matrix containing the solution.</returns> public Matrix COFSolve(Matrix A, Matrix B, double rcond) { if (this._dgelsy == null) { this._dgelsy = new DGELSY(); } Matrix AClon = A.Clone(); double[] AClonData = AClon.Data; Matrix ClonB = new Matrix(Math.Max(A.RowCount, A.ColumnCount), B.ColumnCount); double[] ClonData = ClonB.Data; for (int j = 0; j < ClonB.ColumnCount; j++) { for (int i = 0; i < B.RowCount; i++) { ClonB[i, j] = B[i, j]; } } int Info = 0; //int LWork double[] Work = new double[1]; int[] JPVT = new int[A.ColumnCount]; int RANK = 1; int LWork = -1; //Calculamos LWORK ideal this._dgelsy.Run(A.RowCount, A.ColumnCount, B.ColumnCount, ref AClonData, 0, A.RowCount, ref ClonData, 0, ClonB.RowCount, ref JPVT, 0, rcond, ref RANK, ref Work, 0, LWork, ref Info); LWork = Convert.ToInt32(Work[0]); if (LWork > 0) { Work = new double[LWork]; this._dgelsy.Run(A.RowCount, A.ColumnCount, B.ColumnCount, ref AClonData, 0, A.RowCount, ref ClonData, 0, ClonB.RowCount, ref JPVT, 0, rcond, ref RANK, ref Work, 0, LWork, ref Info); } else { //Error } #region Error // INFO (output) INTEGER // = 0: successful exit // < 0: If INFO = -i, the i-th argument had an illegal value. // if (Info < 0) { string infoSTg = Math.Abs(Info).ToString(); throw new ArgumentException("the " + infoSTg + " -th argument had an illegal value"); } else if (Info > 0) { //Aqui no se espqcifica nungun error, asi que en principio este valor no es posible, de cualquier forma se lo //pongo por si las dudas string infoSTg = Math.Abs(Info).ToString(); throw new Exception("Error The algorithm ... "); } #endregion Matrix Solution = new Matrix(A.ColumnCount, B.ColumnCount); for (int j = 0; j < Solution.ColumnCount; j++) { for (int i = 0; i < Solution.RowCount; i++) { Solution[i, j] = ClonB[i, j]; } } return(Solution); }