/// <summary> /// Batch decomposition of the given matrix. /// The decomposed matrices can be retrieved via instance methods. /// </summary> /// <param name="arg"> /// A rectangular matrix. /// </param> /// <param name="wantU"> /// Whether the matrix U is needed. /// </param> /// <param name="wantV"> /// Whether the matrix V is needed. /// </param> /// <param name="order"> /// whether the singular values must be ordered. /// </param> /// <exception cref="ArgumentException"> /// If /// <code> /// a.Rows < a.Columns /// </code> /// . /// </exception> private void BatchSVD(DoubleMatrix2D arg, bool wantU, bool wantV, bool order) { Property.DEFAULT.CheckRectangular(arg); // Derived from LINPACK code. // Initialize. double[][] a = arg.ToArray(); _m = arg.Rows; _n = arg.Columns; int nu = Math.Min(_m, _n); _s = new double[Math.Min(_m + 1, _n)]; _u = new DenseDoubleMatrix2D(_m, nu); if (wantV) { _v = new DenseDoubleMatrix2D(_n, _n); } var e = new double[_n]; var work = new double[_m]; // Reduce A to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int nct = Math.Min(_m - 1, _n); int nrt = Math.Max(0, Math.Min(_n - 2, _m)); for (int k = 0; k < Math.Max(nct, nrt); k++) { if (k < nct) { // Compute the transformation for the k-th column and // place the k-th diagonal in s[k]. // Compute 2-norm of k-th column without under/overflow. _s[k] = 0; for (int i = k; i < _m; i++) { _s[k] = Algebra.Hypot(_s[k], a[i][k]); } if (_s[k] != 0.0) { if (a[k][k] < 0.0) { _s[k] = -_s[k]; } for (int i = k; i < _m; i++) { a[i][k] /= _s[k]; } a[k][k] += 1.0; } _s[k] = -_s[k]; } for (int j = k + 1; j < _n; j++) { if ((k < nct) & (_s[k] != 0.0)) { // Apply the transformation. double t = 0; for (int i = k; i < _m; i++) { t += a[i][k] * a[i][j]; } t = -t / a[k][k]; for (int i = k; i < _m; i++) { a[i][j] += t * a[i][k]; } } // Place the k-th row of A into e for the // subsequent calculation of the row transformation. e[j] = a[k][j]; } if (wantU & (k < nct)) { // Place the transformation in U for subsequent back multiplication. for (int i = k; i < _m; i++) { _u[i, k] = a[i][k]; } } if (k < nrt) { // Compute the k-th row transformation and place the // k-th super-diagonal in e[k]. // Compute 2-norm without under/overflow. e[k] = 0; for (int i = k + 1; i < _n; i++) { e[k] = Algebra.Hypot(e[k], e[i]); } if (e[k] != 0.0) { if (e[k + 1] < 0.0) { e[k] = -e[k]; } for (int i = k + 1; i < _n; i++) { e[i] /= e[k]; } e[k + 1] += 1.0; } e[k] = -e[k]; if ((k + 1 < _m) & (e[k] != 0.0)) { // Apply the transformation. for (int i = k + 1; i < _m; i++) { work[i] = 0.0; } for (int j = k + 1; j < _n; j++) { for (int i = k + 1; i < _m; i++) { work[i] += e[j] * a[i][j]; } } for (int j = k + 1; j < _n; j++) { double t = -e[j] / e[k + 1]; for (int i = k + 1; i < _m; i++) { a[i][j] += t * work[i]; } } } if (wantV) { // Place the transformation in V for subsequent back multiplication. for (int i = k + 1; i < _n; i++) { _v[i, k] = e[i]; } } } } // Set up the final bidiagonal matrix or order p. int p = Math.Min(_n, _m + 1); if (nct < _n) { _s[nct] = a[nct][nct]; } if (_m < p) { _s[p - 1] = 0.0; } if (nrt + 1 < p) { e[nrt] = a[nrt][p - 1]; } e[p - 1] = 0.0; // If required, generate U. if (wantU) { for (int j = nct; j < nu; j++) { for (int i = 0; i < _m; i++) { _u[i, j] = 0.0; } _u[j, j] = 1.0; } for (int k = nct - 1; k >= 0; k--) { if (_s[k] != 0.0) { for (int j = k + 1; j < nu; j++) { double t = 0; for (int i = k; i < _m; i++) { t += _u[i, k] * _u[i, j]; } t = -t / _u[k, k]; for (int i = k; i < _m; i++) { _u[i, j] += t * _u[i, k]; } } for (int i = k; i < _m; i++) { _u[i, k] = -_u[i, k]; } _u[k, k] = 1.0 + _u[k, k]; for (int i = 0; i < k - 1; i++) { _u[i, k] = 0.0; } } else { for (int i = 0; i < _m; i++) { _u[i, k] = 0.0; } _u[k, k] = 1.0; } } } // If required, generate V. if (wantV) { for (int k = _n - 1; k >= 0; k--) { if ((k < nrt) & (e[k] != 0.0)) { for (int j = k + 1; j < nu; j++) { double t = 0; for (int i = k + 1; i < _n; i++) { t += _v[i, k] * _v[i, j]; } t = -t / _v[k + 1, k]; for (int i = k + 1; i < _n; i++) { _v[i, j] += t * _v[i, k]; } } } for (int i = 0; i < _n; i++) { _v[i, k] = 0.0; } _v[k, k] = 1.0; } } // Main iteration loop for the singular values. int pp = p - 1; int iter = 0; double eps = Math.Pow(2.0, -52.0); while (p > 0) { int k, kase; // Here is where a test for too many iterations would go. // This section of the program inspects for // negligible elements in the s and e arrays. On // completion the variables kase and k are set as follows. // kase = 1 if s(p) and e[k-1] are negligible and k<p // kase = 2 if s(k) is negligible and k<p // kase = 3 if e[k-1] is negligible, k<p, and // s(k), .., s(p) are not negligible (qr step). // kase = 4 if e(p-1) is negligible (convergence). for (k = p - 2; k >= -1; k--) { if (k == -1) { break; } if (Math.Abs(e[k]) <= eps * (Math.Abs(_s[k]) + Math.Abs(_s[k + 1]))) { e[k] = 0.0; break; } } if (k == p - 2) { kase = 4; } else { int ks; for (ks = p - 1; ks >= k; ks--) { if (ks == k) { break; } double t = (ks != p ? Math.Abs(e[ks]) : 0) + (ks != k + 1 ? Math.Abs(e[ks - 1]) : 0); if (Math.Abs(_s[ks]) <= eps * t) { _s[ks] = 0.0; break; } } if (ks == k) { kase = 3; } else if (ks == p - 1) { kase = 1; } else { kase = 2; k = ks; } } k++; // Perform the task indicated by kase. switch (kase) { // Deflate negligible s(p). case 1: { double f = e[p - 2]; e[p - 2] = 0.0; for (int j = p - 2; j >= k; j--) { double t = Algebra.Hypot(_s[j], f); double cs = _s[j] / t; double sn = f / t; _s[j] = t; if (j != k) { f = -sn * e[j - 1]; e[j - 1] = cs * e[j - 1]; } if (wantV) { for (int i = 0; i < _n; i++) { t = (cs * _v[i, j]) + (sn * _v[i, p - 1]); _v[i, p - 1] = -(sn * _v[i, j]) + (cs * _v[i, p - 1]); _v[i, j] = t; } } } } break; // Split at negligible s(k). case 2: { double f = e[k - 1]; e[k - 1] = 0.0; for (int j = k; j < p; j++) { double t = Algebra.Hypot(_s[j], f); double cs = _s[j] / t; double sn = f / t; _s[j] = t; f = -sn * e[j]; e[j] = cs * e[j]; if (wantU) { for (int i = 0; i < _m; i++) { t = (cs * _u[i, j]) + (sn * _u[i, k - 1]); _u[i, k - 1] = -(sn * _u[i, j]) + (cs * _u[i, k - 1]); _u[i, j] = t; } } } } break; // Perform one qr step. case 3: { // Calculate the shift. double scale = Math.Max( Math.Max( Math.Max(Math.Max(Math.Abs(_s[p - 1]), Math.Abs(_s[p - 2])), Math.Abs(e[p - 2])), Math.Abs(_s[k])), Math.Abs(e[k])); double sp = _s[p - 1] / scale; double spm1 = _s[p - 2] / scale; double epm1 = e[p - 2] / scale; double sk = _s[k] / scale; double ek = e[k] / scale; double b = (((spm1 + sp) * (spm1 - sp)) + (epm1 * epm1)) / 2.0; double c = (sp * epm1) * (sp * epm1); double shift = 0.0; if ((b != 0.0) | (c != 0.0)) { shift = Math.Sqrt((b * b) + c); if (b < 0.0) { shift = -shift; } shift = c / (b + shift); } double f = ((sk + sp) * (sk - sp)) + shift; double g = sk * ek; // Chase zeros. for (int j = k; j < p - 1; j++) { double t = Algebra.Hypot(f, g); double cs = f / t; double sn = g / t; if (j != k) { e[j - 1] = t; } f = (cs * _s[j]) + (sn * e[j]); e[j] = (cs * e[j]) - (sn * _s[j]); g = sn * _s[j + 1]; _s[j + 1] = cs * _s[j + 1]; if (wantV) { for (int i = 0; i < _n; i++) { t = (cs * _v[i, j]) + (sn * _v[i, j + 1]); _v[i, j + 1] = -(sn * _v[i, j]) + (cs * _v[i, j + 1]); _v[i, j] = t; } } t = Algebra.Hypot(f, g); cs = f / t; sn = g / t; _s[j] = t; f = (cs * e[j]) + (sn * _s[j + 1]); _s[j + 1] = -(sn * e[j]) + (cs * _s[j + 1]); g = sn * e[j + 1]; e[j + 1] = cs * e[j + 1]; if (wantU && (j < _m - 1)) { for (int i = 0; i < _m; i++) { t = (cs * _u[i, j]) + (sn * _u[i, j + 1]); _u[i, j + 1] = -(sn * _u[i, j]) + (cs * _u[i, j + 1]); _u[i, j] = t; } } } e[p - 2] = f; iter = iter + 1; } break; // Convergence. case 4: { // Make the singular values positive. if (_s[k] <= 0.0) { _s[k] = _s[k] < 0.0 ? -_s[k] : 0.0; if (wantV) { for (int i = 0; i <= pp; i++) { _v[i, k] = -_v[i, k]; } } } // Order the singular values. if (order) { while (k < pp) { if (_s[k] >= _s[k + 1]) { break; } double t = _s[k]; _s[k] = _s[k + 1]; _s[k + 1] = t; if (wantV && (k < _n - 1)) { for (int i = 0; i < _n; i++) { t = _v[i, k + 1]; _v[i, k + 1] = _v[i, k]; _v[i, k] = t; } } if (k < _m - 1) { for (int i = 0; i < _m; i++) { t = _u[i, k + 1]; _u[i, k + 1] = _u[i, k]; _u[i, k] = t; } } k++; } } iter = 0; p--; } break; } } }
/// <summary> /// Constructs and returns a new QR decomposition object; computed by Householder reflections; /// The decomposed matrices can be retrieved via instance methods of the returned decomposition object. /// Return a decomposition object to access <i>R</i> and the Householder vectors <i>H</i>, and to compute <i>Q</i>. /// </summary> /// <param name="A">A rectangular matrix.</param> /// <exception cref="ArgumentException">if <i>A.Rows < A.Columns</i>.</exception> public QRDecomposition(DoubleMatrix2D A) { Property.DEFAULT.CheckRectangular(A); Functions F = Functions.functions; // Initialize. QR = A.Copy(); m = A.Rows; n = A.Columns; Rdiag = A.Like1D(n); //Rdiag = new double[n]; DoubleDoubleFunction hypot = Algebra.HypotFunction(); // precompute and cache some views to avoid regenerating them time and again DoubleMatrix1D[] QRcolumns = new DoubleMatrix1D[n]; DoubleMatrix1D[] QRcolumnsPart = new DoubleMatrix1D[n]; for (int k = 0; k < n; k++) { QRcolumns[k] = QR.ViewColumn(k); QRcolumnsPart[k] = QR.ViewColumn(k).ViewPart(k, m - k); } // Main loop. for (int k = 0; k < n; k++) { //DoubleMatrix1D QRcolk = QR.ViewColumn(k).ViewPart(k,m-k); // Compute 2-norm of k-th column without under/overflow. double nrm = 0; //if (k<m) nrm = QRcolumnsPart[k].aggregate(hypot,F.identity); for (int i = k; i < m; i++) { // fixes bug reported by [email protected] nrm = Algebra.Hypot(nrm, QR[i, k]); } if (nrm != 0.0) { // Form k-th Householder vector. if (QR[k, k] < 0) { nrm = -nrm; } QRcolumnsPart[k].Assign(F2.Div(nrm)); /* * for (int i = k; i < m; i++) { * QR[i][k] /= nrm; * } */ QR[k, k] = QR[k, k] + 1; // Apply transformation to remaining columns. for (int j = k + 1; j < n; j++) { DoubleMatrix1D QRcolj = QR.ViewColumn(j).ViewPart(k, m - k); double s = QRcolumnsPart[k].ZDotProduct(QRcolj); /* * // fixes bug reported by John Chambers * DoubleMatrix1D QRcolj = QR.ViewColumn(j).ViewPart(k,m-k); * double s = QRcolumnsPart[k].ZDotProduct(QRcolumns[j]); * double s = 0.0; * for (int i = k; i < m; i++) { * s += QR[i][k]*QR[i][j]; * } */ s = -s / QR[k, k]; //QRcolumnsPart[j].Assign(QRcolumns[k], F.PlusMult(s)); for (int i = k; i < m; i++) { QR[i, j] = QR[i, j] + s * QR[i, k]; } } } Rdiag[k] = -nrm; } }
/// <summary> /// Symmetric tridiagonal QL algorithm. /// </summary> private void Tql2() { // This is derived from the Algol procedures tql2, by // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for // Autod Compd, Vol.ii-Linear Algebra, and the corresponding // Fortran subroutine in EISPACK. for (int i = 1; i < n; i++) { e[i - 1] = e[i]; } e[n - 1] = 0.0; double f = 0.0; double tst1 = 0.0; double eps = System.Math.Pow(2.0, -52.0); for (int l = 0; l < n; l++) { // Find small subdiagonal element tst1 = System.Math.Max(tst1, System.Math.Abs(d[l]) + System.Math.Abs(e[l])); int m = l; while (m < n) { if (System.Math.Abs(e[m]) <= eps * tst1) { break; } m++; } // If m == l, d[l] is an eigenvalue, // otherwise, iterate. if (m > l) { int iter = 0; do { iter = iter + 1; // (Could check iteration count hered) // Compute implicit shift double g = d[l]; double p = (d[l + 1] - g) / (2.0 * e[l]); double r = Algebra.Hypot(p, 1.0); if (p < 0) { r = -r; } d[l] = e[l] / (p + r); d[l + 1] = e[l] * (p + r); double dl1 = d[l + 1]; double h = g - d[l]; for (int i = l + 2; i < n; i++) { d[i] -= h; } f = f + h; // Implicit QL transformation. p = d[m]; double c = 1.0; double c2 = c; double c3 = c; double el1 = e[l + 1]; double s = 0.0; double s2 = 0.0; for (int i = m - 1; i >= l; i--) { c3 = c2; c2 = c; s2 = s; g = c * e[i]; h = c * p; r = Algebra.Hypot(p, e[i]); e[i + 1] = s * r; s = e[i] / r; c = p / r; p = c * d[i] - s * g; d[i + 1] = h + s * (c * g + s * d[i]); // Accumulate transformation. for (int k = 0; k < n; k++) { h = v[k][i + 1]; v[k][i + 1] = s * v[k][i] + c * h; v[k][i] = c * v[k][i] - s * h; } } p = -s * s2 * c3 * el1 * e[l] / dl1; e[l] = s * p; d[l] = c * p; // Check for convergence. } while (System.Math.Abs(e[l]) > eps * tst1); } d[l] = d[l] + f; e[l] = 0.0; } // Sort eigenvalues and corresponding vectors. for (int i = 0; i < n - 1; i++) { int k = i; double p = d[i]; for (int j = i + 1; j < n; j++) { if (d[j] < p) { k = j; p = d[j]; } } if (k != i) { d[k] = d[i]; d[i] = p; for (int j = 0; j < n; j++) { p = v[j][i]; v[j][i] = v[j][k]; v[j][k] = p; } } } }
public double Dnrm2(DoubleMatrix1D x) { return(System.Math.Sqrt(Algebra.Norm2(x))); }
public void Solve(DoubleMatrix2D B) { int CUT_OFF = 10; //algebra.property().checkRectangular(LU); int m = M; int n = N; if (B.Rows != m) { throw new ArgumentException("Matrix row dimensions must agree."); } if (!this.IsNonsingular) { throw new ArgumentException("Matrix is singular."); } // right hand side with pivoting // Matrix Xmat = B.getMatrix(piv,0,nx-1); if (this.work1 == null || this.work1.Length < m) { this.work1 = new int[m]; } //if (this.work2 == null || this.work2.Length < m) this.work2 = new int[m]; Algebra.PermuteRows(B, this.piv, this.work1); if (m * n == 0) { return; // nothing to do } int nx = B.Columns; //precompute and cache some views to avoid regenerating them time and again DoubleMatrix1D[] Brows = new DoubleMatrix1D[n]; for (int k = 0; k < n; k++) { Brows[k] = B.ViewRow(k); } // transformations Cern.Jet.Math.Mult div = Cern.Jet.Math.Mult.Div(0); Cern.Jet.Math.PlusMult minusMult = Cern.Jet.Math.PlusMult.MinusMult(0); IntArrayList nonZeroIndexes = new IntArrayList(); // sparsity DoubleMatrix1D Browk = Cern.Colt.Matrix.DoubleFactory1D.Dense.Make(nx); // blocked row k // Solve L*Y = B(piv,:) for (int k = 0; k < n; k++) { // blocking (make copy of k-th row to localize references) Browk.Assign(Brows[k]); // sparsity detection int maxCardinality = nx / CUT_OFF; // == heuristic depending on speedup Browk.GetNonZeros(nonZeroIndexes, null, maxCardinality); int cardinality = nonZeroIndexes.Count; Boolean sparse = (cardinality < maxCardinality); for (int i = k + 1; i < n; i++) { //for (int j = 0; j < nx; j++) B[i][j] -= B[k][j]*LU[i][k]; //for (int j = 0; j < nx; j++) B.set(i,j, B.Get(i,j) - B.Get(k,j)*LU.Get(i,k)); minusMult.Multiplicator = -LU[i, k]; if (minusMult.Multiplicator != 0) { if (sparse) { Brows[i].Assign(Browk, minusMult, nonZeroIndexes); } else { Brows[i].Assign(Browk, minusMult); } } } } // Solve U*B = Y; for (int k = n - 1; k >= 0; k--) { // for (int j = 0; j < nx; j++) B[k][j] /= LU[k][k]; // for (int j = 0; j < nx; j++) B.set(k,j, B.Get(k,j) / LU.Get(k,k)); div.Multiplicator = 1 / LU[k, k]; Brows[k].Assign(div); // blocking if (Browk == null) { Browk = Cern.Colt.Matrix.DoubleFactory1D.Dense.Make(B.Columns); } Browk.Assign(Brows[k]); // sparsity detection int maxCardinality = nx / CUT_OFF; // == heuristic depending on speedup Browk.GetNonZeros(nonZeroIndexes, null, maxCardinality); int cardinality = nonZeroIndexes.Count; Boolean sparse = (cardinality < maxCardinality); //Browk.GetNonZeros(nonZeroIndexes,null); //Boolean sparse = nonZeroIndexes.Count < nx/10; for (int i = 0; i < k; i++) { // for (int j = 0; j < nx; j++) B[i][j] -= B[k][j]*LU[i][k]; // for (int j = 0; j < nx; j++) B.set(i,j, B.Get(i,j) - B.Get(k,j)*LU.Get(i,k)); minusMult.Multiplicator = -LU[i, k]; if (minusMult.Multiplicator != 0) { if (sparse) { Brows[i].Assign(Browk, minusMult, nonZeroIndexes); } else { Brows[i].Assign(Browk, minusMult); } } } } }
public void Solve(DoubleMatrix1D B) { //algebra.property().checkRectangular(LU); int m = M; int n = N; if (B.Count() != m) { throw new ArgumentException("Matrix dimensions must agree."); } if (!this.IsNonsingular) { throw new ArgumentException("Matrix is singular."); } // right hand side with pivoting // Matrix Xmat = B.getMatrix(piv,0,nx-1); if (this.workDouble == null || this.workDouble.Length < m) { this.workDouble = new double[m]; } Algebra.Permute(B, this.piv, this.workDouble); if (m * n == 0) { return; // nothing to do } // Solve L*Y = B(piv,:) for (int k = 0; k < n; k++) { double f = B[k]; if (f != 0) { for (int i = k + 1; i < n; i++) { // B[i] -= B[k]*LU[i][k]; double v = LU[i, k]; if (v != 0) { B[i] = B[i] - f * v; } } } } // Solve U*B = Y; for (int k = n - 1; k >= 0; k--) { // B[k] /= LU[k,k] B[k] = B[k] / LU[k, k]; double f = B[k]; if (f != 0) { for (int i = 0; i < k; i++) { // B[i] -= B[k]*LU[i][k]; double v = LU[i, k]; if (v != 0) { B[i] = B[i] - f * v; } } } } }