/******************************  su3.h **********************************
*									*
*  Defines and subroutine declarations for SU3 simulation		*
*  MIMD version 3 							*
*									*
*/
/* #define radix double   takes radix from complex.h */
typedef struct { complex e[3][3]; } su3_matrix;
typedef struct { complex c[3]; } su3_vector;
typedef struct
  { complex m01,m02,m12; radix m00im,m11im,m22im; radix space; } anti_hermitmat;
typedef struct { su3_vector d[4]; } wilson_vector;
typedef struct { su3_vector h[2]; } half_wilson_vector;
typedef struct { wilson_vector c[3]; } color_wilson_vector;
typedef struct { color_wilson_vector d[4]; } wilson_matrix;

typedef struct { radix l[8]; } adjoint_matrix;

#define GAMMAFIVE -1    /* some integer which is not a direction */
#define PLUS 1          /* flags for selecting M or M_adjoint */
#define MINUS -1
/* Macros to multiply complex numbers by +-1 and +-i */
#define TIMESPLUSONE(a,b) { (b).real =  (a).real; (b).imag = (a).imag; }
#define TIMESMINUSONE(a,b) { (b).real =  -(a).real; (b).imag = -(a).imag; }
#define TIMESPLUSI(a,b) { (b).real = -(a).imag; (b).imag =  (a).real; }
#define TIMESMINUSI(a,b) { (b).real =  (a).imag; (b).imag = -(a).real; }


