private static void rotateArray(SVDRec R, int x) { if (x == 0) return; x *= R.Vt.cols; int i, j, n, start, nRow, nCol; double t1, t2; int size = R.Vt.rows * R.Vt.cols; j = start = 0; t1 = R.Vt.value[0][0]; for (i = 0; i < size; i++) { if (j >= x) n = j - x; else n = j - x + size; nRow = n / R.Vt.cols; nCol = n - nRow * R.Vt.cols; t2 = R.Vt.value[nRow][nCol]; R.Vt.value[nRow][nCol] = t1; t1 = t2; j = n; if (j == start) { start = ++j; nRow = j / R.Vt.cols; nCol = j - nRow * R.Vt.cols; t1 = R.Vt.value[nRow][nCol]; } } }
private static SVDRec svdLAS2(SMat A) { int ibeta, it, irnd, machep, negep, n, steps, nsig, neig; double kappa = 1e-6; double[] las2end = new double[2] { -1.0e-30, 1.0e-30 }; double[] ritz, bnd; double[][] wptr = new double[10][]; svdResetCounters(); int dimensions = A.rows; if (A.cols < dimensions) dimensions = A.cols; int iterations = dimensions; // Check parameters if (check_parameters(A, dimensions, iterations, las2end[0], las2end[1]) > 0) return null; // If A is wide, the SVD is computed on its transpose for speed. bool transpose = false; if (A.cols >= A.rows * 1.2) { //Console.WriteLine("TRANSPOSING THE MATRIX FOR SPEED\n"); transpose = true; A = svdTransposeS(A); } n = A.cols; // Compute machine precision ibeta = it = irnd = machep = negep = 0; machar(ref ibeta, ref it, ref irnd, ref machep, ref negep); eps1 = eps * Math.Sqrt((double)n); reps = Math.Sqrt(eps); eps34 = reps * Math.Sqrt(reps); //Console.WriteLine("Machine precision {0} {1} {2} {3} {4}", ibeta, it, irnd, machep, negep); // Allocate temporary space. wptr[0] = new double[n]; for (int i = 0; i < n; ++i) wptr[0][i] = 0.0; wptr[1] = new double[n]; wptr[2] = new double[n]; wptr[3] = new double[n]; wptr[4] = new double[n]; wptr[5] = new double[n]; wptr[6] = new double[iterations]; wptr[7] = new double[iterations]; wptr[8] = new double[iterations]; wptr[9] = new double[iterations + 1]; ritz = new double[iterations + 1]; for (int i = 0; i < iterations + 1; ++i) ritz[0] = 0.0; bnd = new double[iterations + 1]; for (int i = 0; i < iterations + 1; ++i) bnd[0] = 0.0; LanStore = new double[iterations + MAXLL][]; for (int i = 0; i < iterations + MAXLL; ++i) { LanStore[i] = null; } OPBTemp = new double[A.rows]; // Actually run the lanczos thing: neig = 0; steps = lanso(A, iterations, dimensions, las2end[0], las2end[1], ritz, bnd, wptr, ref neig, n); //Console.WriteLine("NUMBER OF LANCZOS STEPS {0}", steps + 1); //Console.WriteLine("RITZ VALUES STABILIZED = RANK {0}", neig); kappa = svd_dmax(Math.Abs(kappa), eps34); SVDRec R = new SVDRec(); R.d = dimensions; DMat Tmp1 = new DMat(); Tmp1.rows = R.d; Tmp1.cols = A.rows; Tmp1.value = new double[Tmp1.rows][]; for (int mm = 0; mm < Tmp1.rows; ++mm) { Tmp1.value[mm] = new double[Tmp1.cols]; for (int j = 0; j < Tmp1.cols; ++j) { Tmp1.value[mm][j] = 0.0; } } R.Ut = Tmp1; R.S = new double[R.d]; for (int k = 0; k < R.d; ++k) { R.S[k] = 0.0; } DMat Tmp2 = new DMat(); Tmp2.rows = R.d; Tmp2.cols = A.cols; Tmp2.value = new double[Tmp2.rows][]; for (int mm = 0; mm < Tmp2.rows; ++mm) { Tmp2.value[mm] = new double[Tmp2.cols]; for (int j = 0; j < Tmp2.cols; ++j) { Tmp2.value[mm][j] = 0.0; } } R.Vt = Tmp2; nsig = ritvec(n, A, R, kappa, ritz, bnd, wptr[6], wptr[9], wptr[5], steps, neig); // This swaps and transposes the singular matrices if A was transposed. if (transpose) { DMat T; T = R.Ut; R.Ut = R.Vt; R.Vt = T; } return R; }
private static int ritvec(int n, SMat A, SVDRec R, double kappa, double[] ritz, double[] bnd, double[] alf, double[] bet, double[] w2, int steps, int neig) { int js, jsq, i, k, id2, tmp, nsig = 0, x; double tmp0, tmp1, xnorm; double[] s; double[] xv2; double[] w1 = R.Vt.value[0]; js = steps + 1; jsq = js * js; s = new double[jsq]; for (k = 0; k < jsq; ++k) s[k] = 0.0; xv2 = new double[n]; for (i = 0; i < jsq; i += (js + 1)) s[i] = 1.0; svd_dcopy(js, alf, 0, 1, w1, 0, -1); svd_dcopy(steps, bet, 1, 1, w2, 1, -1); imtql2(js, js, w1, w2, s); if (ierr != 0) return 0; nsig = 0; x = 0; id2 = jsq - js; for (k = 0; k < js; k++) { tmp = id2; if (bnd[k] <= kappa * Math.Abs(ritz[k]) && k > js - neig - 1) { if (--x < 0) x = R.d - 1; w1 = R.Vt.value[x]; for (i = 0; i < n; i++) w1[i] = 0.0; for (i = 0; i < js; i++) { store(n, (int)(storeVals.RETRQ), i, w2); svd_daxpy(n, s[tmp], w2, 1, w1, 1); tmp -= js; } nsig++; } id2++; } // x is now the location of the highest singular value. rotateArray(R, x); R.d = svd_imin(R.d, nsig); for (x = 0; x < R.d; x++) { svd_opb(A, R.Vt.value[x], xv2, OPBTemp); tmp0 = svd_ddot(n, R.Vt.value[x], 1, xv2, 1); svd_daxpy(n, -tmp0, R.Vt.value[x], 1, xv2, 1); tmp0 = Math.Sqrt(tmp0); xnorm = Math.Sqrt(svd_ddot(n, xv2, 1, xv2, 1)); svd_opa(A, R.Vt.value[x], R.Ut.value[x]); tmp1 = 1.0 / tmp0; svd_dscal(A.rows, tmp1, R.Ut.value[x], 1); xnorm *= tmp1; bnd[i] = xnorm; R.S[x] = tmp0; } return nsig; }