#include "./include/includes.h"
/* create gaussian random wilson vector */
void grand_wvec( wilson_vector * chi, int parity )
{
    register int i, j, k;
    register site *s;
    FORSOMEPARITY( i, s, parity )
    {
	for ( k = 0; k < 4; k++ )
	    for ( j = 0; j < 3; j++ )
	    {
#ifdef FUNNY
		chi[i].COLORSPINOR( j, k ).real = ( double ) ( ( s->x ) * ( s->t ) ) / 137.0 - k * 0.1 + 0.2;
		chi[i].COLORSPINOR( j, k ).imag = -( double ) ( ( s->y ) + ( s->z ) ) / 42.0 + j * 0.2 - 0.1;
#else
		chi[i].COLORSPINOR( j, k ).real = gaussian_rand_no_KE(  );
		chi[i].COLORSPINOR( j, k ).imag = gaussian_rand_no_KE(  );
#endif
	    }
    }
}

/* all real element is 1 */
void unit_wvec(wilson_vector *wvec, int parity)
{
    int i;
    site *s;
    FORSOMEPARITY(i,s,parity)
    {
        clear_wvec(wvec+i);
        (wvec+i)->COLORSPINOR(0,0).real=1.0;
        (wvec+i)->COLORSPINOR(1,0).real=1.0;
        (wvec+i)->COLORSPINOR(2,0).real=1.0;
        (wvec+i)->COLORSPINOR(0,1).real=1.0;
        (wvec+i)->COLORSPINOR(1,1).real=1.0;
        (wvec+i)->COLORSPINOR(2,1).real=1.0;
        (wvec+i)->COLORSPINOR(0,2).real=1.0;
        (wvec+i)->COLORSPINOR(1,2).real=1.0;
        (wvec+i)->COLORSPINOR(2,2).real=1.0;
        (wvec+i)->COLORSPINOR(0,3).real=1.0;
        (wvec+i)->COLORSPINOR(1,3).real=1.0;
        (wvec+i)->COLORSPINOR(2,3).real=1.0;
    }
}

/* create gaussian random wilson vector */
void clear_latwvec( wilson_vector * chi, int parity )
{
    register int i, j, k;
    register site *s;
    FORSOMEPARITY( i, s, parity )
    {
	for ( k = 0; k < 4; k++ )
	    for ( j = 0; j < 3; j++ )
	    {
		chi[i].COLORSPINOR( j, k ).real = 0.0;
		chi[i].COLORSPINOR( j, k ).imag = 0.0;
	    }
    }
}

/* funny vector */
void funny_wvec( wilson_vector * chi )
{
    register int i, j, k;
    register site *s;
    FORALLSITES( i, s )
    {
	for ( k = 0; k < 4; k++ )
	    for ( j = 0; j < 3; j++ )
	    {
		chi[i].COLORSPINOR( j, k ).real = ( double ) ( ( s->x ) * ( s->t ) ) / 137.0 - k * 0.1 + 0.2;
		chi[i].COLORSPINOR( j, k ).imag = -( double ) ( ( s->y ) + ( s->z ) ) / 42.0 + j * 0.2 - 0.1;
	    }

    }
}


/* some linear algebra */
void latutil_xpay_32(float * x, float a, float * y, int parity)
{
    int i, lat_begin, lat_end;
    
    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node*24;
    lat_end = sites_on_node*24;
    if( parity == EVEN )
	lat_end = even_sites_on_node*24;
    for (i=lat_begin;i<lat_end; i++)
        y[i]=a*y[i]+x[i];
}

void latutil_axpy_32(float a, float * x, float * y, int parity)
{
    int i, lat_begin, lat_end;
    
    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node*24;
    lat_end = sites_on_node*24;
    if( parity == EVEN )
	lat_end = even_sites_on_node*24;
    for (i=lat_begin;i<lat_end; i++)
        y[i]=y[i]+a*x[i];
}

