Grid 0.7.0
Chebyshev.h
Go to the documentation of this file.
1/*************************************************************************************
2
3 Grid physics library, www.github.com/paboyle/Grid
4
5 Source file: ./lib/algorithms/approx/Chebyshev.h
6
7 Copyright (C) 2015
8
9Author: Peter Boyle <paboyle@ph.ed.ac.uk>
10Author: paboyle <paboyle@ph.ed.ac.uk>
11Author: Christoph Lehner <clehner@bnl.gov>
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License along
24 with this program; if not, write to the Free Software Foundation, Inc.,
25 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26
27 See the full license in the file "LICENSE" in the top level distribution directory
28*************************************************************************************/
29/* END LEGAL */
30#ifndef GRID_CHEBYSHEV_H
31#define GRID_CHEBYSHEV_H
32
34
36
37struct ChebyParams : Serializable {
39 RealD, alpha,
40 RealD, beta,
41 int, Npoly);
42};
43
45// Generic Chebyshev approximations
47template<class Field>
48class Chebyshev : public OperatorFunction<Field> {
49private:
50 using OperatorFunction<Field>::operator();
51
52 std::vector<RealD> Coeffs;
53 int order;
56
57public:
58 void csv(std::ostream &out){
59 RealD diff = hi-lo;
60 RealD delta = diff*1.0e-9;
61 for (RealD x=lo; x<hi; x+=delta) {
62 delta*=1.02;
63 RealD f = approx(x);
64 out<< x<<" "<<f<<std::endl;
65 }
66 return;
67 }
68
69 // Convenience for plotting the approximation
70 void PlotApprox(std::ostream &out) {
71 out<<"Polynomial approx ["<<lo<<","<<hi<<"]"<<std::endl;
72 for(RealD x=lo;x<hi;x+=(hi-lo)/50.0){
73 out <<x<<"\t"<<approx(x)<<std::endl;
74 }
75 };
76
78 Chebyshev(ChebyParams p){ Init(p.alpha,p.beta,p.Npoly);};
79 Chebyshev(RealD _lo,RealD _hi,int _order, RealD (* func)(RealD) ) {Init(_lo,_hi,_order,func);};
80 Chebyshev(RealD _lo,RealD _hi,int _order) {Init(_lo,_hi,_order);};
81
83 // c.f. numerical recipes "chebft"/"chebev". This is sec 5.8 "Chebyshev approximation".
85 // CJ: the one we need for Lanczos
86 void Init(RealD _lo,RealD _hi,int _order)
87 {
88 lo=_lo;
89 hi=_hi;
90 order=_order;
91
92 if(order < 2) exit(-1);
93 Coeffs.resize(order,0.0);
94 Coeffs[order-1] = 1.0;
95 };
96
97 // PB - more efficient low pass drops high modes above the low as 1/x uses all Chebyshev's.
98 // Similar kick effect below the threshold as Lanczos filter approach
99 void InitLowPass(RealD _lo,RealD _hi,int _order)
100 {
101 lo=_lo;
102 hi=_hi;
103 order=_order;
104
105 if(order < 2) exit(-1);
106 Coeffs.resize(order);
107 for(int j=0;j<order;j++){
108 RealD k=(order-1.0);
109 RealD s=std::cos( j*M_PI*(k+0.5)/order );
110 Coeffs[j] = s * 2.0/order;
111 }
112
113 };
114
115 void Init(RealD _lo,RealD _hi,int _order, RealD (* func)(RealD))
116 {
117 lo=_lo;
118 hi=_hi;
119 order=_order;
120
121 if(order < 2) exit(-1);
122 Coeffs.resize(order);
123 for(int j=0;j<order;j++){
124 RealD s=0;
125 for(int k=0;k<order;k++){
126 RealD y=std::cos(M_PI*(k+0.5)/order);
127 RealD x=0.5*(y*(hi-lo)+(hi+lo));
128 RealD f=func(x);
129 s=s+f*std::cos( j*M_PI*(k+0.5)/order );
130 }
131 Coeffs[j] = s * 2.0/order;
132 }
133 };
134 template<class functor>
135 void Init(RealD _lo,RealD _hi,int _order, functor & func)
136 {
137 lo=_lo;
138 hi=_hi;
139 order=_order;
140
141 if(order < 2) exit(-1);
142 Coeffs.resize(order);
143 for(int j=0;j<order;j++){
144 RealD s=0;
145 for(int k=0;k<order;k++){
146 RealD y=std::cos(M_PI*(k+0.5)/order);
147 RealD x=0.5*(y*(hi-lo)+(hi+lo));
148 RealD f=func(x);
149 s=s+f*std::cos( j*M_PI*(k+0.5)/order );
150 }
151 Coeffs[j] = s * 2.0/order;
152 }
153 };
154
155
156 void JacksonSmooth(void){
157 RealD M=order;
158 RealD alpha = M_PI/(M+2);
159 RealD lmax = std::cos(alpha);
160 RealD sumUsq =0;
161 std::vector<RealD> U(M);
162 std::vector<RealD> a(M);
163 std::vector<RealD> g(M);
164 for(int n=0;n<=M;n++){
165 U[n] = std::sin((n+1)*std::acos(lmax))/std::sin(std::acos(lmax));
166 sumUsq += U[n]*U[n];
167 }
168 sumUsq = std::sqrt(sumUsq);
169
170 for(int i=1;i<=M;i++){
171 a[i] = U[i]/sumUsq;
172 }
173 g[0] = 1.0;
174 for(int m=1;m<=M;m++){
175 g[m] = 0;
176 for(int i=0;i<=M-m;i++){
177 g[m]+= a[i]*a[m+i];
178 }
179 }
180 for(int m=1;m<=M;m++){
181 Coeffs[m]*=g[m];
182 }
183 }
184 RealD approx(RealD x) // Convenience for plotting the approximation
185 {
186 RealD Tn;
187 RealD Tnm;
188 RealD Tnp;
189
190 RealD y=( x-0.5*(hi+lo))/(0.5*(hi-lo));
191
192 RealD T0=1;
193 RealD T1=y;
194
195 RealD sum;
196 sum = 0.5*Coeffs[0]*T0;
197 sum+= Coeffs[1]*T1;
198
199 Tn =T1;
200 Tnm=T0;
201 for(int i=2;i<order;i++){
202 Tnp=2*y*Tn-Tnm;
203 Tnm=Tn;
204 Tn =Tnp;
205 sum+= Tn*Coeffs[i];
206 }
207 return sum;
208 };
209
211 {
212 RealD Un;
213 RealD Unm;
214 RealD Unp;
215
216 RealD y=( x-0.5*(hi+lo))/(0.5*(hi-lo));
217
218 RealD U0=1;
219 RealD U1=2*y;
220
221 RealD sum;
222 sum = Coeffs[1]*U0;
223 sum+= Coeffs[2]*U1*2.0;
224
225 Un =U1;
226 Unm=U0;
227 for(int i=2;i<order-1;i++){
228 Unp=2*y*Un-Unm;
229 Unm=Un;
230 Un =Unp;
231 sum+= Un*Coeffs[i+1]*(i+1.0);
232 }
233 return sum/(0.5*(hi-lo));
234 };
235
236 RealD approxInv(RealD z, RealD x0, int maxiter, RealD resid) {
237 RealD x = x0;
238 RealD eps;
239
240 int i;
241 for (i=0;i<maxiter;i++) {
242 eps = approx(x) - z;
243 if (fabs(eps / z) < resid)
244 return x;
245 x = x - eps / approxD(x);
246 }
247
248 return std::numeric_limits<double>::quiet_NaN();
249 }
250
251 // Implement the required interface
252 void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) {
253
254 GridBase *grid=in.Grid();
255
256 int vol=grid->gSites();
257 typedef typename Field::vector_type vector_type;
258
259 Field T0(grid); T0 = in;
260 Field T1(grid);
261 Field T2(grid);
262 Field y(grid);
263
264 Field *Tnm = &T0;
265 Field *Tn = &T1;
266 Field *Tnp = &T2;
267
268 // Tn=T1 = (xscale M + mscale)in
269 RealD xscale = 2.0/(hi-lo);
270 RealD mscale = -(hi+lo)/(hi-lo);
271 Linop.HermOp(T0,y);
272 grid->Barrier();
273 axpby(T1,xscale,mscale,y,in);
274 grid->Barrier();
275
276 // sum = .5 c[0] T0 + c[1] T1
277 // out = ()*T0 + Coeffs[1]*T1;
278 axpby(out,0.5*Coeffs[0],Coeffs[1],T0,T1);
279 for(int n=2;n<order;n++){
280
281 Linop.HermOp(*Tn,y);
282 axpby(y,xscale,mscale,y,(*Tn));
283 axpby(*Tnp,2.0,-1.0,y,(*Tnm));
284 if ( Coeffs[n] != 0.0) {
285 axpy(out,Coeffs[n],*Tnp,out);
286 }
287
288 // Cycle pointers to avoid copies
289 Field *swizzle = Tnm;
290 Tnm =Tn;
291 Tn =Tnp;
292 Tnp =swizzle;
293
294 }
295 }
296};
297
298
299template<class Field>
300class ChebyshevLanczos : public Chebyshev<Field> {
301private:
302 std::vector<RealD> Coeffs;
303 int order;
307
308public:
309 ChebyshevLanczos(RealD _alpha,RealD _beta,RealD _mu,int _order) :
310 alpha(_alpha),
311 beta(_beta),
312 mu(_mu)
313 {
314 order=_order;
315 Coeffs.resize(order);
316 for(int i=0;i<_order;i++){
317 Coeffs[i] = 0.0;
318 }
319 Coeffs[order-1]=1.0;
320 };
321
322 void csv(std::ostream &out){
323 for (RealD x=-1.2*alpha; x<1.2*alpha; x+=(2.0*alpha)/10000) {
324 RealD f = approx(x);
325 out<< x<<" "<<f<<std::endl;
326 }
327 return;
328 }
329
330 RealD approx(RealD xx) // Convenience for plotting the approximation
331 {
332 RealD Tn;
333 RealD Tnm;
334 RealD Tnp;
335 Real aa = alpha * alpha;
336 Real bb = beta * beta;
337
338 RealD x = ( 2.0 * (xx-mu)*(xx-mu) - (aa+bb) ) / (aa-bb);
339
340 RealD y= x;
341
342 RealD T0=1;
343 RealD T1=y;
344
345 RealD sum;
346 sum = 0.5*Coeffs[0]*T0;
347 sum+= Coeffs[1]*T1;
348
349 Tn =T1;
350 Tnm=T0;
351 for(int i=2;i<order;i++){
352 Tnp=2*y*Tn-Tnm;
353 Tnm=Tn;
354 Tn =Tnp;
355 sum+= Tn*Coeffs[i];
356 }
357 return sum;
358 };
359
360 // shift_Multiply in Rudy's code
361 void AminusMuSq(LinearOperatorBase<Field> &Linop, const Field &in, Field &out)
362 {
363 GridBase *grid=in.Grid();
364 Field tmp(grid);
365
366 RealD aa= alpha*alpha;
367 RealD bb= beta * beta;
368
369 Linop.HermOp(in,out);
370 out = out - mu*in;
371
372 Linop.HermOp(out,tmp);
373 tmp = tmp - mu * out;
374
375 out = (2.0/ (aa-bb) ) * tmp - ((aa+bb)/(aa-bb))*in;
376 };
377 // Implement the required interface
378 void operator() (LinearOperatorBase<Field> &Linop, const Field &in, Field &out) {
379
380 GridBase *grid=in.Grid();
381
382 int vol=grid->gSites();
383
384 Field T0(grid); T0 = in;
385 Field T1(grid);
386 Field T2(grid);
387 Field y(grid);
388
389 Field *Tnm = &T0;
390 Field *Tn = &T1;
391 Field *Tnp = &T2;
392
393 // Tn=T1 = (xscale M )*in
394 AminusMuSq(Linop,T0,T1);
395
396 // sum = .5 c[0] T0 + c[1] T1
397 out = (0.5*Coeffs[0])*T0 + Coeffs[1]*T1;
398 for(int n=2;n<order;n++){
399
400 AminusMuSq(Linop,*Tn,y);
401
402 *Tnp=2.0*y-(*Tnm);
403
404 out=out+Coeffs[n]* (*Tnp);
405
406 // Cycle pointers to avoid copies
407 Field *swizzle = Tnm;
408 Tnm =Tn;
409 Tn =Tnp;
410 Tnp =swizzle;
411
412 }
413 }
414};
416#endif
#define U0
Definition BGQQPX.h:105
#define U1
Definition BGQQPX.h:106
constexpr Real delta(int a, int b)
void axpy(Lattice< vobj > &ret, sobj a, const Lattice< vobj > &x, const Lattice< vobj > &y)
void axpby(Lattice< vobj > &ret, sobj a, sobj b, const Lattice< vobj > &x, const Lattice< vobj > &y)
vobj::scalar_object sum(const vobj *arg, Integer osites)
#define NAMESPACE_BEGIN(A)
Definition Namespace.h:35
#define NAMESPACE_END(A)
Definition Namespace.h:36
RealF Real
Definition Simd.h:65
double RealD
Definition Simd.h:61
#define T2
#define T1
#define T0
static INTERNAL_PRECISION U
Definition Zolotarev.cc:230
#define M_PI
Definition Zolotarev.cc:41
void csv(std::ostream &out)
Definition Chebyshev.h:322
void operator()(LinearOperatorBase< Field > &Linop, const Field &in, Field &out)
Definition Chebyshev.h:378
void AminusMuSq(LinearOperatorBase< Field > &Linop, const Field &in, Field &out)
Definition Chebyshev.h:361
RealD approx(RealD xx)
Definition Chebyshev.h:330
ChebyshevLanczos(RealD _alpha, RealD _beta, RealD _mu, int _order)
Definition Chebyshev.h:309
std::vector< RealD > Coeffs
Definition Chebyshev.h:302
void Init(RealD _lo, RealD _hi, int _order, RealD(*func)(RealD))
Definition Chebyshev.h:115
Chebyshev(RealD _lo, RealD _hi, int _order)
Definition Chebyshev.h:80
void PlotApprox(std::ostream &out)
Definition Chebyshev.h:70
void Init(RealD _lo, RealD _hi, int _order, functor &func)
Definition Chebyshev.h:135
RealD approxInv(RealD z, RealD x0, int maxiter, RealD resid)
Definition Chebyshev.h:236
Chebyshev(ChebyParams p)
Definition Chebyshev.h:78
void JacksonSmooth(void)
Definition Chebyshev.h:156
std::vector< RealD > Coeffs
Definition Chebyshev.h:52
RealD approx(RealD x)
Definition Chebyshev.h:184
void Init(RealD _lo, RealD _hi, int _order)
Definition Chebyshev.h:86
RealD approxD(RealD x)
Definition Chebyshev.h:210
int order
Definition Chebyshev.h:53
Chebyshev(RealD _lo, RealD _hi, int _order, RealD(*func)(RealD))
Definition Chebyshev.h:79
RealD lo
Definition Chebyshev.h:55
void operator()(LinearOperatorBase< Field > &Linop, const Field &in, Field &out)
Definition Chebyshev.h:252
void InitLowPass(RealD _lo, RealD _hi, int _order)
Definition Chebyshev.h:99
RealD hi
Definition Chebyshev.h:54
void csv(std::ostream &out)
Definition Chebyshev.h:58
int64_t gSites(void) const
virtual void HermOp(const Field &in, Field &out)=0
GRID_SERIALIZABLE_CLASS_MEMBERS(ChebyParams, RealD, alpha, RealD, beta, int, Npoly)