1515namespace irlba {
1616
1717template <class EigenMatrix_ , class EigenVector_ >
18- void orthogonalize_vector (const EigenMatrix_& mat, EigenVector_& vec, size_t ncols, EigenVector_& tmp) {
19- tmp.head (ncols).noalias () = mat.leftCols (ncols).adjoint () * vec;
20- vec.noalias () -= mat.leftCols (ncols) * tmp.head (ncols);
18+ void orthogonalize_vector (const EigenMatrix_& mat, EigenVector_& vec, Eigen::Index ncols) {
19+ // Original package uses classical Gram Schmidt but modified GS is actually faster when we
20+ // sum the timing across all orthogonalization steps in the Lanczos process.
21+ // Possibly because it allows us to modify 'vec' for each of mat's progressive column vectors,
22+ // rather than requiring a temporary space to store the projections from the original 'vec'.
23+ for (Eigen::Index c = 0 ; c < ncols; ++c) {
24+ // No need to divide by the norm of mat.col(c), as this is always 1.
25+ vec -= mat.col (c) * vec.dot (mat.col (c));
26+ }
2127}
2228
2329template <class EigenVector_ , class Matrix_ >
2430struct LanczosWorkspace {
2531 LanczosWorkspace (const Matrix_& mat) :
2632 F (mat.cols()),
2733 W_next (mat.rows()),
28- orthog_tmp (mat.cols()),
2934 work (mat.new_known_workspace()),
3035 awork (mat.new_known_adjoint_workspace())
3136 {}
3237
3338 EigenVector_ F;
3439 EigenVector_ W_next;
35- EigenVector_ orthog_tmp;
3640
3741 I<decltype (std::declval<Matrix_>().new_known_workspace())> work;
3842 I<decltype (std::declval<Matrix_>().new_known_adjoint_workspace())> awork;
@@ -68,15 +72,14 @@ int run_lanczos_bidiagonalization(
6872 const Eigen::Index work = W.cols ();
6973 auto & F = inter.F ;
7074 auto & W_next = inter.W_next ;
71- auto & otmp = inter.orthog_tmp ;
7275
7376 F = V.col (start);
7477 inter.work ->multiply (F, W_next); // i.e., W_next = mat * F;
7578 int mult = 1 ;
7679
7780 // If start = 0, there's nothing to orthogonalize against.
7881 if (start) {
79- orthogonalize_vector (W, W_next, start, otmp );
82+ orthogonalize_vector (W, W_next, start);
8083 }
8184
8285 Float S = W_next.norm ();
@@ -95,14 +98,14 @@ int run_lanczos_bidiagonalization(
9598 ++mult;
9699
97100 F -= S * V.col (j); // equivalent to daxpy.
98- orthogonalize_vector (V, F, j + 1 , otmp );
101+ orthogonalize_vector (V, F, j + 1 );
99102
100103 if (j + 1 < work) {
101104 Float R_F = F.norm ();
102105
103106 if (R_F < eps) {
104107 fill_with_random_normals (F, eng);
105- orthogonalize_vector (V, F, j + 1 , otmp );
108+ orthogonalize_vector (V, F, j + 1 );
106109 R_F = F.norm ();
107110 F /= R_F ;
108111 R_F = 0 ;
@@ -121,12 +124,12 @@ int run_lanczos_bidiagonalization(
121124 // Full re-orthogonalization, using the left-most 'j + 1' columns of W.
122125 // Recall that W_next will be the 'j + 2'-th column, i.e., W.col(j + 1) in
123126 // 0-indexed terms, so we want to orthogonalize to all previous columns.
124- orthogonalize_vector (W, W_next, j + 1 , otmp );
127+ orthogonalize_vector (W, W_next, j + 1 );
125128
126129 S = W_next.norm ();
127130 if (S < eps) {
128131 fill_with_random_normals (W_next, eng);
129- orthogonalize_vector (W, W_next, j + 1 , otmp );
132+ orthogonalize_vector (W, W_next, j + 1 );
130133 S = W_next.norm ();
131134 W_next /= S;
132135 S = 0 ;
0 commit comments