0
$\begingroup$

I am trying to get invert shift mode working on ARPACK, and I am interfacing the library through rust.

I am using this laplacian matrix for testing:

2, -1,  0,  0,  0, -1,  0,  0,  0,  0
-1,  3, -1,  0,  0,  0, -1,  0,  0,  0
 0, -1,  3, -1,  0,  0,  0, -1,  0,  0
 0,  0, -1,  3, -1,  0,  0,  0, -1,  0
 0,  0,  0, -1,  3, -1,  0,  0,  0, -1
-1,  0,  0,  0, -1,  3, -1,  0,  0,  0
 0, -1,  0,  0,  0, -1,  3, -1,  0,  0
 0,  0, -1,  0,  0,  0, -1,  3, -1,  0
 0,  0,  0, -1,  0,  0,  0, -1,  3, -1
 0,  0,  0,  0, -1,  0,  0,  0, -1,  2

For the regular mode I am getting the correct eigenvalues according to scipy. However if I try switching to inverse shift mode I get incorrect values. I tried setting it up in rust as follows:

fn faer_arpack_symmetric_f64(
    mat: &SparseColMat<usize, f64>,
    dimension: usize,
    eigenvalue_kind: &str,
    number_of_eigenvalues: usize,
    number_of_lanczos_vectors: usize,
    maxiter: usize,
    vectors: bool,
) -> (Col<f64>, Mat<f64>)
{
    let mut ido = 0;
    let mut residual: Col<f64> = Col::zeros(dimension);
    let mut arnoldi_data = vec![0.0; dimension * number_of_lanczos_vectors];
    let mut iparam = [0; 11];
    iparam[0] = 1;
    iparam[2] = maxiter as i32;
    iparam[6] = 3; // code 3 means inverse shift according to the book
    let mut ipntr = [0; 11];
    let mut workd = Col::zeros(3 * dimension);
    let lworkl = number_of_lanczos_vectors * (number_of_lanczos_vectors + 8);
    let mut workl = Col::<f64>::zeros(lworkl);
    let mut info = 0;

    let sigma = 0.0;
    loop
    {
        unsafe {
            dsaupd_c(
                &mut ido,
                "I".as_ptr() as *const i8,
                dimension as i32,
                eigenvalue_kind.as_ptr() as *const i8,
                number_of_eigenvalues as i32,
                f64::EPSILON,
                residual.as_ptr_mut() as *mut f64,
                number_of_lanczos_vectors as i32,
                arnoldi_data.as_mut_ptr() as *mut f64,
                dimension as i32,
                iparam.as_mut_ptr(), 
                ipntr.as_mut_ptr(),  
                workd.as_ptr_mut() as *mut f64,
                workl.as_ptr_mut() as *mut f64,
                lworkl as i32,
                &mut info,
            );

            match info
            {
                0 =>
                {}
                1 =>
                {
                    panic!("Maximum number of Lanczos iterations reached.")
                }
                3 =>
                {
                    panic!(
                        "No shifts could be applied during implicit Arnoldi update, try increasing NCV."
                    )
                }
                -1 => panic!("N must be positive."),
                -2 => panic!("NEV must be positive."),
                -3 => panic!("NCV-NEV >= 2 and less than or equal to N."),
                -4 => panic!("Maximum iterations must be greater than 0."),
                -5 => panic!("Maximum iterations must be greater than 0."),
                i => panic!("dsaupd_c returned error code {}", i),
            }

            if (ido == -1) || (ido == 1)
            {
                let res = mat * workd.subrows(ipntr[0] as usize - 1, dimension);
                let y = faer_shift_invert_solve(mat, sigma, &res);
                workd
                    .subrows_mut(ipntr[1] as usize - 1, dimension)
                    .copy_from(&y);
            }
            else if ido == 99
            {
                break;
            }
            else
            {
                panic!("ido code: {}", ido);
            }
        }
    }

    let select = vec![false as i32; number_of_lanczos_vectors];
    let mut d: Col<f64> = Col::zeros(number_of_eigenvalues + 1);
    let mut z_storage = vec![0.0; dimension * number_of_lanczos_vectors];
    unsafe {
        dseupd_c(
            vectors as i32,
            "A".as_ptr() as *const i8,
            select.as_ptr(),
            d.as_ptr_mut() as *mut f64,
            z_storage.as_mut_ptr() as *mut f64,
            dimension as i32,
            sigma,
            "I".as_ptr() as *const i8,
            dimension as i32,
            eigenvalue_kind.as_ptr() as *const i8,
            number_of_eigenvalues as i32,
            f64::EPSILON,
            residual.as_ptr_mut() as *mut f64,
            number_of_lanczos_vectors as i32,
            arnoldi_data.as_mut_ptr() as *mut f64,
            dimension as i32,
            iparam.as_mut_ptr(),
            ipntr.as_mut_ptr(),
            workd.as_ptr_mut() as *mut f64,
            workl.as_ptr_mut() as *mut f64,
            lworkl as i32,
            &mut info,
        );
    }

    match info {
        0 => { /* Normal exit, do nothing */ }
        1 => panic!("INFO = 1: The Schur form computed by LAPACK routine dsytrd failed to reorder or to compute eigenvalues and eigenvectors to high relative accuracy."),
        3 => panic!("INFO = 3: No shifts could be applied during a cycle of the implicitly restarted Arnoldi iteration. One possible reason is that the Schur vectors failed to converge."),
        -1 => panic!("INFO = -1: N must be greater than 0."),
        -2 => panic!("INFO = -2: NEV must be greater than 0 and less than N."),
        -3 => panic!("INFO = -3: NCV must be greater than NEV and less than or equal to N."),
        -5 => panic!("INFO = -5: WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI'."),
        -6 => panic!("INFO = -6: BMAT must be one of 'I' or 'G'."),
        -7 => panic!("INFO = -7: The part of the spectrum specified by WHICH is not supported."),
        -8 => panic!("INFO = -8: The spectrum range parameters are inconsistent."),
        -9 => panic!("INFO = -9: WORKD[1:N] is not correctly allocated."),
        -10 => panic!("INFO = -10: The starting vector is zero."),
        -11 => panic!("INFO = -11: The standard Lanczos iteration (for generalized symmetric eigenvalue problem) failed to converge."),
        -12 => panic!("INFO = -12: The shifts could not be applied during a cycle of the implicitly restarted Arnoldi iteration. One possible reason is that the Schur vectors failed to converge."),
        _ => panic!("Unknown INFO value: {}", info),
    }

    let mut eigs = d.subrows(0, number_of_eigenvalues).to_owned();

    (
        eigs,
        faer::mat::from_column_major_slice_mut(
            &mut z_storage,
            dimension,
            number_of_lanczos_vectors,
        )
        .to_owned(),
    )
}

fn faer_shift_invert_solve(
    a: &SparseColMat<usize, f64>,
    sigma: f64,
    b: &Col<f64>,
) -> Col<f64>
{
    let triplets = (0..a.nrows()).map(|i| (i, i, 1.)).collect::<Vec<_>>();
    let identity =
        SparseColMat::try_new_from_triplets(a.nrows(), a.nrows(), &triplets).unwrap();

    use faer::prelude::SpSolver;
    let qr = (a - sigma * identity).sp_qr().unwrap();
    qr.solve(b)
}
```
$\endgroup$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.