143    const Matrix_& matrix,
 
  144    const Eigen::Index number,
 
  150    const Eigen::Index smaller = std::min(matrix.rows(), matrix.cols());
 
  151    Eigen::Index requested_number = sanisizer::cast<Eigen::Index>(number);
 
  152    if (requested_number > smaller) {
 
  154            requested_number = smaller;
 
  156            throw std::runtime_error(
"requested number of singular values cannot be greater than the smaller matrix dimension");
 
  159        throw std::runtime_error(
"requested number of singular values must be less than the smaller matrix dimension for IRLBA iterations");
 
  166        (options.
exact_for_large_number && requested_greater_than_or_equal_to_half_smaller(requested_number, smaller))
 
  168        exact(matrix, requested_number, outU, outV, outD);
 
  169        return std::make_pair(
true, 0);
 
  172    Eigen::Index work = choose_requested_plus_extra_work_or_smaller(requested_number, options.
extra_work, smaller);
 
  174        throw std::runtime_error(
"number of requested dimensions must be positive");
 
  179    EigenMatrix_ V(matrix.cols(), work);
 
  180    std::mt19937_64 eng(options.
seed);
 
  182        auto init = 
reinterpret_cast<EigenVector_*
>(options.
initial);
 
  183        if (init->size() != V.rows()) {
 
  184            throw std::runtime_error(
"initialization vector does not have expected number of rows");
 
  188        fill_with_random_normals(V, 0, eng);
 
  190    V.col(0) /= V.col(0).norm();
 
  192    bool converged = 
false;
 
  195    JacobiSVD<EigenMatrix_> svd(work, work);
 
  197    LanczosWorkspace<EigenVector_, Matrix_> lpwork(matrix);
 
  199    EigenMatrix_ W(matrix.rows(), work);
 
  200    EigenMatrix_ Wtmp(matrix.rows(), work);
 
  201    EigenMatrix_ Vtmp(matrix.cols(), work);
 
  203    EigenMatrix_ B(work, work);
 
  204    B.setZero(work, work);
 
  205    EigenVector_ res(work);
 
  206    EigenVector_ F(matrix.cols());
 
  208    EigenVector_ prevS(work);
 
  211    typename EigenMatrix_::Scalar svtol_actual = (svtol >= 0 ? svtol : tol);
 
  217        run_lanczos_bidiagonalization(lpwork, W, V, B, eng, k, options);
 
  226        const auto& BS = svd.singularValues();
 
  227        const auto& BU = svd.matrixU();
 
  228        const auto& BV = svd.matrixV();
 
  231        if (B(work - 1, work - 1) == 0) { 
 
  236        const auto& F = lpwork.F; 
 
  244        res = R_F * BU.row(work - 1);
 
  246        Eigen::Index n_converged = 0;
 
  248            const auto Smax = *std::max_element(BS.begin(), BS.end());
 
  249            const auto threshold = Smax * tol;
 
  251            for (Eigen::Index j = 0; j < work; ++j) {
 
  252                if (std::abs(res[j]) <= threshold) {
 
  253                    const auto ratio = std::abs(BS[j] - prevS[j]) / BS[j];
 
  254                    if (ratio <= svtol_actual) {
 
  260            if (n_converged >= requested_number) {
 
  267        k = update_k(k, requested_number, n_converged, work);
 
  268        Vtmp.leftCols(k).noalias() = V * BV.leftCols(k);
 
  269        V.leftCols(k) = Vtmp.leftCols(k);
 
  279        Wtmp.leftCols(k).noalias() = W * BU.leftCols(k);
 
  280        W.leftCols(k) = Wtmp.leftCols(k);
 
  282        B.setZero(work, work);
 
  283        for (I<
decltype(k)> l = 0; l < k; ++l) {
 
  298    outD.resize(requested_number);
 
  299    outD = svd.singularValues().head(requested_number);
 
  301    outU.resize(matrix.rows(), requested_number);
 
  302    outU.noalias() = W * svd.matrixU().leftCols(requested_number);
 
  304    outV.resize(matrix.cols(), requested_number);
 
  305    outV.noalias() = V * svd.matrixV().leftCols(requested_number);
 
  307    return std::make_pair(converged, (converged ? iter + 1 : iter));