HILA
Loading...
Searching...
No Matches
KennedyPendleton.h
1#ifndef KENNEDY_PENDLETON_H
2#define KENNEDY_PENDLETON_H
3
4#include "plumbing/hila.h"
5#include "datatypes/su2.h"
6
7// this is might be too much to have in a single kernel
8
9/**
10 * @brief \f$ SU(2) \f$ heatbath
11 * @details Generate an \f$ SU(2)\f$ matrix according to Kennedy-Pendleton heatbath.
12 * This assumes that the action due to gauge link U is Re Tr U.S^+,
13 * where S is the staple. Note sign and normalization of the staple (beta is absorbed in S),
14 * and we include hermitian conjugation in definition of the staple for consistency with conventions elsewhere in HILA.
15 * @tparam T float-type
16 * @param staple Hermitian conjugate of the staple to compute heatbath with. Action ~ Re Tr U.S^+, so this input is S.
17 * NB: In general the staple is NOT an SU(2) matrix,
18 * however we can describe it using the SU2 class because (i) The sum of SU(2) matrices is proportional to SU(2),
19 * (ii) SU2 class does not require that the determinant is always normalized to 1.
20 *
21 * @return SU2<T>
22 */
23template <typename T>
24SU2<T> KennedyPendleton(const SU2<T> &staple) {
25
26 // action Tr U.S^+ => weight exp(-Tr U.S^+) (for SU2 the trace is real).
27 // Following K-P we need to bring this to form exp(xi Tr a),
28 // where a is an SU2 matrix. For this we could project the staple to SU2 (eq. (10) of K-P paper).
29 // But since the staple is proportional to SU2 matrix,
30 // this just means we normalize by its det and flip the sign:
31 // V = S/sqrt(|S|) => xi = 1/sqrt(|S|), a = -U.V^+
32 // The K-P algorithm generates a new SU2 matrix a = -U.V^+
33 // from which the new link U is -a.V.
34 // This way of writing things minimizes the needed number of conjugations
35
36 const T xi = ::sqrt(det(staple));
37 const SU2<T> V = staple / xi; // this is now in SU(2)
38
39 // 'alpha' that appears in eq (15)
40 T alpha = 2.0*xi;
41
42 // Now generate new a = -U.V^+, section 4 of K-P
43
44 int nloops;
45 const int LOOPLIM = 100;
46 const double pi2 = M_PI * 2.0;
47 double r1, r2, r3, delta;
48 nloops = 0;
49 do {
50 // r1, r2 need division by alpha but this is done in one go when setting delta (micro-optimization?)
51 r1 = -::log(1.0 - hila::random());
52 r2 = -::log(1.0 - hila::random());
53 r3 = ::cos(pi2 * hila::random());
54 r3 *= r3;
55 delta = (r1*r3 + r2) / alpha;
56
57 r3 = hila::random(); // R'''
58 nloops++;
59 } while (nloops < LOOPLIM && r3*r3 > 1.0 - 0.5*delta);
60
61 T a0 = 1.0 - delta;
62 if (nloops >= LOOPLIM) {
63 // Failed to find new a0...
64 // TODO some error or warning
65 a0 = 1e-9;
66 }
67
68 // Generate random vector on S2, radius sqrt(1.0-a0**2)
69 T rd = 1.0 - a0*a0;
70
71 if (rd <= 0.0) {
72 // negative radius^2, something went wrong...
73 // TODO some error or warning
74 rd = 0.0;
75 }
76
77 // ... and put them in the 'a' matrix. Notation gets messy, reminder:
78 // SU2 = d + a i\sigma_1 + b i\sigma_2 + c i\sigma_3$
79 SU2<T> a;
80 a.d = a0;
81
82 r3 = 2.0 * hila::random() - 1.0;
83 a.c = ::sqrt(rd) * r3;
84 T theta = pi2 * hila::random();
85 rd = ::sqrt(rd * (1.0 - ::sqr(r3)));
86 a.b = rd * ::cos(theta);
87 a.a = rd * ::sin(theta);
88 // Could this be optimized by removing sin, cos? http://corysimon.github.io/articles/uniformdistn-on-sphere/
89
90 // Now just get the new link variable from a = -U.V^+
91 return -a * V;
92}
93
94
95#endif
Definition su2.h:14
constexpr T sqr(const T &arg)
Define convenience function sqr(), returning square of argument.
Definition defs.h:149
double random()
Real valued uniform random number generator.
Definition hila_gpu.cpp:120