tensor-0.1.0
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Enumerator Groups Pages
arpack_t.cc
1 // -*- mode: c++; fill-column: 80; c-basic-offset: 2; indent-tabs-mode: nil -*-
2 /*
3  Copyright (c) 2010 Juan Jose Garcia Ripoll
4 
5  Tensor is free software; you can redistribute it and/or modify it
6  under the terms of the GNU Library General Public License as published
7  by the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Library General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License along
16  with this program; if not, write to the Free Software Foundation, Inc.,
17  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include <algorithm>
21 
22 using namespace tensor;
23 using namespace linalg;
24 
25 ARPACK::ARPACK(size_t _n, enum EigType _t, size_t _nev)
26 {
27 #ifdef COMPLEX
28  static const char *whichs[6] = {"LM", "SM", "LR", "SR", "LI", "SI"};
29 #else
30  static const char *whichs[6] = {"LM", "SM", "LA", "SA", NULL, NULL};
31  if (_t == LargestImaginary) {
32  std::cerr << "Cannot use LargestImaginary eigenvalue selector with real problems."
33  << std::endl;
34  abort();
35  }
36  if (_t == SmallestImaginary) {
37  std::cerr << "Cannot use SmallestImaginary eigenvalue selector with real problems."
38  << std::endl;
39  abort();
40  }
41 #endif
42  if (_t < 0 || _t > 6) {
43  std::cerr << "Invalid argument EigType passed to Arpack constructor"
44  << std::endl;
45  abort();
46  }
47 
48  // Select the type of problem
49  which_eig = _t;
50  which = whichs[which_eig];
51 #ifdef COMPLEX
52  symmetric = 0;
53 #else
54  symmetric = 1;
55 #endif
56 
57  // Default tolerance is machine precision
58  tol = -1.0;
59 
60  // Select the problem size
61  n = _n;
62  nev = _nev;
63 
64  // There's a limit in the number of eigenvalues we can get
65  if ((nev == 0) || (nev > (n-1))) {
66  std::cerr << "Error in ARPACK::ARPACK(): \n "
67  << "You request NEV=" << nev << " eigenvalues, while only between 1 and "
68  << (n-1) << " eigenvalues can be computed.";
69  abort();
70  }
71 
72  // Tell the library we are just beginning
73  ido = 0;
74 
75  // By default, random vector
76  info = 0;
77  resid = new ELT_T[n];
78 
79  // Reserve space for the lanczos basis in which the eigenvectors are
80  // approximated.
81  ncv = std::min<integer>(std::max<integer>(2 * nev, 20), n);
82  V = new ELT_T[n * ncv];
83 
84  // Conservative estimate by Matlab
85 
86  maxit = std::max<integer>(300,(int)(ceil(2.0*n/std::max<integer>(ncv,1))));
87 
88  // Parameters for the algorithm: the (-1) in the index is to make it
89  // look like FORTRAN.
90  for (size_t i = 1; i < 12; i++)
91  iparam[i-1] = 0;
92  iparam[1-1] = 1; // Shift produced by user
93  iparam[3-1] = maxit; // Maximum number of iterations
94  iparam[4-1] = 1; // Block size to be used in the recurrence
95  iparam[7-1] = 1; // Standard eigenvalue problem
96 
97  // Standard eigenvalue problem, A * x = lambda * x
98  bmat = 'I';
99 
100  // When computing eigenvectors, compute them all
101  hwmny = 'A';
102 
103  // Work space for reverse communication
104  //
105  lworkl = symmetric? ncv*(ncv + 8) : ncv*(3*ncv + 5);
106  lworkv = ncv * 3;
107  workd = new ELT_T[n * 3];
108  workl = new ELT_T[lworkl];
109  workv = new ELT_T[lworkv];
110  rwork = new double[ncv];
111  for (size_t i = 0; i < 15; i++)
112  ipntr[i] = 0;
113 
114  // We have initialized this structure
115  status = Initialized;
116 }
117 
118 ARPACK::~ARPACK() {
119 
120  // Deleting working arrays
121  delete[] workd; workd = 0;
122  delete[] workl; workl = 0;
123  delete[] workv; workv = 0;
124  delete[] rwork; rwork = 0;
125  delete[] V; V = 0;
126 
127  // Deleting input and output arrays
128  delete[] resid; resid = 0;
129 }
130 
131 ARPACK::Status ARPACK::update() {
132 
133  if (status < Initialized) {
134  error = "ARPACK: Cannot call update() with an uninitialized ARPACK object.";
135  status = Error;
136  return status;
137  }
138  if (status > Running) {
139  error = "ARPACK: Cannot call update() after the algorithm is finished.";
140  status = Error;
141  return status;
142  }
143 
144 #ifdef COMPLEX
145  caupp(ido, bmat, n, which, nev, tol, resid, ncv, V, n, iparam, ipntr, workd,
146  workl, lworkl, rwork, info);
147 #else
148  saupp(ido, bmat, n, which, nev, tol, resid, ncv, V, n, iparam, ipntr, workd,
149  workl, lworkl, info);
150 #endif
151 
152  if (ido == 99) {
153  status = Error;
154  if (info == 1) {
155  error = "Maximum number of iterations reached";
156  status = TooManyIterations;
157  } else if (info > 0) {
158  error = "Algorithm failed to converge";
159  status = NoConvergence;
160  } else if (info < 0) {
161  switch (info) {
162  case -9: error = "Starting vector is zero"; break;
163  default: error = "Internal error -- some parameter is wrong"; break;
164  }
165  std::cerr << error << ' ' << info << '\n';
166  abort();
167  } else {
168  status = Finished;
169  }
170  } else if (ido != 1 && ido != -1) {
171  error = "Internal error -- ARPACK asks for B matrix";
172  status = Error;
173  } else {
174  status = Running;
175  }
176  return status;
177 }
178 
179 Tensor<ELT_T> ARPACK::get_data(Tensor<ELT_T> *vectors) {
180  if (vectors) {
181  *vectors = Tensor<ELT_T>(n, nev);
182  }
183  return get_data(vectors? vectors->begin() : NULL);
184 }
185 
186 Tensor<ELT_T> ARPACK::get_data(Tensor<ELT_T>::elt_t *z) {
187  // Do we want eigenvectors?
188  bool rvec;
189  int ldz;
190  if (z) {
191  rvec = 1;
192  ldz = n;
193  } else {
194  rvec = 0;
195  ldz = 1;
196  }
197 
198  // Room for eigenvalues
199  Tensor<ELT_T> output(nev+1);
200  ELT_T *d = output.begin();
201 
202  // Unused here
203  ELT_T sigma = number_zero<ELT_T>();
204 
205 #ifdef COMPLEX
206  ceupp(rvec, hwmny, d, z, ldz, sigma, workv, bmat, n, which, nev, tol,
207  resid, ncv, V, n, iparam, ipntr, workd, workl, lworkl, rwork, info);
208 #else
209  seupp(rvec, hwmny, d, z, ldz, sigma, bmat, n, which, nev, tol,
210  resid, ncv, V, n, iparam, ipntr, workd, workl, lworkl, info);
211 #endif
212  if (info != 0) {
213  static const char *const messages[17] = {
214  "Unknown error.",
215  "N must be positive.",
216  "NEV must be positive.",
217  "NCV must satisfy NEV < NCV <= N.",
218  "WHICH be one of 'LM', 'SM', 'LA', 'SA' or 'BE'.",
219  "BMAT must be one of 'I' or 'G'.",
220  "Length of private work workl array is not sufficient.",
221  "Error return from trid. eigenvalue calculation.",
222  "Starting vector is zero.",
223  "IPARAM[7] must be 1,2,3,4,5.",
224  "IPARAM[7] = 1 and BMAT = 'G' are incompatible.",
225  "NEV and WHICH = 'BE' are incompatible.",
226  "DSAUPP did not find any eigenvalues to sufficient accuracy.",
227  "HOWMNY must be one of 'A' or 'S' if rvec = true.",
228  "HOWMNY = 'S' not yet implemented."};
229  std::cerr << "Routine ARPACK::get_data() failed" << std::endl
230  << messages[(info < -16 || info > 0) ? 0 : (-info)] << std::endl
231  << "N=" << n << std::endl
232  << "NEV=" << n << std::endl
233  << "WHICH=" << which << std::endl
234  << "BMAT=" << bmat << std::endl
235  << "LWORKL=" << workl << std::endl;
236  for (int i = 0; i < 12; i++)
237  std::cerr << "IPARAM[" << i << "]=" << iparam[i] << std::endl;
238  for (int i = 8; i < 11; i++)
239  std::cerr << "IPNTR[" << i << "]=" << ipntr[i] << std::endl;
240  abort();
241  }
242  return output(range(0,nev-1));
243 }
244 
245 void ARPACK::set_start_vector(const ELT_T *v) {
246  if (status >= Running) {
247  std::cerr << "ARPACK:: Cannot change start vector while running\n";
248  abort();
249  }
250  info = 1;
251  memcpy(resid, v, n * sizeof(ELT_T));
252 }
253 
254 void ARPACK::set_random_start_vector() {
255  info = 0;
256 }
257 
258 void ARPACK::set_tolerance(double _tol) {
259  if (status >= Running) {
260  std::cerr << "ARPACK:: Cannot change tolerance while running\n";
261  abort();
262  }
263  tol = _tol;
264 }
265 
266 void ARPACK::set_maxiter(size_t new_maxiter) {
267  if (status >= Running) {
268  std::cerr << "ARPACK:: Cannot change number of iterations while running\n";
269  abort();
270  }
271  maxit = new_maxiter;
272  iparam[2] = maxit;
273 }
274 
275 ELT_T *ARPACK::get_x_vector() {
276  if (status != Running) {
277  std::cerr << "ARPACK:: get_x_vector() invoked outside main loop";
278  abort();
279  }
280  // IPNTR[1] has a FORTRAN index, which is one-based, instead of zero-based
281  return &workd[ipntr[1-1]-1];
282 }
283 
284 ELT_T *ARPACK::get_y_vector() {
285  if (status != Running) {
286  std::cerr << "ARPACK:: get_y_vector() invoked outside main loop";
287  abort();
288  }
289  // IPNTR[2] has a FORTRAN index, which is one-based, instead of zero-based
290  return &workd[ipntr[2-1]-1];
291 }
292 
293 const Tensor<ELT_T> ARPACK::get_x()
294 {
295  return Vector<ELT_T>(n, get_x_vector());
296 }
297 
298 Tensor<ELT_T> ARPACK::get_y()
299 {
300  return Vector<ELT_T>(n, get_y_vector());
301 }
302 
303 void ARPACK::set_y(const Tensor<ELT_T> &y)
304 {
305  memcpy(get_y_vector(), y.begin(), sizeof(Tensor<ELT_T>::elt_t)*n);
306 }
307 
308 Indices
309 ARPACK::sort_values(const CTensor &values, EigType t)
310 {
311  RTensor aux;
312  switch (t) {
313  case LargestReal:
314  aux = -tensor::real(values);
315  break;
316  case LargestMagnitude:
317  aux = -abs(values);
318  break;
319  case SmallestMagnitude:
320  aux = abs(values);
321  break;
322  case LargestImaginary:
323  aux = -imag(values);
324  break;
325  case SmallestImaginary:
326  aux = imag(values);
327  break;
328  case SmallestReal:
329  aux = tensor::real(values);
330  break;
331  }
332  return sort_indices(aux);
333 }
334 
An N-dimensional array of numbers.
Definition: tensor.h:47
Real Tensor with elements of type "double".
Definition: tensor.h:349
iterator begin()
Iterator at the beginning.
Definition: tensor.h:256
Complex Tensor with elements of type "cdouble".
Definition: tensor.h:435
Vector of 'index' type, where 'index' fits the indices of a tensor.
Definition: indices.h:35
EigType
Type of eigenvalues that eigs and Arpack compute.
Definition: linalg.h:69