/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./lib/tensors/Tensor_exp.h Copyright (C) 2015 Author: neo This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. See the full license in the file "LICENSE" in the top level distribution directory *************************************************************************************/ /* END LEGAL */ #ifndef GRID_MATH_EXP_H #define GRID_MATH_EXP_H #define DEFAULT_MAT_EXP 12 namespace Grid { /////////////////////////////////////////////// // Exponentiate function for scalar, vector, matrix /////////////////////////////////////////////// template inline iScalar Exponentiate(const iScalar&r, RealD alpha , Integer Nexp = DEFAULT_MAT_EXP) { iScalar ret; ret._internal = Exponentiate(r._internal, alpha, Nexp); return ret; } template inline iVector Exponentiate(const iVector&r, RealD alpha , Integer Nexp = DEFAULT_MAT_EXP) { iVector ret; for (int i = 0; i < N; i++) ret._internal[i] = Exponentiate(r._internal[i], alpha, Nexp); return ret; } // Specialisation: Cayley-Hamilton exponential for SU(3) template::TensorLevel == 0>::type * =nullptr> inline iMatrix Exponentiate(const iMatrix &arg, RealD alpha , Integer Nexp = DEFAULT_MAT_EXP ) { // for SU(3) 2x faster than the std implementation using Nexp=12 // notice that it actually computes // exp ( input matrix ) // the i sign is coming from outside // input matrix is anti-hermitian NOT hermitian typedef iMatrix mat; typedef iScalar scalar; mat unit(1.0); mat temp(unit); const Complex one_over_three = 1.0 / 3.0; const Complex one_over_two = 1.0 / 2.0; scalar c0, c1, tmp, c0max, theta, u, w; scalar xi0, u2, w2, cosw; scalar fden, h0, h1, h2; scalar e2iu, emiu, ixi0, qt; scalar f0, f1, f2; scalar unity(1.0); mat iQ2 = arg*arg*alpha*alpha; mat iQ3 = arg*iQ2*alpha; // sign in c0 from the conventions on the Ta c0 = -imag( trace(iQ3) ) * one_over_three; c1 = -real( trace(iQ2) ) * one_over_two; // Cayley Hamilton checks to machine precision, tested tmp = c1 * one_over_three; c0max = 2.0 * pow(tmp, 1.5); theta = acos(c0 / c0max) * one_over_three; u = sqrt(tmp) * cos(theta); w = sqrt(c1) * sin(theta); xi0 = sin(w) / w; u2 = u * u; w2 = w * w; cosw = cos(w); ixi0 = timesI(xi0); emiu = cos(u) - timesI(sin(u)); e2iu = cos(2.0 * u) + timesI(sin(2.0 * u)); h0 = e2iu * (u2 - w2) + emiu * ((8.0 * u2 * cosw) + (2.0 * u * (3.0 * u2 + w2) * ixi0)); h1 = e2iu * (2.0 * u) - emiu * ((2.0 * u * cosw) - (3.0 * u2 - w2) * ixi0); h2 = e2iu - emiu * (cosw + (3.0 * u) * ixi0); fden = unity / (9.0 * u2 - w2); // reals f0 = h0 * fden; f1 = h1 * fden; f2 = h2 * fden; return (f0 * unit + timesMinusI(f1) * arg*alpha - f2 * iQ2); } // General exponential template::TensorLevel == 0 >::type * =nullptr> inline iMatrix Exponentiate(const iMatrix &arg, RealD alpha , Integer Nexp = DEFAULT_MAT_EXP ) { // notice that it actually computes // exp ( input matrix ) // the i sign is coming from outside // input matrix is anti-hermitian NOT hermitian typedef iMatrix mat; mat unit(1.0); mat temp(unit); for(int i=Nexp; i>=1;--i){ temp *= alpha/RealD(i); temp = unit + temp*arg; } return temp; } } #endif