///<summary>Computes the algorithm.</summary> protected override void InternalCompute() { rows = matrix.RowLength; cols = matrix.ColumnLength; int mm = System.Math.Min(rows + 1, cols); s = new FloatVector(mm); // singular values #if MANAGED // Derived from LINPACK code. // Initialize. u = new FloatMatrix(rows, rows); // left vectors v = new FloatMatrix(cols, cols); // right vectors FloatVector e = new FloatVector(cols); FloatVector work = new FloatVector(rows); int i, iter, j, k, kase, l, lp1, ls = 0, lu, m, nct, nctp1, ncu, nrt, nrtp1; float b, c, cs = 0.0f, el, emm1, f, g, scale, shift, sl, sm, sn = 0.0f, smm1, t1, test, ztest, xnorm, enorm; float t, r; ncu = rows; // reduce matrix to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int info = 0; nct = System.Math.Min(rows - 1, cols); nrt = System.Math.Max(0, System.Math.Min(cols - 2, rows)); lu = System.Math.Max(nct, nrt); for (l = 0; l < lu; l++) { lp1 = l + 1; if (l < nct) { // compute the transformation for the l-th column and // place the l-th diagonal in s[l]. xnorm = dnrm2Column(matrix, l, l); s[l] = xnorm; if (s[l] != 0.0f) { if (matrix[l, l] != 0.0f) { s[l] = dsign(s[l], matrix[l, l]); } dscalColumn(matrix, l, l, 1.0f / s[l]); matrix[l, l] = 1.0f + matrix[l, l]; } s[l] = -s[l]; } for (j = lp1; j < cols; j++) { if (l < nct) { if (s[l] != 0.0f) { // apply the transformation. t = -ddot(matrix, l, j, l) / matrix[l, l]; for (int ii = l; ii < matrix.RowLength; ii++) { matrix[ii, j] += t * matrix[ii, l]; } } } //place the l-th row of matrix into e for the //subsequent calculation of the row transformation. e[j] = matrix[l, j]; } if (computeVectors && l < nct) { // place the transformation in u for subsequent back multiplication. for (i = l; i < rows; i++) { u[i, l] = matrix[i, l]; } } if (l < nrt) { // compute the l-th row transformation and place the l-th super-diagonal in e(l). enorm = dnrm2Vector(e, lp1); e[l] = enorm; if (e[l] != 0.0f) { if (e[lp1] != 0.0f) { e[l] = dsign(e[l], e[lp1]); } dscalVector(e, lp1, 1.0f / e[l]); e[lp1] = 1.0f + e[lp1]; } e[l] = -e[l]; if (lp1 < rows && e[l] != 0.0f) { // apply the transformation. for (i = lp1; i < rows; i++) { work[i] = 0.0f; } for (j = lp1; j < cols; j++) { for (int ii = lp1; ii < matrix.RowLength; ii++) { work[ii] += e[j] * matrix[ii, j]; } } for (j = lp1; j < cols; j++) { float ww = -e[j] / e[lp1]; for (int ii = lp1; ii < matrix.RowLength; ii++) { matrix[ii, j] += ww * work[ii]; } } } if (computeVectors) { // place the transformation in v for subsequent back multiplication. for (i = lp1; i < cols; i++) { v[i, l] = e[i]; } } } } // set up the final bidiagonal matrix or order m. m = System.Math.Min(cols, rows + 1); nctp1 = nct + 1; nrtp1 = nrt + 1; if (nct < cols) { s[nctp1 - 1] = matrix[nctp1 - 1, nctp1 - 1]; } if (rows < m) { s[m - 1] = 0.0f; } if (nrtp1 < m) { e[nrtp1 - 1] = matrix[nrtp1 - 1, m - 1]; } e[m - 1] = 0.0f; // if required, generate u. if (computeVectors) { for (j = nctp1 - 1; j < ncu; j++) { for (i = 0; i < rows; i++) { u[i, j] = 0.0f; } u[j, j] = 1.0f; } for (l = nct - 1; l >= 0; l--) { if (s[l] != 0.0f) { for (j = l + 1; j < ncu; j++) { t = -ddot(u, l, j, l) / u[l, l]; for (int ii = l; ii < u.RowLength; ii++) { u[ii, j] += t * u[ii, l]; } } dscalColumn(u, l, l, -1.0f); u[l, l] = 1.0f + u[l, l]; for (i = 0; i < l; i++) { u[i, l] = 0.0f; } } else { for (i = 0; i < rows; i++) { u[i, l] = 0.0f; } u[l, l] = 1.0f; } } } // if it is required, generate v. if (computeVectors) { for (l = cols - 1; l >= 0; l--) { lp1 = l + 1; if (l < nrt) { if (e[l] != 0.0f) { for (j = lp1; j < cols; j++) { t = -ddot(v, l, j, lp1) / v[lp1, l]; for (int ii = l; ii < v.RowLength; ii++) { v[ii, j] += t * v[ii, l]; } } } } for (i = 0; i < cols; i++) { v[i, l] = 0.0f; } v[l, l] = 1.0f; } } // transform s and e so that they are float . for (i = 0; i < m; i++) { if (s[i] != 0.0f) { t = s[i]; r = s[i] / t; s[i] = t; if (i < m - 1) { e[i] = e[i] / r; } if (computeVectors) { dscalColumn(u, i, 0, r); } } // ...exit if (i == m - 1) { break; } if (e[i] != 0.0) { t = e[i]; r = t / e[i]; e[i] = t; s[i + 1] = s[i + 1] * r; if (computeVectors) { dscalColumn(v, i + 1, 0, r); } } } // main iteration loop for the singular values. mm = m; iter = 0; while (m > 0) { // quit if all the singular values have been found. // if too many iterations have been performed, set // flag and return. if (iter >= MAXITER) { info = m; // ......exit break; } // this section of the program inspects for // negligible elements in the s and e arrays. on // completion the variables kase and l are set as follows. // kase = 1 if s[m] and e[l-1] are negligible and l < m // kase = 2 if s[l] is negligible and l < m // kase = 3 if e[l-1] is negligible, l < m, and // s[l, ..., s[m] are not negligible (qr step). // kase = 4 if e[m-1] is negligible (convergence). for (l = m - 2; l >= 0; l--) { test = ComplexMath.Absolute(s[l]) + ComplexMath.Absolute(s[l + 1]); ztest = test + ComplexMath.Absolute(e[l]); if (ztest == test) { e[l] = 0.0f; break; } } if (l == m - 2) { kase = 4; } else { for (ls = m - 1; ls > l; ls--) { test = 0.0f; if (ls != m - 1) { test = test + ComplexMath.Absolute(e[ls]); } if (ls != l + 1) { test = test + ComplexMath.Absolute(e[ls - 1]); } ztest = test + ComplexMath.Absolute(s[ls]); if (ztest == test) { s[ls] = 0.0f; break; } } if (ls == l) { kase = 3; } else if (ls == m - 1) { kase = 1; } else { kase = 2; l = ls; } } l = l + 1; // perform the task indicated by kase. switch (kase) { // deflate negligible s[m]. case 1: f = e[m - 2]; e[m - 2] = 0.0f; for (k = m - 2; k >= 0; k--) { t1 = s[k]; drotg(ref t1, ref f, ref cs, ref sn); s[k] = t1; if (k != l) { f = -sn * e[k - 1]; e[k - 1] = cs * e[k - 1]; } if (computeVectors) { drot(v, k, m - 1, cs, sn); } } break; // split at negligible s[l]. case 2: f = e[l - 1]; e[l - 1] = 0.0f; for (k = l; k < m; k++) { t1 = s[k]; drotg(ref t1, ref f, ref cs, ref sn); s[k] = t1; f = -sn * e[k]; e[k] = cs * e[k]; if (computeVectors) { drot(u, k, l - 1, cs, sn); } } break; // perform one qr step. case 3: // calculate the shift. scale = 0.0f; scale = System.Math.Max(scale, ComplexMath.Absolute(s[m - 1])); scale = System.Math.Max(scale, ComplexMath.Absolute(s[m - 2])); scale = System.Math.Max(scale, ComplexMath.Absolute(e[m - 2])); scale = System.Math.Max(scale, ComplexMath.Absolute(s[l])); scale = System.Math.Max(scale, ComplexMath.Absolute(e[l])); sm = s[m - 1] / scale; smm1 = s[m - 2] / scale; emm1 = e[m - 2] / scale; sl = s[l] / scale; el = e[l] / scale; b = ((smm1 + sm) * (smm1 - sm) + emm1 * emm1) / 2.0f; c = (sm * emm1) * (sm * emm1); shift = 0.0f; if (b != 0.0f || c != 0.0f) { shift = (float)System.Math.Sqrt(b * b + c); if (b < 0.0f) { shift = -shift; } shift = c / (b + shift); } f = (sl + sm) * (sl - sm) + shift; g = sl * el; // chase zeros. for (k = l; k < m - 1; k++) { drotg(ref f, ref g, ref cs, ref sn); if (k != l) e[k - 1] = f; f = cs * s[k] + sn * e[k]; e[k] = cs * e[k] - sn * s[k]; g = sn * s[k + 1]; s[k + 1] = cs * s[k + 1]; if (computeVectors) { drot(v, k, k + 1, cs, sn); } drotg(ref f, ref g, ref cs, ref sn); s[k] = f; f = cs * e[k] + sn * s[k + 1]; s[k + 1] = -sn * e[k] + cs * s[k + 1]; g = sn * e[k + 1]; e[k + 1] = cs * e[k + 1]; if (computeVectors && k < rows) { drot(u, k, k + 1, cs, sn); } } e[m - 2] = f; iter = iter + 1; break; // convergence. case 4: // make the singular value positive if (s[l] < 0.0f) { s[l] = -s[l]; if (computeVectors) { dscalColumn(v, l, 0, -1.0f); } } // order the singular value. while (l != mm - 1) { if (s[l] >= s[l + 1]) { break; } t = s[l]; s[l] = s[l + 1]; s[l + 1] = t; if (computeVectors && l < cols) { dswap(v, l, l + 1); } if (computeVectors && l < rows) { dswap(u, l, l + 1); } l = l + 1; } iter = 0; m = m - 1; break; } } // make matrix w from vector s // there is no constructor, creating diagonal matrix from vector // doing it ourselves mm = System.Math.Min(matrix.RowLength, matrix.ColumnLength); #else u = new FloatMatrix(rows); v = new FloatMatrix(cols); float[] a = new float[matrix.data.Length]; Array.Copy(matrix.data, a, matrix.data.Length); Lapack.Gesvd.Compute(rows, cols, a, s.data, u.data, v.data ); v.Transpose(); #endif w = new FloatMatrix(matrix.RowLength, matrix.ColumnLength); for (int ii = 0; ii < matrix.RowLength; ii++) { for (int jj = 0; jj < matrix.ColumnLength; jj++) { if (ii == jj) { w[ii, ii] = s[ii]; } } } float eps = (float)System.Math.Pow(2.0, -52.0); float tol = (float)System.Math.Max(matrix.RowLength, matrix.ColumnLength) * s[0] * eps; rank = 0; for (int h = 0; h < mm; h++) { if (s[h] > tol) { rank++; } } if (!computeVectors) { u = null; v = null; } matrix = null; }
public void TransposeLong() { FloatMatrix a = new FloatMatrix(3, 2); a[0, 0] = 1; a[0, 1] = 2; a[1, 0] = 3; a[1, 1] = 4; a[2, 0] = 5; a[2, 1] = 6; a.Transpose(); Assert.AreEqual(a[0, 0], 1); Assert.AreEqual(a[0, 1], 3); Assert.AreEqual(a[0, 2], 5); Assert.AreEqual(a[1, 0], 2); Assert.AreEqual(a[1, 1], 4); Assert.AreEqual(a[1, 2], 6); Assert.AreEqual(a.RowLength, 2); Assert.AreEqual(a.ColumnLength, 3); }
///<summary>Computes the algorithm.</summary> protected override void InternalCompute() { rows = matrix.RowLength; cols = matrix.ColumnLength; int mm = System.Math.Min(rows + 1, cols); s = new FloatVector(mm); // singular values #if MANAGED // Derived from LINPACK code. // Initialize. u = new FloatMatrix(rows, rows); // left vectors v = new FloatMatrix(cols, cols); // right vectors var e = new FloatVector(cols); var work = new FloatVector(rows); int i, iter, j, k, kase, l, lp1, ls = 0, lu, m, nct, nctp1, ncu, nrt, nrtp1; float b, c, cs = 0.0f, el, emm1, f, g, scale, shift, sl, sm, sn = 0.0f, smm1, t1, test, ztest, xnorm, enorm; float t, r; ncu = rows; // reduce matrix to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int info = 0; nct = System.Math.Min(rows - 1, cols); nrt = System.Math.Max(0, System.Math.Min(cols - 2, rows)); lu = System.Math.Max(nct, nrt); for (l = 0; l < lu; l++) { lp1 = l + 1; if (l < nct) { // compute the transformation for the l-th column and // place the l-th diagonal in s[l]. xnorm = dnrm2Column(matrix, l, l); s[l] = xnorm; if (s[l] != 0.0f) { if (matrix[l, l] != 0.0f) { s[l] = dsign(s[l], matrix[l, l]); } dscalColumn(matrix, l, l, 1.0f / s[l]); matrix[l, l] = 1.0f + matrix[l, l]; } s[l] = -s[l]; } for (j = lp1; j < cols; j++) { if (l < nct) { if (s[l] != 0.0f) { // apply the transformation. t = -ddot(matrix, l, j, l) / matrix[l, l]; for (int ii = l; ii < matrix.RowLength; ii++) { matrix[ii, j] += t * matrix[ii, l]; } } } //place the l-th row of matrix into e for the //subsequent calculation of the row transformation. e[j] = matrix[l, j]; } if (computeVectors && l < nct) { // place the transformation in u for subsequent back multiplication. for (i = l; i < rows; i++) { u[i, l] = matrix[i, l]; } } if (l < nrt) { // compute the l-th row transformation and place the l-th super-diagonal in e(l). enorm = dnrm2Vector(e, lp1); e[l] = enorm; if (e[l] != 0.0f) { if (e[lp1] != 0.0f) { e[l] = dsign(e[l], e[lp1]); } dscalVector(e, lp1, 1.0f / e[l]); e[lp1] = 1.0f + e[lp1]; } e[l] = -e[l]; if (lp1 < rows && e[l] != 0.0f) { // apply the transformation. for (i = lp1; i < rows; i++) { work[i] = 0.0f; } for (j = lp1; j < cols; j++) { for (int ii = lp1; ii < matrix.RowLength; ii++) { work[ii] += e[j] * matrix[ii, j]; } } for (j = lp1; j < cols; j++) { float ww = -e[j] / e[lp1]; for (int ii = lp1; ii < matrix.RowLength; ii++) { matrix[ii, j] += ww * work[ii]; } } } if (computeVectors) { // place the transformation in v for subsequent back multiplication. for (i = lp1; i < cols; i++) { v[i, l] = e[i]; } } } } // set up the final bidiagonal matrix or order m. m = System.Math.Min(cols, rows + 1); nctp1 = nct + 1; nrtp1 = nrt + 1; if (nct < cols) { s[nctp1 - 1] = matrix[nctp1 - 1, nctp1 - 1]; } if (rows < m) { s[m - 1] = 0.0f; } if (nrtp1 < m) { e[nrtp1 - 1] = matrix[nrtp1 - 1, m - 1]; } e[m - 1] = 0.0f; // if required, generate u. if (computeVectors) { for (j = nctp1 - 1; j < ncu; j++) { for (i = 0; i < rows; i++) { u[i, j] = 0.0f; } u[j, j] = 1.0f; } for (l = nct - 1; l >= 0; l--) { if (s[l] != 0.0f) { for (j = l + 1; j < ncu; j++) { t = -ddot(u, l, j, l) / u[l, l]; for (int ii = l; ii < u.RowLength; ii++) { u[ii, j] += t * u[ii, l]; } } dscalColumn(u, l, l, -1.0f); u[l, l] = 1.0f + u[l, l]; for (i = 0; i < l; i++) { u[i, l] = 0.0f; } } else { for (i = 0; i < rows; i++) { u[i, l] = 0.0f; } u[l, l] = 1.0f; } } } // if it is required, generate v. if (computeVectors) { for (l = cols - 1; l >= 0; l--) { lp1 = l + 1; if (l < nrt) { if (e[l] != 0.0f) { for (j = lp1; j < cols; j++) { t = -ddot(v, l, j, lp1) / v[lp1, l]; for (int ii = l; ii < v.RowLength; ii++) { v[ii, j] += t * v[ii, l]; } } } } for (i = 0; i < cols; i++) { v[i, l] = 0.0f; } v[l, l] = 1.0f; } } // transform s and e so that they are float . for (i = 0; i < m; i++) { if (s[i] != 0.0f) { t = s[i]; r = s[i] / t; s[i] = t; if (i < m - 1) { e[i] = e[i] / r; } if (computeVectors) { dscalColumn(u, i, 0, r); } } // ...exit if (i == m - 1) { break; } if (e[i] != 0.0) { t = e[i]; r = t / e[i]; e[i] = t; s[i + 1] = s[i + 1] * r; if (computeVectors) { dscalColumn(v, i + 1, 0, r); } } } // main iteration loop for the singular values. mm = m; iter = 0; while (m > 0) { // quit if all the singular values have been found. // if too many iterations have been performed, set // flag and return. if (iter >= MAXITER) { info = m; // ......exit break; } // this section of the program inspects for // negligible elements in the s and e arrays. on // completion the variables kase and l are set as follows. // kase = 1 if s[m] and e[l-1] are negligible and l < m // kase = 2 if s[l] is negligible and l < m // kase = 3 if e[l-1] is negligible, l < m, and // s[l, ..., s[m] are not negligible (qr step). // kase = 4 if e[m-1] is negligible (convergence). for (l = m - 2; l >= 0; l--) { test = ComplexMath.Absolute(s[l]) + ComplexMath.Absolute(s[l + 1]); ztest = test + ComplexMath.Absolute(e[l]); if (ztest == test) { e[l] = 0.0f; break; } } if (l == m - 2) { kase = 4; } else { for (ls = m - 1; ls > l; ls--) { test = 0.0f; if (ls != m - 1) { test = test + ComplexMath.Absolute(e[ls]); } if (ls != l + 1) { test = test + ComplexMath.Absolute(e[ls - 1]); } ztest = test + ComplexMath.Absolute(s[ls]); if (ztest == test) { s[ls] = 0.0f; break; } } if (ls == l) { kase = 3; } else if (ls == m - 1) { kase = 1; } else { kase = 2; l = ls; } } l = l + 1; // perform the task indicated by kase. switch (kase) { // deflate negligible s[m]. case 1: f = e[m - 2]; e[m - 2] = 0.0f; for (k = m - 2; k >= 0; k--) { t1 = s[k]; drotg(ref t1, ref f, ref cs, ref sn); s[k] = t1; if (k != l) { f = -sn * e[k - 1]; e[k - 1] = cs * e[k - 1]; } if (computeVectors) { drot(v, k, m - 1, cs, sn); } } break; // split at negligible s[l]. case 2: f = e[l - 1]; e[l - 1] = 0.0f; for (k = l; k < m; k++) { t1 = s[k]; drotg(ref t1, ref f, ref cs, ref sn); s[k] = t1; f = -sn * e[k]; e[k] = cs * e[k]; if (computeVectors) { drot(u, k, l - 1, cs, sn); } } break; // perform one qr step. case 3: // calculate the shift. scale = 0.0f; scale = System.Math.Max(scale, ComplexMath.Absolute(s[m - 1])); scale = System.Math.Max(scale, ComplexMath.Absolute(s[m - 2])); scale = System.Math.Max(scale, ComplexMath.Absolute(e[m - 2])); scale = System.Math.Max(scale, ComplexMath.Absolute(s[l])); scale = System.Math.Max(scale, ComplexMath.Absolute(e[l])); sm = s[m - 1] / scale; smm1 = s[m - 2] / scale; emm1 = e[m - 2] / scale; sl = s[l] / scale; el = e[l] / scale; b = ((smm1 + sm) * (smm1 - sm) + emm1 * emm1) / 2.0f; c = (sm * emm1) * (sm * emm1); shift = 0.0f; if (b != 0.0f || c != 0.0f) { shift = (float)System.Math.Sqrt(b * b + c); if (b < 0.0f) { shift = -shift; } shift = c / (b + shift); } f = (sl + sm) * (sl - sm) + shift; g = sl * el; // chase zeros. for (k = l; k < m - 1; k++) { drotg(ref f, ref g, ref cs, ref sn); if (k != l) { e[k - 1] = f; } f = cs * s[k] + sn * e[k]; e[k] = cs * e[k] - sn * s[k]; g = sn * s[k + 1]; s[k + 1] = cs * s[k + 1]; if (computeVectors) { drot(v, k, k + 1, cs, sn); } drotg(ref f, ref g, ref cs, ref sn); s[k] = f; f = cs * e[k] + sn * s[k + 1]; s[k + 1] = -sn * e[k] + cs * s[k + 1]; g = sn * e[k + 1]; e[k + 1] = cs * e[k + 1]; if (computeVectors && k < rows) { drot(u, k, k + 1, cs, sn); } } e[m - 2] = f; iter = iter + 1; break; // convergence. case 4: // make the singular value positive if (s[l] < 0.0f) { s[l] = -s[l]; if (computeVectors) { dscalColumn(v, l, 0, -1.0f); } } // order the singular value. while (l != mm - 1) { if (s[l] >= s[l + 1]) { break; } t = s[l]; s[l] = s[l + 1]; s[l + 1] = t; if (computeVectors && l < cols) { dswap(v, l, l + 1); } if (computeVectors && l < rows) { dswap(u, l, l + 1); } l = l + 1; } iter = 0; m = m - 1; break; } } // make matrix w from vector s // there is no constructor, creating diagonal matrix from vector // doing it ourselves mm = System.Math.Min(matrix.RowLength, matrix.ColumnLength); #else u = new FloatMatrix(rows); v = new FloatMatrix(cols); float[] a = new float[matrix.data.Length]; Array.Copy(matrix.data, a, matrix.data.Length); Lapack.Gesvd.Compute(rows, cols, a, s.data, u.data, v.data); v.Transpose(); #endif w = new FloatMatrix(matrix.RowLength, matrix.ColumnLength); for (int ii = 0; ii < matrix.RowLength; ii++) { for (int jj = 0; jj < matrix.ColumnLength; jj++) { if (ii == jj) { w[ii, ii] = s[ii]; } } } float eps = (float)System.Math.Pow(2.0, -52.0); float tol = System.Math.Max(matrix.RowLength, matrix.ColumnLength) * s[0] * eps; rank = 0; for (int h = 0; h < mm; h++) { if (s[h] > tol) { rank++; } } if (!computeVectors) { u = null; v = null; } matrix = null; }
public void TransposeSquare() { FloatMatrix a = new FloatMatrix(2, 2); a[0, 0] = 1; a[0, 1] = 2; a[1, 0] = 3; a[1, 1] = 4; a.Transpose(); Assert.AreEqual(a[0, 0], 1); Assert.AreEqual(a[0, 1], 3); Assert.AreEqual(a[1, 0], 2); Assert.AreEqual(a[1, 1], 4); }