void latutil_5xpay_32(float * x, float a, float * y, int parity)
{
    int i, lat_begin, lat_end;
    
    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node;
    lat_end = sites_on_node;
    if( parity == EVEN )
	lat_end = even_sites_on_node;
   
    for (i=lat_begin;i<lat_end; i++)
    {
#ifdef SPINORFIRST
        y[24*i+ 0]= (y[24*i+ 0]*a+x[24*i+ 0]);
        y[24*i+ 1]= (y[24*i+ 1]*a+x[24*i+ 1]);
        y[24*i+ 2]= (y[24*i+ 2]*a+x[24*i+ 2]);
        y[24*i+ 3]= (y[24*i+ 3]*a+x[24*i+ 3]);
        y[24*i+ 4]= (y[24*i+ 4]*a+x[24*i+ 4]);
        y[24*i+ 5]= (y[24*i+ 5]*a+x[24*i+ 5]);
        y[24*i+ 6]= (y[24*i+ 6]*a+x[24*i+ 6]);
        y[24*i+ 7]= (y[24*i+ 7]*a+x[24*i+ 7]);
        y[24*i+ 8]= (y[24*i+ 8]*a+x[24*i+ 8]);
        y[24*i+ 9]= (y[24*i+ 9]*a+x[24*i+ 9]);
        y[24*i+10]= (y[24*i+10]*a+x[24*i+10]);
        y[24*i+11]= (y[24*i+11]*a+x[24*i+11]);
        y[24*i+12]=-(y[24*i+12]*a+x[24*i+12]);
        y[24*i+13]=-(y[24*i+13]*a+x[24*i+13]);
        y[24*i+14]=-(y[24*i+14]*a+x[24*i+14]);
        y[24*i+15]=-(y[24*i+15]*a+x[24*i+15]);
        y[24*i+16]=-(y[24*i+16]*a+x[24*i+16]);
        y[24*i+17]=-(y[24*i+17]*a+x[24*i+17]);
        y[24*i+18]=-(y[24*i+18]*a+x[24*i+18]);
        y[24*i+19]=-(y[24*i+19]*a+x[24*i+19]);
        y[24*i+20]=-(y[24*i+20]*a+x[24*i+20]);
        y[24*i+21]=-(y[24*i+21]*a+x[24*i+21]);
        y[24*i+22]=-(y[24*i+22]*a+x[24*i+22]);
        y[24*i+23]=-(y[24*i+23]*a+x[24*i+23]);
#else
        y[24*i+ 0]= (y[24*i+ 0]*a+x[24*i+ 0]);
        y[24*i+ 1]= (y[24*i+ 1]*a+x[24*i+ 1]);
        y[24*i+ 2]= (y[24*i+ 2]*a+x[24*i+ 2]);
        y[24*i+ 3]= (y[24*i+ 3]*a+x[24*i+ 3]);
        y[24*i+ 4]=-(y[24*i+ 4]*a+x[24*i+ 4]);
        y[24*i+ 5]=-(y[24*i+ 5]*a+x[24*i+ 5]);
        y[24*i+ 6]=-(y[24*i+ 6]*a+x[24*i+ 6]);
        y[24*i+ 7]=-(y[24*i+ 7]*a+x[24*i+ 7]);
        y[24*i+ 8]= (y[24*i+ 8]*a+x[24*i+ 8]);
        y[24*i+ 9]= (y[24*i+ 9]*a+x[24*i+ 9]);
        y[24*i+10]= (y[24*i+10]*a+x[24*i+10]);
        y[24*i+11]= (y[24*i+11]*a+x[24*i+11]);
        y[24*i+12]=-(y[24*i+12]*a+x[24*i+12]);
        y[24*i+13]=-(y[24*i+13]*a+x[24*i+13]);
        y[24*i+14]=-(y[24*i+14]*a+x[24*i+14]);
        y[24*i+15]=-(y[24*i+15]*a+x[24*i+15]);
        y[24*i+16]= (y[24*i+16]*a+x[24*i+16]);
        y[24*i+17]= (y[24*i+17]*a+x[24*i+17]);
        y[24*i+18]= (y[24*i+18]*a+x[24*i+18]);
        y[24*i+19]= (y[24*i+19]*a+x[24*i+19]);
        y[24*i+20]=-(y[24*i+20]*a+x[24*i+20]);
        y[24*i+21]=-(y[24*i+21]*a+x[24*i+21]);
        y[24*i+22]=-(y[24*i+22]*a+x[24*i+22]);
        y[24*i+23]=-(y[24*i+23]*a+x[24*i+23]);

#endif
    }
}

