File: rnsymgsc.cc

package info (click to toggle)
arpack%2B%2B 2.3-5
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 4,548 kB
  • ctags: 3,751
  • sloc: cpp: 16,612; sh: 8,819; ansic: 2,312; makefile: 257
file content (247 lines) | stat: -rw-r--r-- 7,005 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*
   ARPACK++ v1.2 2/18/2000
   c++ interface to ARPACK code.

   MODULE RNSymGSC.cc.
   Example program that illustrates how to solve a real
   nonsymmetric generalized eigenvalue problem in complex shift
   and invert mode using the ARrcNonSymGenEig class.

   1) Problem description:

      In this example we try to solve A*x = B*x*lambda in shift and
      invert mode, where A is the tridiagonal matrix with 2 on the
      diagonal, -2 on the subdiagonal and 3 on the superdiagonal, and
      B is the tridiagonal matrix with 4 on the diagonal and 1 on the
      off-diagonals.
      The shift sigma is a complex number.

   2) Data structure used to represent matrix A:

      To obtain the eigenvalues of the above problem, the user is
      required to provide a way to perform the matrix-vector products
      w = OP*Bv = real{inv(A-sigma*B)}*B*v, w = A*v and w = B*v. In
      this example, a class called NonSymGenProblemC was created with
      this purpose. NonSymGenProblemC contains a member function,
      MultOPv(v,w), that takes a vector v and returns the product OPv
      in w. It also contains two objects, A and B, that
      store matrices A and B, respectively. The product Bv is
      performed by MultMv, a member function of B, and Av is obtained
      by calling A.MultMv.

   3) The reverse communication interface:

      This example uses the reverse communication interface, which
      means that the desired eigenvalues cannot be obtained directly
      from an ARPACK++ class.
      Here, the overall process of finding eigenvalues by using the
      Arnoldi method is splitted into two parts. In the first, a
      sequence of calls to a function called TakeStep is combined
      with matrix-vector products in order to find an Arnoldi basis.
      In the second part, an ARPACK++ function like FindEigenvectors
      (or EigenValVectors) is used to extract eigenvalues and
      eigenvectors.

   4) Included header files:

      File             Contents
      -----------      -------------------------------------------
      ngenprbc.h       The NonSymGenProblemC class definition.
      arrgnsym.h       The ARrcNonSymGenEig class definition.
      rnsymgsl.h       The Solution function.

   5) ARPACK Authors:

      Richard Lehoucq
      Kristyn Maschhoff
      Danny Sorensen
      Chao Yang
      Dept. of Computational & Applied Mathematics
      Rice University
      Houston, Texas
*/

#include "ngenprbc.h"
#include "rnsymgsl.h"
#include "arrgnsym.h"


template<class ARFLOAT>
void RecoverEigenvalues(long nconv, NonSymGenProblemC<ARFLOAT>& P,
                        ARFLOAT EigVec[], ARFLOAT EigValR[], ARFLOAT EigValI[])
/*
   This function is used to recover the eigenvalues of the original
   problem A.x = B.x.lambda, after calling ARPACK++.
   When a complex shift is used to solve a nonsymmetric problem
   defined by the ARRCNonSymGenEig class, the Rayleigh quotient
   lambda = x'Ax/x'Bx must be formed by the user to obtain the
   desired eigenvalues.
   The Rayleigh quotient cannot be calculated automatically by
   ARPACK++ because ARRCNonSymGenEig do not handle matrix information.
   Other classes such as ARNonSymGenEig and ARLUNonSymGenEig do
   not require the user to define this eigenvalue transformation.
*/

