GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
eigs-base.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2005-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cmath>
31 
32 #include <ostream>
33 
34 #include "Array.h"
35 #include "CSparse.h"
36 #include "MatrixType.h"
37 #include "PermMatrix.h"
38 #include "chol.h"
39 #include "dSparse.h"
40 #include "eigs-base.h"
41 #include "lo-arpack-proto.h"
42 #include "lo-blas-proto.h"
43 #include "lo-error.h"
44 #include "lo-ieee.h"
45 #include "lu.h"
46 #include "mx-ops.h"
47 #include "oct-locbuf.h"
48 #include "oct-rand.h"
49 #include "sparse-chol.h"
50 #include "sparse-lu.h"
51 
52 #if defined (HAVE_ARPACK)
53 
54 static void
56 {
57  (*current_liboctave_warning_with_id_handler)
58  ("Octave:convergence",
59  "eigs: 'A - sigma*B' is singular, indicating sigma is exactly "
60  "an eigenvalue so convergence is not guaranteed");
61 }
62 
63 // Conversion from error number to strings
64 std::string
65 arpack_errno2str (const octave_idx_type& errnum, const std::string& fcn_name)
66 {
67  std::string msg;
68  std::string bug_msg = "\nThis should not happen. Please, see https://www.gnu.org/software/octave/bugs.html, and file a bug report";
69 
70  switch (errnum)
71  {
72  case -1:
73  msg = "N must be positive";
74  break;
75 
76  case -2:
77  msg = "NEV must be positive";
78  break;
79 
80  case -3:
81  msg = "NCV-NEV >= 2 and less than or equal to N";
82  break;
83 
84  case -4:
85  msg = "The maximum number of Arnoldi update iterations allowed must be greater than zero";
86  break;
87 
88  case -5:
89  msg = "WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI'";
90  break;
91 
92  case -6:
93  msg = "BMAT must be one of 'I' or 'G'";
94  break;
95 
96  case -7:
97  msg = "Length of private work WORKL array is insufficient";
98  break;
99 
100  case -8:
101  msg = "Error return from LAPACK eigenvalue calculation";
102  break;
103 
104  case -9:
105  if (fcn_name.compare ("zneupd") == 0)
106  msg = "Error return from calculation of eigenvectors. Informational error from LAPACK routine ztrevc";
107  else if (fcn_name.compare ("dneupd") == 0)
108  msg = "Error return from calculation of eigenvectors. Informational error from LAPACK routine dtrevc";
109  else
110  msg = "Starting vector is zero";
111 
112  break;
113 
114  case -10:
115  if (fcn_name.compare ("dneupd") == 0
116  || fcn_name.compare ("dnaupd") == 0)
117  msg = "IPARAM(7) must be 1,2,3,4";
118  else if (fcn_name.compare ("zneupd") == 0
119  || fcn_name.compare ("znaupd") == 0)
120  msg = "IPARAM(7) must be 1,2,3";
121  else
122  msg = "IPARAM(7) must be 1,2,3,4,5";
123 
124  break;
125 
126  case -11:
127  msg = "IPARAM(7) = 1 and BMAT = 'G' are incompatible";
128  break;
129 
130  case -12:
131  if (fcn_name.compare ("dnaupd") == 0
132  || fcn_name.compare ("znaupd") == 0
133  || fcn_name.compare ("dsaupd") == 0)
134  msg = std::string ("IPARAM(1) must be equal to 0 or 1");
135  else if (fcn_name.compare ("dneupd") == 0
136  || fcn_name.compare ("zneupd") == 0)
137  msg = "HOWMNY = 'S' not yet implemented";
138  else
139  msg = "NEV and WHICH = 'BE' are incompatible";
140 
141  break;
142 
143  case -13:
144  if (fcn_name.compare ("dneupd") == 0
145  || fcn_name.compare ("zneupd") == 0)
146  msg = "HOWMNY must be one of 'A' or 'P' if RVEC = .true.";
147  else if (fcn_name.compare ("dsaupd") == 0)
148  msg = "NEV and WHICH = 'BE' are incompatible";
149 
150  break;
151 
152  case -14:
153  if (fcn_name.compare ("dneupd") == 0)
154  msg = "DNAUPD did not find any eigenvalues to sufficient accuracy.";
155  else if (fcn_name.compare ("zneupd") == 0)
156  msg = "ZNAUPD did not find any eigenvalues to sufficient accuracy.";
157  else if (fcn_name.compare ("dseupd") == 0)
158  msg = "DSAUPD did not find any eigenvalues to sufficient accuracy.";
159 
160  break;
161 
162  case -15:
163  if (fcn_name.compare ("dseupd") == 0)
164  msg = "HOWMNY must be one of 'A' or 'S' if RVEC = .true.";
165 
166  break;
167 
168  case -16:
169  if (fcn_name.compare ("dseupd") == 0)
170  msg = "HOWMNY = 'S' not yet implemented";
171 
172  break;
173 
174  case -9999:
175  if (fcn_name.compare ("dnaupd") == 0)
176  msg = "Could not build an Arnoldi factorization. IPARAM(5) returns the size of the current Arnoldi factorization";
177 
178  break;
179 
180  case 1:
181  if (fcn_name.compare ("dneupd") == 0)
182  msg = "The Schur form computed by LAPACK routine dlahqr could not be reordered by LAPACK routine dtrsen. Re-enter subroutine DNEUPD with IPARAM(5)=NCV and increase the size of the arrays DR and DI to have dimension at least dimension NCV and allocate at least NCV columns for Z. NOTE: Not necessary if Z and V share the same space. Please notify the authors if this error occurs.";
183  else if (fcn_name.compare ("dnaupd") == 0
184  || fcn_name.compare ("znaupd") == 0
185  || fcn_name.compare ("dsaupd") == 0)
186  msg = "Maximum number of iterations taken. All possible eigenvalues of OP has been found. IPARAM(5) returns the number of wanted converged Ritz values";
187  else if (fcn_name.compare ("znaupd") == 0)
188  msg = "The Schur form computed by LAPACK routine csheqr could not be reordered by LAPACK routine ztrsen. Re-enter subroutine ZNEUPD with IPARAM(5)=NCV and increase the size of the array D to have dimension at least dimension NCV and allocate at least NCV columns for Z. NOTE: Not necessary if Z and V share the same space. Please notify the authors if this error occurs.";
189 
190  break;
191 
192  case 2:
193  if (fcn_name.compare ("dnaupd") == 0
194  || fcn_name.compare ("znaupd") == 0
195  || fcn_name.compare ("dsaupd") == 0)
196  msg = "No longer an informational error. Deprecated starting with release 2 of ARPACK.";
197 
198  break;
199 
200  case 3:
201  if (fcn_name.compare ("dnaupd") == 0
202  || fcn_name.compare ("znaupd") == 0
203  || fcn_name.compare ("dsaupd") == 0)
204  msg = "No shifts could be applied during a cycle of the implicitly restarted Arnoldi iteration. One possibility is to increase the size of NCV relative to NEV.";
205 
206  break;
207 
208  }
209 
210  if ((errno != -9) & (errno != -14) & (errno != -9999))
211  // This is a bug in Octave interface to ARPACK
212  msg.append (bug_msg);
213 
214  return msg;
215 }
216 
217 template <typename M, typename SM>
218 static octave_idx_type
219 lusolve (const SM& L, const SM& U, M& m)
220 {
221  octave_idx_type err = 0;
222  double rcond;
224 
225  // Sparse L is lower triangular, Dense L is permuted lower triangular!!!
227  m = L.solve (ltyp, m, err, rcond, nullptr);
228  if (err)
229  return err;
230 
231  m = U.solve (utyp, m, err, rcond, nullptr);
232 
233  return err;
234 }
235 
236 template <typename SM, typename M>
237 static M
238 ltsolve (const SM& L, const ColumnVector& Q, const M& m)
239 {
240  // Solve (Q_mat * L) * x = m, that is L * x = Q_mat' * m = m(Q)
241  octave_idx_type n = L.cols ();
242  octave_idx_type b_nc = m.cols ();
243  octave_idx_type err = 0;
244  double rcond;
246  M retval (n, b_nc);
247  const double *qv = Q.fortran_vec ();
248  for (octave_idx_type j = 0; j < b_nc; j++)
249  {
250  for (octave_idx_type i = 0; i < n; i++)
251  retval.elem (i,j) = m.elem (static_cast<octave_idx_type> (qv[i]), j);
252  }
253  return L.solve (ltyp, retval, err, rcond, nullptr);
254 }
255 
256 template <typename SM, typename M>
257 static M
258 utsolve (const SM& U, const ColumnVector& Q, const M& m)
259 {
260  // Solve (U * Q_mat') * x = m by U * tmp = m, x(Q) = tmp (Q_mat * tmp = x)
261  octave_idx_type n = U.cols ();
262  octave_idx_type b_nc = m.cols ();
263  octave_idx_type err = 0;
264  double rcond;
266  M tmp = U.solve (utyp, m, err, rcond, nullptr);
267  M retval;
268  const double *qv = Q.fortran_vec ();
269 
270  if (! err)
271  {
272  retval.resize (n, b_nc);
273  for (octave_idx_type j = 0; j < b_nc; j++)
274  {
275  for (octave_idx_type i = 0; i < n; i++)
276  retval.elem (static_cast<octave_idx_type> (qv[i]), j)
277  = tmp.elem (i,j);
278  }
279  }
280 
281  return retval;
282 }
283 
284 static bool
285 vector_product (const SparseMatrix& m, const double *x, double *y)
286 {
287  octave_idx_type nc = m.cols ();
288 
289  for (octave_idx_type j = 0; j < nc; j++)
290  y[j] = 0.;
291 
292  for (octave_idx_type j = 0; j < nc; j++)
293  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
294  y[m.ridx (i)] += m.data (i) * x[j];
295 
296  return true;
297 }
298 
299 static bool
300 vector_product (const Matrix& m, const double *x, double *y)
301 {
302  F77_INT nr = octave::to_f77_int (m.rows ());
303  F77_INT nc = octave::to_f77_int (m.cols ());
304 
305  F77_XFCN (dgemv, DGEMV, (F77_CONST_CHAR_ARG2 ("N", 1),
306  nr, nc, 1.0, m.data (), nr,
307  x, 1, 0.0, y, 1
308  F77_CHAR_ARG_LEN (1)));
309 
310  return true;
311 }
312 
313 static bool
315  Complex *y)
316 {
317  octave_idx_type nc = m.cols ();
318 
319  for (octave_idx_type j = 0; j < nc; j++)
320  y[j] = 0.;
321 
322  for (octave_idx_type j = 0; j < nc; j++)
323  for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++)
324  y[m.ridx (i)] += m.data (i) * x[j];
325 
326  return true;
327 }
328 
329 static bool
331 {
332  F77_INT nr = octave::to_f77_int (m.rows ());
333  F77_INT nc = octave::to_f77_int (m.cols ());
334 
335  F77_XFCN (zgemv, ZGEMV, (F77_CONST_CHAR_ARG2 ("N", 1),
336  nr, nc, 1.0, F77_CONST_DBLE_CMPLX_ARG (m.data ()),
337  nr,
338  F77_CONST_DBLE_CMPLX_ARG (x), 1, 0.0,
339  F77_DBLE_CMPLX_ARG (y), 1
340  F77_CHAR_ARG_LEN (1)));
341 
342  return true;
343 }
344 
345 static bool
347 {
348  octave_idx_type info;
349  octave::math::chol<Matrix> fact (b, info);
350  octave_idx_type n = b.cols ();
351 
352  if (info != 0)
353  return false;
354  else
355  {
356  bt = fact.chol_matrix (); // upper triangular
357  b = bt.transpose ();
358  permB = ColumnVector (n);
359  for (octave_idx_type i = 0; i < n; i++)
360  permB(i) = i;
361  return true;
362  }
363 }
364 
365 static bool
367 {
368  octave_idx_type info;
369  octave::math::sparse_chol<SparseMatrix> fact (b, info, false);
370 
371  if (info != 0)
372  return false;
373  else
374  {
375  b = fact.L (); // lower triangular
376  bt = b.transpose ();
377  permB = fact.perm () - 1.0;
378  return true;
379  }
380 }
381 
382 static bool
384 {
385  octave_idx_type info;
386  octave::math::chol<ComplexMatrix> fact (b, info);
387  octave_idx_type n = b.cols ();
388 
389  if (info != 0)
390  return false;
391  else
392  {
393  bt = fact.chol_matrix (); // upper triangular
394  b = bt.hermitian ();
395  permB = ColumnVector (n);
396  for (octave_idx_type i = 0; i < n; i++)
397  permB(i) = i;
398  return true;
399  }
400 }
401 
402 static bool
404  ColumnVector& permB)
405 {
406  octave_idx_type info;
408 
409  if (info != 0)
410  return false;
411  else
412  {
413  b = fact.L (); // lower triangular
414  bt = b.hermitian ();
415  permB = fact.perm () - 1.0;
416  return true;
417  }
418 }
419 
420 static bool
422  bool cholB, const ColumnVector& permB, double sigma,
425 {
426  bool have_b = ! b.isempty ();
427  octave_idx_type n = m.rows ();
428 
429  // Calculate LU decomposition of 'M = A - sigma * B'
430  // P * (R \ M) * Q = L * U
431  SparseMatrix AminusSigmaB (m);
432 
433  if (sigma != 0.0)
434  {
435  if (have_b)
436  {
437  if (cholB)
438  {
439  if (permB.numel ())
440  {
441  SparseMatrix tmp (n,n,n);
442  for (octave_idx_type i = 0; i < n; i++)
443  {
444  tmp.xcidx (i) = i;
445  tmp.xridx (i) = static_cast<octave_idx_type> (permB(i));
446  tmp.xdata (i) = 1;
447  }
448  tmp.xcidx (n) = n;
449 
450  AminusSigmaB -= sigma * tmp *
451  b.transpose () * b * tmp.transpose ();
452  }
453  else
454  AminusSigmaB -= sigma * b.transpose () * b;
455  }
456  else
457  AminusSigmaB -= sigma * b;
458  }
459  else
460  {
461  SparseMatrix sigmat (n, n, n);
462 
463  // Create sigma * speye (n,n)
464  sigmat.xcidx (0) = 0;
465  for (octave_idx_type i = 0; i < n; i++)
466  {
467  sigmat.xdata (i) = sigma;
468  sigmat.xridx (i) = i;
469  sigmat.xcidx (i+1) = i + 1;
470  }
471 
472  AminusSigmaB -= sigmat;
473  }
474  }
475 
476  octave::math::sparse_lu<SparseMatrix> fact (AminusSigmaB, Matrix (), true);
477 
478  L = fact.L ();
479  U = fact.U ();
480  SparseMatrix R = fact.R ();
481  for (octave_idx_type i = 0; i < n; i++)
482  r(i) = R.xdata(i);
483 
484  const octave_idx_type *P2 = fact.row_perm ();
485  const octave_idx_type *Q2 = fact.col_perm ();
486 
487  for (octave_idx_type j = 0; j < n; j++)
488  {
489  P[j] = P2[j];
490  Q[j] = Q2[j];
491  }
492 
493  // Test condition number of LU decomposition
494  double minU = octave::numeric_limits<double>::NaN ();
495  double maxU = octave::numeric_limits<double>::NaN ();
496  for (octave_idx_type j = 0; j < n; j++)
497  {
498  double d = 0.;
499  if (U.xcidx (j+1) > U.xcidx (j)
500  && U.xridx (U.xcidx (j+1)-1) == j)
501  d = std::abs (U.xdata (U.xcidx (j+1)-1));
502 
503  if (octave::math::isnan (minU) || d < minU)
504  minU = d;
505 
506  if (octave::math::isnan (maxU) || d > maxU)
507  maxU = d;
508  }
509 
510  double rcond = (minU / maxU);
511  volatile double rcond_plus_one = rcond + 1.0;
512 
513  if (rcond_plus_one == 1.0 || octave::math::isnan (rcond))
514  warn_convergence ();
515 
516  return true;
517 }
518 
519 static bool
520 LuAminusSigmaB (const Matrix& m, const Matrix& b,
521  bool cholB, const ColumnVector& permB, double sigma,
523  ColumnVector &r)
524 {
525  bool have_b = ! b.isempty ();
526  octave_idx_type n = m.cols ();
527 
528  // Calculate LU decomposition of 'M = A - sigma * B'
529  // P * M = L * U
530  Matrix AminusSigmaB (m);
531 
532  if (sigma != 0.0)
533  {
534  if (have_b)
535  {
536  if (cholB)
537  {
538  Matrix tmp = sigma * b.transpose () * b;
539  const double *pB = permB.fortran_vec ();
540  double *p = AminusSigmaB.fortran_vec ();
541 
542  if (permB.numel ())
543  {
544  for (octave_idx_type j = 0;
545  j < b.cols (); j++)
546  for (octave_idx_type i = 0;
547  i < b.rows (); i++)
548  *p++ -= tmp.xelem (static_cast<octave_idx_type> (pB[i]),
549  static_cast<octave_idx_type> (pB[j]));
550  }
551  else
552  AminusSigmaB -= tmp;
553  }
554  else
555  AminusSigmaB -= sigma * b;
556  }
557  else
558  {
559  double *p = AminusSigmaB.fortran_vec ();
560 
561  for (octave_idx_type i = 0; i < n; i++)
562  p[i*(n+1)] -= sigma;
563  }
564  }
565 
566  octave::math::lu<Matrix> fact (AminusSigmaB);
567 
568  L = fact.L ();
569  U = fact.U ();
570  ColumnVector P2 = fact.P_vec();
571 
572  for (octave_idx_type j = 0; j < n; j++)
573  {
574  Q[j] = j;
575  P[j] = P2(j) - 1;
576  r(j) = 1.;
577  }
578 
579  // Test condition number of LU decomposition
580  double minU = octave::numeric_limits<double>::NaN ();
581  double maxU = octave::numeric_limits<double>::NaN ();
582  for (octave_idx_type j = 0; j < n; j++)
583  {
584  double d = std::abs (U.xelem (j,j));
585  if (octave::math::isnan (minU) || d < minU)
586  minU = d;
587 
588  if (octave::math::isnan (maxU) || d > maxU)
589  maxU = d;
590  }
591 
592  double rcond = (minU / maxU);
593  volatile double rcond_plus_one = rcond + 1.0;
594 
595  if (rcond_plus_one == 1.0 || octave::math::isnan (rcond))
596  warn_convergence ();
597 
598  return true;
599 }
600 
601 static bool
603  bool cholB, const ColumnVector& permB, Complex sigma,
606 {
607  bool have_b = ! b.isempty ();
608  octave_idx_type n = m.rows ();
609 
610  // Calculate LU decomposition of 'M = A - sigma * B'
611  // P * (R \ M) * Q = L * U
612  SparseComplexMatrix AminusSigmaB (m);
613 
614  if (std::real (sigma) != 0.0 || std::imag (sigma) != 0.0)
615  {
616  if (have_b)
617  {
618  if (cholB)
619  {
620  if (permB.numel ())
621  {
622  SparseMatrix tmp (n,n,n);
623  for (octave_idx_type i = 0; i < n; i++)
624  {
625  tmp.xcidx (i) = i;
626  tmp.xridx (i) = static_cast<octave_idx_type> (permB(i));
627  tmp.xdata (i) = 1;
628  }
629  tmp.xcidx (n) = n;
630 
631  AminusSigmaB -= tmp * b.hermitian () * b *
632  tmp.transpose () * sigma;
633  }
634  else
635  AminusSigmaB -= sigma * b.hermitian () * b;
636  }
637  else
638  AminusSigmaB -= sigma * b;
639  }
640  else
641  {
642  SparseComplexMatrix sigmat (n, n, n);
643 
644  // Create sigma * speye (n,n)
645  sigmat.xcidx (0) = 0;
646  for (octave_idx_type i = 0; i < n; i++)
647  {
648  sigmat.xdata (i) = sigma;
649  sigmat.xridx (i) = i;
650  sigmat.xcidx (i+1) = i + 1;
651  }
652 
653  AminusSigmaB -= sigmat;
654  }
655  }
656 
658  true);
659 
660  L = fact.L ();
661  U = fact.U ();
662  SparseMatrix R = fact.R ();
663  for (octave_idx_type i = 0; i < n; i++)
664  r(i) = R.xdata(i);
665 
666  const octave_idx_type *P2 = fact.row_perm ();
667  const octave_idx_type *Q2 = fact.col_perm ();
668 
669  for (octave_idx_type j = 0; j < n; j++)
670  {
671  P[j] = P2[j];
672  Q[j] = Q2[j];
673  }
674 
675  // Test condition number of LU decomposition
676  double minU = octave::numeric_limits<double>::NaN ();
677  double maxU = octave::numeric_limits<double>::NaN ();
678  for (octave_idx_type j = 0; j < n; j++)
679  {
680  double d = 0.;
681  if (U.xcidx (j+1) > U.xcidx (j)
682  && U.xridx (U.xcidx (j+1)-1) == j)
683  d = std::abs (U.xdata (U.xcidx (j+1)-1));
684 
685  if (octave::math::isnan (minU) || d < minU)
686  minU = d;
687 
688  if (octave::math::isnan (maxU) || d > maxU)
689  maxU = d;
690  }
691 
692  double rcond = (minU / maxU);
693  volatile double rcond_plus_one = rcond + 1.0;
694 
695  if (rcond_plus_one == 1.0 || octave::math::isnan (rcond))
696  warn_convergence ();
697 
698  return true;
699 }
700 
701 static bool
703  bool cholB, const ColumnVector& permB, Complex sigma,
706 {
707  bool have_b = ! b.isempty ();
708  octave_idx_type n = m.cols ();
709 
710  // Calculate LU decomposition of 'M = A - sigma * B'
711  // P * M = L * U
712  ComplexMatrix AminusSigmaB (m);
713 
714  if (std::real (sigma) != 0.0 || std::imag (sigma) != 0.0)
715  {
716  if (have_b)
717  {
718  if (cholB)
719  {
720  ComplexMatrix tmp = sigma * b.hermitian () * b;
721  const double *pB = permB.fortran_vec ();
722  Complex *p = AminusSigmaB.fortran_vec ();
723 
724  if (permB.numel ())
725  {
726  for (octave_idx_type j = 0;
727  j < b.cols (); j++)
728  for (octave_idx_type i = 0;
729  i < b.rows (); i++)
730  *p++ -= tmp.xelem (static_cast<octave_idx_type> (pB[i]),
731  static_cast<octave_idx_type> (pB[j]));
732  }
733  else
734  AminusSigmaB -= tmp;
735  }
736  else
737  AminusSigmaB -= sigma * b;
738  }
739  else
740  {
741  Complex *p = AminusSigmaB.fortran_vec ();
742 
743  for (octave_idx_type i = 0; i < n; i++)
744  p[i*(n+1)] -= sigma;
745  }
746  }
747 
748  octave::math::lu<ComplexMatrix> fact (AminusSigmaB);
749 
750  L = fact.L ();
751  U = fact.U ();
752  ColumnVector P2 = fact.P_vec ();
753 
754  for (octave_idx_type j = 0; j < n; j++)
755  {
756  Q[j] = j;
757  P[j] = P2(j) - 1;
758  r(j) = 1.;
759  }
760 
761  // Test condition number of LU decomposition
762  double minU = octave::numeric_limits<double>::NaN ();
763  double maxU = octave::numeric_limits<double>::NaN ();
764  for (octave_idx_type j = 0; j < n; j++)
765  {
766  double d = std::abs (U.xelem (j,j));
767  if (octave::math::isnan (minU) || d < minU)
768  minU = d;
769 
770  if (octave::math::isnan (maxU) || d > maxU)
771  maxU = d;
772  }
773 
774  double rcond = (minU / maxU);
775  volatile double rcond_plus_one = rcond + 1.0;
776 
777  if (rcond_plus_one == 1.0 || octave::math::isnan (rcond))
778  warn_convergence ();
779 
780  return true;
781 }
782 
783 template <typename M>
785 EigsRealSymmetricMatrix (const M& m, const std::string typ,
786  octave_idx_type k_arg, octave_idx_type p_arg,
787  octave_idx_type& info, Matrix& eig_vec,
788  ColumnVector& eig_val, const M& _b,
789  ColumnVector& permB, ColumnVector& resid,
790  std::ostream& os, double tol, bool rvec,
791  bool cholB, int disp, int maxit)
792 {
793  F77_INT k = octave::to_f77_int (k_arg);
794  F77_INT p = octave::to_f77_int (p_arg);
795  M b(_b);
796  F77_INT n = octave::to_f77_int (m.cols ());
797  F77_INT mode = 1;
798  bool have_b = ! b.isempty ();
799  bool note3 = false;
800  char bmat = 'I';
801  double sigma = 0.;
802  M bt;
803 
804  if (m.rows () != m.cols ())
805  (*current_liboctave_error_handler) ("eigs: A must be square");
806  if (have_b && (m.rows () != b.rows () || m.rows () != b.cols ()))
808  ("eigs: B must be square and the same size as A");
809 
810  if (resid.isempty ())
811  {
812  std::string rand_dist = octave::rand::distribution ();
813  octave::rand::distribution ("uniform");
814  resid = ColumnVector (octave::rand::vector (n));
815  octave::rand::distribution (rand_dist);
816  }
817  else if (m.cols () != resid.numel ())
818  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
819 
820  if (n < 3)
821  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
822 
823  if (p < 0)
824  {
825  p = k * 2;
826 
827  if (p < 20)
828  p = 20;
829 
830  if (p > n)
831  p = n;
832  }
833 
834  if (k < 1 || k > n - 2)
835  (*current_liboctave_error_handler)
836  ("eigs: Invalid number of eigenvalues to extract"
837  " (must be 0 < k < n-1-1).\n"
838  " Use 'eig (full (A))' instead");
839 
840  if (p <= k || p > n)
841  (*current_liboctave_error_handler)
842  ("eigs: opts.p must be greater than k and less than or equal to n");
843 
844  if (have_b && cholB && ! permB.isempty ())
845  {
846  // Check the we really have a permutation vector
847  if (permB.numel () != n)
848  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
849 
850  Array<bool> checked (dim_vector (n, 1), false);
851  for (F77_INT i = 0; i < n; i++)
852  {
853  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
854 
855  if (checked(bidx) || bidx < 0 || bidx >= n
856  || octave::math::x_nint (bidx) != bidx)
857  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
858  }
859  }
860 
861  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
862  && typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI"
863  && typ != "SI")
864  (*current_liboctave_error_handler) ("eigs: unrecognized sigma value");
865 
866  if (typ == "LI" || typ == "SI" || typ == "LR" || typ == "SR")
867  (*current_liboctave_error_handler)
868  ("eigs: invalid sigma value for real symmetric problem");
869 
870  if (have_b)
871  {
872  // See Note 3 dsaupd
873  note3 = true;
874  if (cholB)
875  {
876  bt = b;
877  b = b.transpose ();
878  if (permB.isempty ())
879  {
880  permB = ColumnVector (n);
881  for (F77_INT i = 0; i < n; i++)
882  permB(i) = i;
883  }
884  }
885  else
886  {
887  if (! make_cholb (b, bt, permB))
888  (*current_liboctave_error_handler)
889  ("eigs: The matrix B is not positive definite");
890  }
891  }
892 
893  Array<F77_INT> ip (dim_vector (11, 1));
894  F77_INT *iparam = ip.fortran_vec ();
895 
896  ip(0) = 1; //ishift
897  ip(1) = 0; // ip(1) not referenced
898  ip(2) = maxit; // mxiter, maximum number of iterations
899  ip(3) = 1; // NB blocksize in recurrence
900  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
901  ip(5) = 0; //ip(5) not referenced
902  ip(6) = mode; // mode
903  ip(7) = 0;
904  ip(8) = 0;
905  ip(9) = 0;
906  ip(10) = 0;
907  // ip(7) to ip(10) return values
908 
909  Array<F77_INT> iptr (dim_vector (14, 1));
910  F77_INT *ipntr = iptr.fortran_vec ();
911 
912  F77_INT ido = 0;
913  int iter = 0;
914  F77_INT lwork = p * (p + 8);
915 
916  OCTAVE_LOCAL_BUFFER (double, v, n * p);
917  OCTAVE_LOCAL_BUFFER (double, workl, lwork);
918  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n);
919  double *presid = resid.fortran_vec ();
920 
921  do
922  {
923  F77_INT tmp_info = octave::to_f77_int (info);
924 
925  F77_FUNC (dsaupd, DSAUPD)
926  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
927  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
928  k, tol, presid, p, v, n, iparam,
929  ipntr, workd, workl, lwork, tmp_info
930  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
931 
932  info = tmp_info;
933 
934  if (disp > 0 && ! octave::math::isnan (workl[iptr (5)-1]))
935  {
936  if (iter++)
937  {
938  os << "Iteration " << iter - 1 <<
939  ": a few Ritz values of the " << p << "-by-" <<
940  p << " matrix\n";
941  if (ido == 99) // convergence
942  {
943  for (F77_INT i = 0; i < k; i++)
944  os << " " << workl[iptr(5)+i-1] << "\n";
945  }
946  else
947  {
948  // the wanted Ritz estimates are at the end
949  for (F77_INT i = p - k; i < p; i++)
950  os << " " << workl[iptr(5)+i-1] << "\n";
951  }
952  }
953 
954  // This is a kludge, as ARPACK doesn't give its
955  // iteration pointer. But as workl[iptr(5)-1] is
956  // an output value updated at each iteration, setting
957  // a value in this array to NaN and testing for it
958  // is a way of obtaining the iteration counter.
959  if (ido != 99)
960  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
961  }
962 
963  if (ido == -1 || ido == 1 || ido == 2)
964  {
965  if (have_b)
966  {
967  Matrix mtmp (n,1);
968  for (F77_INT i = 0; i < n; i++)
969  mtmp(i,0) = workd[i + iptr(0) - 1];
970 
971  mtmp = ltsolve (b, permB, m * utsolve (bt, permB, mtmp));
972 
973  for (F77_INT i = 0; i < n; i++)
974  workd[i+iptr(1)-1] = mtmp(i,0);
975  }
976  else if (! vector_product (m, workd + iptr(0) - 1,
977  workd + iptr(1) - 1))
978  break;
979  }
980  else
981  {
982  if (info < 0)
983  (*current_liboctave_error_handler)
984  ("eigs: error in dsaupd: %s",
985  arpack_errno2str (info, "dsaupd").c_str ());
986 
987  break;
988  }
989  }
990  while (1);
991 
992  F77_INT info2;
993 
994  // We have a problem in that the size of the C++ bool
995  // type relative to the fortran logical type. It appears
996  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
997  // per bool, though this might be system dependent. As
998  // long as the HOWMNY arg is not "S", the logical array
999  // is just workspace for ARPACK, so use int type to
1000  // avoid problems.
1001  Array<F77_INT> s (dim_vector (p, 1));
1002  F77_INT *sel = s.fortran_vec ();
1003 
1004  eig_vec.resize (n, k);
1005  double *z = eig_vec.fortran_vec ();
1006 
1007  eig_val.resize (k);
1008  double *d = eig_val.fortran_vec ();
1009 
1010  F77_FUNC (dseupd, DSEUPD)
1011  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma,
1012  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
1013  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
1014  ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1)
1015  F77_CHAR_ARG_LEN(2));
1016 
1017  if (info2 == 0)
1018  {
1019  for (F77_INT i = ip(4); i < k; i++)
1021  F77_INT k2 = ip(4) / 2;
1022  if (typ != "SM" && typ != "BE" && ! (typ == "SA" && rvec))
1023  {
1024  for (F77_INT i = 0; i < k2; i++)
1025  {
1026  double dtmp = d[i];
1027  d[i] = d[ip(4) - i - 1];
1028  d[ip(4) - i - 1] = dtmp;
1029  }
1030  }
1031 
1032  if (rvec)
1033  {
1034  for (F77_INT i = ip(4); i < k; i++)
1035  {
1036  F77_INT off1 = i * n;
1037  for (F77_INT j = 0; j < n; j++)
1038  z[off1 + j] = octave::numeric_limits<double>::NaN ();
1039  }
1040  if (typ != "SM" && typ != "BE" && typ != "SA")
1041  {
1042  OCTAVE_LOCAL_BUFFER (double, dtmp, n);
1043 
1044  for (F77_INT i = 0; i < k2; i++)
1045  {
1046  F77_INT off1 = i * n;
1047  F77_INT off2 = (ip(4) - i - 1) * n;
1048 
1049  if (off1 == off2)
1050  continue;
1051 
1052  for (F77_INT j = 0; j < n; j++)
1053  dtmp[j] = z[off1 + j];
1054 
1055  for (F77_INT j = 0; j < n; j++)
1056  z[off1 + j] = z[off2 + j];
1057 
1058  for (F77_INT j = 0; j < n; j++)
1059  z[off2 + j] = dtmp[j];
1060  }
1061  }
1062 
1063  if (note3)
1064  eig_vec = utsolve (bt, permB, eig_vec);
1065  }
1066  }
1067  else
1069  ("eigs: error in dseupd: %s",
1070  arpack_errno2str (info2, "dseupd").c_str ());
1071 
1072  return ip(4);
1073 }
1074 
1075 template <typename M>
1077 EigsRealSymmetricMatrixShift (const M& m, double sigma,
1078  octave_idx_type k_arg, octave_idx_type p_arg,
1079  octave_idx_type& info, Matrix& eig_vec,
1080  ColumnVector& eig_val, const M& _b,
1081  ColumnVector& permB, ColumnVector& resid,
1082  std::ostream& os, double tol, bool rvec,
1083  bool cholB, int disp, int maxit)
1084 {
1085  F77_INT k = octave::to_f77_int (k_arg);
1086  F77_INT p = octave::to_f77_int (p_arg);
1087  M b(_b);
1088  F77_INT n = octave::to_f77_int (m.cols ());
1089  F77_INT mode = 3;
1090  bool have_b = ! b.isempty ();
1091  std::string typ = "LM";
1092 
1093  if (m.rows () != m.cols ())
1094  (*current_liboctave_error_handler) ("eigs: A must be square");
1095  if (have_b && (m.rows () != b.rows () || m.rows () != b.cols ()))
1097  ("eigs: B must be square and the same size as A");
1098 
1099  // FIXME: The "SM" type for mode 1 seems unstable though faster!!
1100  //if (! std::abs (sigma))
1101  // return EigsRealSymmetricMatrix (m, "SM", k, p, info, eig_vec, eig_val,
1102  // _b, permB, resid, os, tol, rvec, cholB,
1103  // disp, maxit);
1104 
1105  if (resid.isempty ())
1106  {
1107  std::string rand_dist = octave::rand::distribution ();
1108  octave::rand::distribution ("uniform");
1109  resid = ColumnVector (octave::rand::vector (n));
1110  octave::rand::distribution (rand_dist);
1111  }
1112  else if (m.cols () != resid.numel ())
1113  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
1114 
1115  if (n < 3)
1116  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
1117 
1118  if (k <= 0 || k >= n - 1)
1119  (*current_liboctave_error_handler)
1120  ("eigs: Invalid number of eigenvalues to extract"
1121  " (must be 0 < k < n-1-1).\n"
1122  " Use 'eig (full (A))' instead");
1123 
1124  if (p < 0)
1125  {
1126  p = k * 2;
1127 
1128  if (p < 20)
1129  p = 20;
1130 
1131  if (p > n)
1132  p = n;
1133  }
1134 
1135  if (p <= k || p > n)
1136  (*current_liboctave_error_handler)
1137  ("eigs: opts.p must be greater than k and less than or equal to n");
1138 
1139  if (have_b && cholB && ! permB.isempty ())
1140  {
1141  // Check the we really have a permutation vector
1142  if (permB.numel () != n)
1143  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
1144 
1145  Array<bool> checked (dim_vector (n, 1), false);
1146  for (F77_INT i = 0; i < n; i++)
1147  {
1148  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
1149 
1150  if (checked(bidx) || bidx < 0 || bidx >= n
1151  || octave::math::x_nint (bidx) != bidx)
1152  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
1153  }
1154  }
1155 
1156  char bmat = 'I';
1157  if (have_b)
1158  bmat = 'G';
1159 
1160  Array<F77_INT> ip (dim_vector (11, 1));
1161  F77_INT *iparam = ip.fortran_vec ();
1162 
1163  ip(0) = 1; //ishift
1164  ip(1) = 0; // ip(1) not referenced
1165  ip(2) = maxit; // mxiter, maximum number of iterations
1166  ip(3) = 1; // NB blocksize in recurrence
1167  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
1168  ip(5) = 0; //ip(5) not referenced
1169  ip(6) = mode; // mode
1170  ip(7) = 0;
1171  ip(8) = 0;
1172  ip(9) = 0;
1173  ip(10) = 0;
1174  // ip(7) to ip(10) return values
1175 
1176  Array<F77_INT> iptr (dim_vector (14, 1));
1177  F77_INT *ipntr = iptr.fortran_vec ();
1178 
1179  F77_INT ido = 0;
1180  int iter = 0;
1181  M L, U;
1182  ColumnVector r(n);
1183 
1184  OCTAVE_LOCAL_BUFFER (octave_idx_type, P, (have_b ? b.rows () : m.rows ()));
1185  OCTAVE_LOCAL_BUFFER (octave_idx_type, Q, (have_b ? b.cols () : m.cols ()));
1186 
1187  if (! LuAminusSigmaB (m, b, cholB, permB, sigma, L, U, P, Q, r))
1188  return -1;
1189 
1190  F77_INT lwork = p * (p + 8);
1191 
1192  OCTAVE_LOCAL_BUFFER (double, v, n * p);
1193  OCTAVE_LOCAL_BUFFER (double, workl, lwork);
1194  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n);
1195  double *presid = resid.fortran_vec ();
1196 
1197  do
1198  {
1199  F77_INT tmp_info = octave::to_f77_int (info);
1200 
1201  F77_FUNC (dsaupd, DSAUPD)
1202  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
1203  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
1204  k, tol, presid, p, v, n, iparam,
1205  ipntr, workd, workl, lwork, tmp_info
1206  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
1207  info = tmp_info;
1208 
1209  if (disp > 0 && ! octave::math::isnan (workl[iptr (5)-1]))
1210  {
1211  if (iter++)
1212  {
1213  os << "Iteration " << iter - 1 <<
1214  ": a few Ritz values of the " << p << "-by-" <<
1215  p << " matrix\n";
1216  if (ido == 99) // convergence
1217  {
1218  for (F77_INT i = 0; i < k; i++)
1219  os << " " << workl[iptr(5)+i-1] << "\n";
1220  }
1221  else
1222  {
1223  // the wanted Ritz estimates are at the end
1224  for (F77_INT i = p - k; i < p; i++)
1225  os << " " << workl[iptr(5)+i-1] << "\n";
1226  }
1227  }
1228 
1229  // This is a kludge, as ARPACK doesn't give its
1230  // iteration pointer. But as workl[iptr(5)-1] is
1231  // an output value updated at each iteration, setting
1232  // a value in this array to NaN and testing for it
1233  // is a way of obtaining the iteration counter.
1234  if (ido != 99)
1235  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
1236  }
1237 
1238  if (ido == -1 || ido == 1 || ido == 2)
1239  {
1240  if (have_b)
1241  {
1242  if (ido == -1)
1243  {
1244  OCTAVE_LOCAL_BUFFER (double, dtmp, n);
1245 
1246  vector_product (b, workd+iptr(0)-1, dtmp);
1247 
1248  Matrix tmp (n, 1);
1249 
1250  for (F77_INT i = 0; i < n; i++)
1251  tmp(i,0) = dtmp[P[i]] / r(P[i]);
1252 
1253  lusolve (L, U, tmp);
1254 
1255  double *ip2 = workd+iptr(1)-1;
1256  for (F77_INT i = 0; i < n; i++)
1257  ip2[Q[i]] = tmp(i,0);
1258  }
1259  else if (ido == 2)
1260  vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
1261  else
1262  {
1263  double *ip2 = workd+iptr(2)-1;
1264  Matrix tmp (n, 1);
1265 
1266  for (F77_INT i = 0; i < n; i++)
1267  tmp(i,0) = ip2[P[i]] / r(P[i]);
1268 
1269  lusolve (L, U, tmp);
1270 
1271  ip2 = workd+iptr(1)-1;
1272  for (F77_INT i = 0; i < n; i++)
1273  ip2[Q[i]] = tmp(i,0);
1274  }
1275  }
1276  else
1277  {
1278  // ido cannot be 2 for non-generalized problems (see dsaupd2).
1279  double *ip2 = workd+iptr(0)-1;
1280  Matrix tmp (n, 1);
1281 
1282  for (F77_INT i = 0; i < n; i++)
1283  tmp(i,0) = ip2[P[i]] / r(P[i]);
1284 
1285  lusolve (L, U, tmp);
1286 
1287  ip2 = workd+iptr(1)-1;
1288  for (F77_INT i = 0; i < n; i++)
1289  ip2[Q[i]] = tmp(i,0);
1290  }
1291  }
1292  else
1293  {
1294  if (info < 0)
1295  (*current_liboctave_error_handler)
1296  ("eigs: error in dsaupd: %s",
1297  arpack_errno2str (info, "dsaupd").c_str ());
1298 
1299  break;
1300  }
1301  }
1302  while (1);
1303 
1304  F77_INT info2;
1305 
1306  // We have a problem in that the size of the C++ bool
1307  // type relative to the fortran logical type. It appears
1308  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
1309  // per bool, though this might be system dependent. As
1310  // long as the HOWMNY arg is not "S", the logical array
1311  // is just workspace for ARPACK, so use int type to
1312  // avoid problems.
1313  Array<F77_INT> s (dim_vector (p, 1));
1314  F77_INT *sel = s.fortran_vec ();
1315 
1316  eig_vec.resize (n, k);
1317  double *z = eig_vec.fortran_vec ();
1318 
1319  eig_val.resize (k);
1320  double *d = eig_val.fortran_vec ();
1321 
1322  F77_FUNC (dseupd, DSEUPD)
1323  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma,
1324  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
1325  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
1326  k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, info2
1327  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
1328 
1329  if (info2 == 0)
1330  {
1331  for (F77_INT i = ip(4); i < k; i++)
1333  F77_INT k2 = ip(4) / 2;
1334  for (F77_INT i = 0; i < k2; i++)
1335  {
1336  double dtmp = d[i];
1337  d[i] = d[ip(4) - i - 1];
1338  d[ip(4) - i - 1] = dtmp;
1339  }
1340 
1341  if (rvec)
1342  {
1343  OCTAVE_LOCAL_BUFFER (double, dtmp, n);
1344 
1345  for (F77_INT i = ip(4); i < k; i++)
1346  {
1347  F77_INT off1 = i * n;
1348  for (F77_INT j = 0; j < n; j++)
1349  z[off1 + j] = octave::numeric_limits<double>::NaN ();
1350  }
1351  for (F77_INT i = 0; i < k2; i++)
1352  {
1353  F77_INT off1 = i * n;
1354  F77_INT off2 = (ip(4) - i - 1) * n;
1355 
1356  if (off1 == off2)
1357  continue;
1358 
1359  for (F77_INT j = 0; j < n; j++)
1360  dtmp[j] = z[off1 + j];
1361 
1362  for (F77_INT j = 0; j < n; j++)
1363  z[off1 + j] = z[off2 + j];
1364 
1365  for (F77_INT j = 0; j < n; j++)
1366  z[off2 + j] = dtmp[j];
1367  }
1368  }
1369  }
1370  else
1372  ("eigs: error in dseupd: %s",
1373  arpack_errno2str (info2, "dseupd").c_str ());
1374 
1375  return ip(4);
1376 }
1377 
1378 template <typename M>
1381  const std::string& _typ, double sigma,
1382  octave_idx_type k_arg, octave_idx_type p_arg,
1383  octave_idx_type& info, Matrix& eig_vec,
1384  ColumnVector& eig_val, const M& _b,
1385  ColumnVector& permB, ColumnVector& resid,
1386  std::ostream& os, double tol, bool rvec,
1387  bool cholB, int disp, int maxit)
1388 {
1389  F77_INT n = octave::to_f77_int (n_arg);
1390  F77_INT k = octave::to_f77_int (k_arg);
1391  F77_INT p = octave::to_f77_int (p_arg);
1392  M b(_b);
1393  std::string typ (_typ);
1394  bool have_sigma = (sigma ? true : false);
1395  bool have_b = ! b.isempty ();
1396  bool note3 = false;
1397  char bmat = 'I';
1398  F77_INT mode = 1;
1399  int err = 0;
1400  M bt;
1401 
1402  if (resid.isempty ())
1403  {
1404  std::string rand_dist = octave::rand::distribution ();
1405  octave::rand::distribution ("uniform");
1406  resid = ColumnVector (octave::rand::vector (n));
1407  octave::rand::distribution (rand_dist);
1408  }
1409  else if (n != resid.numel ())
1410  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
1411 
1412  if (n < 3)
1413  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
1414 
1415  if (p < 0)
1416  {
1417  p = k * 2;
1418 
1419  if (p < 20)
1420  p = 20;
1421 
1422  if (p > n)
1423  p = n;
1424  }
1425 
1426  if (k <= 0 || k >= n - 1)
1427  (*current_liboctave_error_handler)
1428  ("eigs: Invalid number of eigenvalues to extract"
1429  " (must be 0 < k < n-1).\n"
1430  " Use 'eig (full (A))' instead");
1431 
1432  if (p <= k || p > n)
1433  (*current_liboctave_error_handler)
1434  ("eigs: opts.p must be greater than k and less than or equal to n");
1435 
1436  if (have_b && cholB && ! permB.isempty ())
1437  {
1438  // Check the we really have a permutation vector
1439  if (permB.numel () != n)
1440  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
1441 
1442  Array<bool> checked (dim_vector (n, 1), false);
1443  for (F77_INT i = 0; i < n; i++)
1444  {
1445  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
1446 
1447  if (checked(bidx) || bidx < 0 || bidx >= n
1448  || octave::math::x_nint (bidx) != bidx)
1449  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
1450  }
1451  }
1452 
1453  if (! have_sigma)
1454  {
1455  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
1456  && typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI"
1457  && typ != "SI")
1458  (*current_liboctave_error_handler) ("eigs: unrecognized sigma value");
1459 
1460  if (typ == "LI" || typ == "SI" || typ == "LR" || typ == "SR")
1461  (*current_liboctave_error_handler)
1462  ("eigs: invalid sigma value for real symmetric problem");
1463 
1464  if (typ != "SM" && have_b)
1465  note3 = true;
1466 
1467  if (typ == "SM")
1468  {
1469  typ = "LM";
1470  sigma = 0.;
1471  mode = 3;
1472  if (have_b)
1473  bmat = 'G';
1474  }
1475  }
1476  else if (! std::abs (sigma))
1477  {
1478  typ = "SM";
1479  if (have_b)
1480  bmat = 'G';
1481  }
1482  else
1483  {
1484  typ = "LM";
1485  mode = 3;
1486  if (have_b)
1487  bmat = 'G';
1488  }
1489 
1490  if (mode == 1 && have_b)
1491  {
1492  // See Note 3 dsaupd
1493  note3 = true;
1494  if (cholB)
1495  {
1496  bt = b;
1497  b = b.transpose ();
1498  if (permB.isempty ())
1499  {
1500  permB = ColumnVector (n);
1501  for (F77_INT i = 0; i < n; i++)
1502  permB(i) = i;
1503  }
1504  }
1505  else
1506  {
1507  if (! make_cholb (b, bt, permB))
1508  (*current_liboctave_error_handler)
1509  ("eigs: The matrix B is not positive definite");
1510  }
1511  }
1512 
1513  Array<F77_INT> ip (dim_vector (11, 1));
1514  F77_INT *iparam = ip.fortran_vec ();
1515 
1516  ip(0) = 1; //ishift
1517  ip(1) = 0; // ip(1) not referenced
1518  ip(2) = maxit; // mxiter, maximum number of iterations
1519  ip(3) = 1; // NB blocksize in recurrence
1520  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
1521  ip(5) = 0; //ip(5) not referenced
1522  ip(6) = mode; // mode
1523  ip(7) = 0;
1524  ip(8) = 0;
1525  ip(9) = 0;
1526  ip(10) = 0;
1527  // ip(7) to ip(10) return values
1528 
1529  Array<F77_INT> iptr (dim_vector (14, 1));
1530  F77_INT *ipntr = iptr.fortran_vec ();
1531 
1532  F77_INT ido = 0;
1533  int iter = 0;
1534  F77_INT lwork = p * (p + 8);
1535 
1536  OCTAVE_LOCAL_BUFFER (double, v, n * p);
1537  OCTAVE_LOCAL_BUFFER (double, workl, lwork);
1538  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n);
1539  double *presid = resid.fortran_vec ();
1540 
1541  do
1542  {
1543  F77_INT tmp_info = octave::to_f77_int (info);
1544 
1545  F77_FUNC (dsaupd, DSAUPD)
1546  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
1547  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
1548  k, tol, presid, p, v, n, iparam,
1549  ipntr, workd, workl, lwork, tmp_info
1550  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
1551 
1552  info = tmp_info;
1553 
1554  if (disp > 0 && ! octave::math::isnan (workl[iptr (5)-1]))
1555  {
1556  if (iter++)
1557  {
1558  os << "Iteration " << iter - 1 <<
1559  ": a few Ritz values of the " << p << "-by-" <<
1560  p << " matrix\n";
1561  if (ido == 99) // convergence
1562  {
1563  for (F77_INT i = 0; i < k; i++)
1564  os << " " << workl[iptr(5)+i-1] << "\n";
1565  }
1566  else
1567  {
1568  // the wanted Ritz estimates are at the end
1569  for (F77_INT i = p - k; i < p; i++)
1570  os << " " << workl[iptr(5)+i-1] << "\n";
1571  }
1572  }
1573 
1574  // This is a kludge, as ARPACK doesn't give its
1575  // iteration pointer. But as workl[iptr(5)-1] is
1576  // an output value updated at each iteration, setting
1577  // a value in this array to NaN and testing for it
1578  // is a way of obtaining the iteration counter.
1579  if (ido != 99)
1580  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
1581  }
1582 
1583  if (ido == -1 || ido == 1 || ido == 2)
1584  {
1585  if (have_b)
1586  {
1587  if (mode == 1) // regular mode with factorized B
1588  {
1589  Matrix mtmp (n,1);
1590  for (F77_INT i = 0; i < n; i++)
1591  mtmp(i,0) = workd[i + iptr(0) - 1];
1592 
1593  mtmp = utsolve (bt, permB, mtmp);
1594  ColumnVector y = fun (mtmp, err);
1595 
1596  if (err)
1597  return false;
1598 
1599  mtmp = ltsolve (b, permB, y);
1600 
1601  for (F77_INT i = 0; i < n; i++)
1602  workd[i+iptr(1)-1] = mtmp(i,0);
1603  }
1604  else // shift-invert mode
1605  {
1606  if (ido == -1)
1607  {
1608  OCTAVE_LOCAL_BUFFER (double, dtmp, n);
1609 
1610  vector_product (b, workd+iptr(0)-1, dtmp);
1611 
1612  ColumnVector x(n);
1613 
1614  for (F77_INT i = 0; i < n; i++)
1615  x(i) = dtmp[i];
1616 
1617  ColumnVector y = fun (x, err);
1618 
1619  if (err)
1620  return false;
1621 
1622  double *ip2 = workd + iptr(1) - 1;
1623  for (F77_INT i = 0; i < n; i++)
1624  ip2[i] = y(i);
1625  }
1626  else if (ido == 2)
1627  vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
1628  else
1629  {
1630  double *ip2 = workd+iptr(2)-1;
1631  ColumnVector x(n);
1632 
1633  for (F77_INT i = 0; i < n; i++)
1634  x(i) = *ip2++;
1635 
1636  ColumnVector y = fun (x, err);
1637 
1638  if (err)
1639  return false;
1640 
1641  ip2 = workd + iptr(1) - 1;
1642  for (F77_INT i = 0; i < n; i++)
1643  *ip2++ = y(i);
1644  }
1645  }
1646  }
1647  else
1648  {
1649  double *ip2 = workd + iptr(0) - 1;
1650  ColumnVector x(n);
1651 
1652  for (F77_INT i = 0; i < n; i++)
1653  x(i) = *ip2++;
1654 
1655  ColumnVector y = fun (x, err);
1656 
1657  if (err)
1658  return false;
1659 
1660  ip2 = workd + iptr(1) - 1;
1661  for (F77_INT i = 0; i < n; i++)
1662  *ip2++ = y(i);
1663  }
1664  }
1665  else
1666  {
1667  if (info < 0)
1668  (*current_liboctave_error_handler)
1669  ("eigs: error in dsaupd: %s",
1670  arpack_errno2str (info, "dsaupd").c_str ());
1671 
1672  break;
1673  }
1674  }
1675  while (1);
1676 
1677  F77_INT info2;
1678 
1679  // We have a problem in that the size of the C++ bool
1680  // type relative to the fortran logical type. It appears
1681  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
1682  // per bool, though this might be system dependent. As
1683  // long as the HOWMNY arg is not "S", the logical array
1684  // is just workspace for ARPACK, so use int type to
1685  // avoid problems.
1686  Array<F77_INT> s (dim_vector (p, 1));
1687  F77_INT *sel = s.fortran_vec ();
1688 
1689  eig_vec.resize (n, k);
1690  double *z = eig_vec.fortran_vec ();
1691 
1692  eig_val.resize (k);
1693  double *d = eig_val.fortran_vec ();
1694 
1695  F77_FUNC (dseupd, DSEUPD)
1696  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, d, z, n, sigma,
1697  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
1698  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
1699  k, tol, presid, p, v, n, iparam, ipntr, workd, workl, lwork, info2
1700  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
1701 
1702  if (info2 == 0)
1703  {
1704  for (F77_INT i = ip(4); i < k; i++)
1706  F77_INT k2 = ip(4) / 2;
1707  if (mode == 3 || (mode == 1 && typ != "SM" && typ != "BE"))
1708  {
1709  for (F77_INT i = 0; i < k2; i++)
1710  {
1711  double dtmp = d[i];
1712  d[i] = d[ip(4) - i - 1];
1713  d[ip(4) - i - 1] = dtmp;
1714  }
1715  }
1716 
1717  if (rvec)
1718  {
1719  for (F77_INT i = ip(4); i < k; i++)
1720  {
1721  F77_INT off1 = i * n;
1722  for (F77_INT j = 0; j < n; j++)
1723  z[off1 + j] = octave::numeric_limits<double>::NaN ();
1724  }
1725  if (mode == 3 || (mode == 1 && typ != "SM" && typ != "BE"))
1726  {
1727  OCTAVE_LOCAL_BUFFER (double, dtmp, n);
1728 
1729  for (F77_INT i = 0; i < k2; i++)
1730  {
1731  F77_INT off1 = i * n;
1732  F77_INT off2 = (ip(4) - i - 1) * n;
1733 
1734  if (off1 == off2)
1735  continue;
1736 
1737  for (F77_INT j = 0; j < n; j++)
1738  dtmp[j] = z[off1 + j];
1739 
1740  for (F77_INT j = 0; j < n; j++)
1741  z[off1 + j] = z[off2 + j];
1742 
1743  for (F77_INT j = 0; j < n; j++)
1744  z[off2 + j] = dtmp[j];
1745  }
1746  }
1747  if (note3)
1748  eig_vec = utsolve (bt, permB, eig_vec);
1749  }
1750  }
1751  else
1753  ("eigs: error in dseupd: %s",
1754  arpack_errno2str (info2, "dseupd").c_str ());
1755 
1756  return ip(4);
1757 }
1758 
1759 template <typename M>
1761 EigsRealNonSymmetricMatrix (const M& m, const std::string typ,
1762  octave_idx_type k_arg, octave_idx_type p_arg,
1763  octave_idx_type& info, ComplexMatrix& eig_vec,
1764  ComplexColumnVector& eig_val, const M& _b,
1765  ColumnVector& permB, ColumnVector& resid,
1766  std::ostream& os, double tol, bool rvec,
1767  bool cholB, int disp, int maxit)
1768 {
1769  F77_INT k = octave::to_f77_int (k_arg);
1770  F77_INT p = octave::to_f77_int (p_arg);
1771  M b(_b);
1772  F77_INT n = octave::to_f77_int (m.cols ());
1773  F77_INT mode = 1;
1774  bool have_b = ! b.isempty ();
1775  bool note3 = false;
1776  char bmat = 'I';
1777  double sigmar = 0.;
1778  double sigmai = 0.;
1779  M bt;
1780 
1781  if (m.rows () != m.cols ())
1782  (*current_liboctave_error_handler) ("eigs: A must be square");
1783  if (have_b && (m.rows () != b.rows () || m.rows () != b.cols ()))
1785  ("eigs: B must be square and the same size as A");
1786 
1787  if (resid.isempty ())
1788  {
1789  std::string rand_dist = octave::rand::distribution ();
1790  octave::rand::distribution ("uniform");
1791  resid = ColumnVector (octave::rand::vector (n));
1792  octave::rand::distribution (rand_dist);
1793  }
1794  else if (m.cols () != resid.numel ())
1795  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
1796 
1797  if (n < 3)
1798  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
1799 
1800  if (p < 0)
1801  {
1802  p = k * 2 + 1;
1803 
1804  if (p < 20)
1805  p = 20;
1806 
1807  if (p > n)
1808  p = n;
1809  }
1810 
1811  if (k <= 0 || k >= n - 1)
1812  (*current_liboctave_error_handler)
1813  ("eigs: Invalid number of eigenvalues to extract"
1814  " (must be 0 < k < n-1).\n"
1815  " Use 'eig (full (A))' instead");
1816 
1817  if (p <= k || p > n)
1818  (*current_liboctave_error_handler)
1819  ("eigs: opts.p must be greater than k and less than or equal to n");
1820 
1821  if (have_b && cholB && ! permB.isempty ())
1822  {
1823  // Check the we really have a permutation vector
1824  if (permB.numel () != n)
1825  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
1826 
1827  Array<bool> checked (dim_vector (n, 1), false);
1828  for (F77_INT i = 0; i < n; i++)
1829  {
1830  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
1831 
1832  if (checked(bidx) || bidx < 0 || bidx >= n
1833  || octave::math::x_nint (bidx) != bidx)
1834  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
1835  }
1836  }
1837 
1838  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
1839  && typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI"
1840  && typ != "SI")
1841  (*current_liboctave_error_handler) ("eigs: unrecognized sigma value");
1842 
1843  if (typ == "LA" || typ == "SA" || typ == "BE")
1844  (*current_liboctave_error_handler)
1845  ("eigs: invalid sigma value for unsymmetric problem");
1846 
1847  if (have_b)
1848  {
1849  // See Note 3 dsaupd
1850  note3 = true;
1851  if (cholB)
1852  {
1853  bt = b;
1854  b = b.transpose ();
1855  if (permB.isempty ())
1856  {
1857  permB = ColumnVector (n);
1858  for (F77_INT i = 0; i < n; i++)
1859  permB(i) = i;
1860  }
1861  }
1862  else
1863  {
1864  if (! make_cholb (b, bt, permB))
1865  (*current_liboctave_error_handler)
1866  ("eigs: The matrix B is not positive definite");
1867  }
1868  }
1869 
1870  Array<F77_INT> ip (dim_vector (11, 1));
1871  F77_INT *iparam = ip.fortran_vec ();
1872 
1873  ip(0) = 1; //ishift
1874  ip(1) = 0; // ip(1) not referenced
1875  ip(2) = maxit; // mxiter, maximum number of iterations
1876  ip(3) = 1; // NB blocksize in recurrence
1877  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
1878  ip(5) = 0; //ip(5) not referenced
1879  ip(6) = mode; // mode
1880  ip(7) = 0;
1881  ip(8) = 0;
1882  ip(9) = 0;
1883  ip(10) = 0;
1884  // ip(7) to ip(10) return values
1885 
1886  Array<F77_INT> iptr (dim_vector (14, 1));
1887  F77_INT *ipntr = iptr.fortran_vec ();
1888 
1889  F77_INT ido = 0;
1890  int iter = 0;
1891  F77_INT lwork = 3 * p * (p + 2);
1892 
1893  OCTAVE_LOCAL_BUFFER (double, v, n * (p + 1));
1894  OCTAVE_LOCAL_BUFFER (double, workl, lwork + 1);
1895  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n + 1);
1896  double *presid = resid.fortran_vec ();
1897 
1898  do
1899  {
1900  F77_INT tmp_info = octave::to_f77_int (info);
1901 
1902  // On exit, ip(4) <= k + 1 is the number of converged eigenvalues.
1903  // See dnaupd2.
1904  F77_FUNC (dnaupd, DNAUPD)
1905  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
1906  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
1907  k, tol, presid, p, v, n, iparam,
1908  ipntr, workd, workl, lwork, tmp_info
1909  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
1910  // k is not changed
1911 
1912  info = tmp_info;
1913 
1914  if (disp > 0 && ! octave::math::isnan(workl[iptr(5)-1]))
1915  {
1916  if (iter++)
1917  {
1918  os << "Iteration " << iter - 1 <<
1919  ": a few Ritz values of the " << p << "-by-" <<
1920  p << " matrix\n";
1921  if (ido == 99) // convergence
1922  {
1923  os << " " << workl[iptr(5)+k] << "\n";
1924  for (F77_INT i = 0; i < k; i++)
1925  os << " " << workl[iptr(5)+i-1] << "\n";
1926  }
1927  else
1928  {
1929  // the wanted Ritz estimates are at the end
1930  for (F77_INT i = p - k - 1; i < p; i++)
1931  os << " " << workl[iptr(5)+i-1] << "\n";
1932  }
1933  }
1934 
1935  // This is a kludge, as ARPACK doesn't give its
1936  // iteration pointer. But as workl[iptr(5)-1] is
1937  // an output value updated at each iteration, setting
1938  // a value in this array to NaN and testing for it
1939  // is a way of obtaining the iteration counter.
1940  if (ido != 99)
1941  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
1942  }
1943 
1944  if (ido == -1 || ido == 1 || ido == 2)
1945  {
1946  if (have_b)
1947  {
1948  Matrix mtmp (n,1);
1949  for (F77_INT i = 0; i < n; i++)
1950  mtmp(i,0) = workd[i + iptr(0) - 1];
1951 
1952  mtmp = ltsolve (b, permB, m * utsolve (bt, permB, mtmp));
1953 
1954  for (F77_INT i = 0; i < n; i++)
1955  workd[i+iptr(1)-1] = mtmp(i,0);
1956  }
1957  else if (! vector_product (m, workd + iptr(0) - 1,
1958  workd + iptr(1) - 1))
1959  break;
1960  }
1961  else
1962  {
1963  if (info < 0)
1964  (*current_liboctave_error_handler)
1965  ("eigs: error in dnaupd: %s",
1966  arpack_errno2str (info, "dnaupd").c_str ());
1967 
1968  break;
1969  }
1970  }
1971  while (1);
1972 
1973  F77_INT info2;
1974 
1975  // We have a problem in that the size of the C++ bool
1976  // type relative to the fortran logical type. It appears
1977  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
1978  // per bool, though this might be system dependent. As
1979  // long as the HOWMNY arg is not "S", the logical array
1980  // is just workspace for ARPACK, so use int type to
1981  // avoid problems.
1982  Array<F77_INT> s (dim_vector (p, 1));
1983  F77_INT *sel = s.fortran_vec ();
1984 
1985  // FIXME: initialize eig_vec2 to zero; apparently dneupd can skip
1986  // the assignment to elements of Z that represent imaginary parts.
1987  // Found with valgrind and
1988  //
1989  // A = [1,0,0,-1;0,1,0,0;0,0,1,0;0,0,2,1];
1990  // [vecs, vals, f] = eigs (A, 1)
1991 
1992  Matrix eig_vec2 (n, k + 1, 0.0);
1993  double *z = eig_vec2.fortran_vec ();
1994 
1995  OCTAVE_LOCAL_BUFFER (double, dr, k + 1);
1996  OCTAVE_LOCAL_BUFFER (double, di, k + 1);
1997  OCTAVE_LOCAL_BUFFER (double, workev, 3 * p);
1998  for (F77_INT i = 0; i < k+1; i++)
1999  dr[i] = di[i] = 0.;
2000 
2001  F77_INT k0 = k; // original number of eigenvalues required
2002  F77_FUNC (dneupd, DNEUPD)
2003  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar,
2004  sigmai, workev, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
2005  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
2006  ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1)
2007  F77_CHAR_ARG_LEN(2));
2008  // on exit, if (and only if) rvec == true, k may have been increased by one
2009  // and be equal to ip(4), see dngets.
2010 
2011  if (! rvec && ip(4) > k)
2012  k = ip(4);
2013 
2014  eig_val.resize (k);
2015  Complex *d = eig_val.fortran_vec ();
2016 
2017  if (info2 == 0)
2018  {
2019  bool have_cplx_eig = false;
2020  for (F77_INT i = 0; i < ip(4); i++)
2021  {
2022  if (di[i] == 0)
2023  d[i] = Complex (dr[i], 0.);
2024  else
2025  {
2026  have_cplx_eig = true;
2027  d[i] = Complex (dr[i], di[i]);
2028  }
2029  }
2030  if (have_cplx_eig)
2031  {
2032  for (F77_INT i = ip(4); i < k; i++)
2035  }
2036  else
2037  {
2038  for (F77_INT i = ip(4); i < k; i++)
2040  }
2041  if (! rvec)
2042  {
2043  // ARPACK seems to give the eigenvalues in reversed order
2044  F77_INT k2 = ip(4) / 2;
2045  for (F77_INT i = 0; i < k2; i++)
2046  {
2047  Complex dtmp = d[i];
2048  d[i] = d[ip(4) - i - 1];
2049  d[ip(4) - i - 1] = dtmp;
2050  }
2051  }
2052  else
2053  {
2054  // When eigenvectors required, ARPACK seems to give the right order
2055  eig_vec.resize (n, k);
2056  F77_INT i = 0;
2057  while (i < ip(4))
2058  {
2059  F77_INT off1 = i * n;
2060  F77_INT off2 = (i+1) * n;
2061  if (std::imag (eig_val(i)) == 0)
2062  {
2063  for (F77_INT j = 0; j < n; j++)
2064  eig_vec(j,i) = Complex (z[j+off1], 0.);
2065  i++;
2066  }
2067  else
2068  {
2069  for (F77_INT j = 0; j < n; j++)
2070  {
2071  eig_vec(j,i) = Complex (z[j+off1],z[j+off2]);
2072  if (i < ip(4) - 1)
2073  eig_vec(j,i+1) = Complex (z[j+off1],-z[j+off2]);
2074  }
2075  i+=2;
2076  }
2077  }
2078  if (have_cplx_eig)
2079  {
2080  for (F77_INT ii = ip(4); ii < k; ii++)
2081  for (F77_INT jj = 0; jj < n; jj++)
2082  eig_vec(jj,ii)
2085  }
2086  else
2087  {
2088  for (F77_INT ii = ip(4); ii < k; ii++)
2089  for (F77_INT jj = 0; jj < n; jj++)
2090  eig_vec(jj,ii)
2092  }
2093  if (note3)
2094  eig_vec = utsolve (bt, permB, eig_vec);
2095  }
2096  if (k0 < k)
2097  {
2098  eig_val.resize (k0);
2099  eig_vec.resize (n, k0);
2100  }
2101  }
2102  else
2104  ("eigs: error in dneupd: %s",
2105  arpack_errno2str (info2, "dneupd").c_str ());
2106 
2107  return ip(4);
2108 }
2109 
2110 template <typename M>
2112 EigsRealNonSymmetricMatrixShift (const M& m, double sigmar,
2113  octave_idx_type k_arg, octave_idx_type p_arg,
2114  octave_idx_type& info,
2115  ComplexMatrix& eig_vec,
2116  ComplexColumnVector& eig_val, const M& _b,
2117  ColumnVector& permB, ColumnVector& resid,
2118  std::ostream& os, double tol, bool rvec,
2119  bool cholB, int disp, int maxit)
2120 {
2121  F77_INT k = octave::to_f77_int (k_arg);
2122  F77_INT p = octave::to_f77_int (p_arg);
2123  M b(_b);
2124  F77_INT n = octave::to_f77_int (m.cols ());
2125  F77_INT mode = 3;
2126  bool have_b = ! b.isempty ();
2127  std::string typ = "LM";
2128  double sigmai = 0.;
2129 
2130  if (m.rows () != m.cols ())
2131  (*current_liboctave_error_handler) ("eigs: A must be square");
2132  if (have_b && (m.rows () != b.rows () || m.rows () != b.cols ()))
2134  ("eigs: B must be square and the same size as A");
2135 
2136  // FIXME: The "SM" type for mode 1 seems unstable though faster!!
2137  //if (! std::abs (sigmar))
2138  // return EigsRealNonSymmetricMatrix (m, "SM", k, p, info, eig_vec, eig_val,
2139  // _b, permB, resid, os, tol, rvec, cholB,
2140  // disp, maxit);
2141 
2142  if (resid.isempty ())
2143  {
2144  std::string rand_dist = octave::rand::distribution ();
2145  octave::rand::distribution ("uniform");
2146  resid = ColumnVector (octave::rand::vector (n));
2147  octave::rand::distribution (rand_dist);
2148  }
2149  else if (m.cols () != resid.numel ())
2150  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
2151 
2152  if (n < 3)
2153  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
2154 
2155  if (p < 0)
2156  {
2157  p = k * 2 + 1;
2158 
2159  if (p < 20)
2160  p = 20;
2161 
2162  if (p > n)
2163  p = n;
2164  }
2165 
2166  if (k <= 0 || k >= n - 1)
2167  (*current_liboctave_error_handler)
2168  ("eigs: Invalid number of eigenvalues to extract"
2169  " (must be 0 < k < n-1).\n"
2170  " Use 'eig (full (A))' instead");
2171 
2172  if (p <= k || p > n)
2173  (*current_liboctave_error_handler)
2174  ("eigs: opts.p must be greater than k and less than or equal to n");
2175 
2176  if (have_b && cholB && ! permB.isempty ())
2177  {
2178  // Check that we really have a permutation vector
2179  if (permB.numel () != n)
2180  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
2181 
2182  Array<bool> checked (dim_vector (n, 1), false);
2183  for (F77_INT i = 0; i < n; i++)
2184  {
2185  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
2186 
2187  if (checked(bidx) || bidx < 0 || bidx >= n
2188  || octave::math::x_nint (bidx) != bidx)
2189  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
2190  }
2191  }
2192 
2193  char bmat = 'I';
2194  if (have_b)
2195  bmat = 'G';
2196 
2197  Array<F77_INT> ip (dim_vector (11, 1));
2198  F77_INT *iparam = ip.fortran_vec ();
2199 
2200  ip(0) = 1; //ishift
2201  ip(1) = 0; // ip(1) not referenced
2202  ip(2) = maxit; // mxiter, maximum number of iterations
2203  ip(3) = 1; // NB blocksize in recurrence
2204  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
2205  ip(5) = 0; //ip(5) not referenced
2206  ip(6) = mode; // mode
2207  ip(7) = 0;
2208  ip(8) = 0;
2209  ip(9) = 0;
2210  ip(10) = 0;
2211  // ip(7) to ip(10) return values
2212 
2213  Array<F77_INT> iptr (dim_vector (14, 1));
2214  F77_INT *ipntr = iptr.fortran_vec ();
2215 
2216  F77_INT ido = 0;
2217  int iter = 0;
2218  M L, U;
2219  ColumnVector r(n);
2220 
2221  OCTAVE_LOCAL_BUFFER (octave_idx_type, P, (have_b ? b.rows () : m.rows ()));
2222  OCTAVE_LOCAL_BUFFER (octave_idx_type, Q, (have_b ? b.cols () : m.cols ()));
2223 
2224  if (! LuAminusSigmaB (m, b, cholB, permB, sigmar, L, U, P, Q, r))
2225  return -1;
2226 
2227  F77_INT lwork = 3 * p * (p + 2);
2228 
2229  OCTAVE_LOCAL_BUFFER (double, v, n * (p + 1));
2230  OCTAVE_LOCAL_BUFFER (double, workl, lwork + 1);
2231  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n + 1);
2232  double *presid = resid.fortran_vec ();
2233 
2234  do
2235  {
2236  F77_INT tmp_info = octave::to_f77_int (info);
2237 
2238  // On exit, ip(4) <= k + 1 is the number of converged eigenvalues.
2239  // See dnaupd2.
2240  F77_FUNC (dnaupd, DNAUPD)
2241  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
2242  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
2243  k, tol, presid, p, v, n, iparam,
2244  ipntr, workd, workl, lwork, tmp_info
2245  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
2246  // k is not changed
2247 
2248  info = tmp_info;
2249 
2250  if (disp > 0 && ! octave::math::isnan (workl[iptr (5)-1]))
2251  {
2252  if (iter++)
2253  {
2254  os << "Iteration " << iter - 1 <<
2255  ": a few Ritz values of the " << p << "-by-" <<
2256  p << " matrix\n";
2257  if (ido == 99) // convergence
2258  {
2259  os << " " << workl[iptr(5)+k] << "\n";
2260  for (F77_INT i = 0; i < k; i++)
2261  os << " " << workl[iptr(5)+i-1] << "\n";
2262  }
2263  else
2264  {
2265  // the wanted Ritz estimates are at the end
2266  for (F77_INT i = p - k - 1; i < p; i++)
2267  os << " " << workl[iptr(5)+i-1] << "\n";
2268  }
2269  }
2270 
2271  // This is a kludge, as ARPACK doesn't give its
2272  // iteration pointer. But as workl[iptr(5)-1] is
2273  // an output value updated at each iteration, setting
2274  // a value in this array to NaN and testing for it
2275  // is a way of obtaining the iteration counter.
2276  if (ido != 99)
2277  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
2278  }
2279 
2280  if (ido == -1 || ido == 1 || ido == 2)
2281  {
2282  if (have_b)
2283  {
2284  if (ido == -1)
2285  {
2286  OCTAVE_LOCAL_BUFFER (double, dtmp, n);
2287 
2288  vector_product (b, workd+iptr(0)-1, dtmp);
2289 
2290  Matrix tmp (n, 1);
2291 
2292  for (F77_INT i = 0; i < n; i++)
2293  tmp(i,0) = dtmp[P[i]] / r(P[i]);
2294 
2295  lusolve (L, U, tmp);
2296 
2297  double *ip2 = workd+iptr(1)-1;
2298  for (F77_INT i = 0; i < n; i++)
2299  ip2[Q[i]] = tmp(i,0);
2300  }
2301  else if (ido == 2)
2302  vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
2303  else
2304  {
2305  double *ip2 = workd+iptr(2)-1;
2306  Matrix tmp (n, 1);
2307 
2308  for (F77_INT i = 0; i < n; i++)
2309  tmp(i,0) = ip2[P[i]] / r(P[i]);
2310 
2311  lusolve (L, U, tmp);
2312 
2313  ip2 = workd+iptr(1)-1;
2314  for (F77_INT i = 0; i < n; i++)
2315  ip2[Q[i]] = tmp(i,0);
2316  }
2317  }
2318  else
2319  {
2320  // ido cannot be 2 for non-generalized problems (see dnaupd2).
2321  double *ip2 = workd+iptr(0)-1;
2322  Matrix tmp (n, 1);
2323 
2324  for (F77_INT i = 0; i < n; i++)
2325  tmp(i,0) = ip2[P[i]] / r(P[i]);
2326 
2327  lusolve (L, U, tmp);
2328 
2329  ip2 = workd+iptr(1)-1;
2330  for (F77_INT i = 0; i < n; i++)
2331  ip2[Q[i]] = tmp(i,0);
2332  }
2333  }
2334  else
2335  {
2336  if (info < 0)
2337  (*current_liboctave_error_handler)
2338  ("eigs: error in dnaupd: %s",
2339  arpack_errno2str (info, "dnaupd").c_str ());
2340 
2341  break;
2342  }
2343  }
2344  while (1);
2345 
2346  F77_INT info2;
2347 
2348  // We have a problem in that the size of the C++ bool
2349  // type relative to the fortran logical type. It appears
2350  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
2351  // per bool, though this might be system dependent. As
2352  // long as the HOWMNY arg is not "S", the logical array
2353  // is just workspace for ARPACK, so use int type to
2354  // avoid problems.
2355  Array<F77_INT> s (dim_vector (p, 1));
2356  F77_INT *sel = s.fortran_vec ();
2357 
2358  // FIXME: initialize eig_vec2 to zero; apparently dneupd can skip
2359  // the assignment to elements of Z that represent imaginary parts.
2360  // Found with valgrind and
2361  //
2362  // A = [1,0,0,-1;0,1,0,0;0,0,1,0;0,0,2,1];
2363  // [vecs, vals, f] = eigs (A, 1)
2364 
2365  Matrix eig_vec2 (n, k + 1, 0.0);
2366  double *z = eig_vec2.fortran_vec ();
2367 
2368  OCTAVE_LOCAL_BUFFER (double, dr, k + 1);
2369  OCTAVE_LOCAL_BUFFER (double, di, k + 1);
2370  OCTAVE_LOCAL_BUFFER (double, workev, 3 * p);
2371  for (F77_INT i = 0; i < k+1; i++)
2372  dr[i] = di[i] = 0.;
2373 
2374  F77_INT k0 = k; // original number of eigenvalues required
2375  F77_FUNC (dneupd, DNEUPD)
2376  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar,
2377  sigmai, workev, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
2378  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
2379  ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1)
2380  F77_CHAR_ARG_LEN(2));
2381  // On exit, if (and only if) rvec == true, k may have been increased by one
2382  // and be equal to ip(4), see dngets.
2383 
2384  if (! rvec && ip(4) > k)
2385  k = ip(4);
2386 
2387  eig_val.resize (k);
2388  Complex *d = eig_val.fortran_vec ();
2389 
2390  if (info2 == 0)
2391  {
2392  bool have_cplx_eig = false;
2393  for (F77_INT i = 0; i < ip(4); i++)
2394  {
2395  if (di[i] == 0.)
2396  d[i] = Complex (dr[i], 0.);
2397  else
2398  {
2399  have_cplx_eig = true;
2400  d[i] = Complex (dr[i], di[i]);
2401  }
2402  }
2403  if (have_cplx_eig)
2404  {
2405  for (F77_INT i = ip(4); i < k; i++)
2408  }
2409  else
2410  {
2411  for (F77_INT i = ip(4); i < k; i++)
2413  }
2414 
2415  if (! rvec)
2416  {
2417  // ARPACK seems to give the eigenvalues in reversed order
2418  F77_INT k2 = ip(4) / 2;
2419  for (F77_INT i = 0; i < k2; i++)
2420  {
2421  Complex dtmp = d[i];
2422  d[i] = d[ip(4) - i - 1];
2423  d[ip(4) - i - 1] = dtmp;
2424  }
2425  }
2426  else
2427  {
2428  // When eigenvectors required, ARPACK seems to give the right order
2429  eig_vec.resize (n, k);
2430  F77_INT i = 0;
2431  while (i < ip(4))
2432  {
2433  F77_INT off1 = i * n;
2434  F77_INT off2 = (i+1) * n;
2435  if (std::imag (eig_val(i)) == 0)
2436  {
2437  for (F77_INT j = 0; j < n; j++)
2438  eig_vec(j,i) = Complex (z[j+off1], 0.);
2439  i++;
2440  }
2441  else
2442  {
2443  for (F77_INT j = 0; j < n; j++)
2444  {
2445  eig_vec(j,i) = Complex (z[j+off1],z[j+off2]);
2446  if (i < ip(4) - 1)
2447  eig_vec(j,i+1) = Complex (z[j+off1],-z[j+off2]);
2448  }
2449  i+=2;
2450  }
2451  }
2452  if (have_cplx_eig)
2453  {
2454  for (F77_INT ii = ip(4); ii < k; ii++)
2455  for (F77_INT jj = 0; jj < n; jj++)
2456  eig_vec(jj,ii)
2459  }
2460  else
2461  {
2462  for (F77_INT ii = ip(4); ii < k; ii++)
2463  for (F77_INT jj = 0; jj < n; jj++)
2464  eig_vec(jj,ii)
2466  }
2467  }
2468  if (k0 < k)
2469  {
2470  eig_val.resize (k0);
2471  eig_vec.resize (n, k0);
2472  }
2473  }
2474  else
2476  ("eigs: error in dneupd: %s",
2477  arpack_errno2str (info2, "dneupd").c_str ());
2478 
2479  return ip(4);
2480 }
2481 
2482 template <typename M>
2485  const std::string& _typ, double sigmar,
2486  octave_idx_type k_arg, octave_idx_type p_arg,
2487  octave_idx_type& info, ComplexMatrix& eig_vec,
2488  ComplexColumnVector& eig_val, const M& _b,
2489  ColumnVector& permB, ColumnVector& resid,
2490  std::ostream& os, double tol, bool rvec,
2491  bool cholB, int disp, int maxit)
2492 {
2493  F77_INT n = octave::to_f77_int (n_arg);
2494  F77_INT k = octave::to_f77_int (k_arg);
2495  F77_INT p = octave::to_f77_int (p_arg);
2496  M b(_b);
2497  std::string typ (_typ);
2498  bool have_sigma = (sigmar ? true : false);
2499  double sigmai = 0.;
2500  F77_INT mode = 1;
2501  bool have_b = ! b.isempty ();
2502  bool note3 = false;
2503  char bmat = 'I';
2504  int err = 0;
2505  M bt;
2506 
2507  if (resid.isempty ())
2508  {
2509  std::string rand_dist = octave::rand::distribution ();
2510  octave::rand::distribution ("uniform");
2511  resid = ColumnVector (octave::rand::vector (n));
2512  octave::rand::distribution (rand_dist);
2513  }
2514  else if (n != resid.numel ())
2515  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
2516 
2517  if (n < 3)
2518  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
2519 
2520  if (p < 0)
2521  {
2522  p = k * 2 + 1;
2523 
2524  if (p < 20)
2525  p = 20;
2526 
2527  if (p > n)
2528  p = n;
2529  }
2530 
2531  if (k <= 0 || k >= n - 1)
2532  (*current_liboctave_error_handler)
2533  ("eigs: Invalid number of eigenvalues to extract"
2534  " (must be 0 < k < n-1).\n"
2535  " Use 'eig (full (A))' instead");
2536 
2537  if (p <= k || p > n)
2538  (*current_liboctave_error_handler)
2539  ("eigs: opts.p must be greater than k and less than or equal to n");
2540 
2541  if (have_b && cholB && ! permB.isempty ())
2542  {
2543  // Check the we really have a permutation vector
2544  if (permB.numel () != n)
2545  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
2546 
2547  Array<bool> checked (dim_vector (n, 1), false);
2548  for (F77_INT i = 0; i < n; i++)
2549  {
2550  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
2551 
2552  if (checked(bidx) || bidx < 0 || bidx >= n
2553  || octave::math::x_nint (bidx) != bidx)
2554  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
2555  }
2556  }
2557 
2558  if (! have_sigma)
2559  {
2560  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
2561  && typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI"
2562  && typ != "SI")
2563  (*current_liboctave_error_handler) ("eigs: unrecognized sigma value");
2564 
2565  if (typ == "LA" || typ == "SA" || typ == "BE")
2566  (*current_liboctave_error_handler)
2567  ("eigs: invalid sigma value for unsymmetric problem");
2568 
2569  if (typ != "SM" && have_b)
2570  note3 = true;
2571 
2572  if (typ == "SM")
2573  {
2574  typ = "LM";
2575  sigmar = 0.;
2576  mode = 3;
2577  if (have_b)
2578  bmat = 'G';
2579  }
2580  }
2581  else if (! std::abs (sigmar))
2582  {
2583  typ = "SM";
2584  if (have_b)
2585  bmat = 'G';
2586  }
2587  else
2588  {
2589  typ = "LM";
2590  mode = 3;
2591  if (have_b)
2592  bmat = 'G';
2593  }
2594 
2595  if (mode == 1 && have_b)
2596  {
2597  // See Note 3 dsaupd
2598  note3 = true;
2599  if (cholB)
2600  {
2601  bt = b;
2602  b = b.transpose ();
2603  if (permB.isempty ())
2604  {
2605  permB = ColumnVector (n);
2606  for (F77_INT i = 0; i < n; i++)
2607  permB(i) = i;
2608  }
2609  }
2610  else
2611  {
2612  if (! make_cholb (b, bt, permB))
2613  (*current_liboctave_error_handler)
2614  ("eigs: The matrix B is not positive definite");
2615  }
2616  }
2617 
2618  Array<F77_INT> ip (dim_vector (11, 1));
2619  F77_INT *iparam = ip.fortran_vec ();
2620 
2621  ip(0) = 1; //ishift
2622  ip(1) = 0; // ip(1) not referenced
2623  ip(2) = maxit; // mxiter, maximum number of iterations
2624  ip(3) = 1; // NB blocksize in recurrence
2625  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
2626  ip(5) = 0; //ip(5) not referenced
2627  ip(6) = mode; // mode
2628  ip(7) = 0;
2629  ip(8) = 0;
2630  ip(9) = 0;
2631  ip(10) = 0;
2632  // ip(7) to ip(10) return values
2633 
2634  Array<F77_INT> iptr (dim_vector (14, 1));
2635  F77_INT *ipntr = iptr.fortran_vec ();
2636 
2637  F77_INT ido = 0;
2638  int iter = 0;
2639  F77_INT lwork = 3 * p * (p + 2);
2640 
2641  OCTAVE_LOCAL_BUFFER (double, v, n * (p + 1));
2642  OCTAVE_LOCAL_BUFFER (double, workl, lwork + 1);
2643  OCTAVE_LOCAL_BUFFER (double, workd, 3 * n + 1);
2644  double *presid = resid.fortran_vec ();
2645 
2646  do
2647  {
2648  F77_INT tmp_info = octave::to_f77_int (info);
2649 
2650  // On exit, ip(4) <= k + 1 is the number of converged eigenvalues
2651  // see dnaupd2.
2652  F77_FUNC (dnaupd, DNAUPD)
2653  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
2654  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
2655  k, tol, presid, p, v, n, iparam,
2656  ipntr, workd, workl, lwork, tmp_info
2657  F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
2658  // k is not changed
2659 
2660  info = tmp_info;
2661 
2662  if (disp > 0 && ! octave::math::isnan(workl[iptr(5)-1]))
2663  {
2664  if (iter++)
2665  {
2666  os << "Iteration " << iter - 1 <<
2667  ": a few Ritz values of the " << p << "-by-" <<
2668  p << " matrix\n";
2669  if (ido == 99) // convergence
2670  {
2671  os << " " << workl[iptr(5)+k] << "\n";
2672  for (F77_INT i = 0; i < k; i++)
2673  os << " " << workl[iptr(5)+i-1] << "\n";
2674  }
2675  else
2676  {
2677  // the wanted Ritz estimates are at the end
2678  for (F77_INT i = p - k - 1; i < p; i++)
2679  os << " " << workl[iptr(5)+i-1] << "\n";
2680  }
2681  }
2682 
2683  // This is a kludge, as ARPACK doesn't give its
2684  // iteration pointer. But as workl[iptr(5)-1] is
2685  // an output value updated at each iteration, setting
2686  // a value in this array to NaN and testing for it
2687  // is a way of obtaining the iteration counter.
2688  if (ido != 99)
2689  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
2690  }
2691 
2692  if (ido == -1 || ido == 1 || ido == 2)
2693  {
2694  if (have_b)
2695  {
2696  if (mode == 1) // regular mode with factorized B
2697  {
2698  Matrix mtmp (n,1);
2699  for (F77_INT i = 0; i < n; i++)
2700  mtmp(i,0) = workd[i + iptr(0) - 1];
2701 
2702  mtmp = utsolve (bt, permB, mtmp);
2703  ColumnVector y = fun (mtmp, err);
2704 
2705  if (err)
2706  return false;
2707 
2708  mtmp = ltsolve (b, permB, y);
2709 
2710  for (F77_INT i = 0; i < n; i++)
2711  workd[i+iptr(1)-1] = mtmp(i,0);
2712  }
2713  else // shift-invert mode
2714  {
2715  if (ido == -1)
2716  {
2717  OCTAVE_LOCAL_BUFFER (double, dtmp, n);
2718 
2719  vector_product (b, workd+iptr(0)-1, dtmp);
2720 
2721  ColumnVector x(n);
2722 
2723  for (F77_INT i = 0; i < n; i++)
2724  x(i) = dtmp[i];
2725 
2726  ColumnVector y = fun (x, err);
2727 
2728  if (err)
2729  return false;
2730 
2731  double *ip2 = workd + iptr(1) - 1;
2732  for (F77_INT i = 0; i < n; i++)
2733  ip2[i] = y(i);
2734  }
2735  else if (ido == 2)
2736  vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
2737  else
2738  {
2739  double *ip2 = workd+iptr(2)-1;
2740  ColumnVector x(n);
2741 
2742  for (F77_INT i = 0; i < n; i++)
2743  x(i) = *ip2++;
2744 
2745  ColumnVector y = fun (x, err);
2746 
2747  if (err)
2748  return false;
2749 
2750  ip2 = workd + iptr(1) - 1;
2751  for (F77_INT i = 0; i < n; i++)
2752  *ip2++ = y(i);
2753  }
2754  }
2755  }
2756  else
2757  {
2758  double *ip2 = workd + iptr(0) - 1;
2759  ColumnVector x(n);
2760 
2761  for (F77_INT i = 0; i < n; i++)
2762  x(i) = *ip2++;
2763 
2764  ColumnVector y = fun (x, err);
2765 
2766  if (err)
2767  return false;
2768 
2769  ip2 = workd + iptr(1) - 1;
2770  for (F77_INT i = 0; i < n; i++)
2771  *ip2++ = y(i);
2772  }
2773  }
2774  else
2775  {
2776  if (info < 0)
2777  (*current_liboctave_error_handler)
2778  ("eigs: error in dnaupd: %s",
2779  arpack_errno2str (info, "dnaupd").c_str ());
2780 
2781  break;
2782  }
2783  }
2784  while (1);
2785 
2786  F77_INT info2;
2787 
2788  // We have a problem in that the size of the C++ bool
2789  // type relative to the fortran logical type. It appears
2790  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
2791  // per bool, though this might be system dependent. As
2792  // long as the HOWMNY arg is not "S", the logical array
2793  // is just workspace for ARPACK, so use int type to
2794  // avoid problems.
2795  Array<F77_INT> s (dim_vector (p, 1));
2796  F77_INT *sel = s.fortran_vec ();
2797 
2798  // FIXME: initialize eig_vec2 to zero; apparently dneupd can skip
2799  // the assignment to elements of Z that represent imaginary parts.
2800  // Found with valgrind and
2801  //
2802  // A = [1,0,0,-1;0,1,0,0;0,0,1,0;0,0,2,1];
2803  // [vecs, vals, f] = eigs (A, 1)
2804 
2805  Matrix eig_vec2 (n, k + 1, 0.0);
2806  double *z = eig_vec2.fortran_vec ();
2807 
2808  OCTAVE_LOCAL_BUFFER (double, dr, k + 1);
2809  OCTAVE_LOCAL_BUFFER (double, di, k + 1);
2810  OCTAVE_LOCAL_BUFFER (double, workev, 3 * p);
2811  for (F77_INT i = 0; i < k+1; i++)
2812  dr[i] = di[i] = 0.;
2813 
2814  F77_INT k0 = k; // original number of eigenvalues required
2815  F77_FUNC (dneupd, DNEUPD)
2816  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, dr, di, z, n, sigmar,
2817  sigmai, workev, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
2818  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2), k, tol, presid, p, v, n, iparam,
2819  ipntr, workd, workl, lwork, info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1)
2820  F77_CHAR_ARG_LEN(2));
2821  // On exit, if (and only if) rvec == true, k may have been increased by one
2822  // and be equal to ip(4), see dngets.
2823 
2824  if (! rvec && ip(4) > k)
2825  k = ip(4);
2826 
2827  eig_val.resize (k);
2828  Complex *d = eig_val.fortran_vec ();
2829 
2830  if (info2 == 0)
2831  {
2832  bool have_cplx_eig = false;
2833  for (F77_INT i = 0; i < ip(4); i++)
2834  {
2835  if (di[i] == 0.)
2836  d[i] = Complex (dr[i], 0.);
2837  else
2838  {
2839  have_cplx_eig = true;
2840  d[i] = Complex (dr[i], di[i]);
2841  }
2842  }
2843  if (have_cplx_eig)
2844  {
2845  for (F77_INT i = ip(4); i < k; i++)
2848  }
2849  else
2850  {
2851  for (F77_INT i = ip(4); i < k; i++)
2853  }
2854 
2855  if (! rvec)
2856  {
2857  // ARPACK seems to give the eigenvalues in reversed order
2858  octave_idx_type k2 = ip(4) / 2;
2859  for (F77_INT i = 0; i < k2; i++)
2860  {
2861  Complex dtmp = d[i];
2862  d[i] = d[ip(4) - i - 1];
2863  d[ip(4) - i - 1] = dtmp;
2864  }
2865  }
2866  else
2867  {
2868  // ARPACK seems to give the eigenvalues in reversed order
2869  eig_vec.resize (n, k);
2870  F77_INT i = 0;
2871  while (i < ip(4))
2872  {
2873  F77_INT off1 = i * n;
2874  F77_INT off2 = (i+1) * n;
2875  if (std::imag (eig_val(i)) == 0)
2876  {
2877  for (F77_INT j = 0; j < n; j++)
2878  eig_vec(j,i) = Complex (z[j+off1], 0.);
2879  i++;
2880  }
2881  else
2882  {
2883  for (F77_INT j = 0; j < n; j++)
2884  {
2885  eig_vec(j,i) = Complex (z[j+off1],z[j+off2]);
2886  if (i < ip(4) - 1)
2887  eig_vec(j,i+1) = Complex (z[j+off1],-z[j+off2]);
2888  }
2889  i+=2;
2890  }
2891  }
2892  if (have_cplx_eig)
2893  {
2894  for (F77_INT ii = ip(4); ii < k; ii++)
2895  for (F77_INT jj = 0; jj < n; jj++)
2896  eig_vec(jj,ii)
2899  }
2900  else
2901  {
2902  for (F77_INT ii = ip(4); ii < k; ii++)
2903  for (F77_INT jj = 0; jj < n; jj++)
2904  eig_vec(jj,ii)
2906  }
2907  if (note3)
2908  eig_vec = utsolve (bt, permB, eig_vec);
2909  }
2910  if (k0 < k)
2911  {
2912  eig_val.resize (k0);
2913  eig_vec.resize (n, k0);
2914  }
2915  }
2916  else
2918  ("eigs: error in dneupd: %s",
2919  arpack_errno2str (info2, "dneupd").c_str ());
2920 
2921  return ip(4);
2922 }
2923 
2924 template <typename M>
2926 EigsComplexNonSymmetricMatrix (const M& m, const std::string typ,
2927  octave_idx_type k_arg, octave_idx_type p_arg,
2928  octave_idx_type& info, ComplexMatrix& eig_vec,
2929  ComplexColumnVector& eig_val, const M& _b,
2930  ColumnVector& permB,
2931  ComplexColumnVector& cresid,
2932  std::ostream& os, double tol, bool rvec,
2933  bool cholB, int disp, int maxit)
2934 {
2935  F77_INT k = octave::to_f77_int (k_arg);
2936  F77_INT p = octave::to_f77_int (p_arg);
2937  M b(_b);
2938  F77_INT n = octave::to_f77_int (m.cols ());
2939  F77_INT mode = 1;
2940  bool have_b = ! b.isempty ();
2941  bool note3 = false;
2942  char bmat = 'I';
2943  Complex sigma = 0.;
2944  M bt;
2945 
2946  if (m.rows () != m.cols ())
2947  (*current_liboctave_error_handler) ("eigs: A must be square");
2948  if (have_b && (m.rows () != b.rows () || m.rows () != b.cols ()))
2950  ("eigs: B must be square and the same size as A");
2951 
2952  if (cresid.isempty ())
2953  {
2954  std::string rand_dist = octave::rand::distribution ();
2955  octave::rand::distribution ("uniform");
2958  cresid = ComplexColumnVector (n);
2959  for (F77_INT i = 0; i < n; i++)
2960  cresid(i) = Complex (rr(i),ri(i));
2961  octave::rand::distribution (rand_dist);
2962  }
2963  else if (m.cols () != cresid.numel ())
2964  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
2965 
2966  if (n < 3)
2967  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
2968 
2969  if (p < 0)
2970  {
2971  p = k * 2 + 1;
2972 
2973  if (p < 20)
2974  p = 20;
2975 
2976  if (p > n)
2977  p = n;
2978  }
2979 
2980  if (k <= 0 || k >= n - 1)
2981  (*current_liboctave_error_handler)
2982  ("eigs: Invalid number of eigenvalues to extract"
2983  " (must be 0 < k < n-1).\n"
2984  " Use 'eig (full (A))' instead");
2985 
2986  if (p <= k || p > n)
2987  (*current_liboctave_error_handler)
2988  ("eigs: opts.p must be greater than k and less than or equal to n");
2989 
2990  if (have_b && cholB && ! permB.isempty ())
2991  {
2992  // Check the we really have a permutation vector
2993  if (permB.numel () != n)
2994  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
2995 
2996  Array<bool> checked (dim_vector (n, 1), false);
2997  for (F77_INT i = 0; i < n; i++)
2998  {
2999  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
3000 
3001  if (checked(bidx) || bidx < 0 || bidx >= n
3002  || octave::math::x_nint (bidx) != bidx)
3003  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
3004  }
3005  }
3006 
3007  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
3008  && typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI"
3009  && typ != "SI")
3010  (*current_liboctave_error_handler) ("eigs: unrecognized sigma value");
3011 
3012  if (typ == "LA" || typ == "SA" || typ == "BE")
3013  (*current_liboctave_error_handler)
3014  ("eigs: invalid sigma value for complex problem");
3015 
3016  if (have_b)
3017  {
3018  // See Note 3 dsaupd
3019  note3 = true;
3020  if (cholB)
3021  {
3022  bt = b;
3023  b = b.hermitian ();
3024  if (permB.isempty ())
3025  {
3026  permB = ColumnVector (n);
3027  for (F77_INT i = 0; i < n; i++)
3028  permB(i) = i;
3029  }
3030  }
3031  else
3032  {
3033  if (! make_cholb (b, bt, permB))
3034  (*current_liboctave_error_handler)
3035  ("eigs: The matrix B is not positive definite");
3036  }
3037  }
3038 
3039  Array<F77_INT> ip (dim_vector (11, 1));
3040  F77_INT *iparam = ip.fortran_vec ();
3041 
3042  ip(0) = 1; //ishift
3043  ip(1) = 0; // ip(1) not referenced
3044  ip(2) = maxit; // mxiter, maximum number of iterations
3045  ip(3) = 1; // NB blocksize in recurrence
3046  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
3047  ip(5) = 0; //ip(5) not referenced
3048  ip(6) = mode; // mode
3049  ip(7) = 0;
3050  ip(8) = 0;
3051  ip(9) = 0;
3052  ip(10) = 0;
3053  // ip(7) to ip(10) return values
3054 
3055  Array<F77_INT> iptr (dim_vector (14, 1));
3056  F77_INT *ipntr = iptr.fortran_vec ();
3057 
3058  F77_INT ido = 0;
3059  int iter = 0;
3060  F77_INT lwork = p * (3 * p + 5);
3061 
3062  OCTAVE_LOCAL_BUFFER (Complex, v, n * p);
3063  OCTAVE_LOCAL_BUFFER (Complex, workl, lwork);
3064  OCTAVE_LOCAL_BUFFER (Complex, workd, 3 * n);
3065  OCTAVE_LOCAL_BUFFER (double, rwork, p);
3066  Complex *presid = cresid.fortran_vec ();
3067 
3068  do
3069  {
3070  F77_INT tmp_info = octave::to_f77_int (info);
3071 
3072  F77_FUNC (znaupd, ZNAUPD)
3073  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
3074  F77_CONST_CHAR_ARG2 (typ.c_str (), 2),
3075  k, tol, F77_DBLE_CMPLX_ARG (presid), p, F77_DBLE_CMPLX_ARG (v), n,
3076  iparam, ipntr,
3077  F77_DBLE_CMPLX_ARG (workd), F77_DBLE_CMPLX_ARG (workl), lwork, rwork,
3078  tmp_info F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
3079 
3080  info = tmp_info;
3081 
3082  if (disp > 0 && ! octave::math::isnan (workl[iptr (5)-1]))
3083  {
3084  if (iter++)
3085  {
3086  os << "Iteration " << iter - 1 <<
3087  ": a few Ritz values of the " << p << "-by-" <<
3088  p << " matrix\n";
3089  if (ido == 99) // convergence
3090  {
3091  for (F77_INT i = 0; i < k; i++)
3092  os << " " << workl[iptr(5)+i-1] << "\n";
3093  }
3094  else
3095  {
3096  // the wanted Ritz estimates are at the end
3097  for (F77_INT i = p - k; i < p; i++)
3098  os << " " << workl[iptr(5)+i-1] << "\n";
3099  }
3100  }
3101 
3102  // This is a kludge, as ARPACK doesn't give its
3103  // iteration pointer. But as workl[iptr(5)-1] is
3104  // an output value updated at each iteration, setting
3105  // a value in this array to NaN and testing for it
3106  // is a way of obtaining the iteration counter.
3107  if (ido != 99)
3108  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
3109  }
3110 
3111  if (ido == -1 || ido == 1 || ido == 2)
3112  {
3113  if (have_b)
3114  {
3115  ComplexMatrix mtmp (n,1);
3116  for (F77_INT i = 0; i < n; i++)
3117  mtmp(i,0) = workd[i + iptr(0) - 1];
3118  mtmp = ltsolve (b, permB, m * utsolve (bt, permB, mtmp));
3119  for (F77_INT i = 0; i < n; i++)
3120  workd[i+iptr(1)-1] = mtmp(i,0);
3121 
3122  }
3123  else if (! vector_product (m, workd + iptr(0) - 1,
3124  workd + iptr(1) - 1))
3125  break;
3126  }
3127  else
3128  {
3129  if (info < 0)
3130  (*current_liboctave_error_handler)
3131  ("eigs: error in znaupd: %s",
3132  arpack_errno2str (info, "znaupd").c_str ());
3133 
3134  break;
3135  }
3136  }
3137  while (1);
3138 
3139  F77_INT info2;
3140 
3141  // We have a problem in that the size of the C++ bool
3142  // type relative to the fortran logical type. It appears
3143  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
3144  // per bool, though this might be system dependent. As
3145  // long as the HOWMNY arg is not "S", the logical array
3146  // is just workspace for ARPACK, so use int type to
3147  // avoid problems.
3148  Array<F77_INT> s (dim_vector (p, 1));
3149  F77_INT *sel = s.fortran_vec ();
3150 
3151  eig_vec.resize (n, k);
3152  Complex *z = eig_vec.fortran_vec ();
3153 
3154  eig_val.resize (k+1);
3155  Complex *d = eig_val.fortran_vec ();
3156 
3157  OCTAVE_LOCAL_BUFFER (Complex, workev, 2 * p);
3158 
3159  F77_FUNC (zneupd, ZNEUPD)
3160  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, F77_DBLE_CMPLX_ARG (d),
3162  F77_DBLE_CMPLX_ARG (workev),
3163  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
3164  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
3165  k, tol, F77_DBLE_CMPLX_ARG (presid), p, F77_DBLE_CMPLX_ARG (v), n,
3166  iparam, ipntr,
3167  F77_DBLE_CMPLX_ARG (workd), F77_DBLE_CMPLX_ARG (workl), lwork, rwork,
3168  info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
3169 
3170  if (info2 == 0)
3171  {
3172  for (F77_INT i = ip(4); i < k; i++)
3175 
3176  F77_INT k2 = ip(4) / 2;
3177  for (F77_INT i = 0; i < k2; i++)
3178  {
3179  Complex ctmp = d[i];
3180  d[i] = d[ip(4) - i - 1];
3181  d[ip(4) - i - 1] = ctmp;
3182  }
3183  eig_val.resize (k);
3184 
3185  if (rvec)
3186  {
3187  OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
3188 
3189  for (F77_INT i = ip(4); i < k; i++)
3190  {
3191  F77_INT off1 = i * n;
3192  for (F77_INT j = 0; j < n; j++)
3193  z[off1 + j] = Complex (octave::numeric_limits<double>::NaN (),
3195  }
3196 
3197  for (F77_INT i = 0; i < k2; i++)
3198  {
3199  F77_INT off1 = i * n;
3200  F77_INT off2 = (ip(4) - i - 1) * n;
3201 
3202  if (off1 == off2)
3203  continue;
3204 
3205  for (F77_INT j = 0; j < n; j++)
3206  ctmp[j] = z[off1 + j];
3207 
3208  for (F77_INT j = 0; j < n; j++)
3209  z[off1 + j] = z[off2 + j];
3210 
3211  for (F77_INT j = 0; j < n; j++)
3212  z[off2 + j] = ctmp[j];
3213  }
3214 
3215  if (note3)
3216  eig_vec = utsolve (bt, permB, eig_vec);
3217  }
3218  }
3219  else
3221  ("eigs: error in zneupd: %s",
3222  arpack_errno2str (info2, "zneupd").c_str ());
3223 
3224  return ip(4);
3225 }
3226 
3227 template <typename M>
3230  octave_idx_type k_arg, octave_idx_type p_arg,
3231  octave_idx_type& info,
3232  ComplexMatrix& eig_vec,
3233  ComplexColumnVector& eig_val, const M& _b,
3234  ColumnVector& permB,
3235  ComplexColumnVector& cresid,
3236  std::ostream& os, double tol, bool rvec,
3237  bool cholB, int disp, int maxit)
3238 {
3239  F77_INT k = octave::to_f77_int (k_arg);
3240  F77_INT p = octave::to_f77_int (p_arg);
3241  M b(_b);
3242  F77_INT n = octave::to_f77_int (m.cols ());
3243  F77_INT mode = 3;
3244  bool have_b = ! b.isempty ();
3245  std::string typ = "LM";
3246 
3247  if (m.rows () != m.cols ())
3248  (*current_liboctave_error_handler) ("eigs: A must be square");
3249  if (have_b && (m.rows () != b.rows () || m.rows () != b.cols ()))
3251  ("eigs: B must be square and the same size as A");
3252 
3253  // FIXME: The "SM" type for mode 1 seems unstable though faster!!
3254  //if (! std::abs (sigma))
3255  // return EigsComplexNonSymmetricMatrix (m, "SM", k, p, info, eig_vec,
3256  // eig_val, _b, permB, cresid, os, tol,
3257  // rvec, cholB, disp, maxit);
3258 
3259  if (cresid.isempty ())
3260  {
3261  std::string rand_dist = octave::rand::distribution ();
3262  octave::rand::distribution ("uniform");
3265  cresid = ComplexColumnVector (n);
3266  for (F77_INT i = 0; i < n; i++)
3267  cresid(i) = Complex (rr(i),ri(i));
3268  octave::rand::distribution (rand_dist);
3269  }
3270  else if (m.cols () != cresid.numel ())
3271  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
3272 
3273  if (n < 3)
3274  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
3275 
3276  if (p < 0)
3277  {
3278  p = k * 2 + 1;
3279 
3280  if (p < 20)
3281  p = 20;
3282 
3283  if (p > n)
3284  p = n;
3285  }
3286 
3287  if (k <= 0 || k >= n - 1)
3288  (*current_liboctave_error_handler)
3289  ("eigs: Invalid number of eigenvalues to extract"
3290  " (must be 0 < k < n-1).\n"
3291  " Use 'eig (full (A))' instead");
3292 
3293  if (p <= k || p > n)
3294  (*current_liboctave_error_handler)
3295  ("eigs: opts.p must be greater than k and less than or equal to n");
3296 
3297  if (have_b && cholB && ! permB.isempty ())
3298  {
3299  // Check that we really have a permutation vector
3300  if (permB.numel () != n)
3301  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
3302 
3303  Array<bool> checked (dim_vector (n, 1), false);
3304  for (F77_INT i = 0; i < n; i++)
3305  {
3306  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
3307 
3308  if (checked(bidx) || bidx < 0 || bidx >= n
3309  || octave::math::x_nint (bidx) != bidx)
3310  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
3311  }
3312  }
3313 
3314  char bmat = 'I';
3315  if (have_b)
3316  bmat = 'G';
3317 
3318  Array<F77_INT> ip (dim_vector (11, 1));
3319  F77_INT *iparam = ip.fortran_vec ();
3320 
3321  ip(0) = 1; //ishift
3322  ip(1) = 0; // ip(1) not referenced
3323  ip(2) = maxit; // mxiter, maximum number of iterations
3324  ip(3) = 1; // NB blocksize in recurrence
3325  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
3326  ip(5) = 0; //ip(5) not referenced
3327  ip(6) = mode; // mode
3328  ip(7) = 0;
3329  ip(8) = 0;
3330  ip(9) = 0;
3331  ip(10) = 0;
3332  // ip(7) to ip(10) return values
3333 
3334  Array<F77_INT> iptr (dim_vector (14, 1));
3335  F77_INT *ipntr = iptr.fortran_vec ();
3336 
3337  F77_INT ido = 0;
3338  int iter = 0;
3339  M L, U;
3340  ColumnVector r(n);
3341 
3342  OCTAVE_LOCAL_BUFFER (octave_idx_type, P, (have_b ? b.rows () : m.rows ()));
3343  OCTAVE_LOCAL_BUFFER (octave_idx_type, Q, (have_b ? b.cols () : m.cols ()));
3344 
3345  if (! LuAminusSigmaB (m, b, cholB, permB, sigma, L, U, P, Q, r))
3346  return -1;
3347 
3348  F77_INT lwork = p * (3 * p + 5);
3349 
3350  OCTAVE_LOCAL_BUFFER (Complex, v, n * p);
3351  OCTAVE_LOCAL_BUFFER (Complex, workl, lwork);
3352  OCTAVE_LOCAL_BUFFER (Complex, workd, 3 * n);
3353  OCTAVE_LOCAL_BUFFER (double, rwork, p);
3354  Complex *presid = cresid.fortran_vec ();
3355 
3356  do
3357  {
3358  F77_INT tmp_info = octave::to_f77_int (info);
3359 
3360  F77_FUNC (znaupd, ZNAUPD)
3361  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
3362  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
3363  k, tol, F77_DBLE_CMPLX_ARG (presid), p, F77_DBLE_CMPLX_ARG (v), n,
3364  iparam, ipntr,
3365  F77_DBLE_CMPLX_ARG (workd), F77_DBLE_CMPLX_ARG (workl), lwork, rwork,
3366  tmp_info F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
3367 
3368  info = tmp_info;
3369 
3370  if (disp > 0 && ! octave::math::isnan(workl[iptr(5)-1]))
3371  {
3372  if (iter++)
3373  {
3374  os << "Iteration " << iter - 1 <<
3375  ": a few Ritz values of the " << p << "-by-" <<
3376  p << " matrix\n";
3377  if (ido == 99) // convergence
3378  {
3379  for (F77_INT i = 0; i < k; i++)
3380  os << " " << workl[iptr(5)+i-1] << "\n";
3381  }
3382  else
3383  {
3384  // the wanted Ritz estimates are at the end
3385  for (F77_INT i = p - k; i < p; i++)
3386  os << " " << workl[iptr(5)+i-1] << "\n";
3387  }
3388  }
3389 
3390  // This is a kludge, as ARPACK doesn't give its
3391  // iteration pointer. But as workl[iptr(5)-1] is
3392  // an output value updated at each iteration, setting
3393  // a value in this array to NaN and testing for it
3394  // is a way of obtaining the iteration counter.
3395  if (ido != 99)
3396  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
3397  }
3398 
3399  if (ido == -1 || ido == 1 || ido == 2)
3400  {
3401  if (have_b)
3402  {
3403  if (ido == -1)
3404  {
3405  OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
3406 
3407  vector_product (b, workd+iptr(0)-1, ctmp);
3408 
3409  ComplexMatrix tmp (n, 1);
3410 
3411  for (F77_INT i = 0; i < n; i++)
3412  tmp(i,0) = ctmp[P[i]] / r(P[i]);
3413 
3414  lusolve (L, U, tmp);
3415 
3416  Complex *ip2 = workd+iptr(1)-1;
3417  for (F77_INT i = 0; i < n; i++)
3418  ip2[Q[i]] = tmp(i,0);
3419  }
3420  else if (ido == 2)
3421  vector_product (b, workd + iptr(0) - 1, workd + iptr(1) - 1);
3422  else
3423  {
3424  Complex *ip2 = workd+iptr(2)-1;
3425  ComplexMatrix tmp (n, 1);
3426 
3427  for (F77_INT i = 0; i < n; i++)
3428  tmp(i,0) = ip2[P[i]] / r(P[i]);
3429 
3430  lusolve (L, U, tmp);
3431 
3432  ip2 = workd+iptr(1)-1;
3433  for (F77_INT i = 0; i < n; i++)
3434  ip2[Q[i]] = tmp(i,0);
3435  }
3436  }
3437  else
3438  {
3439  // ido cannot be 2 for non-generalized problems (see znaup2).
3440  Complex *ip2 = workd+iptr(0)-1;
3441  ComplexMatrix tmp (n, 1);
3442 
3443  for (F77_INT i = 0; i < n; i++)
3444  tmp(i,0) = ip2[P[i]] / r(P[i]);
3445 
3446  lusolve (L, U, tmp);
3447 
3448  ip2 = workd+iptr(1)-1;
3449  for (F77_INT i = 0; i < n; i++)
3450  ip2[Q[i]] = tmp(i,0);
3451  }
3452  }
3453  else
3454  {
3455  if (info < 0)
3456  (*current_liboctave_error_handler)
3457  ("eigs: error in znaupd: %s",
3458  arpack_errno2str (info, "znaupd").c_str ());
3459 
3460  break;
3461  }
3462  }
3463  while (1);
3464 
3465  F77_INT info2;
3466 
3467  // We have a problem in that the size of the C++ bool
3468  // type relative to the fortran logical type. It appears
3469  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
3470  // per bool, though this might be system dependent. As
3471  // long as the HOWMNY arg is not "S", the logical array
3472  // is just workspace for ARPACK, so use int type to
3473  // avoid problems.
3474  Array<F77_INT> s (dim_vector (p, 1));
3475  F77_INT *sel = s.fortran_vec ();
3476 
3477  eig_vec.resize (n, k);
3478  Complex *z = eig_vec.fortran_vec ();
3479 
3480  eig_val.resize (k+1);
3481  Complex *d = eig_val.fortran_vec ();
3482 
3483  OCTAVE_LOCAL_BUFFER (Complex, workev, 2 * p);
3484 
3485  F77_FUNC (zneupd, ZNEUPD)
3486  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, F77_DBLE_CMPLX_ARG (d),
3488  F77_DBLE_CMPLX_ARG (workev),
3489  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
3490  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
3491  k, tol, F77_DBLE_CMPLX_ARG (presid), p, F77_DBLE_CMPLX_ARG (v), n,
3492  iparam, ipntr,
3493  F77_DBLE_CMPLX_ARG (workd), F77_DBLE_CMPLX_ARG (workl), lwork, rwork,
3494  info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
3495 
3496  if (info2 == 0)
3497  {
3498  for (F77_INT i = ip(4); i < k; i++)
3501 
3502  F77_INT k2 = ip(4) / 2;
3503  for (F77_INT i = 0; i < k2; i++)
3504  {
3505  Complex ctmp = d[i];
3506  d[i] = d[ip(4) - i - 1];
3507  d[ip(4) - i - 1] = ctmp;
3508  }
3509  eig_val.resize (k);
3510 
3511  if (rvec)
3512  {
3513  OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
3514 
3515  for (F77_INT i = ip(4); i < k; i++)
3516  {
3517  F77_INT off1 = i * n;
3518  for (F77_INT j = 0; j < n; j++)
3519  z[off1 + j] = Complex (octave::numeric_limits<double>::NaN (),
3521  }
3522 
3523  for (F77_INT i = 0; i < k2; i++)
3524  {
3525  F77_INT off1 = i * n;
3526  F77_INT off2 = (ip(4) - i - 1) * n;
3527 
3528  if (off1 == off2)
3529  continue;
3530 
3531  for (F77_INT j = 0; j < n; j++)
3532  ctmp[j] = z[off1 + j];
3533 
3534  for (F77_INT j = 0; j < n; j++)
3535  z[off1 + j] = z[off2 + j];
3536 
3537  for (F77_INT j = 0; j < n; j++)
3538  z[off2 + j] = ctmp[j];
3539  }
3540  }
3541  }
3542  else
3544  ("eigs: error in zneupd: %s",
3545  arpack_errno2str (info2, "zneupd").c_str ());
3546 
3547  return ip(4);
3548 }
3549 
3550 template <typename M>
3553  const std::string& _typ, Complex sigma,
3554  octave_idx_type k_arg, octave_idx_type p_arg,
3555  octave_idx_type& info, ComplexMatrix& eig_vec,
3556  ComplexColumnVector& eig_val, const M& _b,
3557  ColumnVector& permB, ComplexColumnVector& cresid,
3558  std::ostream& os, double tol, bool rvec,
3559  bool cholB, int disp, int maxit)
3560 {
3561  F77_INT n = octave::to_f77_int (n_arg);
3562  F77_INT k = octave::to_f77_int (k_arg);
3563  F77_INT p = octave::to_f77_int (p_arg);
3564  M b(_b);
3565  std::string typ (_typ);
3566  bool have_sigma = (std::abs (sigma) ? true : false);
3567  F77_INT mode = 1;
3568  bool have_b = ! b.isempty ();
3569  bool note3 = false;
3570  char bmat = 'I';
3571  int err = 0;
3572  M bt;
3573 
3574  if (cresid.isempty ())
3575  {
3576  std::string rand_dist = octave::rand::distribution ();
3577  octave::rand::distribution ("uniform");
3580  cresid = ComplexColumnVector (n);
3581  for (F77_INT i = 0; i < n; i++)
3582  cresid(i) = Complex (rr(i),ri(i));
3583  octave::rand::distribution (rand_dist);
3584  }
3585  else if (n != cresid.numel ())
3586  (*current_liboctave_error_handler) ("eigs: opts.v0 must be n-by-1");
3587 
3588  if (n < 3)
3589  (*current_liboctave_error_handler) ("eigs: n must be at least 3");
3590 
3591  if (p < 0)
3592  {
3593  p = k * 2 + 1;
3594 
3595  if (p < 20)
3596  p = 20;
3597 
3598  if (p > n)
3599  p = n;
3600  }
3601 
3602  if (k <= 0 || k >= n - 1)
3603  (*current_liboctave_error_handler)
3604  ("eigs: Invalid number of eigenvalues to extract"
3605  " (must be 0 < k < n-1).\n"
3606  " Use 'eig (full (A))' instead");
3607 
3608  if (p <= k || p > n)
3609  (*current_liboctave_error_handler)
3610  ("eigs: opts.p must be greater than k and less than or equal to n");
3611 
3612  if (have_b && cholB && ! permB.isempty ())
3613  {
3614  // Check the we really have a permutation vector
3615  if (permB.numel () != n)
3616  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
3617 
3618  Array<bool> checked (dim_vector (n, 1), false);
3619  for (F77_INT i = 0; i < n; i++)
3620  {
3621  octave_idx_type bidx = static_cast<octave_idx_type> (permB(i));
3622 
3623  if (checked(bidx) || bidx < 0 || bidx >= n
3624  || octave::math::x_nint (bidx) != bidx)
3625  (*current_liboctave_error_handler) ("eigs: permB vector invalid");
3626  }
3627  }
3628 
3629  if (! have_sigma)
3630  {
3631  if (typ != "LM" && typ != "SM" && typ != "LA" && typ != "SA"
3632  && typ != "BE" && typ != "LR" && typ != "SR" && typ != "LI"
3633  && typ != "SI")
3634  (*current_liboctave_error_handler) ("eigs: unrecognized sigma value");
3635 
3636  if (typ == "LA" || typ == "SA" || typ == "BE")
3637  (*current_liboctave_error_handler)
3638  ("eigs: invalid sigma value for complex problem");
3639 
3640  if (typ != "SM" && have_b)
3641  note3 = true;
3642 
3643  if (typ == "SM")
3644  {
3645  typ = "LM";
3646  sigma = 0.;
3647  mode = 3;
3648  if (have_b)
3649  bmat ='G';
3650  }
3651  }
3652  else if (! std::abs (sigma))
3653  {
3654  typ = "SM";
3655  if (have_b)
3656  bmat = 'G';
3657  }
3658  else
3659  {
3660  typ = "LM";
3661  mode = 3;
3662  if (have_b)
3663  bmat = 'G';
3664  }
3665 
3666  if (mode == 1 && have_b)
3667  {
3668  // See Note 3 dsaupd
3669  note3 = true;
3670  if (cholB)
3671  {
3672  bt = b;
3673  b = b.hermitian ();
3674  if (permB.isempty ())
3675  {
3676  permB = ColumnVector (n);
3677  for (F77_INT i = 0; i < n; i++)
3678  permB(i) = i;
3679  }
3680  }
3681  else
3682  {
3683  if (! make_cholb (b, bt, permB))
3684  (*current_liboctave_error_handler)
3685  ("eigs: The matrix B is not positive definite");
3686  }
3687  }
3688 
3689  Array<F77_INT> ip (dim_vector (11, 1));
3690  F77_INT *iparam = ip.fortran_vec ();
3691 
3692  ip(0) = 1; //ishift
3693  ip(1) = 0; // ip(1) not referenced
3694  ip(2) = maxit; // mxiter, maximum number of iterations
3695  ip(3) = 1; // NB blocksize in recurrence
3696  ip(4) = 0; // nconv, number of Ritz values that satisfy convergence
3697  ip(5) = 0; //ip(5) not referenced
3698  ip(6) = mode; // mode
3699  ip(7) = 0;
3700  ip(8) = 0;
3701  ip(9) = 0;
3702  ip(10) = 0;
3703  // ip(7) to ip(10) return values
3704 
3705  Array<F77_INT> iptr (dim_vector (14, 1));
3706  F77_INT *ipntr = iptr.fortran_vec ();
3707 
3708  F77_INT ido = 0;
3709  int iter = 0;
3710  F77_INT lwork = p * (3 * p + 5);
3711 
3712  OCTAVE_LOCAL_BUFFER (Complex, v, n * p);
3713  OCTAVE_LOCAL_BUFFER (Complex, workl, lwork);
3714  OCTAVE_LOCAL_BUFFER (Complex, workd, 3 * n);
3715  OCTAVE_LOCAL_BUFFER (double, rwork, p);
3716  Complex *presid = cresid.fortran_vec ();
3717 
3718  do
3719  {
3720  F77_INT tmp_info = octave::to_f77_int (info);
3721 
3722  F77_FUNC (znaupd, ZNAUPD)
3723  (ido, F77_CONST_CHAR_ARG2 (&bmat, 1), n,
3724  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
3725  k, tol, F77_DBLE_CMPLX_ARG (presid), p, F77_DBLE_CMPLX_ARG (v), n,
3726  iparam, ipntr,
3727  F77_DBLE_CMPLX_ARG (workd), F77_DBLE_CMPLX_ARG (workl), lwork, rwork,
3728  tmp_info F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
3729 
3730  info = tmp_info;
3731 
3732  if (disp > 0 && ! octave::math::isnan(workl[iptr(5)-1]))
3733  {
3734  if (iter++)
3735  {
3736  os << "Iteration " << iter - 1 <<
3737  ": a few Ritz values of the " << p << "-by-" <<
3738  p << " matrix\n";
3739  if (ido == 99) // convergence
3740  {
3741  for (F77_INT i = 0; i < k; i++)
3742  os << " " << workl[iptr(5)+i-1] << "\n";
3743  }
3744  else
3745  {
3746  // the wanted Ritz estimates are at the end
3747  for (F77_INT i = p - k; i < p; i++)
3748  os << " " << workl[iptr(5)+i-1] << "\n";
3749  }
3750  }
3751 
3752  // This is a kludge, as ARPACK doesn't give its
3753  // iteration pointer. But as workl[iptr(5)-1] is
3754  // an output value updated at each iteration, setting
3755  // a value in this array to NaN and testing for it
3756  // is a way of obtaining the iteration counter.
3757  if (ido != 99)
3758  workl[iptr(5)-1] = octave::numeric_limits<double>::NaN ();
3759  }
3760 
3761  if (ido == -1 || ido == 1 || ido == 2)
3762  {
3763  if (have_b)
3764  {
3765  if (mode == 1) // regular mode with factorized B
3766  {
3767  ComplexMatrix mtmp (n,1);
3768  for (F77_INT i = 0; i < n; i++)
3769  mtmp(i,0) = workd[i + iptr(0) - 1];
3770 
3771  mtmp = utsolve (bt, permB, mtmp);
3772  ComplexColumnVector y = fun (mtmp, err);
3773 
3774  if (err)
3775  return false;
3776 
3777  mtmp = ltsolve (b, permB, y);
3778 
3779  for (F77_INT i = 0; i < n; i++)
3780  workd[i+iptr(1)-1] = mtmp(i,0);
3781  }
3782  else // shift-invert mode
3783  {
3784  if (ido == -1)
3785  {
3786  OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
3787 
3788  vector_product (b, workd+iptr(0)-1, ctmp);
3789 
3791 
3792  for (F77_INT i = 0; i < n; i++)
3793  x(i) = ctmp[i];
3794 
3795  ComplexColumnVector y = fun (x, err);
3796 
3797  if (err)
3798  return false;
3799 
3800  Complex *ip2 = workd+iptr(1)-1;
3801  for (F77_INT i = 0; i < n; i++)
3802  ip2[i] = y(i);
3803  }
3804  else if (ido == 2)
3805  vector_product (b, workd+iptr(0)-1, workd+iptr(1)-1);
3806  else
3807  {
3808  Complex *ip2 = workd+iptr(2)-1;
3810 
3811  for (F77_INT i = 0; i < n; i++)
3812  x(i) = *ip2++;
3813 
3814  ComplexColumnVector y = fun (x, err);
3815 
3816  if (err)
3817  return false;
3818 
3819  ip2 = workd + iptr(1) - 1;
3820  for (F77_INT i = 0; i < n; i++)
3821  *ip2++ = y(i);
3822  }
3823  }
3824  }
3825  else
3826  {
3827  Complex *ip2 = workd + iptr(0) - 1;
3829 
3830  for (F77_INT i = 0; i < n; i++)
3831  x(i) = *ip2++;
3832 
3833  ComplexColumnVector y = fun (x, err);
3834 
3835  if (err)
3836  return false;
3837 
3838  ip2 = workd + iptr(1) - 1;
3839  for (F77_INT i = 0; i < n; i++)
3840  *ip2++ = y(i);
3841  }
3842  }
3843  else
3844  {
3845  if (info < 0)
3846  (*current_liboctave_error_handler)
3847  ("eigs: error in znaupd: %s",
3848  arpack_errno2str (info, "znaupd").c_str ());
3849 
3850  break;
3851  }
3852  }
3853  while (1);
3854 
3855  F77_INT info2;
3856 
3857  // We have a problem in that the size of the C++ bool
3858  // type relative to the fortran logical type. It appears
3859  // that fortran uses 4- or 8-bytes per logical and C++ 1-byte
3860  // per bool, though this might be system dependent. As
3861  // long as the HOWMNY arg is not "S", the logical array
3862  // is just workspace for ARPACK, so use int type to
3863  // avoid problems.
3864  Array<F77_INT> s (dim_vector (p, 1));
3865  F77_INT *sel = s.fortran_vec ();
3866 
3867  eig_vec.resize (n, k);
3868  Complex *z = eig_vec.fortran_vec ();
3869 
3870  eig_val.resize (k+1);
3871  Complex *d = eig_val.fortran_vec ();
3872 
3873  OCTAVE_LOCAL_BUFFER (Complex, workev, 2 * p);
3874 
3875  F77_FUNC (zneupd, ZNEUPD)
3876  (rvec, F77_CONST_CHAR_ARG2 ("A", 1), sel, F77_DBLE_CMPLX_ARG (d),
3877  F77_DBLE_CMPLX_ARG (z), n, F77_DBLE_CMPLX_ARG (&sigma),
3878  F77_DBLE_CMPLX_ARG (workev),
3879  F77_CONST_CHAR_ARG2 (&bmat, 1), n,
3880  F77_CONST_CHAR_ARG2 ((typ.c_str ()), 2),
3881  k, tol, F77_DBLE_CMPLX_ARG (presid), p, F77_DBLE_CMPLX_ARG (v), n,
3882  iparam, ipntr,
3883  F77_DBLE_CMPLX_ARG (workd), F77_DBLE_CMPLX_ARG (workl), lwork, rwork,
3884  info2 F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(1) F77_CHAR_ARG_LEN(2));
3885 
3886  if (info2 == 0)
3887  {
3888  for (F77_INT i = ip(4); i < k; i++)
3891 
3892  F77_INT k2 = ip(4) / 2;
3893  for (F77_INT i = 0; i < k2; i++)
3894  {
3895  Complex ctmp = d[i];
3896  d[i] = d[ip(4) - i - 1];
3897  d[ip(4) - i - 1] = ctmp;
3898  }
3899  eig_val.resize (k);
3900 
3901  if (rvec)
3902  {
3903  OCTAVE_LOCAL_BUFFER (Complex, ctmp, n);
3904 
3905  for (F77_INT i = ip(4); i < k; i++)
3906  {
3907  F77_INT off1 = i * n;
3908  for (F77_INT j = 0; j < n; j++)
3909  z[off1 + j] = Complex (octave::numeric_limits<double>::NaN (),
3911  }
3912 
3913  for (F77_INT i = 0; i < k2; i++)
3914  {
3915  F77_INT off1 = i * n;
3916  F77_INT off2 = (ip(4) - i - 1) * n;
3917 
3918  if (off1 == off2)
3919  continue;
3920 
3921  for (F77_INT j = 0; j < n; j++)
3922  ctmp[j] = z[off1 + j];
3923 
3924  for (F77_INT j = 0; j < n; j++)
3925  z[off1 + j] = z[off2 + j];
3926 
3927  for (F77_INT j = 0; j < n; j++)
3928  z[off2 + j] = ctmp[j];
3929  }
3930  if (note3)
3931  eig_vec = utsolve (bt, permB, eig_vec);
3932  }
3933  }
3934  else
3936  ("eigs: error in zneupd: %s",
3937  arpack_errno2str (info2, "zneupd").c_str ());
3938 
3939  return ip(4);
3940 }
3941 
3942 // Instantiations for the types we need.
3943 
3944 // Matrix
3945 
3946 template
3949  (const Matrix& m, const std::string typ, octave_idx_type k,
3950  octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
3951  ColumnVector& eig_val, const Matrix& _b, ColumnVector& permB,
3952  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
3953  bool cholB, int disp, int maxit);
3954 
3955 template
3958  (const Matrix& m, double sigma, octave_idx_type k,
3959  octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
3960  ColumnVector& eig_val, const Matrix& _b, ColumnVector& permB,
3961  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
3962  bool cholB, int disp, int maxit);
3963 
3964 template
3967 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigma,
3969  Matrix& eig_vec, ColumnVector& eig_val, const Matrix& _b,
3970  ColumnVector& permB, ColumnVector& resid, std::ostream& os, double tol,
3971  bool rvec, bool cholB, int disp, int maxit);
3972 
3973 template
3976  (const Matrix& m, const std::string typ, octave_idx_type k,
3977  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
3978  ComplexColumnVector& eig_val, const Matrix& _b, ColumnVector& permB,
3979  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
3980  bool cholB, int disp, int maxit);
3981 
3982 template
3985  (const Matrix& m, double sigmar, octave_idx_type k,
3986  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
3987  ComplexColumnVector& eig_val, const Matrix& _b, ColumnVector& permB,
3988  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
3989  bool cholB, int disp, int maxit);
3990 
3991 template
3994 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigmar,
3996  ComplexMatrix& eig_vec, ComplexColumnVector& eig_val, const Matrix& _b,
3997  ColumnVector& permB, ColumnVector& resid, std::ostream& os, double tol,
3998  bool rvec, bool cholB, int disp, int maxit);
3999 
4000 // SparseMatrix
4001 
4002 template
4005  (const SparseMatrix& m, const std::string typ, octave_idx_type k,
4006  octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
4007  ColumnVector& eig_val, const SparseMatrix& _b, ColumnVector& permB,
4008  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
4009  bool cholB, int disp, int maxit);
4010 
4011 template
4014  (const SparseMatrix& m, double sigma, octave_idx_type k,
4015  octave_idx_type p, octave_idx_type& info, Matrix& eig_vec,
4016  ColumnVector& eig_val, const SparseMatrix& _b, ColumnVector& permB,
4017  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
4018  bool cholB, int disp, int maxit);
4019 
4020 template
4023 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigma,
4025  Matrix& eig_vec, ColumnVector& eig_val, const SparseMatrix& _b,
4026  ColumnVector& permB, ColumnVector& resid, std::ostream& os, double tol,
4027  bool rvec, bool cholB, int disp, int maxit);
4028 
4029 template
4032  (const SparseMatrix& m, const std::string typ, octave_idx_type k,
4033  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
4034  ComplexColumnVector& eig_val, const SparseMatrix& _b, ColumnVector& permB,
4035  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
4036  bool cholB, int disp, int maxit);
4037 
4038 template
4041  (const SparseMatrix& m, double sigmar, octave_idx_type k,
4042  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
4043  ComplexColumnVector& eig_val, const SparseMatrix& _b, ColumnVector& permB,
4044  ColumnVector& resid, std::ostream& os, double tol, bool rvec,
4045  bool cholB, int disp, int maxit);
4046 
4047 template
4050 (EigsFunc fun, octave_idx_type n, const std::string& _typ, double sigmar,
4052  ComplexMatrix& eig_vec, ComplexColumnVector& eig_val,
4053  const SparseMatrix& _b, ColumnVector& permB, ColumnVector& resid,
4054  std::ostream& os, double tol, bool rvec, bool cholB, int disp, int maxit);
4055 
4056 // ComplexMatrix
4057 
4058 template
4061  (const ComplexMatrix& m, const std::string typ, octave_idx_type k,
4062  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
4063  ComplexColumnVector& eig_val, const ComplexMatrix& _b, ColumnVector& permB,
4064  ComplexColumnVector& cresid, std::ostream& os, double tol,
4065  bool rvec, bool cholB, int disp, int maxit);
4066 
4067 template
4070  (const ComplexMatrix& m, Complex sigma, octave_idx_type k,
4071  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
4072  ComplexColumnVector& eig_val, const ComplexMatrix& _b, ColumnVector& permB,
4073  ComplexColumnVector& cresid, std::ostream& os, double tol,
4074  bool rvec, bool cholB, int disp, int maxit);
4075 
4076 template
4079 (EigsComplexFunc fun, octave_idx_type n, const std::string& _typ, Complex sigma,
4081  ComplexMatrix& eig_vec, ComplexColumnVector& eig_val,
4082  const ComplexMatrix& _b, ColumnVector& permB, ComplexColumnVector& cresid,
4083  std::ostream& os, double tol, bool rvec, bool cholB, int disp, int maxit);
4084 
4085 // SparseComplexMatrix
4086 
4087 template
4090  (const SparseComplexMatrix& m, const std::string typ, octave_idx_type k,
4091  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
4092  ComplexColumnVector& eig_val, const SparseComplexMatrix& _b,
4093  ColumnVector& permB, ComplexColumnVector& cresid, std::ostream& os,
4094  double tol, bool rvec, bool cholB, int disp, int maxit);
4095 
4096 template
4099  (const SparseComplexMatrix& m, Complex sigma, octave_idx_type k,
4100  octave_idx_type p, octave_idx_type& info, ComplexMatrix& eig_vec,
4101  ComplexColumnVector& eig_val, const SparseComplexMatrix& _b,
4102  ColumnVector& permB, ComplexColumnVector& cresid, std::ostream& os,
4103  double tol, bool rvec, bool cholB, int disp, int maxit);
4104 
4105 template
4108 (EigsComplexFunc fun, octave_idx_type n, const std::string& _typ, Complex sigma,
4110  ComplexMatrix& eig_vec, ComplexColumnVector& eig_val,
4111  const SparseComplexMatrix& _b, ColumnVector& permB,
4112  ComplexColumnVector& cresid, std::ostream& os, double tol, bool rvec,
4113  bool cholB, int disp, int maxit);
4114 #endif
#define NaN
Definition: Faddeeva.cc:248
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:469
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:499
octave_idx_type cols(void) const
Definition: Array.h:423
octave_idx_type rows(void) const
Definition: Array.h:415
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:572
void resize(octave_idx_type n, const double &rfv=0)
Definition: dColVector.h:109
void resize(octave_idx_type n, const Complex &rfv=Complex(0))
Definition: CColVector.h:142
ComplexMatrix hermitian(void) const
Definition: CMatrix.h:169
void resize(octave_idx_type nr, octave_idx_type nc, const Complex &rfv=Complex(0))
Definition: CMatrix.h:190
Definition: dMatrix.h:42
Matrix transpose(void) const
Definition: dMatrix.h:135
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:151
SparseComplexMatrix hermitian(void) const
Definition: CSparse.cc:606
SparseMatrix transpose(void) const
Definition: dSparse.h:128
octave_idx_type * xridx(void)
Definition: Sparse.h:485
bool isempty(void) const
Definition: Sparse.h:466
octave_idx_type * xcidx(void)
Definition: Sparse.h:498
T * xdata(void)
Definition: Sparse.h:472
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
T chol_matrix(void) const
Definition: chol.h:74
T U(void) const
Definition: lu.cc:123
ColumnVector P_vec(void) const
Definition: lu.cc:196
T L(void) const
Definition: lu.cc:96
RowVector perm(void) const
Definition: sparse-chol.cc:498
chol_type L(void) const
Definition: sparse-chol.cc:460
lu_type U(void) const
Definition: sparse-lu.h:89
const octave_idx_type * row_perm(void) const
Definition: sparse-lu.h:107
const octave_idx_type * col_perm(void) const
Definition: sparse-lu.h:109
lu_type L(void) const
Definition: sparse-lu.h:87
SparseMatrix R(void) const
Definition: sparse-lu.h:91
static std::string distribution(void)
Definition: oct-rand.h:99
static Array< double > vector(octave_idx_type n, double a=1.0)
Definition: oct-rand.h:157
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
octave_idx_type EigsRealSymmetricFunc(EigsFunc fun, octave_idx_type n_arg, const std::string &_typ, double sigma, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const M &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:1380
static M utsolve(const SM &U, const ColumnVector &Q, const M &m)
Definition: eigs-base.cc:258
template octave_idx_type EigsComplexNonSymmetricMatrix< SparseComplexMatrix >(const SparseComplexMatrix &m, const std::string typ, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const SparseComplexMatrix &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsComplexNonSymmetricFunc< SparseComplexMatrix >(EigsComplexFunc fun, octave_idx_type n, const std::string &_typ, Complex sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const SparseComplexMatrix &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealNonSymmetricFunc< Matrix >(EigsFunc fun, octave_idx_type n, const std::string &_typ, double sigmar, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const Matrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealSymmetricFunc< Matrix >(EigsFunc fun, octave_idx_type n, const std::string &_typ, double sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const Matrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsComplexNonSymmetricMatrixShift< SparseComplexMatrix >(const SparseComplexMatrix &m, Complex sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const SparseComplexMatrix &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
static bool make_cholb(Matrix &b, Matrix &bt, ColumnVector &permB)
Definition: eigs-base.cc:346
octave_idx_type EigsRealNonSymmetricMatrixShift(const M &m, double sigmar, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const M &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:2112
octave_idx_type EigsRealSymmetricMatrixShift(const M &m, double sigma, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const M &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:1077
static M ltsolve(const SM &L, const ColumnVector &Q, const M &m)
Definition: eigs-base.cc:238
template octave_idx_type EigsComplexNonSymmetricFunc< ComplexMatrix >(EigsComplexFunc fun, octave_idx_type n, const std::string &_typ, Complex sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const ComplexMatrix &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealNonSymmetricMatrixShift< Matrix >(const Matrix &m, double sigmar, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const Matrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
static void warn_convergence(void)
Definition: eigs-base.cc:55
static bool LuAminusSigmaB(const SparseMatrix &m, const SparseMatrix &b, bool cholB, const ColumnVector &permB, double sigma, SparseMatrix &L, SparseMatrix &U, octave_idx_type *P, octave_idx_type *Q, ColumnVector &r)
Definition: eigs-base.cc:421
octave_idx_type EigsRealNonSymmetricMatrix(const M &m, const std::string typ, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const M &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:1761
octave_idx_type EigsComplexNonSymmetricMatrix(const M &m, const std::string typ, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const M &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:2926
octave_idx_type EigsComplexNonSymmetricFunc(EigsComplexFunc fun, octave_idx_type n_arg, const std::string &_typ, Complex sigma, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const M &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:3552
std::string arpack_errno2str(const octave_idx_type &errnum, const std::string &fcn_name)
Definition: eigs-base.cc:65
template octave_idx_type EigsRealSymmetricMatrixShift< SparseMatrix >(const SparseMatrix &m, double sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const SparseMatrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealNonSymmetricMatrixShift< SparseMatrix >(const SparseMatrix &m, double sigmar, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const SparseMatrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
static octave_idx_type lusolve(const SM &L, const SM &U, M &m)
Definition: eigs-base.cc:219
octave_idx_type EigsRealNonSymmetricFunc(EigsFunc fun, octave_idx_type n_arg, const std::string &_typ, double sigmar, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const M &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:2484
template octave_idx_type EigsRealNonSymmetricFunc< SparseMatrix >(EigsFunc fun, octave_idx_type n, const std::string &_typ, double sigmar, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const SparseMatrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealSymmetricFunc< SparseMatrix >(EigsFunc fun, octave_idx_type n, const std::string &_typ, double sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const SparseMatrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsComplexNonSymmetricMatrixShift< ComplexMatrix >(const ComplexMatrix &m, Complex sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const ComplexMatrix &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealNonSymmetricMatrix< Matrix >(const Matrix &m, const std::string typ, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const Matrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealSymmetricMatrixShift< Matrix >(const Matrix &m, double sigma, octave_idx_type k, octave_idx_type p, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const Matrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealSymmetricMatrix< Matrix >(const Matrix &m, const std::string typ, octave_idx_type k, octave_idx_type p, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const Matrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
octave_idx_type EigsComplexNonSymmetricMatrixShift(const M &m, Complex sigma, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const M &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:3229
template octave_idx_type EigsRealNonSymmetricMatrix< SparseMatrix >(const SparseMatrix &m, const std::string typ, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const SparseMatrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
octave_idx_type EigsRealSymmetricMatrix(const M &m, const std::string typ, octave_idx_type k_arg, octave_idx_type p_arg, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const M &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
Definition: eigs-base.cc:785
static bool vector_product(const SparseMatrix &m, const double *x, double *y)
Definition: eigs-base.cc:285
template octave_idx_type EigsComplexNonSymmetricMatrix< ComplexMatrix >(const ComplexMatrix &m, const std::string typ, octave_idx_type k, octave_idx_type p, octave_idx_type &info, ComplexMatrix &eig_vec, ComplexColumnVector &eig_val, const ComplexMatrix &_b, ColumnVector &permB, ComplexColumnVector &cresid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
template octave_idx_type EigsRealSymmetricMatrix< SparseMatrix >(const SparseMatrix &m, const std::string typ, octave_idx_type k, octave_idx_type p, octave_idx_type &info, Matrix &eig_vec, ColumnVector &eig_val, const SparseMatrix &_b, ColumnVector &permB, ColumnVector &resid, std::ostream &os, double tol, bool rvec, bool cholB, int disp, int maxit)
ColumnVector(* EigsFunc)(const ColumnVector &x, int &eigs_error)
Definition: eigs-base.h:41
ComplexColumnVector(* EigsComplexFunc)(const ComplexColumnVector &x, int &eigs_error)
Definition: eigs-base.h:43
#define F77_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:315
#define F77_XFCN(f, F, args)
Definition: f77-fcn.h:44
octave_f77_int_type F77_INT
Definition: f77-fcn.h:305
#define F77_CONST_DBLE_CMPLX_ARG(x)
Definition: f77-fcn.h:318
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition: lo-error.c:41
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT & M
F77_RET_T const F77_INT const F77_INT const F77_INT F77_DBLE const F77_INT F77_DBLE const F77_INT F77_DBLE * Q
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
T x_nint(T x)
Definition: lo-mappers.h:262
bool isnan(bool)
Definition: lo-mappers.h:178
std::complex< double > Complex
Definition: oct-cmplx.h:33
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
static T abs(T x)
Definition: pr-output.cc:1678
F77_RET_T F77_FUNC(xerbla, XERBLA)(F77_CONST_CHAR_ARG_DEF(s_arg