/*
* ROUTINES FOR SU(3) MATRIX OPERATIONS
*
* void mult_su3_nn( a,b,c )
*	su3_matrix *a,*b,*c;
*	matrix multiply, no adjoints
*	files "m_mat_nn.c", "m_mat_nn.m4"
* void mult_su3_na( a,b,c )
*	su3_matrix *a,*b,*c;
*	matrix multiply, second matrix is adjoint
*	files "m_mat_na.c", "m_mat_na.m4"
* void mult_su3_an( a,b,c )
*	su3_matrix *a,*b,*c;
*	matrix multiply, first matrix is adjoint
*	files "m_mat_an.c", "m_mat_an.m4"
* radix realtrace_su3(a,b)
*	su3_matrix *a,*b;  (Re(Tr( A_adjoint*B)) )
*	file "realtr.c"
* complex trace_su3(a)
*	su3_matrix *a; 
*	file "trace_su3.c"
* complex complextrace_su3(a,b)
*	su3_matrix *a,*b;  (Tr( A_adjoint*B))
*	file "complextr.c"
* complex det_su3(a)
*	su3_matrix *a;
*	file "det_su3.c"
* void add_su3_matrix(a,b,c)
*	su3_matrix *a,*b,*c;
*	file "addmat.c"
* void sub_su3_matrix(a,b,c)
*	su3_matrix *a,*b,*c;
*	file "submat.c"
* void scalar_mult_su3_matrix(a,s,b)
*	su3_matrix *a,*b; radix s;
*	file "s_m_mat.c"
* void scalar_mult_add_su3_matrix(a,b,s,c)
*	su3_matrix *a,*b,*c; radix s;
*	file "s_m_a_mat.c"
* void scalar_mult_sub_su3_matrix(a,b,s,c)
*	su3_matrix *a,*b,*c; radix s;
*	file "s_m_s_mat.c"
* void c_scalar_mult_su3mat(m1,phase,m2)
*	su3_matrix *m1,*m2; complex *phase;
*	file "cs_m_mat.c"
* void c_scalar_mult_add_su3mat(m1,m2,phase,m3)
*	su3_matrix *m1,*m2,*m3; complex *phase;
*	file "cs_m_a_mat.c"
* void c_scalar_mult_sub_su3mat(m1,m2,phase,m3)
*	su3_matrix *m1,*m2,*m3; complex *phase;
*	file "cs_m_s_mat.c"
* void su3_adjoint(a,b)
*	su3_matrix *a,*b;
*	file "su3_adjoint.c"
* void make_anti_hermitian(m3,ah3)
*	su3_matrix *m3; anti_hermitmat *ah3;
*	file "make_ahmat.c"
* void random_anti_hermitian(mat_antihermit,prn_pt)
*	anti_hermitmat *mat_antihermit;
*	void *prn_pt;   (passed through to myrand())
*	file "rand_ahmat.c"
* void uncompress_anti_hermitian(mat_antihermit,mat_su3)
*	anti_hermitmat *mat_antihermit; su3_matrix *mat_su3;
*	file "uncmp_ahmat.c"
* void compress_anti_hermitian(mat_su3,mat_antihermit)
*	anti_hermitmat *mat_antihermit; su3_matrix *mat_su3;
*	file "cmp_ahmat.c"
* void su3mat_copy(a,b)
*	su3_matrix *a,*b;
*	file "su3mat_copy.c"
*
*
* ROUTINES FOR su3_vector OPERATIONS ( 3 COMPONENT COMPLEX )
*
* void c_scalar_mult_su3vec(v1,phase,v2)
*	su3_vector *v1,*v2; complex *phase;
*	file "cs_m_vec.c"
* void c_scalar_mult_add_su3vec(v1,phase,v2)
*	su3_vector *v1,*v2; complex *phase;
*	file "cs_m_a_vec.c"
* void c_scalar_mult_sub_su3vec(v1,phase,v2)
*	su3_vector *v1,*v2; complex *phase;
*	file "cs_m_s_vec.c"
* void su3_projector(a,b,c)
*	su3_vector *a,*b; su3_matrix *c;
*	( outer product of A and B)
*	file "su3_proj.c"
* void su3vec_copy(a,b)
*	su3_vector *a,*b;
*	file "su3vec_copy.c"
* 
* void mult_su3_mat_vec( a,b,c )
*	su3_matrix *a; su3_vector *b,*c;
*	file "m_matvec.c", "m_matvec.m4"
* void mult_su3_mat_vec_sum( a,b,c )
*	su3_matrix *a; su3_vector *b,*c;
*	file "m_matvec_s.c", "m_matvec_s.m4"
* void mult_su3_mat_vec_sum_4dir( a,b0,b1,b2,b3,c )
*	su3_matrix *a; su3_vector *b0,*b1,*b2,*b3,*c;
*	file "m_mv_s_4dir.c", "m_mv_s_4dir.m4"
*	file "m_mv_s_4di2.m4" is alternate version with pipelined loads.
*	Multiply four su3_vectors by elements of an array of su3_matrices,
*	sum results.
*	C <- A[0]*B0 + A[1]*B1 + A[2]*B2 + A[3]*B3
* void mult_su3_mat_vec_nsum( a,b,c )
*	su3_matrix *a; su3_vector *b,*c;
*	file "m_matvec_ns.c"
* void mult_adj_su3_mat_vec( a,b,c )
*	su3_matrix *a; su3_vector *b,*c;
*	file "m_amatvec.c", "m_amatvec.m4"
* void mult_adj_su3_mat_vec_4dir( a,b,c )
*	su3_matrix *a; su3_vector *b,*c;
*	file "m_amv_4dir.c", "m_amv_4dir.m4"
*	file "m_amv_4di2.m4" is alternate version with pipelined loads.
*	Multiply an su3_vector by adjoints of elements of an array 
*	of su3_matrices, results in an array of su3_vectors.
*	C[i] <- A_adjoint[i]*B, i = 0,1,2,3
* void mult_adj_su3_mat_vec_sum( a,b,c )
*	su3_matrix *a; su3_vector *b,*c;
*	file "m_amatvec_s.c"
* void mult_adj_su3_mat_vec_nsum( a,b,c )
*	su3_matrix *a; su3_vector *b,*c;
*	file "m_amatvec_ns.c"
* void add_su3_vector(a,b,c)
*	su3_vector *a,*b,*c;
*	file "addvec.c", "addvec.m4"
* void sub_su3_vector(a,b,c)
*	su3_vector *a,*b,*c;
*	file "subvec.c", "subvec.m4"
* void sub_four_su3_vecs(a,b1,b2,b3,b4)
*	su3_vector *a,*b1,*b2,*b3,*b4;
*	file "sub4vecs.c", "sub4vecs.m4"
* void scalar_mult_su3_vector(a,s,c)
*	su3_vector *a,*c; radix s;
*	file "s_m_vec.c"
* void scalar_mult_add_su3_vector(a,b,s,c)
*	su3_vector *a,*b,*c; radix s;
*	file "s_m_a_vec.c", "s_m_a_vec.m4"
* void scalar_mult_sum_su3_vector(a,b,s)
*	su3_vector *a,*b; radix s;
*	file "s_m_s_vec.c", "s_m_s_vec.m4"
* void scalar_mult_sub_su3_vector(a,b,s,c)
*	su3_vector *a,*b,*c; radix s;
*	file "s_m_s_vec.c"
* complex su3_dot(a,b)
*	su3_vector *a,*b;
*	file "su3_dot.c"
* radix su3_rdot(a,b)
*	su3_vector *a,*b;
*	file "su3_rdot.c", "su3_rdot.m4"
* radix magsq_su3vec(a)
*	su3_vector *a;
*	file "msq_su3vec.c", "msq_su3vec.m4"
*
*
* MISCELLANEOUS ROUTINES
*
* radix gaussian_rand_no(prn_pt)
*	void *prn_pt;  ( passed to myrand())
*	file "gaussrand.c"
*
* void dumpmat(m)
*	su3_matrix *m;
*	file "dumpmat.c"
* void dumpvec(v)
*	su3_vector *v;
*	file "dumpvec.c"
*/

