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 double startv(SMat A, double[][] wptr, int step, int n) { double rnm2, t; double[] r; int irand = 0, id, i; rnm2 = svd_ddot(n, wptr[0], 1, wptr[0], 1); irand = 918273 + step; r = wptr[0]; for (id = 0; id < 3; id++) { if (id > 0 || step > 0 || rnm2 == 0) { for (i = 0; i < n; i++) { r[i] = svd_random2(ref irand); } } svd_dcopy(n, wptr[0], 0, 1, wptr[3], 0, 1); svd_opb(A, wptr[3], wptr[0], OPBTemp); svd_dcopy(n, wptr[0], 0, 1, wptr[3], 0, 1); rnm2 = svd_ddot(n, wptr[0], 1, wptr[3], 1); if (rnm2 > 0.0) break; } // fatal error if (rnm2 <= 0.0) { ierr = 8192; return (-1); } if (step > 0) { for (i = 0; i < step; i++) { store(n, (int)storeVals.RETRQ, i, wptr[5]); t = -svd_ddot(n, wptr[3], 1, wptr[5], 1); svd_daxpy(n, t, wptr[5], 1, wptr[0], 1); } t = svd_ddot(n, wptr[4], 1, wptr[0], 1); svd_daxpy(n, -t, wptr[2], 1, wptr[0], 1); svd_dcopy(n, wptr[0], 0, 1, wptr[3], 0, 1); t = svd_ddot(n, wptr[3], 1, wptr[0], 1); if (t <= eps * rnm2) t = 0.0; rnm2 = t; } return Math.Sqrt(rnm2); }
private static void stpone(SMat A, double[][] wrkptr, ref double rnmp, ref double tolp, int n) { double t, rnm, anorm; double[] alf; alf = wrkptr[6]; rnm = startv(A, wrkptr, 0, n); if (rnm == 0.0 || ierr != 0) return; t = 1.0 / rnm; svd_datx(n, t, wrkptr[0], 1, wrkptr[1], 1); svd_dscal(n, t, wrkptr[3], 1); svd_opb(A, wrkptr[3], wrkptr[0], OPBTemp); alf[0] = svd_ddot(n, wrkptr[0], 1, wrkptr[3], 1); svd_daxpy(n, -alf[0], wrkptr[1], 1, wrkptr[0], 1); t = svd_ddot(n, wrkptr[0], 1, wrkptr[3], 1); svd_daxpy(n, -t, wrkptr[1], 1, wrkptr[0], 1); alf[0] += t; svd_dcopy(n, wrkptr[0], 0, 1, wrkptr[4], 0, 1); rnm = Math.Sqrt(svd_ddot(n, wrkptr[0], 1, wrkptr[4], 1)); anorm = rnm + Math.Abs(alf[0]); rnmp = rnm; tolp = reps * anorm; }
private static int lanso(SMat A, int iterations, int dimensions, double endl, double endr, double[] ritz, double[] bnd, double[][] wptr, ref int neigp, int n) { double[] alf, eta, oldeta, bet, wrk; double rnm, tol; int ll, first, last, id2, id3, i, l, neig = 0, j = 0, intro = 0; alf = wptr[6]; eta = wptr[7]; oldeta = wptr[8]; bet = wptr[9]; wrk = wptr[5]; rnm = 0.0; tol = 0.0; stpone(A, wptr, ref rnm, ref tol, n); if (rnm == 0.0 || ierr != 0) return 0; eta[0] = eps1; oldeta[0] = eps1; ll = 0; first = 1; last = svd_imin(dimensions + svd_imax(8, dimensions), iterations); int ENOUGH = 0; while (ENOUGH == 0) { if (rnm <= tol) rnm = 0.0; j = lanczos_step(A, first, last, wptr, alf, eta, oldeta, bet, ref ll, ref ENOUGH, ref rnm, ref tol, n); if (ENOUGH > 0) j = j - 1; else j = last - 1; first = j + 1; bet[j + 1] = rnm; l = 0; for (id2 = 0; id2 < j; id2++) { if (l > j) break; for (i = l; i <= j; i++) if (bet[i + 1] == 0.0) break; if (i > j) i = j; svd_dcopy(i - l + 1, alf, l, 1, ritz, l, -1); svd_dcopy(i - l, bet, l + 1, 1, wrk, l + 1, -1); imtqlb(i - l + 1, ritz, wrk, bnd); if (ierr != 0) { Console.WriteLine("svdLAS2: imtqlb failed to converge {0}", ierr); } for (id3 = l; id3 <= i; id3++) { bnd[id3] = rnm * Math.Abs(bnd[id3]); } l = i + 1; } svd_dsort2((j + 1) / 2, j + 1, ritz, bnd); neig = error_bound(ref ENOUGH, endl, endr, ritz, bnd, j, tol); neigp = neig; if (neig < dimensions) { if (neig == 0) { last = first + 9; intro = first; } else { last = first + svd_imax(3, 1 + ((j - intro) * (dimensions - neig)) / neig); } last = svd_imin(last, iterations); } else { ENOUGH = 1; } int RES = 0; if (first >= iterations) RES = 1; ENOUGH = ENOUGH | RES; } store(n, (int)(storeVals.STORQ), j, wptr[1]); return j; }
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; }
private static void svd_opb(SMat A, double[] x, double[] y, double[] temp) { int i, j, end; int[] pointr = A.pointr; int[] rowind = A.rowind; double[] value = A.value; int n = A.cols; SVDCount[(int)(svdCounters.SVD_MXV)] += 2; for (i = 0; i < n; ++i) y[i] = 0.0; for (i = 0; i < A.rows; i++) temp[i] = 0.0; for (i = 0; i < A.cols; i++) { end = pointr[i + 1]; for (j = pointr[i]; j < end; j++) { temp[rowind[j]] += value[j] * x[i]; } } for (i = 0; i < A.cols; i++) { end = pointr[i + 1]; for (j = pointr[i]; j < end; j++) { y[i] += value[j] * temp[rowind[j]]; } } }
private static int lanczos_step(SMat A, int first, int last, double[][] wptr, double[] alf, double[] eta, double[] oldeta, double[] bet, ref int ll, ref int enough, ref double rnmp, ref double tolp, int n) { double t, anorm; double[] mid; double rnm = rnmp; double tol = tolp; int i, j; for (j = first; j < last; j++) { mid = wptr[2]; wptr[2] = wptr[1]; wptr[1] = mid; mid = wptr[3]; wptr[3] = wptr[4]; wptr[4] = mid; store(n, (int)(storeVals.STORQ), j - 1, wptr[2]); if (j - 1 < MAXLL) store(n, (int)(storeVals.STORP), j - 1, wptr[4]); bet[j] = rnm; if (bet[j] == 0.0) { rnm = startv(A, wptr, j, n); if (rnm < 0.0) { Console.WriteLine("Fatal error: {0}", ierr); Environment.Exit(1); } if (ierr != 0) return j; if (rnm == 0.0) enough = 1; } if (enough == 1) { mid = wptr[2]; wptr[2] = wptr[1]; wptr[1] = mid; break; } t = 1.0 / rnm; svd_datx(n, t, wptr[0], 1, wptr[1], 1); svd_dscal(n, t, wptr[3], 1); svd_opb(A, wptr[3], wptr[0], OPBTemp); svd_daxpy(n, -rnm, wptr[2], 1, wptr[0], 1); alf[j] = svd_ddot(n, wptr[0], 1, wptr[3], 1); svd_daxpy(n, -alf[j], wptr[1], 1, wptr[0], 1); if (j <= MAXLL && (Math.Abs(alf[j - 1]) > 4.0 * Math.Abs(alf[j]))) { ll = j; } for (i = 0; i < svd_imin(ll, j - 1); i++) { store(n, (int)(storeVals.RETRP), i, wptr[5]); t = svd_ddot(n, wptr[5], 1, wptr[0], 1); store(n, (int)(storeVals.RETRQ), i, wptr[5]); svd_daxpy(n, -t, wptr[5], 1, wptr[0], 1); eta[i] = eps1; oldeta[i] = eps1; } t = svd_ddot(n, wptr[0], 1, wptr[4], 1); svd_daxpy(n, -t, wptr[2], 1, wptr[0], 1); if (bet[j] > 0.0) bet[j] = bet[j] + t; t = svd_ddot(n, wptr[0], 1, wptr[3], 1); svd_daxpy(n, -t, wptr[1], 1, wptr[0], 1); alf[j] = alf[j] + t; svd_dcopy(n, wptr[0], 0, 1, wptr[4], 0, 1); rnm = Math.Sqrt(svd_ddot(n, wptr[0], 1, wptr[4], 1)); anorm = bet[j] + Math.Abs(alf[j]) + rnm; tol = reps * anorm; ortbnd(alf, eta, oldeta, bet, j, rnm); purge(n, ll, wptr[0], wptr[1], wptr[4], wptr[3], wptr[5], eta, oldeta, j, rnmp, tol); if (rnm <= tol) rnm = 0.0; } rnmp = rnm; tolp = tol; return j; }
private static void svd_opa(SMat A, double[] x, double[] y) { int end, i, j; int[] pointr = A.pointr; int[] rowind = A.rowind; double[] value = A.value; SVDCount[(int)(svdCounters.SVD_MXV)]++; for (int k = 0; k < A.rows; ++k) { y[k] = 0.0; } for (i = 0; i < A.cols; i++) { end = pointr[i + 1]; for (j = pointr[i]; j < end; j++) { y[rowind[j]] += value[j] * x[i]; } } }
private static int check_parameters(SMat A, int dimensions, int iterations, double endl, double endr) { int error_index; error_index = 0; if (endl > endr) error_index = 2; else if (dimensions > iterations) error_index = 3; else if (A.cols <= 0 || A.rows <= 0) error_index = 4; else if (iterations <= 0 || iterations > A.cols || iterations > A.rows) error_index = 5; else if (dimensions <= 0 || dimensions > iterations) error_index = 6; if (error_index > 0) Console.WriteLine("svdLAS2 parameter error: %s\n"); return error_index; }
private static SMat svdTransposeS(SMat S) { int r, c, i, j; SMat N = svdNewSMat(S.cols, S.rows, S.vals); for (i = 0; i < S.vals; i++) N.pointr[S.rowind[i]]++; N.pointr[S.rows] = S.vals - N.pointr[S.rows - 1]; for (r = S.rows - 1; r > 0; r--) N.pointr[r] = N.pointr[r + 1] - N.pointr[r - 1]; N.pointr[0] = 0; for (c = 0, i = 0; c < S.cols; c++) { for (; i < S.pointr[c + 1]; i++) { r = S.rowind[i]; j = N.pointr[r + 1]++; N.rowind[j] = c; N.value[j] = S.value[i]; } } return N; }
private static SMat svdNewSMat(int rows, int cols, int vals) { SMat S = new SMat(); S.rows = rows; S.cols = cols; S.vals = vals; S.pointr = new int[cols + 1]; S.rowind = new int[vals]; S.value = new double[vals]; return S; }
// Functions for reading-writing data private static SMat svdLoadSparseMatrix(string datafile) { try { SMat S = new SMat(); using (FileStream stream = new FileStream(datafile, FileMode.Open)) { using (BinaryReader reader = new BinaryReader(stream)) { S.rows = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32()); S.cols = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32()); S.vals = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32()); S.pointr = new int[S.cols + 1]; for (int k = 0; k < S.cols + 1; ++k) S.pointr[k] = 0; S.rowind = new int[S.vals]; S.value = new double[S.vals]; for (int c = 0, v = 0; c < S.cols; c++) { int n = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32()); S.pointr[c] = v; for (int i = 0; i < n; i++, v++) { int r = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32()); int nBuf = System.Net.IPAddress.NetworkToHostOrder(reader.ReadInt32()); byte[] b = BitConverter.GetBytes(nBuf); float f = BitConverter.ToSingle(b, 0); S.rowind[v] = r; S.value[v] = f; } S.pointr[S.cols] = S.vals; } reader.Close(); } stream.Close(); } return S; } catch (Exception e) { Console.WriteLine(e.Message); return null; } }