su3 slow_expon(su3 in, int nterm) { su3 out , out_new , aa , aa_old , aa_scale ; int i ; double fact = 1 ; _su3_one(out) ; aa = in ; aa_old = aa ; _su3_plus_su3(out_new,out,aa) ; out = out_new ; for(i=2 ; i < nterm ; ++i) { _su3_times_su3(aa,in,aa_old); aa_old = aa ; aa_scale = aa ; fact *= i ; scale_su3(&aa_scale, 1.0/fact ) ; _su3_plus_su3(out_new,out,aa_scale) ; out = out_new ; } return(out); }
void cayley_hamilton_exponent(su3* expA, su3 const *A) { static double const fac_1_3 = 1 / 3.0; _Complex double f0,f1,f2; /* c0 = det[A] */ double c0 = I * (A->c00 * (A->c11 * A->c22 - A->c12 * A->c21) + A->c01 * (A->c12 * A->c20 - A->c10 * A->c22) + A->c02 * (A->c10 * A->c21 - A->c11 * A->c20) ); /* c1 = 0.5 * Tr[AA] */ double c1 = -0.5 * (A->c00 * A->c00 + A->c01 * A->c10 + A->c02 * A->c20 + A->c10 * A->c01 + A->c11 * A->c11 + A->c12 * A->c21 + A->c20 * A->c02 + A->c21 * A->c12 + A->c22 * A->c22 ); /* There is a special, but common (cold start) case where the given matrix is actually 0! * We need to account for it. */ if (c0 == 0 && c1 == 0) { _su3_one(*expA); f1 = I; f2 = -0.5; return; } /* P&M give symmetry relations that can be used when c0 < 0, to avoid the numerically problematic c0 -> -c0_max limit. We note the sign here for future reference, then continue with c0 as if it were positive. */ int c0_negative = (c0 < 0); c0 = fabs(c0); /* The call to fmin below is needed, because for small deviations alpha from zero -- O(10e-12) -- rounding errors can cause c0 > c0max by epsilon. In that case, acos(c0/c0max) will produce NaNs, whereas the mathematically correct conclusion would be that theta is zero to machine precision! Note that this approach will *not* produce identity and zero for all output, but rather the correct answer of order (I + alpha) for exp(iQ). */ double c0max = 2.0 * pow(fac_1_3 * c1, 1.5); double theta_3 = fac_1_3 * acos(fmin(c0 / c0max, 1.0)); double u = sqrt(fac_1_3 * c1) * cos(theta_3); double w = sqrt(c1) * sin(theta_3); /* Calculate and cache some repeating factors. * * We can fold in the sign immediately -- c.f. f_j(-c0, c1) = -1^j * conj(f_j(c0, c1)) * This should just amount to potentially adding a minus to all imaginary components and an overall phase for f1. */ _Complex double ma = cexp(2 * I * u); _Complex double mb = cexp(-I * u); double cw = cos(w); double u2 = u * u; double w2 = w * w; /* Modification w.r.t. Peardon & Morningstar: w is always positive, so |w| = w */ double xi0 = (w > 0.05) ? (sin(w) / w) : 1 - 0.16666666666666667 * w2 * (1 - 0.05 * w2 * (1 - 0.023809523809523808 * w2)); double divisor = 1.0 / (9.0 * u2 - w2); f0 = divisor * (ma * (u * u - w * w) + mb * (8 * u * u * cw + 2 * I * u * (3 * u * u + w * w) * xi0)); f1 = divisor * (-2 * I * u * ma + mb * (2 * I * u * cw + (3 * u * u - w * w) * xi0)); f2 = divisor * (mb * (cw + 3 * I * u * xi0) - ma); /* The first point where we use the symmetry relations to calculate the negative c0 possibility */ if (c0_negative) { f0 = conj(f0); f1 = conj(f1); f2 = conj(f2); } exponent_from_coefficients(expA, f0, f1, f2, A); return; }
static su3 unit_su3 (void) { su3 u; _su3_one(u); return(u); }
/* Method based on Givens' rotations, as used by Urs Wenger */ void reunitarize(su3 *omega) { static su3 w, rot, tmp; static double trace_old, trace_new; static _Complex double s0, s1; static double scale; _su3_one(w); trace_old = omega->c00 + omega->c11 + omega->c22; for (int iter = 0; iter < 200; ++iter) { /* Givens' rotation 01 */ s0 = omega->c00 + conj(omega->c11); s1 = omega->c01 - conj(omega->c10); scale = 1.0 / sqrt(conj(s0) * s0 + conj(s1) * s1); s0 *= scale; s1 *= scale; /* Projecting */ _su3_one(rot); rot.c00 = s0; rot.c11 = conj(s0); rot.c01 = s1; rot.c10 = -conj(s1); _su3_times_su3(tmp, rot, w); _su3_assign(w, tmp); _su3_times_su3d(tmp, *omega, rot); _su3_assign(*omega, tmp); /* Givens' rotation 12 */ s0 = omega->c11 + conj(omega->c22); s1 = omega->c12 - conj(omega->c21); scale = 1.0 / sqrt(conj(s0) * s0 + conj(s1) * s1); s0 *= scale; s1 *= scale; /* Projecting */ _su3_one(rot); rot.c11 = s0; rot.c22 = conj(s0); rot.c12 = s1; rot.c21 = -conj(s1); _su3_times_su3(tmp, rot, w); _su3_assign(w, tmp); _su3_times_su3d(tmp, *omega, rot); _su3_assign(*omega, tmp); /* Givens' rotation 20 */ s0 = omega->c22 + conj(omega->c00); s1 = omega->c20 - conj(omega->c02); scale = 1.0 / sqrt(conj(s0) * s0 + conj(s1) * s1); s0 *= scale; s1 *= scale; /* Projecting */ _su3_one(rot); rot.c22 = s0; rot.c00 = conj(s0); rot.c20 = s1; rot.c02 = -conj(s1); _su3_times_su3(tmp, rot, w); _su3_assign(w, tmp); _su3_times_su3d(tmp, *omega, rot); _su3_assign(*omega, tmp); trace_new = omega->c00 + omega->c11 + omega->c22; if (trace_new - trace_old < 1e-15) break; trace_old = trace_new; } _su3_assign(*omega, w); }
void sw_term(su3 ** const gf, const double kappa, const double c_sw) { int k,l; int x,xpk,xpl,xmk,xml,xpkml,xplmk,xmkml; su3 *w1,*w2,*w3,*w4; double ka_csw_8 = kappa*c_sw/8.; static su3 v1,v2,plaq; static su3 fkl[4][4]; static su3 magnetic[4],electric[4]; static su3 aux; /* compute the clover-leave */ /* l __ __ | | | | |__| |__| __ __ | | | | |__| |__| k */ for(x = 0; x < VOLUME; x++) { for(k = 0; k < 4; k++) { for(l = k+1; l < 4; l++) { xpk=g_iup[x][k]; xpl=g_iup[x][l]; xmk=g_idn[x][k]; xml=g_idn[x][l]; xpkml=g_idn[xpk][l]; xplmk=g_idn[xpl][k]; xmkml=g_idn[xml][k]; w1=&gf[x][k]; w2=&gf[xpk][l]; w3=&gf[xpl][k]; w4=&gf[x][l]; _su3_times_su3(v1,*w1,*w2); _su3_times_su3(v2,*w4,*w3); _su3_times_su3d(plaq,v1,v2); w1=&gf[x][l]; w2=&gf[xplmk][k]; w3=&gf[xmk][l]; w4=&gf[xmk][k]; _su3_times_su3d(v1,*w1,*w2); _su3d_times_su3(v2,*w3,*w4); _su3_times_su3_acc(plaq,v1,v2); w1=&gf[xmk][k]; w2=&gf[xmkml][l]; w3=&gf[xmkml][k]; w4=&gf[xml][l]; _su3_times_su3(v1,*w2,*w1); _su3_times_su3(v2,*w3,*w4); _su3d_times_su3_acc(plaq,v1,v2); w1=&gf[xml][l]; w2=&gf[xml][k]; w3=&gf[xpkml][l]; w4=&gf[x][k]; _su3d_times_su3(v1,*w1,*w2); _su3_times_su3d(v2,*w3,*w4); _su3_times_su3_acc(plaq,v1,v2); _su3_dagger(v2,plaq); _su3_minus_su3(fkl[k][l],plaq,v2); } } // this is the one in flavour and colour space // twisted mass term is treated in clover, sw_inv and // clover_gamma5 _su3_one(sw[x][0][0]); _su3_one(sw[x][2][0]); _su3_one(sw[x][0][1]); _su3_one(sw[x][2][1]); for(k = 1; k < 4; k++) { _su3_assign(electric[k], fkl[0][k]); } _su3_assign(magnetic[1], fkl[2][3]); _su3_minus_assign(magnetic[2], fkl[1][3]); _su3_assign(magnetic[3], fkl[1][2]); /* upper left block 6x6 matrix */ _itimes_su3_minus_su3(aux,electric[3],magnetic[3]); _su3_refac_acc(sw[x][0][0],ka_csw_8,aux); _itimes_su3_minus_su3(aux,electric[1],magnetic[1]); _su3_minus_su3(v2,electric[2],magnetic[2]); _su3_acc(aux,v2); _real_times_su3(sw[x][1][0],ka_csw_8,aux); _itimes_su3_minus_su3(aux,magnetic[3],electric[3]); _su3_refac_acc(sw[x][2][0],ka_csw_8,aux); /* lower right block 6x6 matrix */ _itimes_su3_plus_su3(aux,electric[3],magnetic[3]); _su3_refac_acc(sw[x][0][1],(-ka_csw_8),aux); _itimes_su3_plus_su3(aux,electric[1],magnetic[1]); _su3_plus_su3(v2,electric[2],magnetic[2]); _su3_acc(aux,v2); _real_times_su3(sw[x][1][1],(-ka_csw_8),aux); _itimes_su3_plus_su3(aux,magnetic[3],electric[3]); _su3_refac_acc(sw[x][2][1],ka_csw_8,aux); } return; }
void flip_subgroup(int ix, int mu, su3 vv, int i){ static double vv0,vv1,vv2,vv3,aa0,aa1,aa2,aa3; static double aux,norm_vv_sq; static su3 a,w,v; su3 *z; _su3_assign(v,vv); _su3_one(a); z=&g_gauge_field[ix][mu]; _su3_times_su3d(w,*z,v); /* According to Peter's notes ``A Cabibbo-Marinari SU(3)....", eqs. (A.14-A.17) we have */ if(i==1) { vv0 = creal(w.c00) + creal(w.c11); vv3 = -cimag(w.c00) + cimag(w.c11); vv1 = -cimag(w.c01) - cimag(w.c10); vv2 = -creal(w.c01) + creal(w.c10); } else if(i==2) { vv0 = creal(w.c00) + creal(w.c22); vv3 = -cimag(w.c00) + cimag(w.c22); vv1 = -cimag(w.c02) - cimag(w.c20); vv2 = -creal(w.c02) + creal(w.c20); } else { vv0 = creal(w.c11) + creal(w.c22); vv3 = -cimag(w.c11) + cimag(w.c22); vv1 = -cimag(w.c12) - cimag(w.c21); vv2 = -creal(w.c12) + creal(w.c21); } norm_vv_sq= vv0 * vv0 + vv1 * vv1 + vv2 * vv2 + vv3 * vv3; aux= 2.0 * vv0 / norm_vv_sq; aa0 = aux * vv0-1.0; aa1 = aux * vv1; aa2 = aux * vv2; aa3 = aux * vv3; /* aa is embedded in the SU(3) matrix (a) which can be multiplied on the link variable using the su3_type operator * . */ if(i==1) { a.c00 = aa0 + aa3 * I; a.c11 = conj(a.c00); a.c01 = aa2 + aa1 * I; a.c10 = -conj(a.c01); } else if(i==2) { a.c00 = aa0 + aa3 * I; a.c22 = conj(a.c00); a.c02 = aa2 + aa1 * I; a.c20 = -conj(a.c02); } else { a.c11 = aa0 + aa3 * I; a.c22 = conj(a.c11); a.c12 = aa2 + aa1 * I; a.c21 = -conj(a.c12); } _su3_times_su3(w,a,*z); *z=w; }