ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
opt_TN.hpp
Go to the documentation of this file.
1#ifndef OPT_TN_H
2#define OPT_TN_H
3
4#include "opt_CG.h"
5
6#include <limits>
7
8namespace ModuleBase
9{
21class Opt_TN
22{
23 public:
25 {
26 this->mach_prec_ = std::numeric_limits<double>::epsilon(); // get machine precise
27 }
28 ~Opt_TN() {};
29
35 void allocate(int nx)
36 {
37 this->nx_ = nx;
38 this->cg_.allocate(this->nx_);
39 }
40
41 void set_para(double dV)
42 {
43 this->dV_ = dV;
44 this->cg_.set_para(this->dV_);
45 }
46
53 void refresh(int nx_new = 0)
54 {
55 this->iter_ = 0;
56 if (nx_new != 0)
57 {
58 this->nx_ = nx_new;
59 }
60 this->cg_.refresh(nx_new);
61 }
62
63 template <class T>
65 double* px, // current x
66 double* pgradient, // df(x)/dx
67 int& flag, // record which truncated condition was triggered, 0 for cond.1, 1 for cond.2, and 2 for cond.3
68 double* rdirect, // next optimization direction
69 T* t, // point of class T, which contains the gradient function
70 void (T::*p_calGradient)(
71 double* ptemp_x,
72 double* rtemp_gradient) // a function point, which calculates the gradient at provided x
73 );
74
76 {
77 return this->iter_;
78 }
79
80 private:
82 double dV_ = 1.;
83
84 int nx_ = 0; // length of the solution array x
85 int iter_ = 0; // number of the iteration
86 double mach_prec_ = 0.; // machine precision
87
88 double inner_product(double* pa, double* pb, int length)
89 {
90 double innerproduct = BlasConnector::dot(length, pa, 1, pb, 1);
91 innerproduct *= this->dV_;
92 return innerproduct;
93 }
94
103 double get_epsilon(double* px, double* pcg_direction)
104 {
105 double epsilon = 0.;
106 double xx = this->inner_product(px, px, this->nx_);
108 double dd = this->inner_product(pcg_direction, pcg_direction, this->nx_);
110 epsilon = 2 * sqrt(this->mach_prec_) * (1 + sqrt(xx)) / sqrt(dd);
111 // epsilon = 2 * sqrt(this->mach_prec_) * (1 + sqrt(this->inner_product(px, px, this->nx_)))
112 // / sqrt(this->inner_product(pcg_direction, pcg_direction, this->nx_));
113 return epsilon;
114 }
115};
116
128template <class T>
129void Opt_TN::next_direct(double* px,
130 double* pgradient,
131 int& flag,
132 double* rdirect,
133 T* t,
134 void (T::*p_calGradient)(double* px, double* rgradient))
135{
136 // initialize arrays and parameters
137 ModuleBase::GlobalFunc::ZEROS(rdirect, this->nx_); // very important
138
139 double* minus_gradient = new double[this->nx_]; // b=-g, which will be used in CG
140 double* temp_x = new double[this->nx_]; // temp_x = x + step * cg_direct, used in interpolation
141 double* temp_gradient = new double[this->nx_]; // df(temp_x)/dx
142 double* cg_direct = new double[this->nx_]; // rdirect += cg_alpha * cg_direct at each step
143 double* temp_Hcgd = new double[this->nx_]; // Hessian * cg_direct
144 for (int i = 0; i < this->nx_; ++i)
145 {
146 minus_gradient[i] = -pgradient[i];
147 }
148 ModuleBase::GlobalFunc::ZEROS(cg_direct, this->nx_);
149 ModuleBase::GlobalFunc::ZEROS(temp_x, this->nx_);
150 ModuleBase::GlobalFunc::ZEROS(temp_gradient, this->nx_);
151 ModuleBase::GlobalFunc::ZEROS(temp_Hcgd, this->nx_);
152
153 cg_.refresh(0, minus_gradient);
154 int cg_iter = 0;
155 int cg_ifPD = 0;
156
157 double epsilon = 0.; // step length in interpolation
158 double cg_alpha = 0.; // step length got by CG
159 double init_residual = 0.; // initial residual of CG
160 double last_residual = 0.; // last residual of CG
161 double curr_residual = 0.; // current residual of CG
162
163 while (true)
164 {
165 cg_.next_direct(temp_Hcgd, 0, cg_direct);
166
167 // get temp_Hcgd with interpolation
168 // Hcgd = (df(temp_x)/dx - df(x)/x) / epsilon, where temp_x = x + step * cg_direct
169 epsilon = this->get_epsilon(px, cg_direct);
170 // epsilon = 1e-9;
171 for (int i = 0; i < this->nx_; ++i)
172 {
173 temp_x[i] = px[i] + epsilon * cg_direct[i];
174 }
175 (t->*p_calGradient)(temp_x, temp_gradient);
176 for (int i = 0; i < this->nx_; ++i)
177 {
178 temp_Hcgd[i] = (temp_gradient[i] - pgradient[i]) / epsilon;
179 }
180
181 // get CG step length and update rdirect
182 cg_alpha = cg_.step_length(temp_Hcgd, cg_direct, cg_ifPD);
183 if (cg_ifPD == -1) // Hessian is not positive definite, and cgiter = 1.
184 {
185 for (int i = 0; i < this->nx_; ++i)
186 {
187 rdirect[i] += cg_alpha * cg_direct[i];
188 }
189 flag = -1;
190 break;
191 }
192 else if (cg_ifPD == -2) // Hessian is not positive definite, and cgiter > 1.
193 {
194 flag = -2;
195 break;
196 }
197
198 for (int i = 0; i < this->nx_; ++i)
199 {
200 rdirect[i] += cg_alpha * cg_direct[i];
201 }
202
203 // store residuals used in truncated conditions
204 last_residual = curr_residual;
205 curr_residual = cg_.get_residual();
206 cg_iter = cg_.get_iter();
207 if (cg_iter == 1)
208 {
209 init_residual = curr_residual;
210 }
211
212 // check truncated conditions
213 // if (curr_residual < 1e-12)
214 if (curr_residual < 0.1 * init_residual)
215 {
216 flag = 0;
217 // std::cout << "cg_ iter_ = " << cg_iter << "\n";
218 break;
219 }
220 else if (cg_iter > 50)
221 {
222 flag = 1;
223 break;
224 }
225 else if ((fabs(curr_residual - last_residual) / curr_residual) < 0.01 && cg_iter > 9)
226 {
227 flag = 2;
228 break;
229 }
230 }
231 this->iter_++;
232 delete[] minus_gradient;
233 delete[] temp_gradient;
234 delete[] temp_x;
235 delete[] temp_Hcgd;
236 delete[] cg_direct;
237}
238} // namespace ModuleBase
239#endif
static float dot(const int n, const float *const X, const int incX, const float *const Y, const int incY, base_device::AbacusDevice_t device_type=base_device::AbacusDevice_t::CpuDevice)
Definition blas_connector_vector.cpp:142
A class designed to deal with optimization problems with CG method. Three forms of CG methods have be...
Definition opt_CG.h:25
void allocate(int nx)
Allocate the space for pdirect_old and pgradient_old.
Definition opt_CG.cpp:36
double get_residual()
Definition opt_CG.h:48
int get_iter()
Definition opt_CG.h:52
void next_direct(double *pgradient, int label, double *rdirect)
Get the next optimization direction.
Definition opt_CG.cpp:85
void refresh(int nx_new=0, double *pinp_b=nullptr)
Refresh the class. If nx changes, reallocate space. If b is provided, initialize it.
Definition opt_CG.cpp:59
void set_para(double dV)
Definition opt_CG.cpp:47
double step_length(double *pAd, double *pdirect, int &ifPD)
Get the step length, only work for standard CG.
Definition opt_CG.cpp:131
A class designed to deal with optimization problems with Truncated-Newton (TN) method....
Definition opt_TN.hpp:22
Opt_CG cg_
Definition opt_TN.hpp:81
double get_epsilon(double *px, double *pcg_direction)
Get epsilon used in interpolation. epsilon = 2*sqrt(mach_prec_) * (1+|x|) / |d|. || means modulu.
Definition opt_TN.hpp:103
void next_direct(double *px, double *pgradient, int &flag, double *rdirect, T *t, void(T::*p_calGradient)(double *ptemp_x, double *rtemp_gradient))
double dV_
Definition opt_TN.hpp:82
double inner_product(double *pa, double *pb, int length)
Definition opt_TN.hpp:88
int nx_
Definition opt_TN.hpp:84
~Opt_TN()
Definition opt_TN.hpp:28
void refresh(int nx_new=0)
Refresh the class. If nx changes, reallocate space in cg_.
Definition opt_TN.hpp:53
Opt_TN()
Definition opt_TN.hpp:24
int get_iter()
Definition opt_TN.hpp:75
double mach_prec_
Definition opt_TN.hpp:86
void allocate(int nx)
Allocate the space for the arrays in cg_.
Definition opt_TN.hpp:35
void set_para(double dV)
Definition opt_TN.hpp:41
int iter_
Definition opt_TN.hpp:85
#define T
Definition exp.cpp:237
void ZEROS(std::complex< T > *u, const TI n)
Definition global_function.h:109
Definition array_pool.h:6
void reduce_all(T &object)
reduce in all process
Definition depend_mock.cpp:14