{

  int      j, n, ColJ, ColJp1;
  ARFLOAT  numr, numi, denr, deni;
  ARFLOAT* Ax;

  n  = P.A.ncols();
  Ax = new ARFLOAT[n];

  for (j=0; j<nconv; j++) {

    ColJ   = j*n;
    ColJp1 = ColJ+n;

    if (EigValI[j] == (ARFLOAT)0.0) {

      // Eigenvalue is real. Computing EigVal = x'(Ax)/x'(Mx).

      P.A.MultMv(&EigVec[ColJ], Ax);
      numr = dot(n, &EigVec[ColJ], 1, Ax, 1);
      P.B.MultMv(&EigVec[ColJ], Ax);
      denr = dot(n, &EigVec[ColJ], 1, Ax, 1);
      EigValR[j] =  numr / denr;

    }
    else {

      // Eigenvalue is complex.

      // Computing x'(Ax).

      P.A.MultMv(&EigVec[ColJ], Ax);
      numr = dot(n, &EigVec[ColJ], 1, Ax, 1);
      numi = dot(n, &EigVec[ColJp1], 1, Ax, 1);
      P.A.MultMv(&EigVec[ColJp1], Ax);
      numr = numr + dot(n, &EigVec[ColJp1], 1, Ax, 1);
      numi = -numi + dot(n, &EigVec[ColJ], 1, Ax, 1);

      // Computing x'(Mx).

      P.B.MultMv(&EigVec[ColJ], Ax);
      denr = dot(n, &EigVec[ColJ], 1, Ax, 1);
      deni = dot(n, &EigVec[ColJp1], 1, Ax, 1);
      P.B.MultMv(&EigVec[ColJp1], Ax);
      denr = denr + dot(n, &EigVec[ColJp1], 1, Ax, 1);
      deni = -deni + dot(n, &EigVec[ColJ], 1, Ax, 1);

      // Computing the first eigenvalue of the conjugate pair.

      EigValR[j] = (numr*denr+numi*deni) / lapy2(denr, deni);
      EigValI[j] = (numi*denr-numr*deni) / lapy2(denr, deni);

      // Getting the second eigenvalue of the conjugate pair by taking
      // the conjugate of the first.

      EigValR[j+1] = EigValR[j];
      EigValI[j+1] = -EigValI[j];
      j++;

    }

  }

  delete[] Ax;

} // RecoverEigenvalues.


template<class T>
void Test(T type)
{

  long nconv;

  // Defining a temporary vector.

  T temp[101];

  // Creating a pencil.

  NonSymGenProblemC<T> P(100, 0.4, 0.6); // n = 100, sigma = (0.4, 0.6).

  // Creating a nonsymmetric eigenvalue problem. 'R' indicates that
  // we will use the real part of OPv. P.A.ncols() furnishes
  // the dimension of the problem. 4 is the number of eigenvalues
  // sought and 0.4 + 0.6I is the shift.

  ARrcNonSymGenEig<T> prob(P.A.ncols(), 4L, 'R', 0.4, 0.6);

  // Finding an Arnoldi basis.

  while (!prob.ArnoldiBasisFound()) {

    // Calling ARPACK FORTRAN code. Almost all work needed to
    // find an Arnoldi basis is performed by TakeStep.

    prob.TakeStep();

    switch (prob.GetIdo()) {
    case -1:

      // Performing w <- Re{OP*B*v} for the first time.
      // This product must be performed only if GetIdo is equal to
      // -1. GetVector supplies a pointer to the input vector, v,
      // and PutVector a pointer to the output vector, w.

      P.B.MultMv(prob.GetVector(), temp);
      P.MultOPvRe(temp, prob.PutVector());
      break;

    case  1:

      // Performing w <- Real{OP*B*v} when Bv is available.
      // This product must be performed whenever GetIdo is equal to
      // 1. GetProd supplies a pointer to the previously calculated
      // product Bv and PutVector a pointer to the output vector w.

      P.MultOPvRe(prob.GetProd(), prob.PutVector());
      break;

    case  2:

      // Performing w <- B*v.

      P.B.MultMv(prob.GetVector(), prob.PutVector());

    }
  }

  // Finding eigenvalues and eigenvectors.

  nconv = prob.FindEigenvectors();

  // Recovering eigenvalues of the original problem
  // using the Rayleigh quotient.

  RecoverEigenvalues(nconv, P, prob.RawEigenvectors(),
                     prob.RawEigenvalues(), prob.RawEigenvaluesImag());

  // Printing solution.

  Solution(prob);

} // Test.


int main()
{

  // Solving a single precision problem with n = 100.

#ifndef __SUNPRO_CC

  Test((float)0.0);

#endif

  // Solving a double precision problem with n = 100.

  Test((double)0.0);

} // main