# HG changeset patch # User Marco Caliari # Date 1490362868 -3600 # Node ID 1310d8b50ec2d173e81f1224762c96a9e311c6e3 # Parent 0da1bdfbfacbb527e476788505d37a149fe7f004 Fix eigs returning an incorrect number or order of eigenvalues (bug #45153, bug #47236). * liboctave/numberic/eigs-base.cc: Always return the required number of eigenvalues. Remove ido == 2 for non-generalized problems. Fix the maximum value for p. Fix the order of eigenvalues. Check the dimension of opts.v0. * script/sparse/eigs.m: Fix the range of p in the description. diff -r 0da1bdfbfacb -r 1310d8b50ec2 liboctave/numeric/eigs-base.cc --- a/liboctave/numeric/eigs-base.cc Sat Nov 11 19:39:23 2017 +0100 +++ b/liboctave/numeric/eigs-base.cc Fri Mar 24 14:41:08 2017 +0100 @@ -626,6 +626,10 @@ resid = ColumnVector (octave_rand::vector (n)); octave_rand::distribution (rand_dist); } + else if (m.cols () != resid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -637,8 +641,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k < 1 || k > n - 2) @@ -647,9 +651,9 @@ " (must be 0 < k < n-1-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (have_b && cholB && ! permB.isempty ()) { @@ -825,7 +829,7 @@ if (info2 == 0) { F77_INT k2 = k / 2; - if (typ != "SM" && typ != "BE") + if (typ != "SM" && typ != "BE" && ! (typ == "SA" && rvec)) { for (F77_INT i = 0; i < k2; i++) { @@ -837,7 +841,7 @@ if (rvec) { - if (typ != "SM" && typ != "BE") + if (typ != "SM" && typ != "BE" && typ != "SA") { OCTAVE_LOCAL_BUFFER (double, dtmp, n); @@ -907,6 +911,10 @@ resid = ColumnVector (octave_rand::vector (n)); octave_rand::distribution (rand_dist); } + else if (m.cols () != resid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -924,13 +932,13 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (have_b && cholB && ! permB.isempty ()) { @@ -1066,25 +1074,19 @@ } else { - if (ido == 2) - { - for (F77_INT i = 0; i < n; i++) - workd[iptr(0) + i - 1] = workd[iptr(1) + i - 1]; - } - else - { - double *ip2 = workd+iptr(0)-1; - Matrix tmp(n, 1); - - for (F77_INT i = 0; i < n; i++) - tmp(i,0) = ip2[P[i]]; - - lusolve (L, U, tmp); - - ip2 = workd+iptr(1)-1; - for (F77_INT i = 0; i < n; i++) - ip2[Q[i]] = tmp(i,0); - } + // ido cannot be 2 for non-generalized problems + // see dsaupd2 + double *ip2 = workd+iptr(0)-1; + Matrix tmp(n, 1); + + for (F77_INT i = 0; i < n; i++) + tmp(i,0) = ip2[P[i]]; + + lusolve (L, U, tmp); + + ip2 = workd+iptr(1)-1; + for (F77_INT i = 0; i < n; i++) + ip2[Q[i]] = tmp(i,0); } } else @@ -1191,6 +1193,10 @@ resid = ColumnVector (octave_rand::vector (n)); octave_rand::distribution (rand_dist); } + else if (n != resid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -1202,8 +1208,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k <= 0 || k >= n - 1) @@ -1212,9 +1218,9 @@ " (must be 0 < k < n-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (! have_sigma) { @@ -1444,6 +1450,10 @@ resid = ColumnVector (octave_rand::vector (n)); octave_rand::distribution (rand_dist); } + else if (m.cols () != resid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -1455,8 +1465,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k <= 0 || k >= n - 1) @@ -1465,9 +1475,9 @@ " (must be 0 < k < n-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (have_b && cholB && ! permB.isempty ()) { @@ -1550,12 +1560,15 @@ { F77_INT tmp_info = octave::to_f77_int (info); + // on exit, ip(4) <= k + 1 is the number of converged eigenvalues + // see dnaupd2 F77_FUNC (dnaupd, DNAUPD) (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n, F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, tmp_info F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2)); + // k is not changed info = tmp_info; @@ -1639,65 +1652,45 @@ for (F77_INT i = 0; i < k+1; i++) dr[i] = di[i] = 0.; + F77_INT k0 = k; // original number of eigenvalues required F77_FUNC (dneupd, DNEUPD) (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar, sigmai, workev, F77_CONST_CHAR_ARG2 (&bmat, 1), n, F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2)); + // on exit, if (and only if) rvec == true, k may have been increased by one + // and be equal to ip(4), see dngets if (f77_exception_encountered) (*current_liboctave_error_handler) ("eigs: unrecoverable exception encountered in dneupd"); - eig_val.resize (k+1); + if (! rvec && ip(4) > k) + k = ip(4); + + eig_val.resize (k); Complex *d = eig_val.fortran_vec (); if (info2 == 0) { - F77_INT jj = 0; - for (F77_INT i = 0; i < k+1; i++) + for (F77_INT i = 0; i < k; i++) + d[i] = Complex (dr[i], di[i]); + + if (! rvec) { - if (dr[i] == 0.0 && di[i] == 0.0 && jj == 0) - jj++; - else - d[i-jj] = Complex (dr[i], di[i]); - } - if (jj == 0 && ! rvec) - for (F77_INT i = 0; i < k; i++) - d[i] = d[i+1]; - - F77_INT k2 = k / 2; - for (F77_INT i = 0; i < k2; i++) - { - Complex dtmp = d[i]; - d[i] = d[k - i - 1]; - d[k - i - 1] = dtmp; - } - eig_val.resize (k); - - if (rvec) - { - OCTAVE_LOCAL_BUFFER (double, dtmp, n); - + // ARPACK seems to give the eigenvalues in reversed order + F77_INT k2 = k / 2; for (F77_INT i = 0; i < k2; i++) { - F77_INT off1 = i * n; - F77_INT off2 = (k - i - 1) * n; - - if (off1 == off2) - continue; - - for (F77_INT j = 0; j < n; j++) - dtmp[j] = z[off1 + j]; - - for (F77_INT j = 0; j < n; j++) - z[off1 + j] = z[off2 + j]; - - for (F77_INT j = 0; j < n; j++) - z[off2 + j] = dtmp[j]; + Complex dtmp = d[i]; + d[i] = d[k - i - 1]; + d[k - i - 1] = dtmp; } - + } + else + { + // When eigenvectors required, ARPACK seems to give the right order eig_vec.resize (n, k); F77_INT i = 0; while (i < k) @@ -1728,6 +1721,11 @@ if (note3) eig_vec = utsolve (bt, permB, eig_vec); } + if (k0 < k) + { + eig_val.resize (k0); + eig_vec.resize (n, k0); + } } else (*current_liboctave_error_handler) ("eigs: error %d in dneupd", info2); @@ -1774,6 +1772,10 @@ resid = ColumnVector (octave_rand::vector (n)); octave_rand::distribution (rand_dist); } + else if (m.cols () != resid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -1785,8 +1787,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k <= 0 || k >= n - 1) @@ -1795,9 +1797,9 @@ " (must be 0 < k < n-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (have_b && cholB && ! permB.isempty ()) { @@ -1860,12 +1862,15 @@ { F77_INT tmp_info = octave::to_f77_int (info); + // on exit, ip(4) <= k + 1 is the number of converged eigenvalues + // see dnaupd2 F77_FUNC (dnaupd, DNAUPD) (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n, F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, tmp_info F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2)); + // k is not changed info = tmp_info; @@ -1933,32 +1938,26 @@ } else { - if (ido == 2) - { - for (F77_INT i = 0; i < n; i++) - workd[iptr(0) + i - 1] = workd[iptr(1) + i - 1]; - } - else - { - double *ip2 = workd+iptr(0)-1; - Matrix tmp(n, 1); - - for (F77_INT i = 0; i < n; i++) - tmp(i,0) = ip2[P[i]]; - - lusolve (L, U, tmp); - - ip2 = workd+iptr(1)-1; - for (F77_INT i = 0; i < n; i++) - ip2[Q[i]] = tmp(i,0); - } + // ido cannot be 2 for non-generalized problems + // see dnaupd2 + double *ip2 = workd+iptr(0)-1; + Matrix tmp(n, 1); + + for (F77_INT i = 0; i < n; i++) + tmp(i,0) = ip2[P[i]]; + + lusolve (L, U, tmp); + + ip2 = workd+iptr(1)-1; + for (F77_INT i = 0; i < n; i++) + ip2[Q[i]] = tmp(i,0); } } else { if (info < 0) (*current_liboctave_error_handler) - ("eigs: error %d in dsaupd", info); + ("eigs: error %d in dnaupd", info); break; } @@ -1993,65 +1992,45 @@ for (F77_INT i = 0; i < k+1; i++) dr[i] = di[i] = 0.; + F77_INT k0 = k; // original number of eigenvalues required F77_FUNC (dneupd, DNEUPD) (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar, sigmai, workev, F77_CONST_CHAR_ARG2 (&bmat, 1), n, F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2)); + // on exit, if (and only if) rvec == true, k may have been increased by one + // and be equal to ip(4), see dngets if (f77_exception_encountered) (*current_liboctave_error_handler) ("eigs: unrecoverable exception encountered in dneupd"); - eig_val.resize (k+1); + if (! rvec && ip(4) > k) + k = ip(4); + + eig_val.resize (k); Complex *d = eig_val.fortran_vec (); if (info2 == 0) { - F77_INT jj = 0; - for (F77_INT i = 0; i < k+1; i++) + for (F77_INT i = 0; i < k; i++) + d[i] = Complex (dr[i], di[i]); + + if (! rvec) { - if (dr[i] == 0.0 && di[i] == 0.0 && jj == 0) - jj++; - else - d[i-jj] = Complex (dr[i], di[i]); - } - if (jj == 0 && ! rvec) - for (F77_INT i = 0; i < k; i++) - d[i] = d[i+1]; - - F77_INT k2 = k / 2; - for (F77_INT i = 0; i < k2; i++) - { - Complex dtmp = d[i]; - d[i] = d[k - i - 1]; - d[k - i - 1] = dtmp; - } - eig_val.resize (k); - - if (rvec) - { - OCTAVE_LOCAL_BUFFER (double, dtmp, n); - + // ARPACK seems to give the eigenvalues in reversed order + F77_INT k2 = k / 2; for (F77_INT i = 0; i < k2; i++) { - F77_INT off1 = i * n; - F77_INT off2 = (k - i - 1) * n; - - if (off1 == off2) - continue; - - for (F77_INT j = 0; j < n; j++) - dtmp[j] = z[off1 + j]; - - for (F77_INT j = 0; j < n; j++) - z[off1 + j] = z[off2 + j]; - - for (F77_INT j = 0; j < n; j++) - z[off2 + j] = dtmp[j]; + Complex dtmp = d[i]; + d[i] = d[k - i - 1]; + d[k - i - 1] = dtmp; } - + } + else + { + // When eigenvectors required, ARPACK seems to give the right order eig_vec.resize (n, k); F77_INT i = 0; while (i < k) @@ -2079,6 +2058,11 @@ } } } + if (k0 < k) + { + eig_val.resize (k0); + eig_vec.resize (n, k0); + } } else (*current_liboctave_error_handler) ("eigs: error %d in dneupd", info2); @@ -2112,6 +2096,10 @@ resid = ColumnVector (octave_rand::vector (n)); octave_rand::distribution (rand_dist); } + else if (n != resid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -2123,8 +2111,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k <= 0 || k >= n - 1) @@ -2133,9 +2121,9 @@ " (must be 0 < k < n-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (! have_sigma) { @@ -2195,12 +2183,15 @@ { F77_INT tmp_info = octave::to_f77_int (info); + // on exit, ip(4) <= k + 1 is the number of converged eigenvalues + // see dnaupd2 F77_FUNC (dnaupd, DNAUPD) - (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n, + (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n, F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, tmp_info F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2)); + // k is not changed info = tmp_info; @@ -2284,65 +2275,45 @@ for (F77_INT i = 0; i < k+1; i++) dr[i] = di[i] = 0.; + F77_INT k0 = k; // original number of eigenvalues required F77_FUNC (dneupd, DNEUPD) (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar, sigmai, workev, F77_CONST_CHAR_ARG2 (&bmat, 1), n, F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2)); + // on exit, if (and only if) rvec == true, k may have been increased by one + // and be equal to ip(4), see dngets if (f77_exception_encountered) (*current_liboctave_error_handler) ("eigs: unrecoverable exception encountered in dneupd"); - eig_val.resize (k+1); + if (! rvec && ip(4) > k) + k = ip(4); + + eig_val.resize (k); Complex *d = eig_val.fortran_vec (); if (info2 == 0) { - F77_INT jj = 0; - for (F77_INT i = 0; i < k+1; i++) + for (F77_INT i = 0; i < k; i++) + d[i] = Complex (dr[i], di[i]); + + if (! rvec) { - if (dr[i] == 0.0 && di[i] == 0.0 && jj == 0) - jj++; - else - d[i-jj] = Complex (dr[i], di[i]); - } - if (jj == 0 && ! rvec) - for (F77_INT i = 0; i < k; i++) - d[i] = d[i+1]; - - F77_INT k2 = k / 2; - for (F77_INT i = 0; i < k2; i++) - { - Complex dtmp = d[i]; - d[i] = d[k - i - 1]; - d[k - i - 1] = dtmp; - } - eig_val.resize (k); - - if (rvec) - { - OCTAVE_LOCAL_BUFFER (double, dtmp, n); - + // ARPACK seems to give the eigenvalues in reversed order + octave_idx_type k2 = k / 2; for (F77_INT i = 0; i < k2; i++) { - F77_INT off1 = i * n; - F77_INT off2 = (k - i - 1) * n; - - if (off1 == off2) - continue; - - for (F77_INT j = 0; j < n; j++) - dtmp[j] = z[off1 + j]; - - for (F77_INT j = 0; j < n; j++) - z[off1 + j] = z[off2 + j]; - - for (F77_INT j = 0; j < n; j++) - z[off2 + j] = dtmp[j]; + Complex dtmp = d[i]; + d[i] = d[k - i - 1]; + d[k - i - 1] = dtmp; } - + } + else + { + // ARPACK seems to give the eigenvalues in reversed order eig_vec.resize (n, k); F77_INT i = 0; while (i < k) @@ -2370,6 +2341,11 @@ } } } + if (k0 < k) + { + eig_val.resize (k0); + eig_vec.resize (n, k0); + } } else (*current_liboctave_error_handler) ("eigs: error %d in dneupd", info2); @@ -2416,6 +2392,10 @@ cresid(i) = Complex (rr(i),ri(i)); octave_rand::distribution (rand_dist); } + else if (m.cols () != cresid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -2427,8 +2407,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k <= 0 || k >= n - 1) @@ -2437,9 +2417,9 @@ " (must be 0 < k < n-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (have_b && cholB && ! permB.isempty ()) { @@ -2705,6 +2685,10 @@ cresid(i) = Complex (rr(i),ri(i)); octave_rand::distribution (rand_dist); } + else if (m.cols () != cresid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) ("eigs: n must be at least 3"); @@ -2716,8 +2700,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k <= 0 || k >= n - 1) @@ -2726,9 +2710,9 @@ " (must be 0 < k < n-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (have_b && cholB && ! permB.isempty ()) { @@ -2866,33 +2850,26 @@ } else { - if (ido == 2) - { - for (F77_INT i = 0; i < n; i++) - workd[iptr(0) + i - 1] = - workd[iptr(1) + i - 1]; - } - else - { - Complex *ip2 = workd+iptr(0)-1; - ComplexMatrix tmp(n, 1); - - for (F77_INT i = 0; i < n; i++) - tmp(i,0) = ip2[P[i]]; - - lusolve (L, U, tmp); - - ip2 = workd+iptr(1)-1; - for (F77_INT i = 0; i < n; i++) - ip2[Q[i]] = tmp(i,0); - } + // ido cannot be 2 for non-generalized problems + // see znaup2 + Complex *ip2 = workd+iptr(0)-1; + ComplexMatrix tmp(n, 1); + + for (F77_INT i = 0; i < n; i++) + tmp(i,0) = ip2[P[i]]; + + lusolve (L, U, tmp); + + ip2 = workd+iptr(1)-1; + for (F77_INT i = 0; i < n; i++) + ip2[Q[i]] = tmp(i,0); } } else { if (info < 0) (*current_liboctave_error_handler) - ("eigs: error %d in dsaupd", info); + ("eigs: error %d in znaupd", info); break; } @@ -3005,6 +2982,10 @@ cresid(i) = Complex (rr(i),ri(i)); octave_rand::distribution (rand_dist); } + else if (n != cresid.numel ()) + { + (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1"); + } if (n < 3) (*current_liboctave_error_handler) @@ -3017,8 +2998,8 @@ if (p < 20) p = 20; - if (p > n - 1) - p = n - 1; + if (p > n) + p = n; } if (k <= 0 || k >= n - 1) @@ -3027,9 +3008,9 @@ " (must be 0 < k < n-1).\n" " Use 'eig (full (A))' instead"); - if (p <= k || p >= n) + if (p <= k || p > n) (*current_liboctave_error_handler) - ("eigs: opts.p must be greater than k and less than n"); + ("eigs: opts.p must be greater than k and less or equal to n"); if (! have_sigma) { diff -r 0da1bdfbfacb -r 1310d8b50ec2 scripts/sparse/eigs.m --- a/scripts/sparse/eigs.m Sat Nov 11 19:39:23 2017 +0100 +++ b/scripts/sparse/eigs.m Fri Mar 24 14:41:08 2017 +0100 @@ -124,7 +124,8 @@ ## @item p ## The number of Lanzcos basis vectors to use. More vectors will result in ## faster convergence, but a greater use of memory. The optimal value of -## @code{p} is problem dependent and should be in the range @var{k} to @var{n}. +## @code{p} is problem dependent and should be in the range +## @code{@var{k} + 1} to @var{n}. ## The default value is @code{2 * @var{k}}. ## ## @item v0 @@ -1229,6 +1230,12 @@ %! for i=1:k %! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); %! endfor +%!testif HAVE_ARPACK +%! [v1,d1] = eigs (A, k, "li"); +%! d1 = diag (d1); +%! for i=1:k +%! assert (max (abs ((A - d1(i)*eye (n))*v1(:,i))), 0, 1e-11); +%! endfor %!test %! A = 2 * diag (ones (10, 1)) - diag (ones (9, 1), 1) - diag (ones (9, 1), -1); @@ -1236,6 +1243,66 @@ %! reseig = eig (A, B); %! [~, idx] = sort (abs (reseig), "ascend"); %! assert (eigs (A, B, 10, 0), reseig (idx)); +%!testif HAVE_ARPACK +%! A = eye (9); +%! A(1, 1) = 0; +%! A(1, 9) = 1; +%! [V, L] = eigs (A, 4, -1); +%! assert (!any (isnan (diag (L)))) +%! assert (any (abs (diag (L)) <= 2 * eps)) +%!testif HAVE_ARPACK +%! A = diag (ones (9, 1), 1); +%! A(10,:) = [-1, zeros(1, 8), -1]; +%! opts.v0 = (1:10)'; +%! typ = "lr"; +%! [v, m] = eigs (A, 5, typ, opts); +%! assert (sort (real (diag (m))), ... +%! [-0.081751; 0.514038; 0.514038; 0.880290; 0.880290], 1e-4) +%! m = eigs (A, 5, typ, opts); +%! assert (sort (real (m)), ... +%! [-0.081751; 0.514038; 0.514038; 0.880290; 0.880290], 1e-4) +%! typ = "li"; +%! [v, m] = eigs (A, 5, typ, opts); +%! assert (sort (abs (imag (diag (m)))), ... +%! [0.75447; 0.78972; 0.78972; 0.96518; 0.96518], 1e-4) +%! m = eigs (A, 5, typ, opts); +%! assert (sort (abs (imag (m))), ... +%! [0.75447; 0.78972; 0.78972; 0.96518; 0.96518], 1e-4) +%! typ = "sr"; +%! [v, m] = eigs (A, 5, typ, opts); +%! assert (sort (real (diag (m))), ... +%! [-1.12180; -1.12180; -0.69077; -0.08175; -0.08175], 1e-4) +%! m = eigs (A, 5, typ, opts); +%! assert (sort (real (m)), ... +%! [-1.12180; -1.12180; -0.69077; -0.69077; -0.08175], 1e-4) +%! typ = "si"; +%! [v, m] = eigs (A, 5, typ, opts); +%! assert (sort (abs (imag (diag (m)))), ... +%! [0.25552; 0.25552; 0.30282; 0.30282; 0.75447], 1e-4) +%! m = eigs (A, 5, typ, opts); +%! assert (sort (abs (imag (m))), ... +%! [0.25552; 0.25552; 0.30282; 0.30282; 0.75447], 1e-4) +%! typ = "lm"; +%! [v, m] = eigs (A, 5, typ, opts); +%! assert (sort (abs (diag (m))), ... +%! [0.96863; 0.96863; 1.02294; 1.15054; 1.15054], 1e-4) +%! m = eigs (A, 5, typ, opts); +%! assert (sort (abs (m)), ... +%! [0.96863; 1.02294; 1.02294; 1.15054; 1.15054], 1e-4) +%! typ = "sm"; +%! [v, m] = eigs (A, 5, typ, opts); +%! assert (sort (abs (diag (m))), ... +%! [0.93092; 0.93092; 0.94228; 0.94228; 0.96863], 1e-4) +%! m = eigs (A, 5, typ, opts); +%! assert (sort (abs (m)), ... +%! [0.93092; 0.93092; 0.94228; 0.94228; 0.96863], 1e-4) +%!testif HAVE_ARPACK +%! A = toeplitz (sparse ([2, 1, zeros(1,8)])); +%! opts.v0 = (1:10)'; +%! [v, m] = eigs (A, 3, "sa", opts); +%! assert (diag (m), [0.081014; 0.317493; 0.690279], 1e-4); +%! m = eigs (A, 3, "sa", opts); +%! assert (m, [0.081014; 0.317493; 0.690279], 1e-4); %!test %! X = [70 47 42 39 50 73 79 23; @@ -1259,3 +1326,7 @@ %!assert (eigs (diag (1:5), 5, "sa"), [1;2;3;4;5]) %!assert (eigs (diag (1:5), 5, "la"), [5;4;3;2;1]) %!assert (eigs (diag (1:5), 3, "be"), [1;4;5]) +%!error +%! A = rand (10); +%! opts.v0 = ones (8, 1); +%! eigs (A, 4, "sm", opts);