/**************************************************************
 *                                                            *
 *   adjoint overrelaxation routine                           *
 *                                                            *
 *************************************************************/

#include "lattice.h"


double Xoverrelax(int parity, adjoint_matrix *ahiggs, adjoint_matrix *adjstaple)
{
  double rp,x,x2,y2,xn,a,b,c,vi,b0,b1,b2,f1,f1p3,f2,f3,f4,f5,f6;
  double xa,xb,pr,r2,a1;
  int i,j,nhits;
  double rsum;

  nhits = rsum = 0;

  /* the coeffs of the polynomial 
   * s = -betaA v p + beta2 v^2 + beta4 v^4
   */

  vi  = 1.0/beta4;

  forparity(i,parity) {

    prefetch_adjoint(&ahiggs[i+1]);
    prefetch_adjoint(&adjstaple[i+1]);

    rp = a1 = r2 = 0.0;
    for (j=0; j<8; j++) {
      a1 += ahiggs[i].l[j] * adjstaple[i].l[j];
      r2 += sqr(ahiggs[i].l[j]);
      rp += sqr(adjstaple[i].l[j]);
    }
    rp = sqrt(rp);

    /* vector angle is given by V*P  =  cos theta; x = V*\hatP */

    x  = a1/rp;
    x2 = sqr(x);
    y2 = r2 - x2;

    /*     NOW rr  == -betaA * rp;
     *         vx2 ==  beta2
     *         vx4 ==  beta4
     *     act = rr*x + vx2*(x2+y2) + vx4*(x2+y2)^2
     *     calculate the coeffs. of the 4-th order action polynomial
     *     act = rr*x + vx2*(x2+y2) + vx4*(x2+y2)^2
     *     => vx4 x^4 + (vx2 + 2*vx4*y2) x^2 + rr x == v0
     *     => x^4 + [(vx2 + 2*vx4*y2)/vx4] x^2 + rr/vx4 x
     *        + [-v0/vx4] == 0
     */

    b2 =  beta2*vi + 2.0*y2;
    b1 = -betaA*rp*vi;
    b0 = -(b1*x + x2*(b2 + x2));

    /* (x-x0)(x^3 + ax^2 + bx + c) = x^4 + b2 x^2 + b1 x + b0 */

    a  = x;
    b  = b2 + x2;
    c  = b1 + x*b;

    /* if (abs(1.0 + c/(b0/a)) .gt. 1e-10) write(*,*)'c-errror',c,b0/a */
    
    /*     Now find the zeros of the 3-deg polynomial
     *     (x^3 + ax^2 + bx + c)
     */
    
    f1   = -sqr(a) + 3.0*b;
    f1p3 = f1*f1*f1;
    f2   = -2.0*a*a*a + 9.0*a*b;
    f6   = f2 - 27.0*c;
    f4   = 4.0*f1p3 + sqr(f6);

    if (f4 >= 0.0) {

      /* only one real solution exists now, this is all what is accepted */

      f5 = sqrt(f4) + f6;
      if (f5 > 0.0) {
	f3 = pow(0.5*f5,((double)1.0)/((double)3.0));
	xn = (-a - f1/f3 + f3)*(1.0/3.0);

	/*     Now accept/reject the update with the derivatives
	 *     d[x^4 + b2 x^2 + b1 x + b0] = 4 x^3 + 2 b2 x + b1
	 */

	xa = x*(4.0*x2  + 2.0*b2) + b1;
	xb = xn*(4.0*sqr(xn) + 2.0*b2) + b1;
	pr = fabs(xa/xb);

	if (pr >= dran()) {
	  nhits++;

	  /*     generate new adj. -- now we have x and xn wrt. p =>
	   *     v  <-  v + (xn-x) \hat p
	   */
	  
	  for (j=0; j<8; j++) {
	    ahiggs[i].l[j] += adjstaple[i].l[j] * ((xn-x)/rp);
	  }

	  r2 = y2 + xn*xn;
	} 

	rsum += r2;    /* cumulate r2-value */

      } else {
	printf(" *** OR branch 1, value of f4: %g    f5: %g\n",f4,f5);
	halt("****** OR stop");
      }
    } else {
      printf(" OR branch 2, value of f4: %g    f5: %g\n",f4,f5);
      halt("****** OR stop");
    }
  } /* FORSOMEPARITY */

  if (parity == EVEN) ahitax += 1.0*nhits/(node.evensites);
  else ahitax += 1.0*nhits/(node.oddsites);
  nhitax++;

  return(rsum);

}




