/// <summary> /// QR decomposition with pivoting, possibly economical sized /// </summary> /// <param name="A">general input matrix A of size [m x n]</param> /// <param name="R">output parameter. Upper triangular matrix R as /// result of decomposition. Size [m x n] or [min(m,n) x n] depending /// on <paramref name="economySize"/> (see remarks). </param> /// <param name="economySize"><para>if true, <list type="bullet"> /// <item>the size of Q and R will be [m x m] and [m x n] respectively. /// However, if m < n, the economySize parameter has no effect on /// those sizes.</item> /// <item>the output parameter E will be returned as row permutation /// vector rather than as permutation matrix</item></list></para> /// <para>if false, this function acts exactly as its overload /// <see cref="ILNumerics.BuiltInFunctions.ILMath.qr(ILArray<double>,ref ILArray<double>,ref ILArray<double>)"/></para> /// </param> /// <param name="E">permutation matrix from pivoting. Size [m x m]. /// If this is not null, the permutation matrix/ vector E will be returned. /// <para>E is of size [n x n], if <paramref name="economySize"/> is /// true, a row vector of length n otherwise</para></param> /// <returns>Orthonormal / unitary matrix Q as result of decomposition. /// Size [m x m] or [m x min(m,n)], depending on <paramref name="economySize"/> /// (see remarks below)</returns> /// <remarks><para> If <paramref name="economySize"/> is false, the function /// returns Q, R and E such that the equation A * E = Q * R holds except /// roundoff errors. </para> /// <para>If <paramref name="economySize"/> is true, E will be a permutation /// vector and the equation A[null,E] == Q * R holds (except roundoff).</para> /// <para>E reflects the pivoting of A done inside LAPACK in order to give R /// increasingly diagonal elements.</para> /// <para>Q, R and E will be solid ILArray's.</para></remarks> public static ILArray <complex> qr( ILArray <complex> A, ref ILArray <complex> R, ref ILArray <complex> E, bool economySize) { if (Object.Equals(R, null)) { return(qr(A)); } int m = A.Dimensions[0]; int n = A.Dimensions[1]; if (m < n && economySize) { return(qr(A, ref R, false)); } ILArray <complex> ret; if (m == 0 || n == 0) { R = new ILArray <complex> (new complex [0], m, n); E = new ILArray <complex> (new complex [0], 1, 0); return(ILArray <complex> .empty(A.Dimensions)); } // prepare IPVT if (object.Equals(E, null)) { return(qr(A, ref R, economySize)); } if (!economySize) { E = new ILArray <complex> (new complex [n * n], n, n); } else { E = new ILArray <complex> (new complex [n], 1, n); } int [] ipvt = new int[n]; int minMN = (m < n)?m:n; int info = 0; complex [] tau = new complex [minMN]; complex [] QArr; if (m >= n) { ret = new ILArray <complex> ( new complex [(economySize)? minMN * m : m * m], m, (economySize)? minMN: m); } else { // economySize is always false ... ! // a temporary array is needed for extraction of the compact lapack Q (?geqrf) ret = new ILArray <complex> ( new complex [m * n], m, n); } QArr = ret.m_data; for (int i = m * n; i-- > 0;) { QArr[i] = A.GetValue(i); } Lapack.zgeqp3(m, n, QArr, m, ipvt, tau, ref info); if (info != 0) { throw new ILArgumentException("qr: error inside lapack library (?geqrf). info=" + info.ToString()); } // extract R, Q if (economySize) { R = copyUpperTriangle(QArr, m, n, minMN); Lapack.zungqr(m, minMN, tau.Length, QArr, m, tau, ref info); // transform E into out typed vector for (int i = 0; i < n; i++) { E.m_data[i] = ipvt[i] - 1; } } else { R = copyUpperTriangle(QArr, m, n, m); Lapack.zungqr(m, m, tau.Length, QArr, m, tau, ref info); if (m < n) { ret = ret[":;0:" + (m - 1)]; } // transform E into matrix for (int i = 0; i < n; i++) { E.m_data[(ipvt[i] - 1) + n * i] = new complex(1.0, 0.0); } } if (info != 0) { throw new ILArgumentException("qr: error in lapack library (???gqr). info=" + info.ToString()); } return(ret); }