double latutil_rdot_32(float * x, float * y, int parity)
{
    int i, lat_begin, lat_end;
    double a;
    
    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node * 24;
    lat_end = sites_on_node * 24;
    if( parity == EVEN )
	lat_end = even_sites_on_node * 24;

    a=0.0;
    for (i=lat_begin;i<lat_end; i++)
    {
        a+=x[i]*y[i];
    }
    
    return a;
}

complex latutil_dot_32(float * x, float * y, int parity)
{
    int i, lat_begin, lat_end;
    complex a;
    
    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node * 12;
    lat_end = sites_on_node * 12;
    if( parity == EVEN )
	lat_end = even_sites_on_node * 12;

    a.real=a.imag=0.0;
    for (i=lat_begin;i<lat_end; i++)
    {
        a.real+=x[2*i+0]*y[2*i+0]+x[2*i+1]*y[2*i+1];
        a.imag+=x[2*i+0]*y[2*i+1]-x[2*i+1]*y[2*i+0];
    }
    
    return a;
}

double latutil_nrm2_32(float * x, int parity)
{
    int i, lat_begin, lat_end;
    double a;
    
    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node * 24;
    lat_end = sites_on_node * 24;
    if( parity == EVEN )
	lat_end = even_sites_on_node * 24;

    a=0.0;
    for (i=lat_begin;i<lat_end; i++)
    {
        a+=x[i]*x[i];
    }
    
    return a;
}

double latutil_axpy_nrm2_32(float a, float * x, float * y, int parity)
{
    int i, lat_begin, lat_end;
    double b;
    
    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node * 24;
    lat_end = sites_on_node * 24;
    if( parity == EVEN )
	lat_end = even_sites_on_node * 24;
   
    b=0.0;
    for (i=lat_begin;i<lat_end; i++)
    {
        y[i]=y[i]+x[i]*a;
        b+=y[i]*y[i];
    }

    return b;
}

/* linalg for Csebisev polinoms */
void latutil_cheb(double *tmp1, double *d, double *dd, double *qsrc, 
        double f1, double f2, double fch)
{
    register int i;
    for (i=0;i<24*sites_on_node;i++)
        dd[i]=fch*qsrc[i]+f1*tmp1[i]+f2*d[i]-dd[i];
}

void latutil_cheb_32(float *tmp1, float *d, float *dd, float *qsrc, 
        float f1, float f2, float fch)
{
    register int i;
    for (i=0;i<24*sites_on_node;i++)
        dd[i]=fch*qsrc[i]+f1*tmp1[i]+f2*d[i]-dd[i];
}

/* linalg for mcongrad */
void latutil_mcg2( wilson_vector ** destm, wilson_vector ** mcg_pm, double *fpa, int varnsigma, int parity )
{
    int i, j, lat_begin, lat_end;
    double a;
    complex *x;
    complex *y;

    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node * 12;
    lat_end = sites_on_node * 12;
    if( parity == EVEN )
	lat_end = even_sites_on_node * 12;

    for ( j = 0; j < varnsigma; j++ )
    {
	x = ( complex * ) ( destm[j] );
	y = ( complex * ) ( mcg_pm[j] );
	a = fpa[j];
	for ( i = lat_begin; i < lat_end; i++ )
	{
	    x[i].real = x[i].real + a * y[i].real;
	    x[i].imag = x[i].imag + a * y[i].imag;
	}
    }
}

void latutil_mcg3( wilson_vector * mcg_r, wilson_vector ** mcg_pm, double *fpa, double *fpb, int varnsigma, int parity )
{
    int i, j, lat_begin, lat_end;
    double a, b;
    complex *x;
    complex *y;

    lat_begin = 0;
    if( parity == ODD )
	lat_begin = even_sites_on_node * 12;
    lat_end = sites_on_node * 12;
    if( parity == EVEN )
	lat_end = even_sites_on_node * 12;

    x = ( complex * ) mcg_r;
    for ( j = 0; j < varnsigma; j++ )
    {
	y = ( complex * ) ( mcg_pm[j] );
	a = fpa[j] * fpb[j];
	b = fpb[j];
	for ( i = lat_begin; i < lat_end; i++ )
	{
	    y[i].real = b * y[i].real + a * x[i].real;
	    y[i].imag = b * y[i].imag + a * x[i].imag;
	}
    }
}