/* Protoed by K.R */


void mult_su3_nn (su3_matrix *, su3_matrix *, su3_matrix *);
void mult_su3_na (su3_matrix *, su3_matrix *, su3_matrix *);
void mult_su3_an (su3_matrix *, su3_matrix *, su3_matrix *);
radix realtrace_su3(su3_matrix *, su3_matrix *);
complex trace_su3(su3_matrix *);
complex complextrace_su3(su3_matrix *, su3_matrix *);
complex det_su3(su3_matrix *);
void add_su3_matrix(su3_matrix *, su3_matrix *, su3_matrix *);
void sub_su3_matrix(su3_matrix *, su3_matrix *, su3_matrix *);
void su3_adjoint(su3_matrix *, su3_matrix *);
void make_anti_hermitian(su3_matrix *, anti_hermitmat *ah3);
void random_anti_hermitian(anti_hermitmat *mat_antihermit,void *prn_pt);
void uncompress_anti_hermitian(anti_hermitmat *mat_antihermit,su3_matrix *mat_su3);
void compress_anti_hermitian(su3_matrix *mat_su3,anti_hermitmat *mat_antihermit);
void su3mat_copy(su3_matrix *, su3_matrix *);
void clear_su3mat( su3_matrix *dest );
void clearvec( su3_vector *v );

void mult_su3_by_I(su3_matrix *,su3_matrix *);
void scalar_add_su3_matrix(su3_matrix *,radix , su3_matrix *);

void c_scalar_mult_su3vec    (su3_vector *, complex *,su3_vector *);
void c_scalar_mult_sub_su3vec(su3_vector *, complex *,su3_vector *);
void su3_projector(su3_vector *, su3_vector *, su3_matrix *);
void su3vec_copy(su3_vector *, su3_vector *);
void mult_su3_mat_vec(su3_matrix *,su3_vector *, su3_vector *);
void mult_su3_mat_vec_sum(su3_matrix *,su3_vector *, su3_vector *);
void mult_su3_mat_vec_sum_4dir(su3_matrix *,su3_vector *,su3_vector *,
			       su3_vector *,su3_vector *,su3_vector *);
void mult_su3_mat_vec_nsum(su3_matrix *,su3_vector *, su3_vector *);
void mult_adj_su3_mat_vec(su3_matrix *,su3_vector *, su3_vector *);
void mult_adj_su3_mat_vec_4dir(su3_matrix *,su3_vector *,su3_vector *);
void mult_adj_su3_mat_vec_sum(su3_matrix *,su3_vector *, su3_vector *);
void mult_adj_su3_mat_vec_nsum(su3_matrix *,su3_vector *, su3_vector *);
void add_su3_vector(su3_vector *,su3_vector *,su3_vector *);
void sub_su3_vector(su3_vector *,su3_vector *,su3_vector *);
void sub_four_su3_vecs(su3_vector *,su3_vector *,su3_vector *,
		       su3_vector *,su3_vector *);

void scalar_mult_su3_vector(  su3_vector *src, radix scalar, 
	su3_vector *dest);
void scalar_mult_add_su3_vector( su3_vector *src1, su3_vector *src2,
	radix scalar, su3_vector *dest);
void scalar_mult_sum_su3_vector( su3_vector *src1, su3_vector *src2,
	radix scalar);
void scalar_mult_sub_su3_vector( su3_vector *src1, su3_vector *src2,
	radix scalar, su3_vector *dest);
void scalar_mult_su3_matrix( su3_matrix *src, radix scalar,
	su3_matrix *dest);
void scalar_mult_add_su3_matrix( su3_matrix *src1, su3_matrix *src2,
	radix scalar, su3_matrix *dest);
void scalar_mult_sub_su3_matrix( su3_matrix *src1, su3_matrix *src2,
	radix scalar, su3_matrix *dest);
void c_scalar_mult_su3mat( su3_matrix *src, complex *scalar,
	su3_matrix *dest);
void c_scalar_mult_add_su3mat( su3_matrix *src1, su3_matrix *src2,
	complex *scalar, su3_matrix *dest);
void c_scalar_mult_sub_su3mat( su3_matrix *src1, su3_matrix *src2,
	complex *scalar, su3_matrix *dest);
void scalar_mult_add_wvec( wilson_vector *src1, wilson_vector *src2,
	radix scalar, wilson_vector *dest);
void scalar_mult_addtm_wvec( wilson_vector *src1, wilson_vector *src2,
	radix scalar, wilson_vector *dest);
