CHROMA
sn_jacob_array.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief Single-node Jacobi routine
3  */
4 
5 #include "chromabase.h"
7 
8 namespace Chroma {
9 
10 //! Single-node Jacobi rotation
11 /*!
12  * \ingroup eig
13  *
14  * This subroutine contains a "single node" Jacobi routine
15  * to be used with the Ritz functional eigenvialue/std::vector finder.
16  *
17  *
18  * Psi Eigenvectors (Modify)
19  * N_eig Eigenvalue number (Read)
20  * lambda Diagonals / Eigenvalues (Modify)
21  * off_diag Upper triang off-diag matrix elems (Modify)
22  * Toler Tolerance for off-diag elems (Read)
23  * N_max Maximal number of Jacobi iters (Read)
24  * Ncb Number of sublattices (Read)
25  * \param sub Subset to use (Read)
26  *
27  * \return Number of Jacobi iters (Write)
28  */
29 template <typename T>
30 int SN_Jacob_Array_t(multi2d<T>& psi,
31  const int N_eig,
32  multi1d<Real>& lambda,
33  multi1d<Complex>& off_diag,
34  Real tolerance,
35  int N_max,
36  const Subset& sub)
37 {
38  START_CODE();
39 
40  int N5 = psi.size1();
41 
42  int n_count;
43  multi1d<T> psi_t1(N5);
44  multi1d<T> psi_t2(N5);
45  Complex ctmp1;
46  Complex ctmp2;
47  Complex v12;
48  Complex v21;
49  Real v11;
50  Real dd;
51  Real ftmp;
52  Real diff_l;
53  Real theta;
54  Real t;
55  Real acc;
56  Real c;
57  Real s;
58  Real al1;
59  Real al2;
60  int i;
61  int j;
62  int ij;
63  int m;
64  int mi;
65  int mj;
66  int i_rot;
67  int k;
68 
69  Real tol_sq = tolerance * tolerance;
70 
71  for(k = 1; k <= N_max; k++)
72  {
73  i_rot = 0;
74  ij = 0;
75 
76  for(j = 1; j < N_eig; j++)
77  {
78  for(i = 0; i < j; i++)
79  {
80  dd = real(conj(off_diag[ij]) * off_diag[ij]);
81  ftmp = fabs(tol_sq * lambda[i] * lambda[j]);
82 
83  if( toBool( dd > ftmp) )
84  {
85  // Make a rotation to set off-diagonal part to zero
86  i_rot++;
87  dd = sqrt(dd);
88 
89  acc = Real(100) * dd;
90 
91  diff_l = lambda[j] - lambda[i];
92  ftmp = fabs(diff_l);
93 
94  if( toBool( (ftmp+acc) == ftmp ) )
95  {
96  t = dd / diff_l;
97  }
98  else
99  {
100  theta = Real(0.5) * diff_l / dd;
101  t = sqrt(Real(1) + theta*theta);
102  ftmp = fabs(theta);
103  t = Real(1) / (ftmp+t);
104  if( toBool( theta < Real(0) ) ) {
105  t = -t;
106  }
107  }
108 
109  if( toBool( diff_l >= Real(0) ) ) {
110  c = Real(1) / sqrt( Real(1) + t*t);
111  s = - t * c;
112  }
113  else
114  {
115  s = Real(1) / sqrt( Real(1) + t*t);
116  c = t * s;
117  }
118 
119  ftmp = c * c;
120  al1 = ftmp * lambda[i];
121  al2 = ftmp * lambda[j];
122  ftmp = s * s;
123  al1 += ftmp * lambda[j];
124  al2 += ftmp * lambda[i];
125  ftmp = Real(2) * dd * s * c;
126  al1 += ftmp;
127  al2 -= ftmp;
128  lambda[i] = al1;
129  lambda[j] = al2;
130  v11 = c;
131  v12 = (s / dd) * off_diag[ij];
132  v21 = -conj(v12);
133  off_diag[ij] = Real(0);
134 
135  // Now rotate the eigenvectors */
136  for(int n=0; n < N5; n++) {
137  psi_t1[n][sub] = psi[i][n] * v11;
138 
139  /* psi_t1 += psi[j][cb] * adj(v12); Wrong?? */
140  psi_t1[n][sub] -= psi[j][n] * v21;
141  psi_t2[n][sub] = psi[j][n] * v11;
142  psi_t2[n][sub] -= psi[i][n] * v12;
143  psi[i][n][sub] = psi_t1[n];
144  psi[j][n][sub] = psi_t2[n];
145  }
146 
147  // Rotate the other matrix elements
148  for(m = 0; m < N_eig; m++) {
149  if( m != i && m != j ) {
150 
151  if( m < i ) {
152 
153  mi = i * (i-1) / 2 + m;
154  mj = j * (j-1) / 2 + m;
155  ctmp1 = off_diag[mi] * v11;
156  /* ctmp1 += off_diag[mj] * adj(v12); ok */
157  ctmp1 -= off_diag[mj] * v21;
158  ctmp2 = off_diag[mj] * v11;
159  ctmp2 -= off_diag[mi] * v12;
160  off_diag[mi] = ctmp1;
161  off_diag[mj] = ctmp2;
162  }
163  else if( m < j) {
164 
165  mi = m * (m-1) / 2 + i;
166  mj = j * (j-1) / 2 + m;
167  ctmp1 = conj(off_diag[mi]) * v11;
168  ctmp1 -= off_diag[mj] * v21;
169  ctmp2 = off_diag[mj] * v11;
170  ctmp2 -= conj(off_diag[mi]) * v12;
171  off_diag[mi] = conj(ctmp1);
172  off_diag[mj] = ctmp2;
173  }
174  else {
175 
176  mi = m * (m-1) / 2 + i;
177  mj = m * (m-1) / 2 + j;
178  ctmp1 = conj(off_diag[mi]) * v11;
179  ctmp1 -= conj(off_diag[mj]) * v21;
180  ctmp2 = conj(off_diag[mj]) * v11;
181  ctmp2 -= conj(off_diag[mi]) * v12;
182  off_diag[mi] = conj(ctmp1);
183  off_diag[mj] = conj(ctmp2);
184  }
185  }
186  }
187  }
188 
189  ij++;
190  }
191  }
192 
193  if( i_rot == 0 )
194  {
195  n_count = k;
196  QDPIO::cout << "Jacobi converged after " << k << " iters" << std::endl;
197 
198  // Sort the eigenvalues
199  // In order of increasing modulus
200  for(j = 1; j < N_eig; j++)
201  {
202  for(i = 0; i < j; i++)
203  {
204  ftmp = fabs(lambda[j]);
205  dd = fabs(lambda[i]);
206 
207  // if( | lambda[j] | < | lambda[i] | )
208  if( toBool( ftmp < dd ) )
209  {
210  ftmp = lambda[i];
211  lambda[i] = lambda[j];
212  lambda[j] = ftmp;
213 
214  for(int n=0; n < N5; n++)
215  {
216  psi_t1[n][sub] = psi[i][n];
217  psi[i][n][sub] = psi[j][n];
218  psi[j][n][sub] = psi_t1[n];
219  }
220  }
221  }
222  }
223  END_CODE();
224  return n_count;
225  }
226  }
227 
228  n_count = k;
229  QDP_error_exit("too many Jacobi iterations: %d\n" ,k);
230  END_CODE();
231 
232  return n_count;
233 }
234 
235 
236 int SN_Jacob_Array(multi2d<LatticeFermion>& psi,
237  const int N_eig,
238  multi1d<Real>& lambda,
239  multi1d<Complex>& off_diag,
240  Real tolerance,
241  int N_max,
242  const Subset& sub)
243 {
244  return SN_Jacob_Array_t(psi, N_eig, lambda, off_diag, tolerance, N_max, sub);
245 }
246 
247 } // end namespace Chroma
Primary include file for CHROMA library code.
int SN_Jacob_Array_t(multi2d< T > &psi, const int N_eig, multi1d< Real > &lambda, multi1d< Complex > &off_diag, Real tolerance, int N_max, const Subset &sub)
Single-node Jacobi rotation.
int SN_Jacob_Array(multi2d< LatticeFermion > &psi, const int N_eig, multi1d< Real > &lambda, multi1d< Complex > &off_diag, Real tolerance, int N_max, const Subset &sub)
Single-node Jacobi rotation.
unsigned j
Definition: ldumul_w.cc:35
unsigned n
Definition: ldumul_w.cc:36
static int m[4]
Definition: make_seeds.cc:16
int t
Definition: meslate.cc:37
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
QDP_error_exit("too many BiCG iterations", n_count, rsd_sq, cp, c, re_rvr, im_rvr, re_a, im_a, re_b, im_b)
int n_count
Definition: invbicg.cc:78
Double c
Definition: invbicg.cc:108
int i
Definition: pbg5p_w.cc:55
LatticeFermion psi
Definition: mespbg5p_w.cc:35
START_CODE()
int k
Definition: invbicg.cc:119
multi1d< LatticeFermion > s(Ncb)