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