TiledArray  0.7.0
conjgrad.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 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 General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Eduard Valeyev
19  * Department of Chemistry, Virginia Tech
20  *
21  * conjgrad.h
22  * May 20, 2013
23  *
24  */
25 
26 #ifndef TILEDARRAY_ALGEBRA_CONJGRAD_H__INCLUDED
27 #define TILEDARRAY_ALGEBRA_CONJGRAD_H__INCLUDED
28 
29 #include <sstream>
32 #include "../dist_array.h"
33 
34 namespace TiledArray {
35 
38 
55  template <typename D, typename F>
57  typedef typename D::element_type value_type;
58 
66  value_type operator()(F& a, const D& b, D& x, const D& preconditioner,
67  value_type convergence_target = -1.0)
68  {
69 
70  std::size_t n = size(x);
71  assert(n == size(preconditioner));
72 
73  const bool use_diis = false;
74  DIIS<D> diis;
75 
76  // solution vector
77  D XX_i;
78  // residual vector
79  D RR_i = clone(b);
80  // preconditioned residual vector
81  D ZZ_i;
82  // direction vector
83  D PP_i;
84  D APP_i = clone(b);
85 
86  // approximate the condition number as the ratio of the min and max elements of the preconditioner
87  // assuming that preconditioner is the approximate inverse of A in Ax - b =0
88  const value_type precond_min = minabs_value(preconditioner);
89  const value_type precond_max = maxabs_value(preconditioner);
90  const value_type cond_number = precond_max / precond_min;
91  //std::cout << "condition number = " << precond_max << " / " << precond_min << " = " << cond_number << std::endl;
92  // if convergence target is given, estimate of how tightly the system can be converged
93  if (convergence_target < 0.0) {
94  convergence_target = 1e-15 * cond_number;
95  }
96  else { // else warn if the given system is not sufficiently well conditioned
97  if (convergence_target < 1e-15 * cond_number)
98  std::cout << "WARNING: ConjugateGradient convergence target (" << convergence_target
99  << ") may be too low for 64-bit precision" << std::endl;
100  }
101 
102  bool converged = false;
103  const unsigned int max_niter = n;
104  value_type rnorm2 = 0.0;
105  const std::size_t rhs_size = size(b);
106 
107  // starting guess: x_0 = D^-1 . b
108  XX_i = copy(b);
109  vec_multiply(XX_i, preconditioner);
110 
111  // r_0 = b - a(x)
112  a(XX_i, RR_i); // RR_i = a(XX_i)
113  scale(RR_i, -1.0);
114  axpy(RR_i, 1.0, b); // RR_i = b - a(XX_i)
115 
116  if (use_diis)
117  diis.extrapolate(XX_i, RR_i, true);
118 
119  // z_0 = D^-1 . r_0
120  ZZ_i = copy(RR_i);
121  vec_multiply(ZZ_i, preconditioner);
122 
123  // p_0 = z_0
124  PP_i = copy(ZZ_i);
125 
126  unsigned int iter = 0;
127  while (not converged) {
128 
129  // alpha_i = (r_i . z_i) / (p_i . A . p_i)
130  value_type rz_norm2 = dot_product(RR_i, ZZ_i);
131  a(PP_i,APP_i);
132 
133  const value_type pAp_i = dot_product(PP_i, APP_i);
134  const value_type alpha_i = rz_norm2 / pAp_i;
135 
136  // x_i += alpha_i p_i
137  axpy(XX_i, alpha_i, PP_i);
138 
139  // r_i -= alpha_i Ap_i
140  axpy(RR_i, -alpha_i, APP_i);
141 
142  if (use_diis)
143  diis.extrapolate(XX_i, RR_i, true);
144 
145  const value_type r_ip1_norm = norm2(RR_i) / rhs_size;
146  if (r_ip1_norm < convergence_target) {
147  converged = true;
148  rnorm2 = r_ip1_norm;
149  }
150 
151  // z_i = D^-1 . r_i
152  ZZ_i = copy(RR_i);
153  vec_multiply(ZZ_i, preconditioner);
154 
155  const value_type rz_ip1_norm2 = dot_product(ZZ_i, RR_i);
156 
157  const value_type beta_i = rz_ip1_norm2 / rz_norm2;
158 
159  // p_i = z_i+1 + beta_i p_i
160  // 1) scale p_i by beta_i
161  // 2) add z_i+1 (i.e. current contents of z_i)
162  scale(PP_i, beta_i);
163  axpy(PP_i, 1.0, ZZ_i);
164 
165  ++iter;
166  //std::cout << "iter=" << iter << " dnorm=" << r_ip1_norm << std::endl;
167 
168  if (iter >= max_niter) {
169  assign(x, XX_i);
170  throw std::domain_error("ConjugateGradient: max # of iterations exceeded");
171  }
172  } // solver loop
173 
174  assign(x, XX_i);
175 
176  return rnorm2;
177  }
178  };
179 
180 };
181 
182 #endif // TILEDARRAY_ALGEBRA_CONJGRAD_H__INCLUDED
DistArray< Tile, Policy >::scalar_type norm2(const DistArray< Tile, Policy > &a)
Definition: utils.h:130
void scale(DistArray< Tile, Policy > &a, typename DistArray< Tile, Policy >::element_type scaling_factor)
Definition: utils.h:108
value_type operator()(F &a, const D &b, D &x, const D &preconditioner, value_type convergence_target=-1.0)
Definition: conjgrad.h:66
DistArray< Tile, Policy >::element_type maxabs_value(const DistArray< Tile, Policy > &a)
Definition: utils.h:76
size_t size(const DistArray< Tile, Policy > &a)
Definition: utils.h:49
DistArray< Tile, Policy > clone(const DistArray< Tile, Policy > &arg)
Create a deep copy of an array.
Definition: clone.h:43
void axpy(DistArray< Tile, Policy > &y, typename DistArray< Tile, Policy >::element_type a, const DistArray< Tile, Policy > &x)
Definition: utils.h:115
void vec_multiply(DistArray< Tile, Policy > &a1, const DistArray< Tile, Policy > &a2)
Definition: utils.h:81
DistArray< Tile, Policy > copy(const DistArray< Tile, Policy > &a)
Definition: utils.h:58
DIIS (‘‘direct inversion of iterative subspace’’) extrapolation.
Definition: diis.h:81
void extrapolate(D &x, D &error, bool extrapolate_error=false)
Definition: diis.h:136
DistArray< Tile, Policy >::element_type minabs_value(const DistArray< Tile, Policy > &a)
Definition: utils.h:70
DistArray< Tile, Policy >::element_type dot_product(const DistArray< Tile, Policy > &a1, const DistArray< Tile, Policy > &a2)
Definition: utils.h:89
void assign(DistArray< Tile, Policy > &m1, const DistArray< Tile, Policy > &m2)
Definition: utils.h:123