diff --git a/lib/qcd/utils/SUn.h b/lib/qcd/utils/SUn.h new file mode 100644 index 00000000..3a8b5f4d --- /dev/null +++ b/lib/qcd/utils/SUn.h @@ -0,0 +1,414 @@ +#ifndef QCD_UTIL_SUN_H +#define QCD_UTIL_SUN_H + + +namespace Grid { + namespace QCD { + +template +class SU { +public: + + static int generators(void) { return ncolour*ncolour-1; } + static int su2subgroups(void) { return (ncolour*(ncolour-1))/2; } + + template using iSUnMatrix = iScalar > > ; + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Types can be accessed as SU<2>::Matrix , SU<2>::vSUnMatrix, SU<2>::LatticeMatrix etc... + ////////////////////////////////////////////////////////////////////////////////////////////////// + typedef iSUnMatrix Matrix; + typedef iSUnMatrix MatrixF; + typedef iSUnMatrix MatrixD; + + typedef iSUnMatrix vMatrix; + typedef iSUnMatrix vMatrixF; + typedef iSUnMatrix vMatrixD; + + typedef Lattice LatticeMatrix; + typedef Lattice LatticeMatrixF; + typedef Lattice LatticeMatrixD; + + //////////////////////////////////////////////////////////////////////// + // There are N^2-1 generators for SU(N). + // + // We take a traceless hermitian generator basis as follows + // + // * Normalisation: trace ta tb = 1/2 delta_ab + // + // * Off diagonal + // - pairs of rows i1,i2 behaving like pauli matrices signma_x, sigma_y + // + // - there are (Nc-1-i1) slots for i2 on each row [ x 0 x ] + // direct count off each row + // + // - Sum of all pairs is Nc(Nc-1)/2: proof arithmetic series + // + // (Nc-1) + (Nc-2)+... 1 ==> Nc*(Nc-1)/2 + // 1+ 2+ + + Nc-1 + // + // - There are 2 x Nc (Nc-1)/ 2 of these = Nc^2 - Nc + // + // - We enumerate the row-col pairs. + // - for each row col pair there is a (sigma_x) and a (sigma_y) like generator + // + // + // t^a_ij = { in 0.. Nc(Nc-1)/2 -1} => delta_{i,i1} delta_{j,i2} + delta_{i,i1} delta_{j,i2} + // t^a_ij = { in Nc(Nc-1)/2 ... Nc^(Nc-1) -1} => i delta_{i,i1} delta_{j,i2} - i delta_{i,i1} delta_{j,i2} + // + // * Diagonal; must be traceless and normalised + // - Sequence is + // N (1,-1,0,0...) + // N (1, 1,-2,0...) + // N (1, 1, 1,-3,0...) + // N (1, 1, 1, 1,-4,0...) + // + // where 1/2 = N^2 (1+.. m^2)etc.... for the m-th diagonal generator + // NB this gives the famous SU3 result for su2 index 8 + // + // N= sqrt(1/2 . 1/6 ) = 1/2 . 1/sqrt(3) + // + // ( 1 ) + // ( 1 ) / sqrt(3) /2 = 1/2 lambda_8 + // ( -2) + //////////////////////////////////////////////////////////////////////// + template + static void generator(int lieIndex,iSUnMatrix &ta){ + // map lie index to which type of generator + int diagIndex; + int su2Index; + int sigxy; + int NNm1 = ncolour*(ncolour-1); + if ( lieIndex>= NNm1 ) { + diagIndex = lieIndex -NNm1; + generatorDiagonal(diagIndex,ta); + return; + } + sigxy = lieIndex&0x1; + su2Index= lieIndex>>1; + if ( sigxy ) generatorSigmaY(su2Index,ta); + else generatorSigmaX(su2Index,ta); + } + template + static void generatorSigmaX(int su2Index,iSUnMatrix &ta){ + ta=zero; + int i1,i2; + su2SubGroupIndex(i1,i2,su2Index); + ta()()(i1,i2)=1.0; + ta()()(i2,i1)=1.0; + ta= ta *0.5; + } + template + static void generatorSigmaY(int su2Index,iSUnMatrix &ta){ + ta=zero; + cplx i(0.0,1.0); + int i1,i2; + su2SubGroupIndex(i1,i2,su2Index); + ta()()(i1,i2)=-i; + ta()()(i2,i1)= i; + ta= ta *0.5; + } + template + static void generatorDiagonal(int diagIndex,iSUnMatrix &ta){ + ta=zero; + int trsq=0; + int last=diagIndex+1; + for(int i=0;i<=diagIndex;i++){ + ta()()(i,i) = 1.0; + trsq++; + } + ta()()(last,last) = -last; + trsq+=last*last; + RealD nrm = 1.0/std::sqrt(2.0*trsq); + ta = ta *nrm; + } + //////////////////////////////////////////////////////////////////////// + // Map a su2 subgroup number to the pair of rows that are non zero + //////////////////////////////////////////////////////////////////////// + static void su2SubGroupIndex(int &i1,int &i2,int su2_index){ + + assert( (su2_index>=0) && (su2_index< (ncolour*(ncolour-1))/2) ); + + int spare=su2_index; + for(i1=0;spare >= (ncolour-1-i1);i1++ ){ + spare = spare - (ncolour-1-i1); // remove the Nc-1-i1 terms + } + i2=i1+1+spare; + } + template + static void su2Extract(std::vector > > &r, + const Lattice > &source, + int su2_index) + { + GridBase *grid(source._grid); + + assert(r.size() == 4); // store in 4 real parts + + for(int i=0;i<4;i++){ + conformable(r[i],source); + } + + int i1,i2; + su2SubGroupIndex(i1,i2,su2_index); + + /* Compute the b(k) of A_SU(2) = b0 + i sum_k bk sigma_k */ + + // r[0] = toReal(real(peekColour(source,i1,i1)) + real(peekColour(source,i2,i2))); + // r[1] = toReal(imag(peekColour(source,i1,i2)) + imag(peekColour(source,i2,i1))); + // r[2] = toReal(real(peekColour(source,i1,i2)) - real(peekColour(source,i2,i1))); + // r[3] = toReal(imag(peekColour(source,i1,i1)) - imag(peekColour(source,i2,i2))); + r[0] = toReal(real(peekColour(source,i1,i1)) + real(peekColour(source,i2,i2))); + r[1] = toReal(imag(peekColour(source,i1,i2)) + imag(peekColour(source,i2,i1))); + r[2] = toReal(real(peekColour(source,i1,i2)) - real(peekColour(source,i2,i1))); + r[3] = toReal(imag(peekColour(source,i1,i1)) - imag(peekColour(source,i2,i2))); + + } + + template + static void su2Insert(const std::vector > > &r, + Lattice > &dest, + int su2_index) + { + typedef typename Lattice >::scalar_type cplx; + typedef Lattice > Lcomplex; + GridBase * grid = dest._grid; + + assert(r.size() == 4); // store in 4 real parts + + Lcomplex tmp(grid); + + std::vector cr(4,grid); + for(int i=0;i r(4,grid); + std::vector a(4,grid); + su2Extract(r,V,su2_subgroup); // HERE + + LatticeReal r_l(grid); + r_l = r[0]*r[0]+r[1]*r[1]+r[2]*r[2]+r[3]*r[3]; + r_l = sqrt(r_l); + + LatticeReal ftmp(grid); + LatticeReal ftmp1(grid); + LatticeReal ftmp2(grid); + LatticeReal one (grid); one = 1.0; + LatticeReal zz (grid); zz = zero; + LatticeReal recip(grid); recip = one/r_l; + + Real machine_epsilon= 1.0e-14; + + ftmp = where(r_l>machine_epsilon,recip,one); + a[0] = where(r_l>machine_epsilon, r[0] * ftmp , one); + a[1] = where(r_l>machine_epsilon, -(r[1] * ftmp), zz); + a[2] = where(r_l>machine_epsilon, -(r[2] * ftmp), zz); + a[3] = where(r_l>machine_epsilon, -(r[3] * ftmp), zz); + + r_l *= beta / ncolour; + + ftmp1 = where(wheremask,one,zz); + Real num_sites = TensorRemove(sum(ftmp1)); + + Integer itrials = (Integer)num_sites; + ntrials = 0; + nfails = 0; + + LatticeInteger lupdate(grid); + LatticeInteger lbtmp(grid); + LatticeInteger lbtmp2(grid); lbtmp2=zero; + + int n_done = 0; + int nhb = 0; + + r[0] = a[0]; + lupdate = 1; + + LatticeReal ones (grid); ones = 1.0; + LatticeReal zeros(grid); zeros=zero; + + const RealD twopi=2.0*M_PI; + while ( nhb < nheatbath && n_done < num_sites ) { + + ntrials += itrials; + + random(pRNG,r[1]); + std::cout<<"RANDOM SPARSE FLOAT r[1]"< b(4,grid); + b[0] = r[0]*a[0] - r[1]*a[1] - r[2]*a[2] - r[3]*a[3]; + b[1] = r[0]*a[1] + r[1]*a[0] - r[2]*a[3] + r[3]*a[2]; + b[2] = r[0]*a[2] + r[2]*a[0] - r[3]*a[1] + r[1]*a[3]; + b[3] = r[0]*a[3] + r[3]*a[0] - r[1]*a[2] + r[2]*a[1]; + + // + // Now fill an SU(3) matrix V with the SU(2) submatrix su2_index + // parametrized by a_k in the sigma matrix basis. + // + su2Insert(b,V,su2_subgroup); + + // U = V*U + LatticeMatrix tmp(grid); + tmp = V * link; + + //mask the assignment back + link = where(wheremask,tmp,link); + + } + + static void printGenerators(void) + { + for(int gen=0;gen SU2; + typedef SU<3> SU3; + typedef SU<4> SU4; + typedef SU<5> SU5; + + } +} +#endif