/************************** relax.c *******************************/
/* Microcanonical overrelaxation by doing successive SU(2) gauge hits */
/* MIMD version 3 */
/* T. DeGrand March 1991 */
/* Heavily modified K.R. 97 & 2002 */

#include "lattice.h"

#define Nc 3

#ifdef T3E
#define prefetch
#endif

typedef struct { complex e[2][2]; } su2_matrix;

/* Codes for interpreting selection of gauge fixing options */

void left_su2_hit_n(su2_matrix *u, int p, int q, su3_matrix *link);

void relax(int dir,int parity, 
	   su3_matrix *link[NDIM], su3_matrix *staple
#ifdef HIGGS
	   , su3_matrix *a_uncmpr
#endif
	   )
{
  /* Do overrelaxation by SU(2) subgroups */
  int Nhit,index1, ina, inb,ii;
  int gahit,gatry;
  double a0,a1,a2,a3,asq,r;
  register int i;
  su3_matrix action;
  su2_matrix u;

  Nhit = 3;

  gahit = gatry = 0;

  /* now for the overrelaxed updating */
  forparity(i,parity) {
    prefetch_matrix(&a_uncmpr[i]);
    prefetch_matrix(&(link[dir][i+1]));
    prefetch_matrix(&(staple[i+1]));

    for(index1=0;index1<Nhit;index1++) {
      /*  pick out an SU(2) subgroup */
      ina=(index1+1) % Nc;
      inb=(index1+2) % Nc;
      if(ina > inb) { ii=ina; ina=inb; inb=ii;}

      mult_su3_na( &(link[dir][i]), &(staple[i]), &action );

      /* decompose the action into SU(2) subgroups using Pauli matrix
       * expansion
       * The SU(2) hit matrix is represented as 
       * a0 + i * Sum j (sigma j * aj)
       */
      a0 =  action.e[ina][ina].real + action.e[inb][inb].real;
      a3 =  action.e[ina][ina].imag - action.e[inb][inb].imag;
      a1 =  action.e[ina][inb].imag + action.e[inb][ina].imag;
      a2 =  action.e[ina][inb].real - action.e[inb][ina].real;
	    
      /* Normalize and complex conjugate u */
      asq = a0*a0 + a1*a1 + a2*a2 + a3*a3;
      r = sqrt( asq );
      a0 = a0/r; a1 = -a1/r; a2 = -a2/r; a3 = -a3/r;
      /* Elements of SU(2) matrix */

      u.e[0][0] = cmplx( a0, a3);
      u.e[0][1] = cmplx( a2, a1);
      u.e[1][0] = cmplx(-a2, a1);
      u.e[1][1] = cmplx( a0,-a3);
    
      /* Do SU(2) hit on all links twice (to overrelax)  */

#ifdef HIGGS

      action = link[dir][i];
      left_su2_hit_n(&u,ina,inb,&action);
      left_su2_hit_n(&u,ina,inb,&action); 

      /* remember: tmpmat contains uncompressed local adj. */
      a1 = act_gauge_adj(&a_uncmpr[i], &link[dir][i], &ahiggs[nb(dir,i)]);
      a2 = act_gauge_adj(&a_uncmpr[i], &action,       &ahiggs[nb(dir,i)]);

      if (exp(a1-a2) >= dran()) {
	link[dir][i] = action;
	gahit++;
      }      
      gatry++;

#else

      left_su2_hit_n(&u,ina,inb,&link[dir][i]);
      left_su2_hit_n(&u,ina,inb,&link[dir][i]); 

#endif

    } /*   st */
  } /*  hits */
  
#ifdef HIGGS
  nhitua++;
  ahitua += 1.0*gahit/gatry;
#endif  

} /* relax */

