QUDA  0.9.0
inv_mre.cpp
Go to the documentation of this file.
1 #include <invert_quda.h>
2 #include <blas_quda.h>
3 
4 #ifdef EIGEN
5 #include <Eigen/Dense>
6 #endif
7 
8 namespace quda {
9 
10  MinResExt::MinResExt(DiracMatrix &mat, bool orthogonal, bool apply_mat, TimeProfile &profile)
11  : mat(mat), orthogonal(orthogonal), apply_mat(apply_mat), profile(profile){
12 
13  }
14 
16 
17  }
18 
19 #ifdef EIGEN
20 
29  void solve(Complex *psi_, std::vector<ColorSpinorField*> &p, std::vector<ColorSpinorField*> &q, ColorSpinorField &b) {
30 
31  using namespace Eigen;
32  typedef Matrix<Complex, Dynamic, Dynamic> matrix;
33  typedef Matrix<Complex, Dynamic, 1> vector;
34 
35  vector phi(p.size()), psi(p.size());
36  matrix A(p.size(),p.size());
37 
38  for (unsigned int i=0; i<p.size(); i++) phi(i) = blas::cDotProduct(*p[i], b);
39 
40  // Construct the matrix
41  for (unsigned int j=0; j<p.size(); j++) {
42  A(j,j) = blas::cDotProduct(*q[j], *p[j]);
43  for (unsigned int k=j+1; k<p.size(); k++) {
44  A(j,k) = blas::cDotProduct(*p[j], *q[k]);
45  A(k,j) = conj(A(j,k));
46  }
47  }
48  JacobiSVD<matrix> svd(A, ComputeThinU | ComputeThinV);
49  psi = svd.solve(phi);
50 
51  for (unsigned int i=0; i<p.size(); i++) psi_[i] = psi(i);
52  }
53 
54 #else
55 
64  void solve(Complex *psi, std::vector<ColorSpinorField*> &p, std::vector<ColorSpinorField*> &q, ColorSpinorField &b) {
65 
66  const int N = p.size();
67 
68  // Array to hold the matrix elements
69  Complex **A = new Complex*[N];
70  for (int i=0; i<N; i++) A[i] = new Complex[N];
71 
72  // Solution and source vectors
73  Complex *phi = new Complex[N];
74 
75  // construct right hand side
76  for (unsigned int i=0; i<p.size(); i++) phi[i] = blas::cDotProduct(*p[i], b);
77 
78  // Construct the matrix
79  for (unsigned int j=0; j<p.size(); j++) {
80  A[j][j] = blas::cDotProduct(*q[j], *p[j]);
81  for (unsigned int k=j+1; k<p.size(); k++) {
82  A[j][k] = blas::cDotProduct(*p[j], *q[k]);
83  A[k][j] = conj(A[j][k]);
84  }
85  }
86 
87  // Gauss-Jordan elimination with partial pivoting
88  for (int i=0; i<N; i++) {
89 
90  // Perform partial pivoting
91  int k = i;
92  for (int j=i+1; j<N; j++) if (abs(A[j][j]) > abs(A[k][k])) k = j;
93  if (k != i) {
94  std::swap<Complex>(phi[k], phi[i]);
95  for (int j=0; j<N; j++) std::swap<Complex>(A[k][j], A[i][j]);
96  }
97 
98  // Convert matrix to upper triangular form
99  for (int j=i+1; j<N; j++) {
100  Complex xp = A[j][i]/A[i][i];
101  phi[j] -= xp * phi[i];
102  for (int k=0; k<N; k++) A[j][k] -= xp * A[i][k];
103  }
104  }
105 
106  // Use Gaussian Elimination to solve equations and calculate initial guess
107  for (int i=N-1; i>=0; i--) {
108  psi[i] = 0.0;
109  for (int j=i+1; j<N; j++) psi[i] += A[i][j] * psi[j];
110  psi[i] = (phi[i]-psi[i])/A[i][i];
111  }
112 
113  for (int j=0; j<N; j++) delete [] A[j];
114  delete [] A;
115 
116  delete [] phi;
117  }
118 
119 #endif // EIGEN
120 
121 
122  /*
123  We want to find the best initial guess of the solution of
124  A x = b, and we have N previous solutions x_i.
125  The method goes something like this:
126 
127  1. Orthonormalise the p_i and q_i
128  2. Form the matrix G_ij = x_i^dagger A x_j
129  3. Form the vector B_i = x_i^dagger b
130  4. solve A_ij a_j = B_i
131  5. x = a_i p_i
132  */
134  std::vector<ColorSpinorField*> p, std::vector<ColorSpinorField*> q) {
135 
136  profile.TPSTART(QUDA_PROFILE_INIT);
137 
138  const int N = p.size();
139 
140  if (getVerbosity() >= QUDA_SUMMARIZE) printfQuda("Constructing minimum residual extrapolation with basis size %d\n", N);
141 
142  // if no guess is required, then set initial guess = 0
143  if (N == 0) {
144  blas::zero(x);
145  return;
146  }
147 
148  // Solution coefficient vectors
149  Complex *alpha = new Complex[N];
150  Complex *minus_alpha = new Complex[N];
151 
152  profile.TPSTOP(QUDA_PROFILE_INIT);
154 
155  double b2 = blas::norm2(b);
156 
157  // Orthonormalise the vector basis
158  if (orthogonal) {
159  for (int i=0; i<N; i++) {
160  double p2 = blas::norm2(*p[i]);
161  blas::ax(1 / sqrt(p2), *p[i]);
162  if (!apply_mat) blas::ax(1 / sqrt(p2), *q[i]);
163  for (int j=i+1; j<N; j++) {
164  Complex xp = blas::cDotProduct(*p[i], *p[j]);
165  blas::caxpy(-xp, *p[i], *p[j]);
166  // if not applying the matrix below then orthongonalize q
167  if (!apply_mat) blas::caxpy(-xp, *q[i], *q[j]);
168  }
169  }
170  }
171 
173  profile.TPSTART(QUDA_PROFILE_COMPUTE);
174 
175 
176  // if operator hasn't already been applied then apply
177  if (apply_mat) for (int i=0; i<N; i++) mat(*q[i], *p[i]);
178 
179  solve(alpha, p, q, b);
180 
181  for (int i=0; i<N; i++) minus_alpha[i] = -alpha[i];
182 
183  blas::zero(x);
184  std::vector<ColorSpinorField*> X, B;
185  X.push_back(&x); B.push_back(&b);
186  blas::caxpy(alpha, p, X);
187  blas::caxpy(minus_alpha, q, B);
188 
189  double rsd = sqrt(blas::norm2(b) / b2 );
190  if (getVerbosity() >= QUDA_SUMMARIZE) printfQuda("MinResExt: N = %d, |res| / |src| = %e\n", N, rsd);
191 
192 
194  profile.TPSTART(QUDA_PROFILE_FREE);
195 
196  delete [] minus_alpha;
197  delete [] alpha;
198 
199  profile.TPSTOP(QUDA_PROFILE_FREE);
200  }
201 
202  // Wrapper for the above
203  void MinResExt::operator()(ColorSpinorField &x, ColorSpinorField &b, std::vector<std::pair<ColorSpinorField*,ColorSpinorField*> > basis) {
204  std::vector<ColorSpinorField*> p(basis.size()), q(basis.size());
205  for (unsigned int i=0; i<basis.size(); i++) { p[i] = basis[i].first; q[i] = basis[i].second; }
206  (*this)(x, b, p, q);
207  }
208 
209 
210 
211 } // namespace quda
QudaVerbosity getVerbosity()
Definition: util_quda.cpp:20
double norm2(const ColorSpinorField &a)
Definition: reduce_quda.cu:241
void operator()(ColorSpinorField &x, ColorSpinorField &b, std::vector< std::pair< ColorSpinorField *, ColorSpinorField *> > basis)
Definition: inv_mre.cpp:203
__host__ __device__ ValueType sqrt(ValueType x)
Definition: complex_quda.h:105
Complex cDotProduct(ColorSpinorField &, ColorSpinorField &)
Definition: reduce_quda.cu:500
std::complex< double > Complex
Definition: eig_variables.h:13
void ax(const double &a, ColorSpinorField &x)
Definition: blas_quda.cu:209
void solve(Complex *psi, std::vector< ColorSpinorField *> &p, std::vector< ColorSpinorField *> &q, ColorSpinorField &b)
Solve the equation A p_k psi_k = b by minimizing the residual and using Gaussian elimination.
Definition: inv_mre.cpp:64
#define b
TimeProfile & profile
Whether to compute q = Ap or assume it is provided.
Definition: invert_quda.h:777
static __inline__ size_t p
void caxpy(const Complex &a, ColorSpinorField &x, ColorSpinorField &y)
Definition: blas_quda.cu:246
void zero(ColorSpinorField &a)
Definition: blas_quda.cu:45
bool apply_mat
Whether to construct an orthogonal basis or not.
Definition: invert_quda.h:776
virtual ~MinResExt()
Definition: inv_mre.cpp:15
#define printfQuda(...)
Definition: util_quda.h:84
__host__ __device__ ValueType abs(ValueType x)
Definition: complex_quda.h:110
__host__ __device__ ValueType conj(ValueType x)
Definition: complex_quda.h:115
void mat(void *out, void **link, void *in, int dagger_bit, int mu, QudaPrecision sPrecision, QudaPrecision gPrecision)
const DiracMatrix & mat
Definition: invert_quda.h:774
MinResExt(DiracMatrix &mat, bool orthogonal, bool apply_mat, TimeProfile &profile)
Definition: inv_mre.cpp:10