void c_scalar_mult_add_su3vec(su3_vector *v1, complex *phase, su3_vector
*v2);
void c_scalar_mult_add_wvec(wilson_vector *src1, wilson_vector *src2, complex *phase, wilson_vector *dest);


/*
 * Adjoint Higgs protos
 */

double act_gauge_adj(su3_matrix *a, su3_matrix *u,adjoint_matrix *b);
void compress_adjmat(su3_matrix *m3,adjoint_matrix *a3);
void uncompress_adjmat(adjoint_matrix *a3,su3_matrix *m3);
void make_adjointmat(su3_matrix *m3,adjoint_matrix *a3);
void add_adjmat(adjoint_matrix *a,adjoint_matrix *b,adjoint_matrix *t);
void adj_scalar_mul(adjoint_matrix *a,double d,adjoint_matrix *t);
void adj_scalar_mul_add(adjoint_matrix *a,double d,adjoint_matrix *t);
radix adj_sqr(adjoint_matrix *a);
radix adj_dot(adjoint_matrix *a,adjoint_matrix *b);
void mult_su3_ahiggs( su3_matrix *m, adjoint_matrix *a, adjoint_matrix *r );
void mult_adj_su3_ahiggs( su3_matrix *m, adjoint_matrix *a, adjoint_matrix *r );

/* 
 *
 * Added new ANSI protos -- Kari R. 
 * first, some Wilson operations
 */

void mult_mat_wilson_vec( su3_matrix *mat, wilson_vector *src,
			 wilson_vector *dest);
void mult_su3_mat_hwvec( su3_matrix *mat, half_wilson_vector *src,
			half_wilson_vector *dest);
void mult_adj_mat_wilson_vec( su3_matrix *mat, wilson_vector *src,
			     wilson_vector *dest);
void mult_adj_su3_mat_hwvec( su3_matrix *mat,
			    half_wilson_vector *src, half_wilson_vector *dest);
void add_wilson_vector( wilson_vector *src1, wilson_vector *src2,
		       wilson_vector *dest);
void sub_wilson_vector( wilson_vector *src1, wilson_vector *src2,
		       wilson_vector *dest);
void scalar_mult_wvec( wilson_vector *src, radix s, wilson_vector *dest);
void scalar_mult_hwvec( half_wilson_vector *src, radix s,
		       half_wilson_vector *dest);
radix magsq_wvec( wilson_vector *src);
complex wvec_dot( wilson_vector *src1, wilson_vector *src2 );
complex wvec2_dot( wilson_vector *src1, wilson_vector *src2 );
radix wvec_rdot( wilson_vector *src1, wilson_vector *src2 );
void su3_projector_w(wilson_vector *a, wilson_vector *b, su3_matrix *c);
void copy_wvec( wilson_vector *src, wilson_vector *dest);
void clear_wvec( wilson_vector *dest);
void wp_shrink( wilson_vector *src, half_wilson_vector *dest,int dir, int sign);
void wp_shrink_4dir(wilson_vector *a,half_wilson_vector *b1,
		    half_wilson_vector *b2,half_wilson_vector *b3,
		    half_wilson_vector *b4,int sign);
void wp_grow( half_wilson_vector *src, wilson_vector *dest,int dir, int sign);
void wp_grow_add( half_wilson_vector *src, wilson_vector *dest,
		 int dir, int sign);
void grow_add_four_wvecs(wilson_vector *a,half_wilson_vector *b1,
			 half_wilson_vector *b2,half_wilson_vector *b3,
			 half_wilson_vector *b4,int sign,int sum);
void mult_by_gamma( wilson_vector *src, wilson_vector *dest, int dir );
void mult_by_gamma_left( wilson_matrix *src, wilson_matrix *dest, int dir );
void mult_by_gamma_right(wilson_matrix *src, wilson_matrix *dest, int dir );
void dump_wilson_vec( wilson_vector *src);

/* SOME SU3 PROTOS
 * Kari R.
 */
 
complex su3_dot(su3_vector *a,su3_vector *b);
radix su3_rdot(su3_vector *a,su3_vector *b);
radix magsq_su3vec(su3_vector *a);

void reunit_su3( su3_matrix *l );
void reunitarize( su3_matrix *link[] );
void random_su3P( su3_matrix *l, int hits );

   
/*
 * MISCELLANEOUS ROUTINES
 * Kari R. : wrote protos
 */

radix gaussian_rand_no( void *);
void dumpmat(su3_matrix *m);
void dumpvec(su3_vector *v);

int prefetch_matrix(su3_matrix *);
int prefetch_vector(su3_vector *);
int prefetch_adjoint(adjoint_matrix *);


