#ifndef QCD_UTIL_SUNADJOINT_H #define QCD_UTIL_SUNADJOINT_H //////////////////////////////////////////////////////////////////////// // // * Adjoint representation generators // // * Normalisation for the fundamental generators: // trace ta tb = 1/2 delta_ab = T_F delta_ab // T_F = 1/2 for SU(N) groups // // // base for NxN hermitian traceless matrices // normalized to 1: // // (e_Adj)^a = t^a / sqrt(T_F) // // then the real, antisymmetric generators for the adjoint representations // are computed ( shortcut: e^a == (e_Adj)^a ) // // (iT_adj)^d_ba = i tr[e^a t^d e^b - t^d e^a e^b] // //////////////////////////////////////////////////////////////////////// namespace Grid { namespace QCD { template class SU_Adjoint : public SU { public: static const int Dimension = ncolour * ncolour - 1; template using iSUnAdjointMatrix = iScalar > >; // Actually the adjoint matrices are real... // Consider this overhead... FIXME typedef iSUnAdjointMatrix AMatrix; typedef iSUnAdjointMatrix AMatrixF; typedef iSUnAdjointMatrix AMatrixD; typedef iSUnAdjointMatrix vAMatrix; typedef iSUnAdjointMatrix vAMatrixF; typedef iSUnAdjointMatrix vAMatrixD; typedef Lattice LatticeAdjMatrix; typedef Lattice LatticeAdjMatrixF; typedef Lattice LatticeAdjMatrixD; typedef Lattice >, Nd> > LatticeAdjField; typedef Lattice >, Nd> > LatticeAdjFieldF; typedef Lattice >, Nd> > LatticeAdjFieldD; template static void generator(int Index, iSUnAdjointMatrix &iAdjTa) { // returns i(T_Adj)^index necessary for the projectors // see definitions above iAdjTa = zero; Vector::template iSUnMatrix > ta(ncolour * ncolour - 1); typename SU::template iSUnMatrix tmp; // FIXME not very efficient to get all the generators everytime for (int a = 0; a < Dimension; a++) SU::generator(a, ta[a]); for (int a = 0; a < Dimension; a++) { tmp = ta[a] * ta[Index] - ta[Index] * ta[a]; for (int b = 0; b < (ncolour * ncolour - 1); b++) { typename SU::template iSUnMatrix tmp1 = 2.0 * tmp * ta[b]; // 2.0 from the normalization Complex iTr = TensorRemove(timesI(trace(tmp1))); iAdjTa()()(b, a) = iTr; } } } static void printGenerators(void) { for (int gen = 0; gen < Dimension; gen++) { AMatrix ta; generator(gen, ta); std::cout << GridLogMessage << "Nc = " << ncolour << " t_" << gen << std::endl; std::cout << GridLogMessage << ta << std::endl; } } static void testGenerators(void) { AMatrix adjTa; std::cout << GridLogMessage << "Adjoint - Checking if real" << std::endl; for (int a = 0; a < Dimension; a++) { generator(a, adjTa); std::cout << GridLogMessage << a << std::endl; assert(norm2(adjTa - conjugate(adjTa)) < 1.0e-6); } std::cout << GridLogMessage << std::endl; std::cout << GridLogMessage << "Adjoint - Checking if antisymmetric" << std::endl; for (int a = 0; a < Dimension; a++) { generator(a, adjTa); std::cout << GridLogMessage << a << std::endl; assert(norm2(adjTa + transpose(adjTa)) < 1.0e-6); } std::cout << GridLogMessage << std::endl; } // Projects the algebra components a lattice matrix (of dimension ncol*ncol -1 ) static void projectOnAlgebra(typename SU::LatticeAlgebraVector &h_out, const LatticeAdjMatrix &in, Real scale = 1.0) { conformable(h_out, in); h_out = zero; AMatrix iTa; for (int a = 0; a < Dimension; a++) { generator(a, iTa); auto tmp = real(trace(iTa * in)) * scale; pokeColour(h_out, tmp, a); } } // a projector that keeps the generators stored to avoid the overhead of recomputing. static void projector(typename SU::LatticeAlgebraVector &h_out, const LatticeAdjMatrix &in, Real scale = 1.0) { conformable(h_out, in); static std::vector iTa(Dimension); // to store the generators h_out = zero; static bool precalculated = false; if (!precalculated){ precalculated = true; for (int a = 0; a < Dimension; a++) generator(a, iTa[a]); } for (int a = 0; a < Dimension; a++) { auto tmp = real(trace(iTa[a] * in)) * scale; pokeColour(h_out, tmp, a); } } }; // Some useful type names typedef SU_Adjoint<2> SU2Adjoint; typedef SU_Adjoint<3> SU3Adjoint; typedef SU_Adjoint<4> SU4Adjoint; typedef SU_Adjoint<5> SU5Adjoint; typedef SU_Adjoint AdjointMatrices; } } #endif